2 * WinBoard.c -- Windows NT front end to XBoard
\r
3 * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
\r
5 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
6 * Massachusetts. Enhancements Copyright
\r
7 * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software
\r
10 * The following terms apply to Digital Equipment Corporation's copyright
\r
11 * interest in XBoard:
\r
12 * ------------------------------------------------------------------------
\r
13 * All Rights Reserved
\r
15 * Permission to use, copy, modify, and distribute this software and its
\r
16 * documentation for any purpose and without fee is hereby granted,
\r
17 * provided that the above copyright notice appear in all copies and that
\r
18 * both that copyright notice and this permission notice appear in
\r
19 * supporting documentation, and that the name of Digital not be
\r
20 * used in advertising or publicity pertaining to distribution of the
\r
21 * software without specific, written prior permission.
\r
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
30 * ------------------------------------------------------------------------
\r
32 * The following terms apply to the enhanced version of XBoard
\r
33 * distributed by the Free Software Foundation:
\r
34 * ------------------------------------------------------------------------
\r
36 * GNU XBoard 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 3 of the License, or (at
\r
39 * your option) any later version.
\r
41 * GNU XBoard is distributed in the hope that it will be useful, but
\r
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
44 * 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, see http://www.gnu.org/licenses/. *
\r
49 *------------------------------------------------------------------------
\r
50 ** See the file ChangeLog for a revision history. */
\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 /* [AS] Restore layout */
\r
692 if( wpMoveHistory.visible ) {
\r
693 MoveHistoryPopUp();
\r
696 if( wpEvalGraph.visible ) {
\r
700 if( wpEngineOutput.visible ) {
\r
701 EngineOutputPopUp();
\r
706 /* Make the window visible; update its client area; and return "success" */
\r
707 EnsureOnScreen(&boardX, &boardY);
\r
708 wp.length = sizeof(WINDOWPLACEMENT);
\r
710 wp.showCmd = nCmdShow;
\r
711 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
712 wp.rcNormalPosition.left = boardX;
\r
713 wp.rcNormalPosition.right = boardX + winWidth;
\r
714 wp.rcNormalPosition.top = boardY;
\r
715 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
716 SetWindowPlacement(hwndMain, &wp);
\r
718 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
719 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
722 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
723 if( gameInfo.variant != VariantFischeRandom ) {
\r
724 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
729 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
730 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
732 ShowWindow(hwndConsole, nCmdShow);
\r
734 UpdateWindow(hwnd);
\r
742 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
743 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
744 ArgSettingsFilename
\r
752 String *pString; // ArgString
\r
753 int *pInt; // ArgInt
\r
754 float *pFloat; // ArgFloat
\r
755 Boolean *pBoolean; // ArgBoolean
\r
756 COLORREF *pColor; // ArgColor
\r
757 ColorClass cc; // ArgAttribs
\r
758 String *pFilename; // ArgFilename
\r
759 BoardSize *pBoardSize; // ArgBoardSize
\r
760 int whichFont; // ArgFont
\r
761 DCB *pDCB; // ArgCommSettings
\r
762 String *pFilename; // ArgSettingsFilename
\r
770 ArgDescriptor argDescriptors[] = {
\r
771 /* positional arguments */
\r
772 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
773 { "", ArgNone, NULL },
\r
774 /* keyword arguments */
\r
775 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
776 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
777 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
778 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
779 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
780 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
781 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
782 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
783 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
784 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
785 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
786 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
787 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
788 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
789 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
790 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
791 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
792 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
794 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
796 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
798 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
799 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
801 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
802 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
803 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
804 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
805 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
806 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
807 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
808 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
809 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
810 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
811 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
812 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
813 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
814 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
815 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
816 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
817 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
818 /*!!bitmapDirectory?*/
\r
819 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
820 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
821 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
822 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
823 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
824 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
825 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
826 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
827 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
828 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
829 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
830 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
831 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
832 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
833 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
834 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
835 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
836 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
837 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
838 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
839 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
840 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
841 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
842 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
843 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
844 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
845 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
846 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
847 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
848 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
849 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
850 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
851 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
852 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
853 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
854 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
855 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
856 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
857 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
858 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
859 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
860 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
861 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
862 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
863 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
864 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
865 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
866 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
867 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
868 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
869 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
870 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
871 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
872 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
873 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
874 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
875 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
876 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
877 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
878 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
879 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
880 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
881 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
882 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
883 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
884 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
885 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
886 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
887 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
888 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
889 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
890 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
891 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
892 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
893 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
894 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
895 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
896 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
897 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
898 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
899 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
900 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
901 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
902 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
903 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
904 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
905 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
906 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
907 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
908 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
909 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
910 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
911 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
912 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
913 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
914 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
915 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
916 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
917 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
918 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
919 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
920 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
921 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
922 TRUE }, /* must come after all fonts */
\r
923 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
924 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
925 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
926 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
927 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
928 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
929 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
930 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
931 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
932 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
933 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
934 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
935 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
936 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
937 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
938 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
939 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
940 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
941 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
942 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
943 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
944 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
945 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
946 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
947 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
948 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
949 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
950 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
951 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
952 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
953 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
955 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
956 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
958 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
959 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
960 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
961 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
962 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
963 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
964 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
965 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
966 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
967 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
968 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
969 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
970 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
971 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
972 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
973 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
974 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
975 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
976 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
977 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
978 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
979 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
980 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
981 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
982 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
983 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
984 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
985 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
986 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
987 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
988 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
989 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
990 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
991 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
992 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
993 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
994 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
995 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
996 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
997 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
998 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
999 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1000 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1001 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1002 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1003 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1004 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1005 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1006 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1007 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1008 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1009 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1010 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1011 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1012 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1013 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1014 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1015 { "highlightLastMove", ArgBoolean,
\r
1016 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1017 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1018 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1019 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1020 { "highlightDragging", ArgBoolean,
\r
1021 (LPVOID) &appData.highlightDragging, TRUE },
\r
1022 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1023 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1024 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1025 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1026 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1027 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1028 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1029 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1030 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1031 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1032 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1033 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1034 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1035 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1036 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1037 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1038 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1039 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1040 { "soundShout", ArgFilename,
\r
1041 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1042 { "soundSShout", ArgFilename,
\r
1043 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1044 { "soundChannel1", ArgFilename,
\r
1045 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1046 { "soundChannel", ArgFilename,
\r
1047 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1048 { "soundKibitz", ArgFilename,
\r
1049 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1050 { "soundTell", ArgFilename,
\r
1051 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1052 { "soundChallenge", ArgFilename,
\r
1053 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1054 { "soundRequest", ArgFilename,
\r
1055 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1056 { "soundSeek", ArgFilename,
\r
1057 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1058 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1059 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1060 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1061 { "soundIcsLoss", ArgFilename,
\r
1062 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1063 { "soundIcsDraw", ArgFilename,
\r
1064 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1065 { "soundIcsUnfinished", ArgFilename,
\r
1066 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1067 { "soundIcsAlarm", ArgFilename,
\r
1068 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1069 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1070 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1071 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1072 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1073 { "reuseChessPrograms", ArgBoolean,
\r
1074 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1075 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1076 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1077 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1078 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1079 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1080 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1081 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1082 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1083 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1084 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1085 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1086 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1087 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1088 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1089 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1090 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1091 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1092 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1093 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1094 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1095 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1096 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1097 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1098 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1099 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1100 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1101 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1102 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1103 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1104 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1105 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1106 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1107 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1108 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1109 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1110 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1111 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1113 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1115 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1116 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1117 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1118 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1119 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1120 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1121 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1122 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1123 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1124 /* [AS] New features */
\r
1125 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1126 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1127 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1128 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1129 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1130 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1131 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1132 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1133 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1134 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1135 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1136 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1137 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1138 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1139 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1140 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1141 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1142 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1143 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1144 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1145 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1146 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1147 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1148 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1149 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1150 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1151 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1152 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1153 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1154 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1155 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1156 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1157 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1158 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1159 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1160 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1161 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1162 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1163 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1164 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1165 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1166 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1167 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1168 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1169 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1170 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1171 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1172 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1173 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1174 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1176 /* [AS] Layout stuff */
\r
1177 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1178 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1179 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1180 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1181 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1183 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1184 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1185 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1186 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1187 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1189 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1190 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1191 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1192 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1193 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1195 /* [HGM] board-size, adjudication and misc. options */
\r
1196 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1197 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1198 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1199 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1200 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1201 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1202 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1203 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1204 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1205 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1206 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1207 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1208 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1209 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1210 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1211 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1212 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1213 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1214 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1215 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1216 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1217 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1218 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1219 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1220 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1221 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1222 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1223 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1224 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1227 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1228 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1229 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1230 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1231 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1232 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1233 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1234 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1235 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1236 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1237 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1238 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1239 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1241 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1242 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1243 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1244 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1245 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1246 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1247 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1249 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1250 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1251 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1252 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1253 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1254 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1255 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1256 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1257 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1258 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1259 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1260 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1261 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1262 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1263 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1264 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1265 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1266 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1268 /* [HGM] options for broadcasting and time odds */
\r
1269 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1270 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1271 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1272 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1273 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1274 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1275 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1276 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1277 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1278 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1279 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, 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 appData.icsEngineAnalyze = FALSE;
\r
1842 dcb.DCBlength = sizeof(DCB);
\r
1843 dcb.BaudRate = 9600;
\r
1844 dcb.fBinary = TRUE;
\r
1845 dcb.fParity = FALSE;
\r
1846 dcb.fOutxCtsFlow = FALSE;
\r
1847 dcb.fOutxDsrFlow = FALSE;
\r
1848 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1849 dcb.fDsrSensitivity = FALSE;
\r
1850 dcb.fTXContinueOnXoff = TRUE;
\r
1851 dcb.fOutX = FALSE;
\r
1853 dcb.fNull = FALSE;
\r
1854 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1855 dcb.fAbortOnError = FALSE;
\r
1856 /* Microsoft SDK >= Feb. 2003 (MS VS >= 2002) */
\r
1857 #if (defined(_MSC_VER) && _MSC_VER <= 1200)
\r
1858 //dcb.wReserved = 0;
\r
1860 dcb.wReserved = 0;
\r
1863 dcb.Parity = SPACEPARITY;
\r
1864 dcb.StopBits = ONESTOPBIT;
\r
1865 settingsFileName = SETTINGS_FILE;
\r
1866 saveSettingsOnExit = TRUE;
\r
1867 boardX = CW_USEDEFAULT;
\r
1868 boardY = CW_USEDEFAULT;
\r
1869 consoleX = CW_USEDEFAULT;
\r
1870 consoleY = CW_USEDEFAULT;
\r
1871 consoleW = CW_USEDEFAULT;
\r
1872 consoleH = CW_USEDEFAULT;
\r
1873 analysisX = CW_USEDEFAULT;
\r
1874 analysisY = CW_USEDEFAULT;
\r
1875 analysisW = CW_USEDEFAULT;
\r
1876 analysisH = CW_USEDEFAULT;
\r
1877 commentX = CW_USEDEFAULT;
\r
1878 commentY = CW_USEDEFAULT;
\r
1879 commentW = CW_USEDEFAULT;
\r
1880 commentH = CW_USEDEFAULT;
\r
1881 editTagsX = CW_USEDEFAULT;
\r
1882 editTagsY = CW_USEDEFAULT;
\r
1883 editTagsW = CW_USEDEFAULT;
\r
1884 editTagsH = CW_USEDEFAULT;
\r
1885 gameListX = CW_USEDEFAULT;
\r
1886 gameListY = CW_USEDEFAULT;
\r
1887 gameListW = CW_USEDEFAULT;
\r
1888 gameListH = CW_USEDEFAULT;
\r
1889 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1890 icsNames = ICS_NAMES;
\r
1891 firstChessProgramNames = FCP_NAMES;
\r
1892 secondChessProgramNames = SCP_NAMES;
\r
1893 appData.initialMode = "";
\r
1894 appData.variant = "normal";
\r
1895 appData.firstProtocolVersion = PROTOVER;
\r
1896 appData.secondProtocolVersion = PROTOVER;
\r
1897 appData.showButtonBar = TRUE;
\r
1899 /* [AS] New properties (see comments in header file) */
\r
1900 appData.firstScoreIsAbsolute = FALSE;
\r
1901 appData.secondScoreIsAbsolute = FALSE;
\r
1902 appData.saveExtendedInfoInPGN = FALSE;
\r
1903 appData.hideThinkingFromHuman = FALSE;
\r
1904 appData.liteBackTextureFile = "";
\r
1905 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1906 appData.darkBackTextureFile = "";
\r
1907 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1908 appData.renderPiecesWithFont = "";
\r
1909 appData.fontToPieceTable = "";
\r
1910 appData.fontBackColorWhite = 0;
\r
1911 appData.fontForeColorWhite = 0;
\r
1912 appData.fontBackColorBlack = 0;
\r
1913 appData.fontForeColorBlack = 0;
\r
1914 appData.fontPieceSize = 80;
\r
1915 appData.overrideLineGap = 1;
\r
1916 appData.adjudicateLossThreshold = 0;
\r
1917 appData.delayBeforeQuit = 0;
\r
1918 appData.delayAfterQuit = 0;
\r
1919 appData.nameOfDebugFile = "winboard.debug";
\r
1920 appData.pgnEventHeader = "Computer Chess Game";
\r
1921 appData.defaultFrcPosition = -1;
\r
1922 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1923 appData.saveOutOfBookInfo = TRUE;
\r
1924 appData.showEvalInMoveHistory = TRUE;
\r
1925 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1926 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1927 appData.highlightMoveWithArrow = FALSE;
\r
1928 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1929 appData.useStickyWindows = TRUE;
\r
1930 appData.adjudicateDrawMoves = 0;
\r
1931 appData.autoDisplayComment = TRUE;
\r
1932 appData.autoDisplayTags = TRUE;
\r
1933 appData.firstIsUCI = FALSE;
\r
1934 appData.secondIsUCI = FALSE;
\r
1935 appData.firstHasOwnBookUCI = TRUE;
\r
1936 appData.secondHasOwnBookUCI = TRUE;
\r
1937 appData.polyglotDir = "";
\r
1938 appData.usePolyglotBook = FALSE;
\r
1939 appData.polyglotBook = "";
\r
1940 appData.defaultHashSize = 64;
\r
1941 appData.defaultCacheSizeEGTB = 4;
\r
1942 appData.defaultPathEGTB = "c:\\egtb";
\r
1943 appData.firstOptions = "";
\r
1944 appData.secondOptions = "";
\r
1946 InitWindowPlacement( &wpMoveHistory );
\r
1947 InitWindowPlacement( &wpEvalGraph );
\r
1948 InitWindowPlacement( &wpEngineOutput );
\r
1950 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1951 appData.NrFiles = -1;
\r
1952 appData.NrRanks = -1;
\r
1953 appData.holdingsSize = -1;
\r
1954 appData.testClaims = FALSE;
\r
1955 appData.checkMates = FALSE;
\r
1956 appData.materialDraws= FALSE;
\r
1957 appData.trivialDraws = FALSE;
\r
1958 appData.ruleMoves = 51;
\r
1959 appData.drawRepeats = 6;
\r
1960 appData.matchPause = 10000;
\r
1961 appData.alphaRank = FALSE;
\r
1962 appData.allWhite = FALSE;
\r
1963 appData.upsideDown = FALSE;
\r
1964 appData.serverPause = 15;
\r
1965 appData.serverMovesName = NULL;
\r
1966 appData.suppressLoadMoves = FALSE;
\r
1967 appData.firstTimeOdds = 1;
\r
1968 appData.secondTimeOdds = 1;
\r
1969 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
1970 appData.secondAccumulateTC = 1;
\r
1971 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
1972 appData.secondNPS = -1;
\r
1973 appData.engineComments = 1;
\r
1974 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
1975 appData.egtFormats = "";
\r
1978 appData.zippyTalk = ZIPPY_TALK;
\r
1979 appData.zippyPlay = ZIPPY_PLAY;
\r
1980 appData.zippyLines = ZIPPY_LINES;
\r
1981 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1982 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1983 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1984 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1985 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1986 appData.zippyUseI = ZIPPY_USE_I;
\r
1987 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1988 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1989 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1990 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1991 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1992 appData.zippyAbort = ZIPPY_ABORT;
\r
1993 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1994 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1995 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1998 /* Point font array elements to structures and
\r
1999 parse default font names */
\r
2000 for (i=0; i<NUM_FONTS; i++) {
\r
2001 for (j=0; j<NUM_SIZES; j++) {
\r
2002 font[j][i] = &fontRec[j][i];
\r
2003 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2007 /* Parse default settings file if any */
\r
2008 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2009 settingsFileName = strdup(buf);
\r
2012 /* Parse command line */
\r
2013 ParseArgs(StringGet, &lpCmdLine);
\r
2015 /* [HGM] make sure board size is acceptable */
\r
2016 if(appData.NrFiles > BOARD_SIZE ||
\r
2017 appData.NrRanks > BOARD_SIZE )
\r
2018 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2020 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2021 * with options from the command line, we now make an even higher priority
\r
2022 * overrule by WB options attached to the engine command line. This so that
\r
2023 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2026 if(appData.firstChessProgram != NULL) {
\r
2027 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2028 static char *f = "first";
\r
2029 char buf[MSG_SIZ], *q = buf;
\r
2030 if(p != NULL) { // engine command line contains WinBoard options
\r
2031 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2032 ParseArgs(StringGet, &q);
\r
2033 p[-1] = 0; // cut them offengine command line
\r
2036 // now do same for second chess program
\r
2037 if(appData.secondChessProgram != NULL) {
\r
2038 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2039 static char *s = "second";
\r
2040 char buf[MSG_SIZ], *q = buf;
\r
2041 if(p != NULL) { // engine command line contains WinBoard options
\r
2042 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2043 ParseArgs(StringGet, &q);
\r
2044 p[-1] = 0; // cut them offengine command line
\r
2049 /* Propagate options that affect others */
\r
2050 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2051 if (appData.icsActive || appData.noChessProgram) {
\r
2052 chessProgram = FALSE; /* not local chess program mode */
\r
2055 /* Open startup dialog if needed */
\r
2056 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2057 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2058 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2059 *appData.secondChessProgram == NULLCHAR))) {
\r
2062 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2063 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2064 FreeProcInstance(lpProc);
\r
2067 /* Make sure save files land in the right (?) directory */
\r
2068 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2069 appData.saveGameFile = strdup(buf);
\r
2071 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2072 appData.savePositionFile = strdup(buf);
\r
2075 /* Finish initialization for fonts and sounds */
\r
2076 for (i=0; i<NUM_FONTS; i++) {
\r
2077 for (j=0; j<NUM_SIZES; j++) {
\r
2078 CreateFontInMF(font[j][i]);
\r
2081 /* xboard, and older WinBoards, controlled the move sound with the
\r
2082 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2083 always turn the option on (so that the backend will call us),
\r
2084 then let the user turn the sound off by setting it to silence if
\r
2085 desired. To accommodate old winboard.ini files saved by old
\r
2086 versions of WinBoard, we also turn off the sound if the option
\r
2087 was initially set to false. */
\r
2088 if (!appData.ringBellAfterMoves) {
\r
2089 sounds[(int)SoundMove].name = strdup("");
\r
2090 appData.ringBellAfterMoves = TRUE;
\r
2092 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2093 SetCurrentDirectory(installDir);
\r
2095 SetCurrentDirectory(currDir);
\r
2097 p = icsTextMenuString;
\r
2098 if (p[0] == '@') {
\r
2099 FILE* f = fopen(p + 1, "r");
\r
2101 DisplayFatalError(p + 1, errno, 2);
\r
2104 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2106 buf[i] = NULLCHAR;
\r
2109 ParseIcsTextMenu(strdup(p));
\r
2116 HMENU hmenu = GetMenu(hwndMain);
\r
2118 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2119 MF_BYCOMMAND|((appData.icsActive &&
\r
2120 *appData.icsCommPort != NULLCHAR) ?
\r
2121 MF_ENABLED : MF_GRAYED));
\r
2122 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2123 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2124 MF_CHECKED : MF_UNCHECKED));
\r
2129 SaveSettings(char* name)
\r
2132 ArgDescriptor *ad;
\r
2133 WINDOWPLACEMENT wp;
\r
2134 char dir[MSG_SIZ];
\r
2136 if (!hwndMain) return;
\r
2138 GetCurrentDirectory(MSG_SIZ, dir);
\r
2139 SetCurrentDirectory(installDir);
\r
2140 f = fopen(name, "w");
\r
2141 SetCurrentDirectory(dir);
\r
2143 DisplayError(name, errno);
\r
2146 fprintf(f, ";\n");
\r
2147 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2148 fprintf(f, ";\n");
\r
2149 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2150 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2151 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2152 fprintf(f, ";\n");
\r
2154 wp.length = sizeof(WINDOWPLACEMENT);
\r
2155 GetWindowPlacement(hwndMain, &wp);
\r
2156 boardX = wp.rcNormalPosition.left;
\r
2157 boardY = wp.rcNormalPosition.top;
\r
2159 if (hwndConsole) {
\r
2160 GetWindowPlacement(hwndConsole, &wp);
\r
2161 consoleX = wp.rcNormalPosition.left;
\r
2162 consoleY = wp.rcNormalPosition.top;
\r
2163 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2164 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2167 if (analysisDialog) {
\r
2168 GetWindowPlacement(analysisDialog, &wp);
\r
2169 analysisX = wp.rcNormalPosition.left;
\r
2170 analysisY = wp.rcNormalPosition.top;
\r
2171 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2172 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2175 if (commentDialog) {
\r
2176 GetWindowPlacement(commentDialog, &wp);
\r
2177 commentX = wp.rcNormalPosition.left;
\r
2178 commentY = wp.rcNormalPosition.top;
\r
2179 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2180 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2183 if (editTagsDialog) {
\r
2184 GetWindowPlacement(editTagsDialog, &wp);
\r
2185 editTagsX = wp.rcNormalPosition.left;
\r
2186 editTagsY = wp.rcNormalPosition.top;
\r
2187 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2188 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2191 if (gameListDialog) {
\r
2192 GetWindowPlacement(gameListDialog, &wp);
\r
2193 gameListX = wp.rcNormalPosition.left;
\r
2194 gameListY = wp.rcNormalPosition.top;
\r
2195 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2196 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2199 /* [AS] Move history */
\r
2200 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2202 if( moveHistoryDialog ) {
\r
2203 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2204 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2205 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2206 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2207 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2210 /* [AS] Eval graph */
\r
2211 wpEvalGraph.visible = EvalGraphIsUp();
\r
2213 if( evalGraphDialog ) {
\r
2214 GetWindowPlacement(evalGraphDialog, &wp);
\r
2215 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2216 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2217 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2218 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2221 /* [AS] Engine output */
\r
2222 wpEngineOutput.visible = EngineOutputIsUp();
\r
2224 if( engineOutputDialog ) {
\r
2225 GetWindowPlacement(engineOutputDialog, &wp);
\r
2226 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2227 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2228 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2229 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2232 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2233 if (!ad->save) continue;
\r
2234 switch (ad->argType) {
\r
2237 char *p = *(char **)ad->argLoc;
\r
2238 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2239 /* Quote multiline values or \-containing values
\r
2240 with { } if possible */
\r
2241 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2243 /* Else quote with " " */
\r
2244 fprintf(f, "/%s=\"", ad->argName);
\r
2246 if (*p == '\n') fprintf(f, "\n");
\r
2247 else if (*p == '\r') fprintf(f, "\\r");
\r
2248 else if (*p == '\t') fprintf(f, "\\t");
\r
2249 else if (*p == '\b') fprintf(f, "\\b");
\r
2250 else if (*p == '\f') fprintf(f, "\\f");
\r
2251 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2252 else if (*p == '\"') fprintf(f, "\\\"");
\r
2253 else if (*p == '\\') fprintf(f, "\\\\");
\r
2257 fprintf(f, "\"\n");
\r
2262 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2265 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2268 fprintf(f, "/%s=%s\n", ad->argName,
\r
2269 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2272 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2275 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2279 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2280 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2281 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2286 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2287 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2288 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2289 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2290 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2291 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2292 (ta->effects) ? " " : "",
\r
2293 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2297 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2298 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2300 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2303 case ArgBoardSize:
\r
2304 fprintf(f, "/%s=%s\n", ad->argName,
\r
2305 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2310 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2311 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2312 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2313 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2314 ad->argName, mfp->faceName, mfp->pointSize,
\r
2315 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2316 mfp->bold ? "b" : "",
\r
2317 mfp->italic ? "i" : "",
\r
2318 mfp->underline ? "u" : "",
\r
2319 mfp->strikeout ? "s" : "");
\r
2323 case ArgCommSettings:
\r
2324 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2332 /*---------------------------------------------------------------------------*\
\r
2334 * GDI board drawing routines
\r
2336 \*---------------------------------------------------------------------------*/
\r
2338 /* [AS] Draw square using background texture */
\r
2339 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2344 return; /* Should never happen! */
\r
2347 SetGraphicsMode( dst, GM_ADVANCED );
\r
2354 /* X reflection */
\r
2359 x.eDx = (FLOAT) dw + dx - 1;
\r
2362 SetWorldTransform( dst, &x );
\r
2365 /* Y reflection */
\r
2371 x.eDy = (FLOAT) dh + dy - 1;
\r
2373 SetWorldTransform( dst, &x );
\r
2381 x.eDx = (FLOAT) dx;
\r
2382 x.eDy = (FLOAT) dy;
\r
2385 SetWorldTransform( dst, &x );
\r
2389 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2397 SetWorldTransform( dst, &x );
\r
2399 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2402 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2404 PM_WP = (int) WhitePawn,
\r
2405 PM_WN = (int) WhiteKnight,
\r
2406 PM_WB = (int) WhiteBishop,
\r
2407 PM_WR = (int) WhiteRook,
\r
2408 PM_WQ = (int) WhiteQueen,
\r
2409 PM_WF = (int) WhiteFerz,
\r
2410 PM_WW = (int) WhiteWazir,
\r
2411 PM_WE = (int) WhiteAlfil,
\r
2412 PM_WM = (int) WhiteMan,
\r
2413 PM_WO = (int) WhiteCannon,
\r
2414 PM_WU = (int) WhiteUnicorn,
\r
2415 PM_WH = (int) WhiteNightrider,
\r
2416 PM_WA = (int) WhiteAngel,
\r
2417 PM_WC = (int) WhiteMarshall,
\r
2418 PM_WAB = (int) WhiteCardinal,
\r
2419 PM_WD = (int) WhiteDragon,
\r
2420 PM_WL = (int) WhiteLance,
\r
2421 PM_WS = (int) WhiteCobra,
\r
2422 PM_WV = (int) WhiteFalcon,
\r
2423 PM_WSG = (int) WhiteSilver,
\r
2424 PM_WG = (int) WhiteGrasshopper,
\r
2425 PM_WK = (int) WhiteKing,
\r
2426 PM_BP = (int) BlackPawn,
\r
2427 PM_BN = (int) BlackKnight,
\r
2428 PM_BB = (int) BlackBishop,
\r
2429 PM_BR = (int) BlackRook,
\r
2430 PM_BQ = (int) BlackQueen,
\r
2431 PM_BF = (int) BlackFerz,
\r
2432 PM_BW = (int) BlackWazir,
\r
2433 PM_BE = (int) BlackAlfil,
\r
2434 PM_BM = (int) BlackMan,
\r
2435 PM_BO = (int) BlackCannon,
\r
2436 PM_BU = (int) BlackUnicorn,
\r
2437 PM_BH = (int) BlackNightrider,
\r
2438 PM_BA = (int) BlackAngel,
\r
2439 PM_BC = (int) BlackMarshall,
\r
2440 PM_BG = (int) BlackGrasshopper,
\r
2441 PM_BAB = (int) BlackCardinal,
\r
2442 PM_BD = (int) BlackDragon,
\r
2443 PM_BL = (int) BlackLance,
\r
2444 PM_BS = (int) BlackCobra,
\r
2445 PM_BV = (int) BlackFalcon,
\r
2446 PM_BSG = (int) BlackSilver,
\r
2447 PM_BK = (int) BlackKing
\r
2450 static HFONT hPieceFont = NULL;
\r
2451 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2452 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2453 static int fontBitmapSquareSize = 0;
\r
2454 static char pieceToFontChar[(int) EmptySquare] =
\r
2455 { 'p', 'n', 'b', 'r', 'q',
\r
2456 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2457 'k', 'o', 'm', 'v', 't', 'w',
\r
2458 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2461 extern BOOL SetCharTable( char *table, const char * map );
\r
2462 /* [HGM] moved to backend.c */
\r
2464 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2467 BYTE r1 = GetRValue( color );
\r
2468 BYTE g1 = GetGValue( color );
\r
2469 BYTE b1 = GetBValue( color );
\r
2475 /* Create a uniform background first */
\r
2476 hbrush = CreateSolidBrush( color );
\r
2477 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2478 FillRect( hdc, &rc, hbrush );
\r
2479 DeleteObject( hbrush );
\r
2482 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2483 int steps = squareSize / 2;
\r
2486 for( i=0; i<steps; i++ ) {
\r
2487 BYTE r = r1 - (r1-r2) * i / steps;
\r
2488 BYTE g = g1 - (g1-g2) * i / steps;
\r
2489 BYTE b = b1 - (b1-b2) * i / steps;
\r
2491 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2492 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2493 FillRect( hdc, &rc, hbrush );
\r
2494 DeleteObject(hbrush);
\r
2497 else if( mode == 2 ) {
\r
2498 /* Diagonal gradient, good more or less for every piece */
\r
2499 POINT triangle[3];
\r
2500 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2501 HBRUSH hbrush_old;
\r
2502 int steps = squareSize;
\r
2505 triangle[0].x = squareSize - steps;
\r
2506 triangle[0].y = squareSize;
\r
2507 triangle[1].x = squareSize;
\r
2508 triangle[1].y = squareSize;
\r
2509 triangle[2].x = squareSize;
\r
2510 triangle[2].y = squareSize - steps;
\r
2512 for( i=0; i<steps; i++ ) {
\r
2513 BYTE r = r1 - (r1-r2) * i / steps;
\r
2514 BYTE g = g1 - (g1-g2) * i / steps;
\r
2515 BYTE b = b1 - (b1-b2) * i / steps;
\r
2517 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2518 hbrush_old = SelectObject( hdc, hbrush );
\r
2519 Polygon( hdc, triangle, 3 );
\r
2520 SelectObject( hdc, hbrush_old );
\r
2521 DeleteObject(hbrush);
\r
2526 SelectObject( hdc, hpen );
\r
2531 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2532 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2533 piece: follow the steps as explained below.
\r
2535 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2539 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2543 int backColor = whitePieceColor;
\r
2544 int foreColor = blackPieceColor;
\r
2546 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2547 backColor = appData.fontBackColorWhite;
\r
2548 foreColor = appData.fontForeColorWhite;
\r
2550 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2551 backColor = appData.fontBackColorBlack;
\r
2552 foreColor = appData.fontForeColorBlack;
\r
2556 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2558 hbm_old = SelectObject( hdc, hbm );
\r
2562 rc.right = squareSize;
\r
2563 rc.bottom = squareSize;
\r
2565 /* Step 1: background is now black */
\r
2566 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2568 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2570 pt.x = (squareSize - sz.cx) / 2;
\r
2571 pt.y = (squareSize - sz.cy) / 2;
\r
2573 SetBkMode( hdc, TRANSPARENT );
\r
2574 SetTextColor( hdc, chroma );
\r
2575 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2576 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2578 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2579 /* Step 3: the area outside the piece is filled with white */
\r
2580 // FloodFill( hdc, 0, 0, chroma );
\r
2581 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2582 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2583 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2584 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2585 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2587 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2588 but if the start point is not inside the piece we're lost!
\r
2589 There should be a better way to do this... if we could create a region or path
\r
2590 from the fill operation we would be fine for example.
\r
2592 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2593 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2595 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2596 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2597 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2599 SelectObject( dc2, bm2 );
\r
2600 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2601 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2602 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2603 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2604 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2607 DeleteObject( bm2 );
\r
2610 SetTextColor( hdc, 0 );
\r
2612 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2613 draw the piece again in black for safety.
\r
2615 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2617 SelectObject( hdc, hbm_old );
\r
2619 if( hPieceMask[index] != NULL ) {
\r
2620 DeleteObject( hPieceMask[index] );
\r
2623 hPieceMask[index] = hbm;
\r
2626 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2628 SelectObject( hdc, hbm );
\r
2631 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2632 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2633 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2635 SelectObject( dc1, hPieceMask[index] );
\r
2636 SelectObject( dc2, bm2 );
\r
2637 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2638 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2641 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2642 the piece background and deletes (makes transparent) the rest.
\r
2643 Thanks to that mask, we are free to paint the background with the greates
\r
2644 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2645 We use this, to make gradients and give the pieces a "roundish" look.
\r
2647 SetPieceBackground( hdc, backColor, 2 );
\r
2648 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2652 DeleteObject( bm2 );
\r
2655 SetTextColor( hdc, foreColor );
\r
2656 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2658 SelectObject( hdc, hbm_old );
\r
2660 if( hPieceFace[index] != NULL ) {
\r
2661 DeleteObject( hPieceFace[index] );
\r
2664 hPieceFace[index] = hbm;
\r
2667 static int TranslatePieceToFontPiece( int piece )
\r
2697 case BlackMarshall:
\r
2701 case BlackNightrider:
\r
2707 case BlackUnicorn:
\r
2711 case BlackGrasshopper:
\r
2723 case BlackCardinal:
\r
2730 case WhiteMarshall:
\r
2734 case WhiteNightrider:
\r
2740 case WhiteUnicorn:
\r
2744 case WhiteGrasshopper:
\r
2756 case WhiteCardinal:
\r
2765 void CreatePiecesFromFont()
\r
2768 HDC hdc_window = NULL;
\r
2774 if( fontBitmapSquareSize < 0 ) {
\r
2775 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2779 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2780 fontBitmapSquareSize = -1;
\r
2784 if( fontBitmapSquareSize != squareSize ) {
\r
2785 hdc_window = GetDC( hwndMain );
\r
2786 hdc = CreateCompatibleDC( hdc_window );
\r
2788 if( hPieceFont != NULL ) {
\r
2789 DeleteObject( hPieceFont );
\r
2792 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2793 hPieceMask[i] = NULL;
\r
2794 hPieceFace[i] = NULL;
\r
2800 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2801 fontHeight = appData.fontPieceSize;
\r
2804 fontHeight = (fontHeight * squareSize) / 100;
\r
2806 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2808 lf.lfEscapement = 0;
\r
2809 lf.lfOrientation = 0;
\r
2810 lf.lfWeight = FW_NORMAL;
\r
2812 lf.lfUnderline = 0;
\r
2813 lf.lfStrikeOut = 0;
\r
2814 lf.lfCharSet = DEFAULT_CHARSET;
\r
2815 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2816 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2817 lf.lfQuality = PROOF_QUALITY;
\r
2818 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2819 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2820 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2822 hPieceFont = CreateFontIndirect( &lf );
\r
2824 if( hPieceFont == NULL ) {
\r
2825 fontBitmapSquareSize = -2;
\r
2828 /* Setup font-to-piece character table */
\r
2829 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2830 /* No (or wrong) global settings, try to detect the font */
\r
2831 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2833 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2835 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2836 /* DiagramTT* family */
\r
2837 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2839 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2840 /* Fairy symbols */
\r
2841 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2843 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2844 /* Good Companion (Some characters get warped as literal :-( */
\r
2845 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2846 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2847 SetCharTable(pieceToFontChar, s);
\r
2850 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2851 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2855 /* Create bitmaps */
\r
2856 hfont_old = SelectObject( hdc, hPieceFont );
\r
2858 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2859 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2860 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2861 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2862 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2863 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2864 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2865 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2866 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2867 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2868 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2869 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2871 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2872 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2873 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2874 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2875 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2876 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2877 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2878 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2879 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2880 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2881 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
2882 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
2883 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
2884 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
2885 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
2886 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
2887 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2888 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2889 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2890 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2891 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2892 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2893 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2894 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2895 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2896 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2897 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
2898 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
2899 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
2900 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
2901 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
2902 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
2904 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2905 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2906 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2908 SelectObject( hdc, hfont_old );
\r
2910 fontBitmapSquareSize = squareSize;
\r
2914 if( hdc != NULL ) {
\r
2918 if( hdc_window != NULL ) {
\r
2919 ReleaseDC( hwndMain, hdc_window );
\r
2924 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2928 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2929 if (gameInfo.event &&
\r
2930 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2931 strcmp(name, "k80s") == 0) {
\r
2932 strcpy(name, "tim");
\r
2934 return LoadBitmap(hinst, name);
\r
2938 /* Insert a color into the program's logical palette
\r
2939 structure. This code assumes the given color is
\r
2940 the result of the RGB or PALETTERGB macro, and it
\r
2941 knows how those macros work (which is documented).
\r
2944 InsertInPalette(COLORREF color)
\r
2946 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2948 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2949 DisplayFatalError("Too many colors", 0, 1);
\r
2950 pLogPal->palNumEntries--;
\r
2954 pe->peFlags = (char) 0;
\r
2955 pe->peRed = (char) (0xFF & color);
\r
2956 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2957 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2963 InitDrawingColors()
\r
2965 if (pLogPal == NULL) {
\r
2966 /* Allocate enough memory for a logical palette with
\r
2967 * PALETTESIZE entries and set the size and version fields
\r
2968 * of the logical palette structure.
\r
2970 pLogPal = (NPLOGPALETTE)
\r
2971 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2972 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2973 pLogPal->palVersion = 0x300;
\r
2975 pLogPal->palNumEntries = 0;
\r
2977 InsertInPalette(lightSquareColor);
\r
2978 InsertInPalette(darkSquareColor);
\r
2979 InsertInPalette(whitePieceColor);
\r
2980 InsertInPalette(blackPieceColor);
\r
2981 InsertInPalette(highlightSquareColor);
\r
2982 InsertInPalette(premoveHighlightColor);
\r
2984 /* create a logical color palette according the information
\r
2985 * in the LOGPALETTE structure.
\r
2987 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2989 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2990 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2991 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2992 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2993 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2994 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2996 /* [AS] Force rendering of the font-based pieces */
\r
2997 if( fontBitmapSquareSize > 0 ) {
\r
2998 fontBitmapSquareSize = 0;
\r
3004 BoardWidth(int boardSize, int n)
\r
3005 { /* [HGM] argument n added to allow different width and height */
\r
3006 int lineGap = sizeInfo[boardSize].lineGap;
\r
3008 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3009 lineGap = appData.overrideLineGap;
\r
3012 return (n + 1) * lineGap +
\r
3013 n * sizeInfo[boardSize].squareSize;
\r
3016 /* Respond to board resize by dragging edge */
\r
3018 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3020 BoardSize newSize = NUM_SIZES - 1;
\r
3021 static int recurse = 0;
\r
3022 if (IsIconic(hwndMain)) return;
\r
3023 if (recurse > 0) return;
\r
3025 while (newSize > 0) {
\r
3026 InitDrawingSizes(newSize, 0);
\r
3027 if(newSizeX >= sizeInfo[newSize].cliWidth ||
\r
3028 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3031 boardSize = newSize;
\r
3032 InitDrawingSizes(boardSize, flags);
\r
3039 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3041 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3042 ChessSquare piece;
\r
3043 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3045 SIZE clockSize, messageSize;
\r
3047 char buf[MSG_SIZ];
\r
3049 HMENU hmenu = GetMenu(hwndMain);
\r
3050 RECT crect, wrect;
\r
3052 LOGBRUSH logbrush;
\r
3054 /* [HGM] call with -1 uses old size (for if nr of files, ranks changes) */
\r
3055 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3057 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3058 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3059 squareSize = sizeInfo[boardSize].squareSize;
\r
3060 lineGap = sizeInfo[boardSize].lineGap;
\r
3061 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3063 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3064 lineGap = appData.overrideLineGap;
\r
3067 if (tinyLayout != oldTinyLayout) {
\r
3068 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3070 style &= ~WS_SYSMENU;
\r
3071 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3072 "&Minimize\tCtrl+F4");
\r
3074 style |= WS_SYSMENU;
\r
3075 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3077 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3079 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3080 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3081 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3083 DrawMenuBar(hwndMain);
\r
3086 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3087 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3089 /* Get text area sizes */
\r
3090 hdc = GetDC(hwndMain);
\r
3091 if (appData.clockMode) {
\r
3092 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3094 sprintf(buf, "White");
\r
3096 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3097 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3098 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3099 str = "We only care about the height here";
\r
3100 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3101 SelectObject(hdc, oldFont);
\r
3102 ReleaseDC(hwndMain, hdc);
\r
3104 /* Compute where everything goes */
\r
3105 if(first.programLogo || second.programLogo) {
\r
3106 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3107 logoHeight = 2*clockSize.cy;
\r
3108 leftLogoRect.left = OUTER_MARGIN;
\r
3109 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3110 leftLogoRect.top = OUTER_MARGIN;
\r
3111 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3113 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3114 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3115 rightLogoRect.top = OUTER_MARGIN;
\r
3116 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3119 blackRect.left = leftLogoRect.right;
\r
3120 blackRect.right = rightLogoRect.left;
\r
3121 blackRect.top = OUTER_MARGIN;
\r
3122 blackRect.bottom = blackRect.top + clockSize.cy;
\r
3124 whiteRect.left = blackRect.left ;
\r
3125 whiteRect.right = blackRect.right;
\r
3126 whiteRect.top = blackRect.bottom;
\r
3127 whiteRect.bottom = leftLogoRect.bottom;
\r
3129 whiteRect.left = OUTER_MARGIN;
\r
3130 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3131 whiteRect.top = OUTER_MARGIN + logoHeight;
\r
3132 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3134 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3135 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3136 blackRect.top = whiteRect.top;
\r
3137 blackRect.bottom = whiteRect.bottom;
\r
3140 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3141 if (appData.showButtonBar) {
\r
3142 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3143 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3145 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3147 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3148 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3150 boardRect.left = OUTER_MARGIN;
\r
3151 boardRect.right = boardRect.left + boardWidth;
\r
3152 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3153 boardRect.bottom = boardRect.top + boardHeight;
\r
3155 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3156 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3157 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3158 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3159 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3160 GetWindowRect(hwndMain, &wrect);
\r
3161 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3162 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3163 /* compensate if menu bar wrapped */
\r
3164 GetClientRect(hwndMain, &crect);
\r
3165 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3166 winHeight += offby;
\r
3168 case WMSZ_TOPLEFT:
\r
3169 SetWindowPos(hwndMain, NULL,
\r
3170 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3171 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3174 case WMSZ_TOPRIGHT:
\r
3176 SetWindowPos(hwndMain, NULL,
\r
3177 wrect.left, wrect.bottom - winHeight,
\r
3178 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3181 case WMSZ_BOTTOMLEFT:
\r
3183 SetWindowPos(hwndMain, NULL,
\r
3184 wrect.right - winWidth, wrect.top,
\r
3185 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3188 case WMSZ_BOTTOMRIGHT:
\r
3192 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3193 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3198 for (i = 0; i < N_BUTTONS; i++) {
\r
3199 if (buttonDesc[i].hwnd != NULL) {
\r
3200 DestroyWindow(buttonDesc[i].hwnd);
\r
3201 buttonDesc[i].hwnd = NULL;
\r
3203 if (appData.showButtonBar) {
\r
3204 buttonDesc[i].hwnd =
\r
3205 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3206 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3207 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3208 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3209 (HMENU) buttonDesc[i].id,
\r
3210 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3212 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3213 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3214 MAKELPARAM(FALSE, 0));
\r
3216 if (buttonDesc[i].id == IDM_Pause)
\r
3217 hwndPause = buttonDesc[i].hwnd;
\r
3218 buttonDesc[i].wndproc = (WNDPROC)
\r
3219 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3222 if (gridPen != NULL) DeleteObject(gridPen);
\r
3223 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3224 if (premovePen != NULL) DeleteObject(premovePen);
\r
3225 if (lineGap != 0) {
\r
3226 logbrush.lbStyle = BS_SOLID;
\r
3227 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3229 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3230 lineGap, &logbrush, 0, NULL);
\r
3231 logbrush.lbColor = highlightSquareColor;
\r
3233 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3234 lineGap, &logbrush, 0, NULL);
\r
3236 logbrush.lbColor = premoveHighlightColor;
\r
3238 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3239 lineGap, &logbrush, 0, NULL);
\r
3241 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3242 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3243 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3244 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3245 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3246 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3247 BOARD_WIDTH * (squareSize + lineGap);
\r
3248 lineGap / 2 + (i * (squareSize + lineGap));
\r
3249 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3251 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3252 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3253 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3254 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3255 lineGap / 2 + (i * (squareSize + lineGap));
\r
3256 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3257 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3258 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3262 /* [HGM] Licensing requirement */
\r
3264 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3267 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3269 GothicPopUp( "", VariantNormal);
\r
3272 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3273 oldBoardSize = boardSize;
\r
3274 oldTinyLayout = tinyLayout;
\r
3276 /* Load piece bitmaps for this board size */
\r
3277 for (i=0; i<=2; i++) {
\r
3278 for (piece = WhitePawn;
\r
3279 (int) piece < (int) BlackPawn;
\r
3280 piece = (ChessSquare) ((int) piece + 1)) {
\r
3281 if (pieceBitmap[i][piece] != NULL)
\r
3282 DeleteObject(pieceBitmap[i][piece]);
\r
3286 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3287 // Orthodox Chess pieces
\r
3288 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3289 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3290 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3291 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3292 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3293 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3294 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3295 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3296 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3297 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3298 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3299 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3300 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3301 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3302 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3303 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3304 // in Shogi, Hijack the unused Queen for Lance
\r
3305 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3306 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3307 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3309 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3310 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3311 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3314 if(squareSize <= 72 && squareSize >= 33) {
\r
3315 /* A & C are available in most sizes now */
\r
3316 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3317 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3318 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3319 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3320 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3321 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3322 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3323 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3324 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3325 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3326 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3327 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3328 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3329 } else { // Smirf-like
\r
3330 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3331 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3332 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3334 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3335 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3336 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3337 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3338 } else { // WinBoard standard
\r
3339 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3340 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3341 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3346 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3347 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3348 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3349 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3350 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3351 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3352 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3353 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3354 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3355 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3356 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3357 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3358 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3359 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3360 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3361 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3362 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3363 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3364 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3365 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3366 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3367 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3368 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3369 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3370 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3371 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3372 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3373 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3374 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3375 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3376 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3378 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3379 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3380 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3381 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3382 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3383 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3384 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3385 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3386 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3387 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3388 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3389 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3390 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3392 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3393 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3394 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3395 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3396 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3397 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3398 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3399 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3400 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3401 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3402 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3403 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3406 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3407 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3408 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3409 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3410 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3411 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3412 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3413 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3414 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3415 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3416 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3417 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3418 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3419 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3420 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3424 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3425 /* special Shogi support in this size */
\r
3426 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3427 for (piece = WhitePawn;
\r
3428 (int) piece < (int) BlackPawn;
\r
3429 piece = (ChessSquare) ((int) piece + 1)) {
\r
3430 if (pieceBitmap[i][piece] != NULL)
\r
3431 DeleteObject(pieceBitmap[i][piece]);
\r
3434 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3435 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3436 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3437 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3438 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3439 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3440 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3441 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3442 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3443 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3444 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3445 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3446 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3447 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3448 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3449 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3450 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3451 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3452 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3453 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3454 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3455 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3456 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3457 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3458 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3459 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3460 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3461 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3462 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3463 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3464 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3465 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3466 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3467 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3468 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3469 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3470 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3471 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3472 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3473 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3474 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3475 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3481 PieceBitmap(ChessSquare p, int kind)
\r
3483 if ((int) p >= (int) BlackPawn)
\r
3484 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3486 return pieceBitmap[kind][(int) p];
\r
3489 /***************************************************************/
\r
3491 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3492 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3494 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3495 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3499 SquareToPos(int row, int column, int * x, int * y)
\r
3502 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3503 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3505 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3506 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3511 DrawCoordsOnDC(HDC hdc)
\r
3513 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
3514 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
3515 char str[2] = { NULLCHAR, NULLCHAR };
\r
3516 int oldMode, oldAlign, x, y, start, i;
\r
3520 if (!appData.showCoords)
\r
3523 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3525 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3526 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3527 oldAlign = GetTextAlign(hdc);
\r
3528 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3530 y = boardRect.top + lineGap;
\r
3531 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3533 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3534 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3535 str[0] = files[start + i];
\r
3536 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3537 y += squareSize + lineGap;
\r
3540 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3542 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3543 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3544 str[0] = ranks[start + i];
\r
3545 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3546 x += squareSize + lineGap;
\r
3549 SelectObject(hdc, oldBrush);
\r
3550 SetBkMode(hdc, oldMode);
\r
3551 SetTextAlign(hdc, oldAlign);
\r
3552 SelectObject(hdc, oldFont);
\r
3556 DrawGridOnDC(HDC hdc)
\r
3560 if (lineGap != 0) {
\r
3561 oldPen = SelectObject(hdc, gridPen);
\r
3562 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3563 SelectObject(hdc, oldPen);
\r
3567 #define HIGHLIGHT_PEN 0
\r
3568 #define PREMOVE_PEN 1
\r
3571 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3574 HPEN oldPen, hPen;
\r
3575 if (lineGap == 0) return;
\r
3577 x1 = boardRect.left +
\r
3578 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3579 y1 = boardRect.top +
\r
3580 lineGap/2 + y * (squareSize + lineGap);
\r
3582 x1 = boardRect.left +
\r
3583 lineGap/2 + x * (squareSize + lineGap);
\r
3584 y1 = boardRect.top +
\r
3585 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3587 hPen = pen ? premovePen : highlightPen;
\r
3588 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3589 MoveToEx(hdc, x1, y1, NULL);
\r
3590 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3591 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3592 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3593 LineTo(hdc, x1, y1);
\r
3594 SelectObject(hdc, oldPen);
\r
3598 DrawHighlightsOnDC(HDC hdc)
\r
3601 for (i=0; i<2; i++) {
\r
3602 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3603 DrawHighlightOnDC(hdc, TRUE,
\r
3604 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3607 for (i=0; i<2; i++) {
\r
3608 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3609 premoveHighlightInfo.sq[i].y >= 0) {
\r
3610 DrawHighlightOnDC(hdc, TRUE,
\r
3611 premoveHighlightInfo.sq[i].x,
\r
3612 premoveHighlightInfo.sq[i].y,
\r
3618 /* Note: sqcolor is used only in monoMode */
\r
3619 /* Note that this code is largely duplicated in woptions.c,
\r
3620 function DrawSampleSquare, so that needs to be updated too */
\r
3622 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3624 HBITMAP oldBitmap;
\r
3628 if (appData.blindfold) return;
\r
3630 /* [AS] Use font-based pieces if needed */
\r
3631 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3632 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3633 CreatePiecesFromFont();
\r
3635 if( fontBitmapSquareSize == squareSize ) {
\r
3636 int index = TranslatePieceToFontPiece(piece);
\r
3638 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3642 squareSize, squareSize,
\r
3647 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3651 squareSize, squareSize,
\r
3660 if (appData.monoMode) {
\r
3661 SelectObject(tmphdc, PieceBitmap(piece,
\r
3662 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3663 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3664 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3666 tmpSize = squareSize;
\r
3668 (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||
\r
3669 piece >= (int)BlackNightrider && piece <= BlackGrasshopper) ) {
\r
3670 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3671 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3672 x += (squareSize - minorSize)>>1;
\r
3673 y += squareSize - minorSize - 2;
\r
3674 tmpSize = minorSize;
\r
3676 if (color || appData.allWhite ) {
\r
3677 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3679 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3680 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3681 if(appData.upsideDown && color==flipView)
\r
3682 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3684 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3686 /* Use black piece color for outline of white pieces */
\r
3687 /* Not sure this looks really good (though xboard does it).
\r
3688 Maybe better to have another selectable color, default black */
\r
3689 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3690 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3691 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3693 /* Use black for outline of white pieces */
\r
3694 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3695 if(appData.upsideDown && color==flipView)
\r
3696 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3698 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3702 /* Use white piece color for details of black pieces */
\r
3703 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3704 WHITE_PIECE ones aren't always the right shape. */
\r
3705 /* Not sure this looks really good (though xboard does it).
\r
3706 Maybe better to have another selectable color, default medium gray? */
\r
3707 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3708 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3709 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3710 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3711 SelectObject(hdc, blackPieceBrush);
\r
3712 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3714 /* Use square color for details of black pieces */
\r
3715 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3716 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3717 if(appData.upsideDown && !flipView)
\r
3718 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3720 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3723 SelectObject(hdc, oldBrush);
\r
3724 SelectObject(tmphdc, oldBitmap);
\r
3728 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3729 int GetBackTextureMode( int algo )
\r
3731 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3735 case BACK_TEXTURE_MODE_PLAIN:
\r
3736 result = 1; /* Always use identity map */
\r
3738 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3739 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3747 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3748 to handle redraws cleanly (as random numbers would always be different).
\r
3750 VOID RebuildTextureSquareInfo()
\r
3760 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3762 if( liteBackTexture != NULL ) {
\r
3763 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3764 lite_w = bi.bmWidth;
\r
3765 lite_h = bi.bmHeight;
\r
3769 if( darkBackTexture != NULL ) {
\r
3770 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3771 dark_w = bi.bmWidth;
\r
3772 dark_h = bi.bmHeight;
\r
3776 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3777 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3778 if( (col + row) & 1 ) {
\r
3780 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3781 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3782 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3783 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3788 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3789 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3790 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3791 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3798 /* [AS] Arrow highlighting support */
\r
3800 static int A_WIDTH = 5; /* Width of arrow body */
\r
3802 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3803 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3805 static double Sqr( double x )
\r
3810 static int Round( double x )
\r
3812 return (int) (x + 0.5);
\r
3815 /* Draw an arrow between two points using current settings */
\r
3816 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3819 double dx, dy, j, k, x, y;
\r
3821 if( d_x == s_x ) {
\r
3822 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3824 arrow[0].x = s_x + A_WIDTH;
\r
3827 arrow[1].x = s_x + A_WIDTH;
\r
3828 arrow[1].y = d_y - h;
\r
3830 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3831 arrow[2].y = d_y - h;
\r
3836 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3837 arrow[4].y = d_y - h;
\r
3839 arrow[5].x = s_x - A_WIDTH;
\r
3840 arrow[5].y = d_y - h;
\r
3842 arrow[6].x = s_x - A_WIDTH;
\r
3845 else if( d_y == s_y ) {
\r
3846 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3849 arrow[0].y = s_y + A_WIDTH;
\r
3851 arrow[1].x = d_x - w;
\r
3852 arrow[1].y = s_y + A_WIDTH;
\r
3854 arrow[2].x = d_x - w;
\r
3855 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3860 arrow[4].x = d_x - w;
\r
3861 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3863 arrow[5].x = d_x - w;
\r
3864 arrow[5].y = s_y - A_WIDTH;
\r
3867 arrow[6].y = s_y - A_WIDTH;
\r
3870 /* [AS] Needed a lot of paper for this! :-) */
\r
3871 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3872 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3874 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3876 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3881 arrow[0].x = Round(x - j);
\r
3882 arrow[0].y = Round(y + j*dx);
\r
3884 arrow[1].x = Round(x + j);
\r
3885 arrow[1].y = Round(y - j*dx);
\r
3888 x = (double) d_x - k;
\r
3889 y = (double) d_y - k*dy;
\r
3892 x = (double) d_x + k;
\r
3893 y = (double) d_y + k*dy;
\r
3896 arrow[2].x = Round(x + j);
\r
3897 arrow[2].y = Round(y - j*dx);
\r
3899 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3900 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3905 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3906 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3908 arrow[6].x = Round(x - j);
\r
3909 arrow[6].y = Round(y + j*dx);
\r
3912 Polygon( hdc, arrow, 7 );
\r
3915 /* [AS] Draw an arrow between two squares */
\r
3916 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3918 int s_x, s_y, d_x, d_y;
\r
3925 if( s_col == d_col && s_row == d_row ) {
\r
3929 /* Get source and destination points */
\r
3930 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3931 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3934 d_y += squareSize / 4;
\r
3936 else if( d_y < s_y ) {
\r
3937 d_y += 3 * squareSize / 4;
\r
3940 d_y += squareSize / 2;
\r
3944 d_x += squareSize / 4;
\r
3946 else if( d_x < s_x ) {
\r
3947 d_x += 3 * squareSize / 4;
\r
3950 d_x += squareSize / 2;
\r
3953 s_x += squareSize / 2;
\r
3954 s_y += squareSize / 2;
\r
3956 /* Adjust width */
\r
3957 A_WIDTH = squareSize / 14;
\r
3960 stLB.lbStyle = BS_SOLID;
\r
3961 stLB.lbColor = appData.highlightArrowColor;
\r
3964 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3965 holdpen = SelectObject( hdc, hpen );
\r
3966 hbrush = CreateBrushIndirect( &stLB );
\r
3967 holdbrush = SelectObject( hdc, hbrush );
\r
3969 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3971 SelectObject( hdc, holdpen );
\r
3972 SelectObject( hdc, holdbrush );
\r
3973 DeleteObject( hpen );
\r
3974 DeleteObject( hbrush );
\r
3977 BOOL HasHighlightInfo()
\r
3979 BOOL result = FALSE;
\r
3981 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3982 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3990 BOOL IsDrawArrowEnabled()
\r
3992 BOOL result = FALSE;
\r
3994 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4001 VOID DrawArrowHighlight( HDC hdc )
\r
4003 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4004 DrawArrowBetweenSquares( hdc,
\r
4005 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4006 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4010 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4012 HRGN result = NULL;
\r
4014 if( HasHighlightInfo() ) {
\r
4015 int x1, y1, x2, y2;
\r
4016 int sx, sy, dx, dy;
\r
4018 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4019 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4021 sx = MIN( x1, x2 );
\r
4022 sy = MIN( y1, y2 );
\r
4023 dx = MAX( x1, x2 ) + squareSize;
\r
4024 dy = MAX( y1, y2 ) + squareSize;
\r
4026 result = CreateRectRgn( sx, sy, dx, dy );
\r
4033 Warning: this function modifies the behavior of several other functions.
\r
4035 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4036 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4037 repaint is scattered all over the place, which is not good for features such as
\r
4038 "arrow highlighting" that require a full repaint of the board.
\r
4040 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4041 user interaction, when speed is not so important) but especially to avoid errors
\r
4042 in the displayed graphics.
\r
4044 In such patched places, I always try refer to this function so there is a single
\r
4045 place to maintain knowledge.
\r
4047 To restore the original behavior, just return FALSE unconditionally.
\r
4049 BOOL IsFullRepaintPreferrable()
\r
4051 BOOL result = FALSE;
\r
4053 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4054 /* Arrow may appear on the board */
\r
4062 This function is called by DrawPosition to know whether a full repaint must
\r
4065 Only DrawPosition may directly call this function, which makes use of
\r
4066 some state information. Other function should call DrawPosition specifying
\r
4067 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4069 BOOL DrawPositionNeedsFullRepaint()
\r
4071 BOOL result = FALSE;
\r
4074 Probably a slightly better policy would be to trigger a full repaint
\r
4075 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4076 but animation is fast enough that it's difficult to notice.
\r
4078 if( animInfo.piece == EmptySquare ) {
\r
4079 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4088 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4090 int row, column, x, y, square_color, piece_color;
\r
4091 ChessSquare piece;
\r
4093 HDC texture_hdc = NULL;
\r
4095 /* [AS] Initialize background textures if needed */
\r
4096 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4097 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4098 if( backTextureSquareSize != squareSize
\r
4099 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4100 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4101 backTextureSquareSize = squareSize;
\r
4102 RebuildTextureSquareInfo();
\r
4105 texture_hdc = CreateCompatibleDC( hdc );
\r
4108 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4109 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4111 SquareToPos(row, column, &x, &y);
\r
4113 piece = board[row][column];
\r
4115 square_color = ((column + row) % 2) == 1;
\r
4116 if( gameInfo.variant == VariantXiangqi ) {
\r
4117 square_color = !InPalace(row, column);
\r
4118 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4119 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4121 piece_color = (int) piece < (int) BlackPawn;
\r
4124 /* [HGM] holdings file: light square or black */
\r
4125 if(column == BOARD_LEFT-2) {
\r
4126 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4129 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4133 if(column == BOARD_RGHT + 1 ) {
\r
4134 if( row < gameInfo.holdingsSize )
\r
4137 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4141 if(column == BOARD_LEFT-1 ) /* left align */
\r
4142 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4143 else if( column == BOARD_RGHT) /* right align */
\r
4144 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4146 if (appData.monoMode) {
\r
4147 if (piece == EmptySquare) {
\r
4148 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4149 square_color ? WHITENESS : BLACKNESS);
\r
4151 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4154 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4155 /* [AS] Draw the square using a texture bitmap */
\r
4156 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4157 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4158 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4161 squareSize, squareSize,
\r
4164 backTextureSquareInfo[r][c].mode,
\r
4165 backTextureSquareInfo[r][c].x,
\r
4166 backTextureSquareInfo[r][c].y );
\r
4168 SelectObject( texture_hdc, hbm );
\r
4170 if (piece != EmptySquare) {
\r
4171 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4175 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4177 oldBrush = SelectObject(hdc, brush );
\r
4178 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4179 SelectObject(hdc, oldBrush);
\r
4180 if (piece != EmptySquare)
\r
4181 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4186 if( texture_hdc != NULL ) {
\r
4187 DeleteDC( texture_hdc );
\r
4191 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4192 void fputDW(FILE *f, int x)
\r
4194 fputc(x & 255, f);
\r
4195 fputc(x>>8 & 255, f);
\r
4196 fputc(x>>16 & 255, f);
\r
4197 fputc(x>>24 & 255, f);
\r
4200 #define MAX_CLIPS 200 /* more than enough */
\r
4203 DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)
\r
4205 HBITMAP bufferBitmap;
\r
4210 int w = 100, h = 50;
\r
4212 if(cps->programLogo == NULL) return;
\r
4213 // GetClientRect(hwndMain, &Rect);
\r
4214 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4215 // Rect.bottom-Rect.top+1);
\r
4216 tmphdc = CreateCompatibleDC(hdc);
\r
4217 hbm = SelectObject(tmphdc, (HBITMAP) cps->programLogo);
\r
4218 if( GetObject( cps->programLogo, sizeof(bi), &bi ) > 0 ) {
\r
4222 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4223 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4224 SelectObject(tmphdc, hbm);
\r
4229 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4231 static Board lastReq, lastDrawn;
\r
4232 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4233 static int lastDrawnFlipView = 0;
\r
4234 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4235 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4238 HBITMAP bufferBitmap;
\r
4239 HBITMAP oldBitmap;
\r
4241 HRGN clips[MAX_CLIPS];
\r
4242 ChessSquare dragged_piece = EmptySquare;
\r
4244 /* I'm undecided on this - this function figures out whether a full
\r
4245 * repaint is necessary on its own, so there's no real reason to have the
\r
4246 * caller tell it that. I think this can safely be set to FALSE - but
\r
4247 * if we trust the callers not to request full repaints unnessesarily, then
\r
4248 * we could skip some clipping work. In other words, only request a full
\r
4249 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4250 * gamestart and similar) --Hawk
\r
4252 Boolean fullrepaint = repaint;
\r
4254 if( DrawPositionNeedsFullRepaint() ) {
\r
4255 fullrepaint = TRUE;
\r
4259 if( fullrepaint ) {
\r
4260 static int repaint_count = 0;
\r
4264 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4265 OutputDebugString( buf );
\r
4269 if (board == NULL) {
\r
4270 if (!lastReqValid) {
\r
4275 CopyBoard(lastReq, board);
\r
4279 if (doingSizing) {
\r
4283 if (IsIconic(hwndMain)) {
\r
4287 if (hdc == NULL) {
\r
4288 hdc = GetDC(hwndMain);
\r
4289 if (!appData.monoMode) {
\r
4290 SelectPalette(hdc, hPal, FALSE);
\r
4291 RealizePalette(hdc);
\r
4295 releaseDC = FALSE;
\r
4299 fprintf(debugFP, "*******************************\n"
\r
4301 "dragInfo.from (%d,%d)\n"
\r
4302 "dragInfo.start (%d,%d)\n"
\r
4303 "dragInfo.pos (%d,%d)\n"
\r
4304 "dragInfo.lastpos (%d,%d)\n",
\r
4305 repaint ? "TRUE" : "FALSE",
\r
4306 dragInfo.from.x, dragInfo.from.y,
\r
4307 dragInfo.start.x, dragInfo.start.y,
\r
4308 dragInfo.pos.x, dragInfo.pos.y,
\r
4309 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4310 fprintf(debugFP, "prev: ");
\r
4311 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4312 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4313 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4316 fprintf(debugFP, "\n");
\r
4317 fprintf(debugFP, "board: ");
\r
4318 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4319 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4320 fprintf(debugFP, "%d ", board[row][column]);
\r
4323 fprintf(debugFP, "\n");
\r
4327 /* Create some work-DCs */
\r
4328 hdcmem = CreateCompatibleDC(hdc);
\r
4329 tmphdc = CreateCompatibleDC(hdc);
\r
4331 /* If dragging is in progress, we temporarely remove the piece */
\r
4332 /* [HGM] or temporarily decrease count if stacked */
\r
4333 /* !! Moved to before board compare !! */
\r
4334 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4335 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4336 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4337 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4338 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4340 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4341 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4342 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4344 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4347 /* Figure out which squares need updating by comparing the
\r
4348 * newest board with the last drawn board and checking if
\r
4349 * flipping has changed.
\r
4351 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4352 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4353 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4354 if (lastDrawn[row][column] != board[row][column]) {
\r
4355 SquareToPos(row, column, &x, &y);
\r
4356 clips[num_clips++] =
\r
4357 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4361 for (i=0; i<2; i++) {
\r
4362 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4363 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4364 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4365 lastDrawnHighlight.sq[i].y >= 0) {
\r
4366 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4367 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4368 clips[num_clips++] =
\r
4369 CreateRectRgn(x - lineGap, y - lineGap,
\r
4370 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4372 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4373 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4374 clips[num_clips++] =
\r
4375 CreateRectRgn(x - lineGap, y - lineGap,
\r
4376 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4380 for (i=0; i<2; i++) {
\r
4381 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4382 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4383 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4384 lastDrawnPremove.sq[i].y >= 0) {
\r
4385 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4386 lastDrawnPremove.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
4391 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4392 premoveHighlightInfo.sq[i].y >= 0) {
\r
4393 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4394 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4395 clips[num_clips++] =
\r
4396 CreateRectRgn(x - lineGap, y - lineGap,
\r
4397 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4402 fullrepaint = TRUE;
\r
4405 /* Create a buffer bitmap - this is the actual bitmap
\r
4406 * being written to. When all the work is done, we can
\r
4407 * copy it to the real DC (the screen). This avoids
\r
4408 * the problems with flickering.
\r
4410 GetClientRect(hwndMain, &Rect);
\r
4411 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4412 Rect.bottom-Rect.top+1);
\r
4413 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4414 if (!appData.monoMode) {
\r
4415 SelectPalette(hdcmem, hPal, FALSE);
\r
4418 /* Create clips for dragging */
\r
4419 if (!fullrepaint) {
\r
4420 if (dragInfo.from.x >= 0) {
\r
4421 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4422 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4424 if (dragInfo.start.x >= 0) {
\r
4425 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4426 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4428 if (dragInfo.pos.x >= 0) {
\r
4429 x = dragInfo.pos.x - squareSize / 2;
\r
4430 y = dragInfo.pos.y - squareSize / 2;
\r
4431 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4433 if (dragInfo.lastpos.x >= 0) {
\r
4434 x = dragInfo.lastpos.x - squareSize / 2;
\r
4435 y = dragInfo.lastpos.y - squareSize / 2;
\r
4436 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4440 /* Are we animating a move?
\r
4442 * - remove the piece from the board (temporarely)
\r
4443 * - calculate the clipping region
\r
4445 if (!fullrepaint) {
\r
4446 if (animInfo.piece != EmptySquare) {
\r
4447 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4448 x = boardRect.left + animInfo.lastpos.x;
\r
4449 y = boardRect.top + animInfo.lastpos.y;
\r
4450 x2 = boardRect.left + animInfo.pos.x;
\r
4451 y2 = boardRect.top + animInfo.pos.y;
\r
4452 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4453 /* Slight kludge. The real problem is that after AnimateMove is
\r
4454 done, the position on the screen does not match lastDrawn.
\r
4455 This currently causes trouble only on e.p. captures in
\r
4456 atomic, where the piece moves to an empty square and then
\r
4457 explodes. The old and new positions both had an empty square
\r
4458 at the destination, but animation has drawn a piece there and
\r
4459 we have to remember to erase it. */
\r
4460 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4464 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4465 if (num_clips == 0)
\r
4466 fullrepaint = TRUE;
\r
4468 /* Set clipping on the memory DC */
\r
4469 if (!fullrepaint) {
\r
4470 SelectClipRgn(hdcmem, clips[0]);
\r
4471 for (x = 1; x < num_clips; x++) {
\r
4472 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4473 abort(); // this should never ever happen!
\r
4477 /* Do all the drawing to the memory DC */
\r
4478 DrawGridOnDC(hdcmem);
\r
4479 DrawHighlightsOnDC(hdcmem);
\r
4480 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4483 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);
\r
4484 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);
\r
4487 if( appData.highlightMoveWithArrow ) {
\r
4488 DrawArrowHighlight(hdcmem);
\r
4491 DrawCoordsOnDC(hdcmem);
\r
4493 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4494 /* to make sure lastDrawn contains what is actually drawn */
\r
4496 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4497 if (dragged_piece != EmptySquare) {
\r
4498 /* [HGM] or restack */
\r
4499 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4500 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4502 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4503 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4504 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4505 x = dragInfo.pos.x - squareSize / 2;
\r
4506 y = dragInfo.pos.y - squareSize / 2;
\r
4507 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4508 ((int) dragged_piece < (int) BlackPawn),
\r
4509 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4512 /* Put the animated piece back into place and draw it */
\r
4513 if (animInfo.piece != EmptySquare) {
\r
4514 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4515 x = boardRect.left + animInfo.pos.x;
\r
4516 y = boardRect.top + animInfo.pos.y;
\r
4517 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4518 ((int) animInfo.piece < (int) BlackPawn),
\r
4519 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4522 /* Release the bufferBitmap by selecting in the old bitmap
\r
4523 * and delete the memory DC
\r
4525 SelectObject(hdcmem, oldBitmap);
\r
4528 /* Set clipping on the target DC */
\r
4529 if (!fullrepaint) {
\r
4530 SelectClipRgn(hdc, clips[0]);
\r
4531 for (x = 1; x < num_clips; x++) {
\r
4532 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4533 abort(); // this should never ever happen!
\r
4537 /* Copy the new bitmap onto the screen in one go.
\r
4538 * This way we avoid any flickering
\r
4540 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4541 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4542 boardRect.right - boardRect.left,
\r
4543 boardRect.bottom - boardRect.top,
\r
4544 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4545 if(saveDiagFlag) {
\r
4546 BITMAP b; int i, j, m, w, wb, fac=0; char pData[1000000];
\r
4547 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4549 GetObject(bufferBitmap, sizeof(b), &b);
\r
4550 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4551 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4552 bih.biWidth = b.bmWidth;
\r
4553 bih.biHeight = b.bmHeight;
\r
4555 bih.biBitCount = b.bmBitsPixel;
\r
4556 bih.biCompression = 0;
\r
4557 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4558 bih.biXPelsPerMeter = 0;
\r
4559 bih.biYPelsPerMeter = 0;
\r
4560 bih.biClrUsed = 0;
\r
4561 bih.biClrImportant = 0;
\r
4562 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4563 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4564 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4565 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4568 wb = b.bmWidthBytes;
\r
4570 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4571 int k = ((int*) pData)[i];
\r
4572 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4573 if(j >= 16) break;
\r
4575 if(j >= nrColors) nrColors = j+1;
\r
4577 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4579 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4580 for(w=0; w<(wb>>2); w+=2) {
\r
4581 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4582 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4583 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4584 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4585 pData[p++] = m | j<<4;
\r
4587 while(p&3) pData[p++] = 0;
\r
4590 wb = (wb+31>>5)<<2;
\r
4592 // write BITMAPFILEHEADER
\r
4593 fprintf(diagFile, "BM");
\r
4594 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4595 fputDW(diagFile, 0);
\r
4596 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4597 // write BITMAPINFOHEADER
\r
4598 fputDW(diagFile, 40);
\r
4599 fputDW(diagFile, b.bmWidth);
\r
4600 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4601 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4602 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4603 fputDW(diagFile, 0);
\r
4604 fputDW(diagFile, 0);
\r
4605 fputDW(diagFile, 0);
\r
4606 fputDW(diagFile, 0);
\r
4607 fputDW(diagFile, 0);
\r
4608 fputDW(diagFile, 0);
\r
4609 // write color table
\r
4611 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4612 // write bitmap data
\r
4613 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4614 fputc(pData[i], diagFile);
\r
4619 SelectObject(tmphdc, oldBitmap);
\r
4621 /* Massive cleanup */
\r
4622 for (x = 0; x < num_clips; x++)
\r
4623 DeleteObject(clips[x]);
\r
4626 DeleteObject(bufferBitmap);
\r
4629 ReleaseDC(hwndMain, hdc);
\r
4631 if (lastDrawnFlipView != flipView) {
\r
4633 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4635 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4638 /* CopyBoard(lastDrawn, board);*/
\r
4639 lastDrawnHighlight = highlightInfo;
\r
4640 lastDrawnPremove = premoveHighlightInfo;
\r
4641 lastDrawnFlipView = flipView;
\r
4642 lastDrawnValid = 1;
\r
4645 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4653 saveDiagFlag = 1; diagFile = f;
\r
4654 HDCDrawPosition(NULL, TRUE, NULL);
\r
4658 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4665 /*---------------------------------------------------------------------------*\
\r
4666 | CLIENT PAINT PROCEDURE
\r
4667 | This is the main event-handler for the WM_PAINT message.
\r
4669 \*---------------------------------------------------------------------------*/
\r
4671 PaintProc(HWND hwnd)
\r
4677 if(hdc = BeginPaint(hwnd, &ps)) {
\r
4678 if (IsIconic(hwnd)) {
\r
4679 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4681 if (!appData.monoMode) {
\r
4682 SelectPalette(hdc, hPal, FALSE);
\r
4683 RealizePalette(hdc);
\r
4685 HDCDrawPosition(hdc, 1, NULL);
\r
4687 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4688 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4689 ETO_CLIPPED|ETO_OPAQUE,
\r
4690 &messageRect, messageText, strlen(messageText), NULL);
\r
4691 SelectObject(hdc, oldFont);
\r
4692 DisplayBothClocks();
\r
4694 EndPaint(hwnd,&ps);
\r
4702 * If the user selects on a border boundary, return -1; if off the board,
\r
4703 * return -2. Otherwise map the event coordinate to the square.
\r
4704 * The offset boardRect.left or boardRect.top must already have been
\r
4705 * subtracted from x.
\r
4708 EventToSquare(int x)
\r
4715 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4717 x /= (squareSize + lineGap);
\r
4718 if (x >= BOARD_SIZE)
\r
4729 DropEnable dropEnables[] = {
\r
4730 { 'P', DP_Pawn, "Pawn" },
\r
4731 { 'N', DP_Knight, "Knight" },
\r
4732 { 'B', DP_Bishop, "Bishop" },
\r
4733 { 'R', DP_Rook, "Rook" },
\r
4734 { 'Q', DP_Queen, "Queen" },
\r
4738 SetupDropMenu(HMENU hmenu)
\r
4740 int i, count, enable;
\r
4742 extern char white_holding[], black_holding[];
\r
4743 char item[MSG_SIZ];
\r
4745 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4746 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4747 dropEnables[i].piece);
\r
4749 while (p && *p++ == dropEnables[i].piece) count++;
\r
4750 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4751 enable = count > 0 || !appData.testLegality
\r
4752 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4753 && !appData.icsActive);
\r
4754 ModifyMenu(hmenu, dropEnables[i].command,
\r
4755 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4756 dropEnables[i].command, item);
\r
4760 static int fromX = -1, fromY = -1, toX, toY;
\r
4762 /* Event handler for mouse messages */
\r
4764 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4768 static int recursive = 0;
\r
4770 BOOLEAN needsRedraw = FALSE;
\r
4771 BOOLEAN saveAnimate;
\r
4772 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4773 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4774 ChessMove moveType;
\r
4777 if (message == WM_MBUTTONUP) {
\r
4778 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4779 to the middle button: we simulate pressing the left button too!
\r
4781 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4782 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4788 pt.x = LOWORD(lParam);
\r
4789 pt.y = HIWORD(lParam);
\r
4790 x = EventToSquare(pt.x - boardRect.left);
\r
4791 y = EventToSquare(pt.y - boardRect.top);
\r
4792 if (!flipView && y >= 0) {
\r
4793 y = BOARD_HEIGHT - 1 - y;
\r
4795 if (flipView && x >= 0) {
\r
4796 x = BOARD_WIDTH - 1 - x;
\r
4799 switch (message) {
\r
4800 case WM_LBUTTONDOWN:
\r
4801 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4802 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4803 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4804 if(gameInfo.holdingsWidth &&
\r
4805 (WhiteOnMove(currentMove)
\r
4806 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4807 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4808 // click in right holdings, for determining promotion piece
\r
4809 ChessSquare p = boards[currentMove][y][x];
\r
4810 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4811 if(p != EmptySquare) {
\r
4812 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4813 fromX = fromY = -1;
\r
4817 DrawPosition(FALSE, boards[currentMove]);
\r
4821 sameAgain = FALSE;
\r
4823 /* Downclick vertically off board; check if on clock */
\r
4824 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4825 if (gameMode == EditPosition) {
\r
4826 SetWhiteToPlayEvent();
\r
4827 } else if (gameMode == IcsPlayingBlack ||
\r
4828 gameMode == MachinePlaysWhite) {
\r
4830 } else if (gameMode == EditGame) {
\r
4831 AdjustClock((logoHeight > 0 ? flipView: flipClock), -1);
\r
4833 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4834 if (gameMode == EditPosition) {
\r
4835 SetBlackToPlayEvent();
\r
4836 } else if (gameMode == IcsPlayingWhite ||
\r
4837 gameMode == MachinePlaysBlack) {
\r
4839 } else if (gameMode == EditGame) {
\r
4840 AdjustClock(!(logoHeight > 0 ? flipView: flipClock), -1);
\r
4843 if (!appData.highlightLastMove) {
\r
4844 ClearHighlights();
\r
4845 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4847 fromX = fromY = -1;
\r
4848 dragInfo.start.x = dragInfo.start.y = -1;
\r
4849 dragInfo.from = dragInfo.start;
\r
4851 } else if (x < 0 || y < 0
\r
4852 /* [HGM] block clicks between board and holdings */
\r
4853 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4854 || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
\r
4855 || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize
\r
4856 /* EditPosition, empty square, or different color piece;
\r
4857 click-click move is possible */
\r
4860 } else if (fromX == x && fromY == y) {
\r
4861 /* Downclick on same square again */
\r
4862 ClearHighlights();
\r
4863 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4864 sameAgain = TRUE;
\r
4865 } else if (fromX != -1 &&
\r
4866 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4868 /* Downclick on different square. */
\r
4869 /* [HGM] if on holdings file, should count as new first click ! */
\r
4870 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4873 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4874 to make sure move is legal before showing promotion popup */
\r
4875 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4876 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4877 fromX = fromY = -1;
\r
4878 ClearHighlights();
\r
4879 DrawPosition(FALSE, boards[currentMove]);
\r
4882 if(moveType != ImpossibleMove) {
\r
4883 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4884 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4885 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4886 appData.alwaysPromoteToQueen) {
\r
4887 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4888 if (!appData.highlightLastMove) {
\r
4889 ClearHighlights();
\r
4890 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4893 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4894 SetHighlights(fromX, fromY, toX, toY);
\r
4895 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4896 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4897 If promotion to Q is legal, all are legal! */
\r
4898 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4899 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4900 // kludge to temporarily execute move on display, wthout promotng yet
\r
4901 promotionChoice = TRUE;
\r
4902 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4903 boards[currentMove][toY][toX] = p;
\r
4904 DrawPosition(FALSE, boards[currentMove]);
\r
4905 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4906 boards[currentMove][toY][toX] = q;
\r
4908 PromotionPopup(hwnd);
\r
4909 } else { /* not a promotion */
\r
4910 if (appData.animate || appData.highlightLastMove) {
\r
4911 SetHighlights(fromX, fromY, toX, toY);
\r
4913 ClearHighlights();
\r
4915 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4916 fromX = fromY = -1;
\r
4917 if (appData.animate && !appData.highlightLastMove) {
\r
4918 ClearHighlights();
\r
4919 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4925 /* [HGM] it seemed that braces were missing here */
\r
4926 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4927 fromX = fromY = -1;
\r
4931 ClearHighlights();
\r
4932 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4934 /* First downclick, or restart on a square with same color piece */
\r
4935 if (!frozen && OKToStartUserMove(x, y)) {
\r
4938 dragInfo.lastpos = pt;
\r
4939 dragInfo.from.x = fromX;
\r
4940 dragInfo.from.y = fromY;
\r
4941 dragInfo.start = dragInfo.from;
\r
4942 SetCapture(hwndMain);
\r
4944 fromX = fromY = -1;
\r
4945 dragInfo.start.x = dragInfo.start.y = -1;
\r
4946 dragInfo.from = dragInfo.start;
\r
4947 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4951 case WM_LBUTTONUP:
\r
4953 if (fromX == -1) break;
\r
4954 if (x == fromX && y == fromY) {
\r
4955 dragInfo.from.x = dragInfo.from.y = -1;
\r
4956 /* Upclick on same square */
\r
4958 /* Clicked same square twice: abort click-click move */
\r
4959 fromX = fromY = -1;
\r
4961 ClearPremoveHighlights();
\r
4963 /* First square clicked: start click-click move */
\r
4964 SetHighlights(fromX, fromY, -1, -1);
\r
4966 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4967 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4968 /* Errant click; ignore */
\r
4971 /* Finish drag move. */
\r
4972 if (appData.debugMode) {
\r
4973 fprintf(debugFP, "release\n");
\r
4975 dragInfo.from.x = dragInfo.from.y = -1;
\r
4978 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4979 appData.animate = appData.animate && !appData.animateDragging;
\r
4980 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4981 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4982 fromX = fromY = -1;
\r
4983 ClearHighlights();
\r
4984 DrawPosition(FALSE, boards[currentMove]);
\r
4987 if(moveType != ImpossibleMove) {
\r
4988 /* [HGM] use move type to determine if move is promotion.
\r
4989 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
4990 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4991 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4992 appData.alwaysPromoteToQueen)
\r
4993 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4995 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4996 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4997 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4998 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4999 // kludge to temporarily execute move on display, wthout promotng yet
\r
5000 promotionChoice = TRUE;
\r
5001 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5002 boards[currentMove][toY][toX] = p;
\r
5003 DrawPosition(FALSE, boards[currentMove]);
\r
5004 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5005 boards[currentMove][toY][toX] = q;
\r
5008 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5009 } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5011 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5012 appData.animate = saveAnimate;
\r
5013 fromX = fromY = -1;
\r
5014 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5015 ClearHighlights();
\r
5017 if (appData.animate || appData.animateDragging ||
\r
5018 appData.highlightDragging || gotPremove) {
\r
5019 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5022 dragInfo.start.x = dragInfo.start.y = -1;
\r
5023 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5026 case WM_MOUSEMOVE:
\r
5027 if ((appData.animateDragging || appData.highlightDragging)
\r
5028 && (wParam & MK_LBUTTON)
\r
5029 && dragInfo.from.x >= 0)
\r
5031 BOOL full_repaint = FALSE;
\r
5033 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5034 if (appData.animateDragging) {
\r
5035 dragInfo.pos = pt;
\r
5037 if (appData.highlightDragging) {
\r
5038 SetHighlights(fromX, fromY, x, y);
\r
5039 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5040 full_repaint = TRUE;
\r
5044 DrawPosition( full_repaint, NULL);
\r
5046 dragInfo.lastpos = dragInfo.pos;
\r
5050 case WM_MOUSEWHEEL: // [DM]
\r
5051 /* Mouse Wheel is being rolled forward
\r
5052 * Play moves forward
\r
5054 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove) ForwardEvent();
\r
5055 /* Mouse Wheel is being rolled backward
\r
5056 * Play moves backward
\r
5058 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove) BackwardEvent();
\r
5061 case WM_MBUTTONDOWN:
\r
5062 case WM_RBUTTONDOWN:
\r
5065 fromX = fromY = -1;
\r
5066 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5067 dragInfo.start.x = dragInfo.start.y = -1;
\r
5068 dragInfo.from = dragInfo.start;
\r
5069 dragInfo.lastpos = dragInfo.pos;
\r
5070 if (appData.highlightDragging) {
\r
5071 ClearHighlights();
\r
5074 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5075 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5076 if (gameMode == EditGame) AdjustClock((logoHeight > 0 ? flipView: flipClock), 1);
\r
5077 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5078 if (gameMode == EditGame) AdjustClock(!(logoHeight > 0 ? flipView: flipClock), 1);
\r
5081 DrawPosition(TRUE, NULL);
\r
5083 switch (gameMode) {
\r
5084 case EditPosition:
\r
5085 case IcsExamining:
\r
5086 if (x < 0 || y < 0) break;
\r
5089 if (message == WM_MBUTTONDOWN) {
\r
5090 buttonCount = 3; /* even if system didn't think so */
\r
5091 if (wParam & MK_SHIFT)
\r
5092 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5094 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5095 } else { /* message == WM_RBUTTONDOWN */
\r
5097 if (buttonCount == 3) {
\r
5098 if (wParam & MK_SHIFT)
\r
5099 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5101 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5103 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5106 /* Just have one menu, on the right button. Windows users don't
\r
5107 think to try the middle one, and sometimes other software steals
\r
5108 it, or it doesn't really exist. */
\r
5109 if(gameInfo.variant != VariantShogi)
\r
5110 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5112 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5116 case IcsPlayingWhite:
\r
5117 case IcsPlayingBlack:
\r
5119 case MachinePlaysWhite:
\r
5120 case MachinePlaysBlack:
\r
5121 if (appData.testLegality &&
\r
5122 gameInfo.variant != VariantBughouse &&
\r
5123 gameInfo.variant != VariantCrazyhouse) break;
\r
5124 if (x < 0 || y < 0) break;
\r
5127 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5128 SetupDropMenu(hmenu);
\r
5129 MenuPopup(hwnd, pt, hmenu, -1);
\r
5140 /* Preprocess messages for buttons in main window */
\r
5142 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5144 int id = GetWindowLong(hwnd, GWL_ID);
\r
5147 for (i=0; i<N_BUTTONS; i++) {
\r
5148 if (buttonDesc[i].id == id) break;
\r
5150 if (i == N_BUTTONS) return 0;
\r
5151 switch (message) {
\r
5156 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5157 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5164 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5167 if (appData.icsActive) {
\r
5168 if (GetKeyState(VK_SHIFT) < 0) {
\r
5170 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5171 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5175 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5176 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5183 if (appData.icsActive) {
\r
5184 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5185 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5187 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5189 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5190 PopUpMoveDialog((char)wParam);
\r
5196 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5199 /* Process messages for Promotion dialog box */
\r
5201 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5205 switch (message) {
\r
5206 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5207 /* Center the dialog over the application window */
\r
5208 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5209 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5210 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5211 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5212 SW_SHOW : SW_HIDE);
\r
5213 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5214 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5215 (PieceToChar(WhiteAngel) >= 'A' &&
\r
5216 PieceToChar(WhiteAngel) != '~' ||
\r
5217 PieceToChar(BlackAngel) >= 'A' &&
\r
5218 PieceToChar(BlackAngel) != '~' ) ?
\r
5219 SW_SHOW : SW_HIDE);
\r
5220 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5221 (PieceToChar(WhiteMarshall) >= 'A' &&
\r
5222 PieceToChar(WhiteMarshall) != '~' ||
\r
5223 PieceToChar(BlackMarshall) >= 'A' &&
\r
5224 PieceToChar(BlackMarshall) != '~' ) ?
\r
5225 SW_SHOW : SW_HIDE);
\r
5226 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5227 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5228 gameInfo.variant != VariantShogi ?
\r
5229 SW_SHOW : SW_HIDE);
\r
5230 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5231 gameInfo.variant != VariantShogi ?
\r
5232 SW_SHOW : SW_HIDE);
\r
5233 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5234 gameInfo.variant == VariantShogi ?
\r
5235 SW_SHOW : SW_HIDE);
\r
5236 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5237 gameInfo.variant == VariantShogi ?
\r
5238 SW_SHOW : SW_HIDE);
\r
5239 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5240 gameInfo.variant == VariantSuper ?
\r
5241 SW_SHOW : SW_HIDE);
\r
5244 case WM_COMMAND: /* message: received a command */
\r
5245 switch (LOWORD(wParam)) {
\r
5247 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5248 ClearHighlights();
\r
5249 DrawPosition(FALSE, NULL);
\r
5252 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5255 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5258 promoChar = PieceToChar(BlackRook);
\r
5261 promoChar = PieceToChar(BlackBishop);
\r
5263 case PB_Chancellor:
\r
5264 promoChar = PieceToChar(BlackMarshall);
\r
5266 case PB_Archbishop:
\r
5267 promoChar = PieceToChar(BlackAngel);
\r
5270 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5275 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5276 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5277 only show the popup when we are already sure the move is valid or
\r
5278 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5279 will figure out it is a promotion from the promoChar. */
\r
5280 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5281 if (!appData.highlightLastMove) {
\r
5282 ClearHighlights();
\r
5283 DrawPosition(FALSE, NULL);
\r
5290 /* Pop up promotion dialog */
\r
5292 PromotionPopup(HWND hwnd)
\r
5296 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5297 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5298 hwnd, (DLGPROC)lpProc);
\r
5299 FreeProcInstance(lpProc);
\r
5302 /* Toggle ShowThinking */
\r
5304 ToggleShowThinking()
\r
5306 appData.showThinking = !appData.showThinking;
\r
5307 ShowThinkingEvent();
\r
5311 LoadGameDialog(HWND hwnd, char* title)
\r
5315 char fileTitle[MSG_SIZ];
\r
5316 f = OpenFileDialog(hwnd, "rb", "",
\r
5317 appData.oldSaveStyle ? "gam" : "pgn",
\r
5319 title, &number, fileTitle, NULL);
\r
5321 cmailMsgLoaded = FALSE;
\r
5322 if (number == 0) {
\r
5323 int error = GameListBuild(f);
\r
5325 DisplayError("Cannot build game list", error);
\r
5326 } else if (!ListEmpty(&gameList) &&
\r
5327 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5328 GameListPopUp(f, fileTitle);
\r
5331 GameListDestroy();
\r
5334 LoadGame(f, number, fileTitle, FALSE);
\r
5339 ChangedConsoleFont()
\r
5342 CHARRANGE tmpsel, sel;
\r
5343 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5344 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5345 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5348 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5349 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5350 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5351 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5352 * size. This was undocumented in the version of MSVC++ that I had
\r
5353 * when I wrote the code, but is apparently documented now.
\r
5355 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5356 cfmt.bCharSet = f->lf.lfCharSet;
\r
5357 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5358 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5359 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5360 /* Why are the following seemingly needed too? */
\r
5361 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5362 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5363 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5365 tmpsel.cpMax = -1; /*999999?*/
\r
5366 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5367 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5368 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5369 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5371 paraf.cbSize = sizeof(paraf);
\r
5372 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5373 paraf.dxStartIndent = 0;
\r
5374 paraf.dxOffset = WRAP_INDENT;
\r
5375 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5376 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5379 /*---------------------------------------------------------------------------*\
\r
5381 * Window Proc for main window
\r
5383 \*---------------------------------------------------------------------------*/
\r
5385 /* Process messages for main window, etc. */
\r
5387 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5390 int wmId, wmEvent;
\r
5394 char fileTitle[MSG_SIZ];
\r
5395 char buf[MSG_SIZ];
\r
5396 static SnapData sd;
\r
5398 switch (message) {
\r
5400 case WM_PAINT: /* message: repaint portion of window */
\r
5404 case WM_ERASEBKGND:
\r
5405 if (IsIconic(hwnd)) {
\r
5406 /* Cheat; change the message */
\r
5407 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5409 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5413 case WM_LBUTTONDOWN:
\r
5414 case WM_MBUTTONDOWN:
\r
5415 case WM_RBUTTONDOWN:
\r
5416 case WM_LBUTTONUP:
\r
5417 case WM_MBUTTONUP:
\r
5418 case WM_RBUTTONUP:
\r
5419 case WM_MOUSEMOVE:
\r
5420 case WM_MOUSEWHEEL:
\r
5421 MouseEvent(hwnd, message, wParam, lParam);
\r
5426 if (appData.icsActive) {
\r
5427 if (wParam == '\t') {
\r
5428 if (GetKeyState(VK_SHIFT) < 0) {
\r
5430 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5431 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5435 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5436 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5440 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5441 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5443 SendMessage(h, message, wParam, lParam);
\r
5445 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5446 PopUpMoveDialog((char)wParam);
\r
5450 case WM_PALETTECHANGED:
\r
5451 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5453 HDC hdc = GetDC(hwndMain);
\r
5454 SelectPalette(hdc, hPal, TRUE);
\r
5455 nnew = RealizePalette(hdc);
\r
5457 paletteChanged = TRUE;
\r
5459 UpdateColors(hdc);
\r
5461 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5464 ReleaseDC(hwnd, hdc);
\r
5468 case WM_QUERYNEWPALETTE:
\r
5469 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5471 HDC hdc = GetDC(hwndMain);
\r
5472 paletteChanged = FALSE;
\r
5473 SelectPalette(hdc, hPal, FALSE);
\r
5474 nnew = RealizePalette(hdc);
\r
5476 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5478 ReleaseDC(hwnd, hdc);
\r
5483 case WM_COMMAND: /* message: command from application menu */
\r
5484 wmId = LOWORD(wParam);
\r
5485 wmEvent = HIWORD(wParam);
\r
5490 AnalysisPopDown();
\r
5493 case IDM_NewGameFRC:
\r
5494 if( NewGameFRC() == 0 ) {
\r
5496 AnalysisPopDown();
\r
5500 case IDM_NewVariant:
\r
5501 NewVariantPopup(hwnd);
\r
5504 case IDM_LoadGame:
\r
5505 LoadGameDialog(hwnd, "Load Game from File");
\r
5508 case IDM_LoadNextGame:
\r
5512 case IDM_LoadPrevGame:
\r
5516 case IDM_ReloadGame:
\r
5520 case IDM_LoadPosition:
\r
5521 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5522 Reset(FALSE, TRUE);
\r
5525 f = OpenFileDialog(hwnd, "rb", "",
\r
5526 appData.oldSaveStyle ? "pos" : "fen",
\r
5528 "Load Position from File", &number, fileTitle, NULL);
\r
5530 LoadPosition(f, number, fileTitle);
\r
5534 case IDM_LoadNextPosition:
\r
5535 ReloadPosition(1);
\r
5538 case IDM_LoadPrevPosition:
\r
5539 ReloadPosition(-1);
\r
5542 case IDM_ReloadPosition:
\r
5543 ReloadPosition(0);
\r
5546 case IDM_SaveGame:
\r
5547 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5548 f = OpenFileDialog(hwnd, "a", defName,
\r
5549 appData.oldSaveStyle ? "gam" : "pgn",
\r
5551 "Save Game to File", NULL, fileTitle, NULL);
\r
5553 SaveGame(f, 0, "");
\r
5557 case IDM_SavePosition:
\r
5558 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5559 f = OpenFileDialog(hwnd, "a", defName,
\r
5560 appData.oldSaveStyle ? "pos" : "fen",
\r
5562 "Save Position to File", NULL, fileTitle, NULL);
\r
5564 SavePosition(f, 0, "");
\r
5568 case IDM_SaveDiagram:
\r
5569 defName = "diagram";
\r
5570 f = OpenFileDialog(hwnd, "wb", defName,
\r
5573 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5579 case IDM_CopyGame:
\r
5580 CopyGameToClipboard();
\r
5583 case IDM_PasteGame:
\r
5584 PasteGameFromClipboard();
\r
5587 case IDM_CopyGameListToClipboard:
\r
5588 CopyGameListToClipboard();
\r
5591 /* [AS] Autodetect FEN or PGN data */
\r
5592 case IDM_PasteAny:
\r
5593 PasteGameOrFENFromClipboard();
\r
5596 /* [AS] Move history */
\r
5597 case IDM_ShowMoveHistory:
\r
5598 if( MoveHistoryIsUp() ) {
\r
5599 MoveHistoryPopDown();
\r
5602 MoveHistoryPopUp();
\r
5606 /* [AS] Eval graph */
\r
5607 case IDM_ShowEvalGraph:
\r
5608 if( EvalGraphIsUp() ) {
\r
5609 EvalGraphPopDown();
\r
5616 /* [AS] Engine output */
\r
5617 case IDM_ShowEngineOutput:
\r
5618 if( EngineOutputIsUp() ) {
\r
5619 EngineOutputPopDown();
\r
5622 EngineOutputPopUp();
\r
5626 /* [AS] User adjudication */
\r
5627 case IDM_UserAdjudication_White:
\r
5628 UserAdjudicationEvent( +1 );
\r
5631 case IDM_UserAdjudication_Black:
\r
5632 UserAdjudicationEvent( -1 );
\r
5635 case IDM_UserAdjudication_Draw:
\r
5636 UserAdjudicationEvent( 0 );
\r
5639 /* [AS] Game list options dialog */
\r
5640 case IDM_GameListOptions:
\r
5641 GameListOptions();
\r
5644 case IDM_CopyPosition:
\r
5645 CopyFENToClipboard();
\r
5648 case IDM_PastePosition:
\r
5649 PasteFENFromClipboard();
\r
5652 case IDM_MailMove:
\r
5656 case IDM_ReloadCMailMsg:
\r
5657 Reset(TRUE, TRUE);
\r
5658 ReloadCmailMsgEvent(FALSE);
\r
5661 case IDM_Minimize:
\r
5662 ShowWindow(hwnd, SW_MINIMIZE);
\r
5669 case IDM_MachineWhite:
\r
5670 MachineWhiteEvent();
\r
5672 * refresh the tags dialog only if it's visible
\r
5674 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5676 tags = PGNTags(&gameInfo);
\r
5677 TagsPopUp(tags, CmailMsg());
\r
5682 case IDM_MachineBlack:
\r
5683 MachineBlackEvent();
\r
5685 * refresh the tags dialog only if it's visible
\r
5687 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5689 tags = PGNTags(&gameInfo);
\r
5690 TagsPopUp(tags, CmailMsg());
\r
5695 case IDM_TwoMachines:
\r
5696 TwoMachinesEvent();
\r
5698 * refresh the tags dialog only if it's visible
\r
5700 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5702 tags = PGNTags(&gameInfo);
\r
5703 TagsPopUp(tags, CmailMsg());
\r
5708 case IDM_AnalysisMode:
\r
5709 if (!first.analysisSupport) {
\r
5710 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5711 DisplayError(buf, 0);
\r
5713 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5714 if (appData.icsActive) {
\r
5715 if (gameMode != IcsObserving) {
\r
5716 sprintf(buf, "You are not observing a game");
\r
5717 DisplayError(buf, 0);
\r
5718 /* secure check */
\r
5719 if (appData.icsEngineAnalyze) {
\r
5720 if (appData.debugMode)
\r
5721 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5722 ExitAnalyzeMode();
\r
5728 /* if enable, user want disable icsEngineAnalyze */
\r
5729 if (appData.icsEngineAnalyze) {
\r
5730 ExitAnalyzeMode();
\r
5734 appData.icsEngineAnalyze = TRUE;
\r
5735 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5738 if (!appData.showThinking) ToggleShowThinking();
\r
5739 AnalyzeModeEvent();
\r
5743 case IDM_AnalyzeFile:
\r
5744 if (!first.analysisSupport) {
\r
5745 char buf[MSG_SIZ];
\r
5746 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5747 DisplayError(buf, 0);
\r
5749 if (!appData.showThinking) ToggleShowThinking();
\r
5750 AnalyzeFileEvent();
\r
5751 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5752 AnalysisPeriodicEvent(1);
\r
5756 case IDM_IcsClient:
\r
5760 case IDM_EditGame:
\r
5764 case IDM_EditPosition:
\r
5765 EditPositionEvent();
\r
5768 case IDM_Training:
\r
5772 case IDM_ShowGameList:
\r
5773 ShowGameListProc();
\r
5776 case IDM_EditTags:
\r
5780 case IDM_EditComment:
\r
5781 if (commentDialogUp && editComment) {
\r
5784 EditCommentEvent();
\r
5804 case IDM_CallFlag:
\r
5824 case IDM_StopObserving:
\r
5825 StopObservingEvent();
\r
5828 case IDM_StopExamining:
\r
5829 StopExaminingEvent();
\r
5832 case IDM_TypeInMove:
\r
5833 PopUpMoveDialog('\000');
\r
5836 case IDM_TypeInName:
\r
5837 PopUpNameDialog('\000');
\r
5840 case IDM_Backward:
\r
5842 SetFocus(hwndMain);
\r
5847 SetFocus(hwndMain);
\r
5852 SetFocus(hwndMain);
\r
5857 SetFocus(hwndMain);
\r
5864 case IDM_TruncateGame:
\r
5865 TruncateGameEvent();
\r
5872 case IDM_RetractMove:
\r
5873 RetractMoveEvent();
\r
5876 case IDM_FlipView:
\r
5877 flipView = !flipView;
\r
5878 DrawPosition(FALSE, NULL);
\r
5881 case IDM_FlipClock:
\r
5882 flipClock = !flipClock;
\r
5883 DisplayBothClocks();
\r
5886 case IDM_GeneralOptions:
\r
5887 GeneralOptionsPopup(hwnd);
\r
5888 DrawPosition(TRUE, NULL);
\r
5891 case IDM_BoardOptions:
\r
5892 BoardOptionsPopup(hwnd);
\r
5895 case IDM_EnginePlayOptions:
\r
5896 EnginePlayOptionsPopup(hwnd);
\r
5899 case IDM_OptionsUCI:
\r
5900 UciOptionsPopup(hwnd);
\r
5903 case IDM_IcsOptions:
\r
5904 IcsOptionsPopup(hwnd);
\r
5908 FontsOptionsPopup(hwnd);
\r
5912 SoundOptionsPopup(hwnd);
\r
5915 case IDM_CommPort:
\r
5916 CommPortOptionsPopup(hwnd);
\r
5919 case IDM_LoadOptions:
\r
5920 LoadOptionsPopup(hwnd);
\r
5923 case IDM_SaveOptions:
\r
5924 SaveOptionsPopup(hwnd);
\r
5927 case IDM_TimeControl:
\r
5928 TimeControlOptionsPopup(hwnd);
\r
5931 case IDM_SaveSettings:
\r
5932 SaveSettings(settingsFileName);
\r
5935 case IDM_SaveSettingsOnExit:
\r
5936 saveSettingsOnExit = !saveSettingsOnExit;
\r
5937 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5938 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5939 MF_CHECKED : MF_UNCHECKED));
\r
5950 case IDM_AboutGame:
\r
5955 appData.debugMode = !appData.debugMode;
\r
5956 if (appData.debugMode) {
\r
5957 char dir[MSG_SIZ];
\r
5958 GetCurrentDirectory(MSG_SIZ, dir);
\r
5959 SetCurrentDirectory(installDir);
\r
5960 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5961 SetCurrentDirectory(dir);
\r
5962 setbuf(debugFP, NULL);
\r
5969 case IDM_HELPCONTENTS:
\r
5970 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5971 MessageBox (GetFocus(),
\r
5972 "Unable to activate help",
\r
5973 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5977 case IDM_HELPSEARCH:
\r
5978 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5979 MessageBox (GetFocus(),
\r
5980 "Unable to activate help",
\r
5981 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5985 case IDM_HELPHELP:
\r
5986 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5987 MessageBox (GetFocus(),
\r
5988 "Unable to activate help",
\r
5989 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5994 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5996 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5997 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5998 FreeProcInstance(lpProc);
\r
6001 case IDM_DirectCommand1:
\r
6002 AskQuestionEvent("Direct Command",
\r
6003 "Send to chess program:", "", "1");
\r
6005 case IDM_DirectCommand2:
\r
6006 AskQuestionEvent("Direct Command",
\r
6007 "Send to second chess program:", "", "2");
\r
6010 case EP_WhitePawn:
\r
6011 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6012 fromX = fromY = -1;
\r
6015 case EP_WhiteKnight:
\r
6016 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6017 fromX = fromY = -1;
\r
6020 case EP_WhiteBishop:
\r
6021 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6022 fromX = fromY = -1;
\r
6025 case EP_WhiteRook:
\r
6026 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6027 fromX = fromY = -1;
\r
6030 case EP_WhiteQueen:
\r
6031 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6032 fromX = fromY = -1;
\r
6035 case EP_WhiteFerz:
\r
6036 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6037 fromX = fromY = -1;
\r
6040 case EP_WhiteWazir:
\r
6041 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6042 fromX = fromY = -1;
\r
6045 case EP_WhiteAlfil:
\r
6046 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6047 fromX = fromY = -1;
\r
6050 case EP_WhiteCannon:
\r
6051 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6052 fromX = fromY = -1;
\r
6055 case EP_WhiteCardinal:
\r
6056 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6057 fromX = fromY = -1;
\r
6060 case EP_WhiteMarshall:
\r
6061 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6062 fromX = fromY = -1;
\r
6065 case EP_WhiteKing:
\r
6066 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6067 fromX = fromY = -1;
\r
6070 case EP_BlackPawn:
\r
6071 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6072 fromX = fromY = -1;
\r
6075 case EP_BlackKnight:
\r
6076 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6077 fromX = fromY = -1;
\r
6080 case EP_BlackBishop:
\r
6081 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6082 fromX = fromY = -1;
\r
6085 case EP_BlackRook:
\r
6086 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6087 fromX = fromY = -1;
\r
6090 case EP_BlackQueen:
\r
6091 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6092 fromX = fromY = -1;
\r
6095 case EP_BlackFerz:
\r
6096 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6097 fromX = fromY = -1;
\r
6100 case EP_BlackWazir:
\r
6101 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6102 fromX = fromY = -1;
\r
6105 case EP_BlackAlfil:
\r
6106 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6107 fromX = fromY = -1;
\r
6110 case EP_BlackCannon:
\r
6111 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6112 fromX = fromY = -1;
\r
6115 case EP_BlackCardinal:
\r
6116 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6117 fromX = fromY = -1;
\r
6120 case EP_BlackMarshall:
\r
6121 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6122 fromX = fromY = -1;
\r
6125 case EP_BlackKing:
\r
6126 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6127 fromX = fromY = -1;
\r
6130 case EP_EmptySquare:
\r
6131 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6132 fromX = fromY = -1;
\r
6135 case EP_ClearBoard:
\r
6136 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6137 fromX = fromY = -1;
\r
6141 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6142 fromX = fromY = -1;
\r
6146 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6147 fromX = fromY = -1;
\r
6151 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6152 fromX = fromY = -1;
\r
6156 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6157 fromX = fromY = -1;
\r
6161 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6162 fromX = fromY = -1;
\r
6166 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6167 fromX = fromY = -1;
\r
6171 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6172 fromX = fromY = -1;
\r
6176 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6177 fromX = fromY = -1;
\r
6181 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6182 fromX = fromY = -1;
\r
6186 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6192 case CLOCK_TIMER_ID:
\r
6193 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6194 clockTimerEvent = 0;
\r
6195 DecrementClocks(); /* call into back end */
\r
6197 case LOAD_GAME_TIMER_ID:
\r
6198 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6199 loadGameTimerEvent = 0;
\r
6200 AutoPlayGameLoop(); /* call into back end */
\r
6202 case ANALYSIS_TIMER_ID:
\r
6203 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6204 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6205 AnalysisPeriodicEvent(0);
\r
6207 KillTimer(hwnd, analysisTimerEvent);
\r
6208 analysisTimerEvent = 0;
\r
6211 case DELAYED_TIMER_ID:
\r
6212 KillTimer(hwnd, delayedTimerEvent);
\r
6213 delayedTimerEvent = 0;
\r
6214 delayedTimerCallback();
\r
6219 case WM_USER_Input:
\r
6220 InputEvent(hwnd, message, wParam, lParam);
\r
6223 /* [AS] Also move "attached" child windows */
\r
6224 case WM_WINDOWPOSCHANGING:
\r
6225 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6226 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6228 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6229 /* Window is moving */
\r
6232 GetWindowRect( hwnd, &rcMain );
\r
6234 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6235 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6236 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6241 /* [AS] Snapping */
\r
6242 case WM_ENTERSIZEMOVE:
\r
6243 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6244 if (hwnd == hwndMain) {
\r
6245 doingSizing = TRUE;
\r
6248 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6252 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6253 if (hwnd == hwndMain) {
\r
6254 lastSizing = wParam;
\r
6259 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6260 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6262 case WM_EXITSIZEMOVE:
\r
6263 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6264 if (hwnd == hwndMain) {
\r
6266 doingSizing = FALSE;
\r
6267 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6268 GetClientRect(hwnd, &client);
\r
6269 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6271 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6273 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6276 case WM_DESTROY: /* message: window being destroyed */
\r
6277 PostQuitMessage(0);
\r
6281 if (hwnd == hwndMain) {
\r
6286 default: /* Passes it on if unprocessed */
\r
6287 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6292 /*---------------------------------------------------------------------------*\
\r
6294 * Misc utility routines
\r
6296 \*---------------------------------------------------------------------------*/
\r
6299 * Decent random number generator, at least not as bad as Windows
\r
6300 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6302 unsigned int randstate;
\r
6307 randstate = randstate * 1664525 + 1013904223;
\r
6308 return (int) randstate & 0x7fffffff;
\r
6312 mysrandom(unsigned int seed)
\r
6319 * returns TRUE if user selects a different color, FALSE otherwise
\r
6323 ChangeColor(HWND hwnd, COLORREF *which)
\r
6325 static BOOL firstTime = TRUE;
\r
6326 static DWORD customColors[16];
\r
6328 COLORREF newcolor;
\r
6333 /* Make initial colors in use available as custom colors */
\r
6334 /* Should we put the compiled-in defaults here instead? */
\r
6336 customColors[i++] = lightSquareColor & 0xffffff;
\r
6337 customColors[i++] = darkSquareColor & 0xffffff;
\r
6338 customColors[i++] = whitePieceColor & 0xffffff;
\r
6339 customColors[i++] = blackPieceColor & 0xffffff;
\r
6340 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6341 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6343 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6344 customColors[i++] = textAttribs[ccl].color;
\r
6346 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6347 firstTime = FALSE;
\r
6350 cc.lStructSize = sizeof(cc);
\r
6351 cc.hwndOwner = hwnd;
\r
6352 cc.hInstance = NULL;
\r
6353 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6354 cc.lpCustColors = (LPDWORD) customColors;
\r
6355 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6357 if (!ChooseColor(&cc)) return FALSE;
\r
6359 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6360 if (newcolor == *which) return FALSE;
\r
6361 *which = newcolor;
\r
6365 InitDrawingColors();
\r
6366 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6371 MyLoadSound(MySound *ms)
\r
6377 if (ms->data) free(ms->data);
\r
6380 switch (ms->name[0]) {
\r
6386 /* System sound from Control Panel. Don't preload here. */
\r
6390 if (ms->name[1] == NULLCHAR) {
\r
6391 /* "!" alone = silence */
\r
6394 /* Builtin wave resource. Error if not found. */
\r
6395 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6396 if (h == NULL) break;
\r
6397 ms->data = (void *)LoadResource(hInst, h);
\r
6398 if (h == NULL) break;
\r
6403 /* .wav file. Error if not found. */
\r
6404 f = fopen(ms->name, "rb");
\r
6405 if (f == NULL) break;
\r
6406 if (fstat(fileno(f), &st) < 0) break;
\r
6407 ms->data = malloc(st.st_size);
\r
6408 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6414 char buf[MSG_SIZ];
\r
6415 sprintf(buf, "Error loading sound %s", ms->name);
\r
6416 DisplayError(buf, GetLastError());
\r
6422 MyPlaySound(MySound *ms)
\r
6424 BOOLEAN ok = FALSE;
\r
6425 switch (ms->name[0]) {
\r
6431 /* System sound from Control Panel (deprecated feature).
\r
6432 "$" alone or an unset sound name gets default beep (still in use). */
\r
6433 if (ms->name[1]) {
\r
6434 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6436 if (!ok) ok = MessageBeep(MB_OK);
\r
6439 /* Builtin wave resource, or "!" alone for silence */
\r
6440 if (ms->name[1]) {
\r
6441 if (ms->data == NULL) return FALSE;
\r
6442 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6448 /* .wav file. Error if not found. */
\r
6449 if (ms->data == NULL) return FALSE;
\r
6450 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6453 /* Don't print an error: this can happen innocently if the sound driver
\r
6454 is busy; for instance, if another instance of WinBoard is playing
\r
6455 a sound at about the same time. */
\r
6458 char buf[MSG_SIZ];
\r
6459 sprintf(buf, "Error playing sound %s", ms->name);
\r
6460 DisplayError(buf, GetLastError());
\r
6468 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6471 OPENFILENAME *ofn;
\r
6472 static UINT *number; /* gross that this is static */
\r
6474 switch (message) {
\r
6475 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6476 /* Center the dialog over the application window */
\r
6477 ofn = (OPENFILENAME *) lParam;
\r
6478 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6479 number = (UINT *) ofn->lCustData;
\r
6480 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6484 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6485 return FALSE; /* Allow for further processing */
\r
6488 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6489 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6491 return FALSE; /* Allow for further processing */
\r
6497 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6499 static UINT *number;
\r
6500 OPENFILENAME *ofname;
\r
6503 case WM_INITDIALOG:
\r
6504 ofname = (OPENFILENAME *)lParam;
\r
6505 number = (UINT *)(ofname->lCustData);
\r
6508 ofnot = (OFNOTIFY *)lParam;
\r
6509 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6510 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6519 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6520 char *nameFilt, char *dlgTitle, UINT *number,
\r
6521 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6523 OPENFILENAME openFileName;
\r
6524 char buf1[MSG_SIZ];
\r
6527 if (fileName == NULL) fileName = buf1;
\r
6528 if (defName == NULL) {
\r
6529 strcpy(fileName, "*.");
\r
6530 strcat(fileName, defExt);
\r
6532 strcpy(fileName, defName);
\r
6534 if (fileTitle) strcpy(fileTitle, "");
\r
6535 if (number) *number = 0;
\r
6537 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6538 openFileName.hwndOwner = hwnd;
\r
6539 openFileName.hInstance = (HANDLE) hInst;
\r
6540 openFileName.lpstrFilter = nameFilt;
\r
6541 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6542 openFileName.nMaxCustFilter = 0L;
\r
6543 openFileName.nFilterIndex = 1L;
\r
6544 openFileName.lpstrFile = fileName;
\r
6545 openFileName.nMaxFile = MSG_SIZ;
\r
6546 openFileName.lpstrFileTitle = fileTitle;
\r
6547 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6548 openFileName.lpstrInitialDir = NULL;
\r
6549 openFileName.lpstrTitle = dlgTitle;
\r
6550 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6551 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6552 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6553 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6554 openFileName.nFileOffset = 0;
\r
6555 openFileName.nFileExtension = 0;
\r
6556 openFileName.lpstrDefExt = defExt;
\r
6557 openFileName.lCustData = (LONG) number;
\r
6558 openFileName.lpfnHook = oldDialog ?
\r
6559 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6560 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6562 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6563 GetOpenFileName(&openFileName)) {
\r
6564 /* open the file */
\r
6565 f = fopen(openFileName.lpstrFile, write);
\r
6567 MessageBox(hwnd, "File open failed", NULL,
\r
6568 MB_OK|MB_ICONEXCLAMATION);
\r
6572 int err = CommDlgExtendedError();
\r
6573 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6582 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6584 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6587 * Get the first pop-up menu in the menu template. This is the
\r
6588 * menu that TrackPopupMenu displays.
\r
6590 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6592 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6595 * TrackPopup uses screen coordinates, so convert the
\r
6596 * coordinates of the mouse click to screen coordinates.
\r
6598 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6600 /* Draw and track the floating pop-up menu. */
\r
6601 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6602 pt.x, pt.y, 0, hwnd, NULL);
\r
6604 /* Destroy the menu.*/
\r
6605 DestroyMenu(hmenu);
\r
6610 int sizeX, sizeY, newSizeX, newSizeY;
\r
6612 } ResizeEditPlusButtonsClosure;
\r
6615 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6617 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6621 if (hChild == cl->hText) return TRUE;
\r
6622 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6623 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6624 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6625 ScreenToClient(cl->hDlg, &pt);
\r
6626 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6627 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6631 /* Resize a dialog that has a (rich) edit field filling most of
\r
6632 the top, with a row of buttons below */
\r
6634 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6637 int newTextHeight, newTextWidth;
\r
6638 ResizeEditPlusButtonsClosure cl;
\r
6640 /*if (IsIconic(hDlg)) return;*/
\r
6641 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6643 cl.hdwp = BeginDeferWindowPos(8);
\r
6645 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6646 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6647 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6648 if (newTextHeight < 0) {
\r
6649 newSizeY += -newTextHeight;
\r
6650 newTextHeight = 0;
\r
6652 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6653 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6659 cl.newSizeX = newSizeX;
\r
6660 cl.newSizeY = newSizeY;
\r
6661 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6663 EndDeferWindowPos(cl.hdwp);
\r
6666 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6668 RECT rChild, rParent;
\r
6669 int wChild, hChild, wParent, hParent;
\r
6670 int wScreen, hScreen, xNew, yNew;
\r
6673 /* Get the Height and Width of the child window */
\r
6674 GetWindowRect (hwndChild, &rChild);
\r
6675 wChild = rChild.right - rChild.left;
\r
6676 hChild = rChild.bottom - rChild.top;
\r
6678 /* Get the Height and Width of the parent window */
\r
6679 GetWindowRect (hwndParent, &rParent);
\r
6680 wParent = rParent.right - rParent.left;
\r
6681 hParent = rParent.bottom - rParent.top;
\r
6683 /* Get the display limits */
\r
6684 hdc = GetDC (hwndChild);
\r
6685 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6686 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6687 ReleaseDC(hwndChild, hdc);
\r
6689 /* Calculate new X position, then adjust for screen */
\r
6690 xNew = rParent.left + ((wParent - wChild) /2);
\r
6693 } else if ((xNew+wChild) > wScreen) {
\r
6694 xNew = wScreen - wChild;
\r
6697 /* Calculate new Y position, then adjust for screen */
\r
6699 yNew = rParent.top + ((hParent - hChild) /2);
\r
6702 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6707 } else if ((yNew+hChild) > hScreen) {
\r
6708 yNew = hScreen - hChild;
\r
6711 /* Set it, and return */
\r
6712 return SetWindowPos (hwndChild, NULL,
\r
6713 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6716 /* Center one window over another */
\r
6717 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6719 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6722 /*---------------------------------------------------------------------------*\
\r
6724 * Startup Dialog functions
\r
6726 \*---------------------------------------------------------------------------*/
\r
6728 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6730 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6732 while (*cd != NULL) {
\r
6733 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6739 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6741 char buf1[ARG_MAX];
\r
6744 if (str[0] == '@') {
\r
6745 FILE* f = fopen(str + 1, "r");
\r
6747 DisplayFatalError(str + 1, errno, 2);
\r
6750 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6752 buf1[len] = NULLCHAR;
\r
6756 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6759 char buf[MSG_SIZ];
\r
6760 char *end = strchr(str, '\n');
\r
6761 if (end == NULL) return;
\r
6762 memcpy(buf, str, end - str);
\r
6763 buf[end - str] = NULLCHAR;
\r
6764 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6770 SetStartupDialogEnables(HWND hDlg)
\r
6772 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6773 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6774 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6775 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6776 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6777 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6778 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6779 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6780 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6781 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6782 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6783 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6784 IsDlgButtonChecked(hDlg, OPT_View));
\r
6788 QuoteForFilename(char *filename)
\r
6790 int dquote, space;
\r
6791 dquote = strchr(filename, '"') != NULL;
\r
6792 space = strchr(filename, ' ') != NULL;
\r
6793 if (dquote || space) {
\r
6805 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6807 char buf[MSG_SIZ];
\r
6810 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6811 q = QuoteForFilename(nthcp);
\r
6812 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6813 if (*nthdir != NULLCHAR) {
\r
6814 q = QuoteForFilename(nthdir);
\r
6815 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6817 if (*nthcp == NULLCHAR) {
\r
6818 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6819 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6820 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6821 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6826 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6828 char buf[MSG_SIZ];
\r
6832 switch (message) {
\r
6833 case WM_INITDIALOG:
\r
6834 /* Center the dialog */
\r
6835 CenterWindow (hDlg, GetDesktopWindow());
\r
6836 /* Initialize the dialog items */
\r
6837 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6838 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6839 firstChessProgramNames);
\r
6840 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6841 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6842 secondChessProgramNames);
\r
6843 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6844 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6845 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6846 if (*appData.icsHelper != NULLCHAR) {
\r
6847 char *q = QuoteForFilename(appData.icsHelper);
\r
6848 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6850 if (*appData.icsHost == NULLCHAR) {
\r
6851 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6852 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6853 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6854 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6855 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6858 if (appData.icsActive) {
\r
6859 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6861 else if (appData.noChessProgram) {
\r
6862 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6865 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6868 SetStartupDialogEnables(hDlg);
\r
6872 switch (LOWORD(wParam)) {
\r
6874 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6875 strcpy(buf, "/fcp=");
\r
6876 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6878 ParseArgs(StringGet, &p);
\r
6879 strcpy(buf, "/scp=");
\r
6880 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6882 ParseArgs(StringGet, &p);
\r
6883 appData.noChessProgram = FALSE;
\r
6884 appData.icsActive = FALSE;
\r
6885 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6886 strcpy(buf, "/ics /icshost=");
\r
6887 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6889 ParseArgs(StringGet, &p);
\r
6890 if (appData.zippyPlay) {
\r
6891 strcpy(buf, "/fcp=");
\r
6892 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6894 ParseArgs(StringGet, &p);
\r
6896 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6897 appData.noChessProgram = TRUE;
\r
6898 appData.icsActive = FALSE;
\r
6900 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6901 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6904 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6905 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6907 ParseArgs(StringGet, &p);
\r
6909 EndDialog(hDlg, TRUE);
\r
6916 case IDM_HELPCONTENTS:
\r
6917 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6918 MessageBox (GetFocus(),
\r
6919 "Unable to activate help",
\r
6920 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6925 SetStartupDialogEnables(hDlg);
\r
6933 /*---------------------------------------------------------------------------*\
\r
6935 * About box dialog functions
\r
6937 \*---------------------------------------------------------------------------*/
\r
6939 /* Process messages for "About" dialog box */
\r
6941 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6943 switch (message) {
\r
6944 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6945 /* Center the dialog over the application window */
\r
6946 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6947 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6950 case WM_COMMAND: /* message: received a command */
\r
6951 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6952 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6953 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6961 /*---------------------------------------------------------------------------*\
\r
6963 * Comment Dialog functions
\r
6965 \*---------------------------------------------------------------------------*/
\r
6968 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6970 static HANDLE hwndText = NULL;
\r
6971 int len, newSizeX, newSizeY, flags;
\r
6972 static int sizeX, sizeY;
\r
6977 switch (message) {
\r
6978 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6979 /* Initialize the dialog items */
\r
6980 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6981 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6982 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6983 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6984 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6985 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6986 SetWindowText(hDlg, commentTitle);
\r
6987 if (editComment) {
\r
6988 SetFocus(hwndText);
\r
6990 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6992 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6993 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6994 MAKELPARAM(FALSE, 0));
\r
6995 /* Size and position the dialog */
\r
6996 if (!commentDialog) {
\r
6997 commentDialog = hDlg;
\r
6998 flags = SWP_NOZORDER;
\r
6999 GetClientRect(hDlg, &rect);
\r
7000 sizeX = rect.right;
\r
7001 sizeY = rect.bottom;
\r
7002 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7003 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7004 WINDOWPLACEMENT wp;
\r
7005 EnsureOnScreen(&commentX, &commentY);
\r
7006 wp.length = sizeof(WINDOWPLACEMENT);
\r
7008 wp.showCmd = SW_SHOW;
\r
7009 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7010 wp.rcNormalPosition.left = commentX;
\r
7011 wp.rcNormalPosition.right = commentX + commentW;
\r
7012 wp.rcNormalPosition.top = commentY;
\r
7013 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7014 SetWindowPlacement(hDlg, &wp);
\r
7016 GetClientRect(hDlg, &rect);
\r
7017 newSizeX = rect.right;
\r
7018 newSizeY = rect.bottom;
\r
7019 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7020 newSizeX, newSizeY);
\r
7027 case WM_COMMAND: /* message: received a command */
\r
7028 switch (LOWORD(wParam)) {
\r
7030 if (editComment) {
\r
7032 /* Read changed options from the dialog box */
\r
7033 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7034 len = GetWindowTextLength(hwndText);
\r
7035 str = (char *) malloc(len + 1);
\r
7036 GetWindowText(hwndText, str, len + 1);
\r
7045 ReplaceComment(commentIndex, str);
\r
7052 case OPT_CancelComment:
\r
7056 case OPT_ClearComment:
\r
7057 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7060 case OPT_EditComment:
\r
7061 EditCommentEvent();
\r
7070 newSizeX = LOWORD(lParam);
\r
7071 newSizeY = HIWORD(lParam);
\r
7072 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7077 case WM_GETMINMAXINFO:
\r
7078 /* Prevent resizing window too small */
\r
7079 mmi = (MINMAXINFO *) lParam;
\r
7080 mmi->ptMinTrackSize.x = 100;
\r
7081 mmi->ptMinTrackSize.y = 100;
\r
7088 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7093 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7095 if (str == NULL) str = "";
\r
7096 p = (char *) malloc(2 * strlen(str) + 2);
\r
7099 if (*str == '\n') *q++ = '\r';
\r
7103 if (commentText != NULL) free(commentText);
\r
7105 commentIndex = index;
\r
7106 commentTitle = title;
\r
7108 editComment = edit;
\r
7110 if (commentDialog) {
\r
7111 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7112 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7114 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7115 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7116 hwndMain, (DLGPROC)lpProc);
\r
7117 FreeProcInstance(lpProc);
\r
7119 commentDialogUp = TRUE;
\r
7123 /*---------------------------------------------------------------------------*\
\r
7125 * Type-in move dialog functions
\r
7127 \*---------------------------------------------------------------------------*/
\r
7130 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7132 char move[MSG_SIZ];
\r
7134 ChessMove moveType;
\r
7135 int fromX, fromY, toX, toY;
\r
7138 switch (message) {
\r
7139 case WM_INITDIALOG:
\r
7140 move[0] = (char) lParam;
\r
7141 move[1] = NULLCHAR;
\r
7142 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7143 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7144 SetWindowText(hInput, move);
\r
7146 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7150 switch (LOWORD(wParam)) {
\r
7152 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7153 gameMode != Training) {
\r
7154 DisplayMoveError("Displayed move is not current");
\r
7156 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7157 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7158 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7159 if (gameMode != Training)
\r
7160 forwardMostMove = currentMove;
\r
7161 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7163 DisplayMoveError("Could not parse move");
\r
7166 EndDialog(hDlg, TRUE);
\r
7169 EndDialog(hDlg, FALSE);
\r
7180 PopUpMoveDialog(char firstchar)
\r
7184 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7185 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7186 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7187 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7188 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7189 gameMode == Training) {
\r
7190 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7191 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7192 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7193 FreeProcInstance(lpProc);
\r
7197 /*---------------------------------------------------------------------------*\
\r
7199 * Type-in name dialog functions
\r
7201 \*---------------------------------------------------------------------------*/
\r
7204 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7206 char move[MSG_SIZ];
\r
7209 switch (message) {
\r
7210 case WM_INITDIALOG:
\r
7211 move[0] = (char) lParam;
\r
7212 move[1] = NULLCHAR;
\r
7213 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7214 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7215 SetWindowText(hInput, move);
\r
7217 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7221 switch (LOWORD(wParam)) {
\r
7223 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7224 appData.userName = strdup(move);
\r
7226 EndDialog(hDlg, TRUE);
\r
7229 EndDialog(hDlg, FALSE);
\r
7240 PopUpNameDialog(char firstchar)
\r
7244 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7245 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7246 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7247 FreeProcInstance(lpProc);
\r
7250 /*---------------------------------------------------------------------------*\
\r
7254 \*---------------------------------------------------------------------------*/
\r
7256 /* Nonmodal error box */
\r
7257 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7258 WPARAM wParam, LPARAM lParam);
\r
7261 ErrorPopUp(char *title, char *content)
\r
7265 BOOLEAN modal = hwndMain == NULL;
\r
7283 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7284 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7287 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7289 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7290 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7291 hwndMain, (DLGPROC)lpProc);
\r
7292 FreeProcInstance(lpProc);
\r
7299 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7300 if (errorDialog == NULL) return;
\r
7301 DestroyWindow(errorDialog);
\r
7302 errorDialog = NULL;
\r
7306 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7311 switch (message) {
\r
7312 case WM_INITDIALOG:
\r
7313 GetWindowRect(hDlg, &rChild);
\r
7316 SetWindowPos(hDlg, NULL, rChild.left,
\r
7317 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7318 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7322 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7323 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7324 and it doesn't work when you resize the dialog.
\r
7325 For now, just give it a default position.
\r
7327 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7329 errorDialog = 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 HWND gothicDialog = NULL;
\r
7355 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7359 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7361 switch (message) {
\r
7362 case WM_INITDIALOG:
\r
7363 GetWindowRect(hDlg, &rChild);
\r
7365 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7369 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7370 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7371 and it doesn't work when you resize the dialog.
\r
7372 For now, just give it a default position.
\r
7374 gothicDialog = hDlg;
\r
7375 SetWindowText(hDlg, errorTitle);
\r
7376 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7377 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7381 switch (LOWORD(wParam)) {
\r
7384 if (errorDialog == hDlg) errorDialog = NULL;
\r
7385 DestroyWindow(hDlg);
\r
7397 GothicPopUp(char *title, VariantClass variant)
\r
7401 BOOLEAN modal = hwndMain == NULL;
\r
7402 static char *lastTitle;
\r
7404 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7405 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7407 if(lastTitle != title && gothicDialog != NULL) {
\r
7408 DestroyWindow(gothicDialog);
\r
7409 gothicDialog = NULL;
\r
7411 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7412 title = lastTitle;
\r
7413 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7414 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7415 hwndMain, (DLGPROC)lpProc);
\r
7416 FreeProcInstance(lpProc);
\r
7421 /*---------------------------------------------------------------------------*\
\r
7423 * Ics Interaction console functions
\r
7425 \*---------------------------------------------------------------------------*/
\r
7427 #define HISTORY_SIZE 64
\r
7428 static char *history[HISTORY_SIZE];
\r
7429 int histIn = 0, histP = 0;
\r
7432 SaveInHistory(char *cmd)
\r
7434 if (history[histIn] != NULL) {
\r
7435 free(history[histIn]);
\r
7436 history[histIn] = NULL;
\r
7438 if (*cmd == NULLCHAR) return;
\r
7439 history[histIn] = StrSave(cmd);
\r
7440 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7441 if (history[histIn] != NULL) {
\r
7442 free(history[histIn]);
\r
7443 history[histIn] = NULL;
\r
7449 PrevInHistory(char *cmd)
\r
7452 if (histP == histIn) {
\r
7453 if (history[histIn] != NULL) free(history[histIn]);
\r
7454 history[histIn] = StrSave(cmd);
\r
7456 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7457 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7459 return history[histP];
\r
7465 if (histP == histIn) return NULL;
\r
7466 histP = (histP + 1) % HISTORY_SIZE;
\r
7467 return history[histP];
\r
7474 BOOLEAN immediate;
\r
7475 } IcsTextMenuEntry;
\r
7476 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7477 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7480 ParseIcsTextMenu(char *icsTextMenuString)
\r
7483 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7484 char *p = icsTextMenuString;
\r
7485 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7488 if (e->command != NULL) {
\r
7490 e->command = NULL;
\r
7494 e = icsTextMenuEntry;
\r
7495 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7496 if (*p == ';' || *p == '\n') {
\r
7497 e->item = strdup("-");
\r
7498 e->command = NULL;
\r
7500 } else if (*p == '-') {
\r
7501 e->item = strdup("-");
\r
7502 e->command = NULL;
\r
7506 char *q, *r, *s, *t;
\r
7508 q = strchr(p, ',');
\r
7509 if (q == NULL) break;
\r
7511 r = strchr(q + 1, ',');
\r
7512 if (r == NULL) break;
\r
7514 s = strchr(r + 1, ',');
\r
7515 if (s == NULL) break;
\r
7518 t = strchr(s + 1, c);
\r
7521 t = strchr(s + 1, c);
\r
7523 if (t != NULL) *t = NULLCHAR;
\r
7524 e->item = strdup(p);
\r
7525 e->command = strdup(q + 1);
\r
7526 e->getname = *(r + 1) != '0';
\r
7527 e->immediate = *(s + 1) != '0';
\r
7531 if (t == NULL) break;
\r
7540 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7544 hmenu = LoadMenu(hInst, "TextMenu");
\r
7545 h = GetSubMenu(hmenu, 0);
\r
7547 if (strcmp(e->item, "-") == 0) {
\r
7548 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7550 if (e->item[0] == '|') {
\r
7551 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7552 IDM_CommandX + i, &e->item[1]);
\r
7554 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7563 WNDPROC consoleTextWindowProc;
\r
7566 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7568 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7569 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7573 SetWindowText(hInput, command);
\r
7575 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7577 sel.cpMin = 999999;
\r
7578 sel.cpMax = 999999;
\r
7579 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7584 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7585 if (sel.cpMin == sel.cpMax) {
\r
7586 /* Expand to surrounding word */
\r
7589 tr.chrg.cpMax = sel.cpMin;
\r
7590 tr.chrg.cpMin = --sel.cpMin;
\r
7591 if (sel.cpMin < 0) break;
\r
7592 tr.lpstrText = name;
\r
7593 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7594 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7598 tr.chrg.cpMin = sel.cpMax;
\r
7599 tr.chrg.cpMax = ++sel.cpMax;
\r
7600 tr.lpstrText = name;
\r
7601 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7602 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7605 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7606 MessageBeep(MB_ICONEXCLAMATION);
\r
7610 tr.lpstrText = name;
\r
7611 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7613 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7614 MessageBeep(MB_ICONEXCLAMATION);
\r
7617 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7620 sprintf(buf, "%s %s", command, name);
\r
7621 SetWindowText(hInput, buf);
\r
7622 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7624 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7625 SetWindowText(hInput, buf);
\r
7626 sel.cpMin = 999999;
\r
7627 sel.cpMax = 999999;
\r
7628 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7634 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7639 switch (message) {
\r
7641 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7644 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7647 sel.cpMin = 999999;
\r
7648 sel.cpMax = 999999;
\r
7649 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7650 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7655 if (wParam == '\t') {
\r
7656 if (GetKeyState(VK_SHIFT) < 0) {
\r
7658 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7659 if (buttonDesc[0].hwnd) {
\r
7660 SetFocus(buttonDesc[0].hwnd);
\r
7662 SetFocus(hwndMain);
\r
7666 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7669 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7671 SendMessage(hInput, message, wParam, lParam);
\r
7675 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7677 return SendMessage(hInput, message, wParam, lParam);
\r
7678 case WM_MBUTTONDOWN:
\r
7679 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7680 case WM_RBUTTONDOWN:
\r
7681 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7682 /* Move selection here if it was empty */
\r
7684 pt.x = LOWORD(lParam);
\r
7685 pt.y = HIWORD(lParam);
\r
7686 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7687 if (sel.cpMin == sel.cpMax) {
\r
7688 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7689 sel.cpMax = sel.cpMin;
\r
7690 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7692 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7695 case WM_RBUTTONUP:
\r
7696 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7697 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7698 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7701 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7702 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7703 if (sel.cpMin == sel.cpMax) {
\r
7704 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7705 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7707 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7708 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7710 pt.x = LOWORD(lParam);
\r
7711 pt.y = HIWORD(lParam);
\r
7712 MenuPopup(hwnd, pt, hmenu, -1);
\r
7716 switch (LOWORD(wParam)) {
\r
7717 case IDM_QuickPaste:
\r
7719 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7720 if (sel.cpMin == sel.cpMax) {
\r
7721 MessageBeep(MB_ICONEXCLAMATION);
\r
7724 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7725 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7726 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7731 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7734 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7737 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7741 int i = LOWORD(wParam) - IDM_CommandX;
\r
7742 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7743 icsTextMenuEntry[i].command != NULL) {
\r
7744 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7745 icsTextMenuEntry[i].getname,
\r
7746 icsTextMenuEntry[i].immediate);
\r
7754 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7757 WNDPROC consoleInputWindowProc;
\r
7760 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7762 char buf[MSG_SIZ];
\r
7764 static BOOL sendNextChar = FALSE;
\r
7765 static BOOL quoteNextChar = FALSE;
\r
7766 InputSource *is = consoleInputSource;
\r
7770 switch (message) {
\r
7772 if (!appData.localLineEditing || sendNextChar) {
\r
7773 is->buf[0] = (CHAR) wParam;
\r
7775 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7776 sendNextChar = FALSE;
\r
7779 if (quoteNextChar) {
\r
7780 buf[0] = (char) wParam;
\r
7781 buf[1] = NULLCHAR;
\r
7782 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7783 quoteNextChar = FALSE;
\r
7787 case '\r': /* Enter key */
\r
7788 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7789 if (consoleEcho) SaveInHistory(is->buf);
\r
7790 is->buf[is->count++] = '\n';
\r
7791 is->buf[is->count] = NULLCHAR;
\r
7792 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7793 if (consoleEcho) {
\r
7794 ConsoleOutput(is->buf, is->count, TRUE);
\r
7795 } else if (appData.localLineEditing) {
\r
7796 ConsoleOutput("\n", 1, TRUE);
\r
7799 case '\033': /* Escape key */
\r
7800 SetWindowText(hwnd, "");
\r
7801 cf.cbSize = sizeof(CHARFORMAT);
\r
7802 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7803 if (consoleEcho) {
\r
7804 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7806 cf.crTextColor = COLOR_ECHOOFF;
\r
7808 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7809 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7811 case '\t': /* Tab key */
\r
7812 if (GetKeyState(VK_SHIFT) < 0) {
\r
7814 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7817 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7818 if (buttonDesc[0].hwnd) {
\r
7819 SetFocus(buttonDesc[0].hwnd);
\r
7821 SetFocus(hwndMain);
\r
7825 case '\023': /* Ctrl+S */
\r
7826 sendNextChar = TRUE;
\r
7828 case '\021': /* Ctrl+Q */
\r
7829 quoteNextChar = TRUE;
\r
7838 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7839 p = PrevInHistory(buf);
\r
7841 SetWindowText(hwnd, p);
\r
7842 sel.cpMin = 999999;
\r
7843 sel.cpMax = 999999;
\r
7844 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7849 p = NextInHistory();
\r
7851 SetWindowText(hwnd, p);
\r
7852 sel.cpMin = 999999;
\r
7853 sel.cpMax = 999999;
\r
7854 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7860 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7864 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7868 case WM_MBUTTONDOWN:
\r
7869 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7870 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7872 case WM_RBUTTONUP:
\r
7873 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7874 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7875 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7879 hmenu = LoadMenu(hInst, "InputMenu");
\r
7880 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7881 if (sel.cpMin == sel.cpMax) {
\r
7882 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7883 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7885 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7886 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7888 pt.x = LOWORD(lParam);
\r
7889 pt.y = HIWORD(lParam);
\r
7890 MenuPopup(hwnd, pt, hmenu, -1);
\r
7894 switch (LOWORD(wParam)) {
\r
7896 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7898 case IDM_SelectAll:
\r
7900 sel.cpMax = -1; /*999999?*/
\r
7901 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7904 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7907 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7910 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7915 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7918 #define CO_MAX 100000
\r
7919 #define CO_TRIM 1000
\r
7922 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7924 static SnapData sd;
\r
7925 static HWND hText, hInput, hFocus;
\r
7926 InputSource *is = consoleInputSource;
\r
7928 static int sizeX, sizeY;
\r
7929 int newSizeX, newSizeY;
\r
7932 switch (message) {
\r
7933 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7934 hwndConsole = hDlg;
\r
7935 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7936 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7938 consoleTextWindowProc = (WNDPROC)
\r
7939 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7940 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7941 consoleInputWindowProc = (WNDPROC)
\r
7942 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7943 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7944 Colorize(ColorNormal, TRUE);
\r
7945 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7946 ChangedConsoleFont();
\r
7947 GetClientRect(hDlg, &rect);
\r
7948 sizeX = rect.right;
\r
7949 sizeY = rect.bottom;
\r
7950 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7951 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7952 WINDOWPLACEMENT wp;
\r
7953 EnsureOnScreen(&consoleX, &consoleY);
\r
7954 wp.length = sizeof(WINDOWPLACEMENT);
\r
7956 wp.showCmd = SW_SHOW;
\r
7957 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7958 wp.rcNormalPosition.left = consoleX;
\r
7959 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7960 wp.rcNormalPosition.top = consoleY;
\r
7961 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7962 SetWindowPlacement(hDlg, &wp);
\r
7965 // [HGM] Chessknight's change 2004-07-13
\r
7966 else { /* Determine Defaults */
\r
7967 WINDOWPLACEMENT wp;
\r
7968 consoleX = winWidth + 1;
\r
7969 consoleY = boardY;
\r
7970 consoleW = screenWidth - winWidth;
\r
7971 consoleH = winHeight;
\r
7972 EnsureOnScreen(&consoleX, &consoleY);
\r
7973 wp.length = sizeof(WINDOWPLACEMENT);
\r
7975 wp.showCmd = SW_SHOW;
\r
7976 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7977 wp.rcNormalPosition.left = consoleX;
\r
7978 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7979 wp.rcNormalPosition.top = consoleY;
\r
7980 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7981 SetWindowPlacement(hDlg, &wp);
\r
7996 if (IsIconic(hDlg)) break;
\r
7997 newSizeX = LOWORD(lParam);
\r
7998 newSizeY = HIWORD(lParam);
\r
7999 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8000 RECT rectText, rectInput;
\r
8002 int newTextHeight, newTextWidth;
\r
8003 GetWindowRect(hText, &rectText);
\r
8004 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8005 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8006 if (newTextHeight < 0) {
\r
8007 newSizeY += -newTextHeight;
\r
8008 newTextHeight = 0;
\r
8010 SetWindowPos(hText, NULL, 0, 0,
\r
8011 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8012 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8013 pt.x = rectInput.left;
\r
8014 pt.y = rectInput.top + newSizeY - sizeY;
\r
8015 ScreenToClient(hDlg, &pt);
\r
8016 SetWindowPos(hInput, NULL,
\r
8017 pt.x, pt.y, /* needs client coords */
\r
8018 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8019 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8025 case WM_GETMINMAXINFO:
\r
8026 /* Prevent resizing window too small */
\r
8027 mmi = (MINMAXINFO *) lParam;
\r
8028 mmi->ptMinTrackSize.x = 100;
\r
8029 mmi->ptMinTrackSize.y = 100;
\r
8032 /* [AS] Snapping */
\r
8033 case WM_ENTERSIZEMOVE:
\r
8034 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8037 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8040 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8042 case WM_EXITSIZEMOVE:
\r
8043 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8046 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8054 if (hwndConsole) return;
\r
8055 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8056 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8061 ConsoleOutput(char* data, int length, int forceVisible)
\r
8066 char buf[CO_MAX+1];
\r
8069 static int delayLF = 0;
\r
8070 CHARRANGE savesel, sel;
\r
8072 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8080 while (length--) {
\r
8088 } else if (*p == '\007') {
\r
8089 MyPlaySound(&sounds[(int)SoundBell]);
\r
8096 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8097 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8098 /* Save current selection */
\r
8099 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8100 exlen = GetWindowTextLength(hText);
\r
8101 /* Find out whether current end of text is visible */
\r
8102 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8103 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8104 /* Trim existing text if it's too long */
\r
8105 if (exlen + (q - buf) > CO_MAX) {
\r
8106 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8109 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8110 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8112 savesel.cpMin -= trim;
\r
8113 savesel.cpMax -= trim;
\r
8114 if (exlen < 0) exlen = 0;
\r
8115 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8116 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8118 /* Append the new text */
\r
8119 sel.cpMin = exlen;
\r
8120 sel.cpMax = exlen;
\r
8121 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8122 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8123 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8124 if (forceVisible || exlen == 0 ||
\r
8125 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8126 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8127 /* Scroll to make new end of text visible if old end of text
\r
8128 was visible or new text is an echo of user typein */
\r
8129 sel.cpMin = 9999999;
\r
8130 sel.cpMax = 9999999;
\r
8131 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8132 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8133 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8134 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8136 if (savesel.cpMax == exlen || forceVisible) {
\r
8137 /* Move insert point to new end of text if it was at the old
\r
8138 end of text or if the new text is an echo of user typein */
\r
8139 sel.cpMin = 9999999;
\r
8140 sel.cpMax = 9999999;
\r
8141 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8143 /* Restore previous selection */
\r
8144 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8146 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8153 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8157 COLORREF oldFg, oldBg;
\r
8161 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8163 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8164 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8165 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8168 rect.right = x + squareSize;
\r
8170 rect.bottom = y + squareSize;
\r
8173 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8174 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8175 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8176 &rect, str, strlen(str), NULL);
\r
8178 (void) SetTextColor(hdc, oldFg);
\r
8179 (void) SetBkColor(hdc, oldBg);
\r
8180 (void) SelectObject(hdc, oldFont);
\r
8184 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8185 RECT *rect, char *color, char *flagFell)
\r
8189 COLORREF oldFg, oldBg;
\r
8192 if (appData.clockMode) {
\r
8194 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8196 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
8203 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8204 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8206 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8207 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8209 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8211 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8212 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8213 rect, str, strlen(str), NULL);
\r
8215 (void) SetTextColor(hdc, oldFg);
\r
8216 (void) SetBkColor(hdc, oldBg);
\r
8217 (void) SelectObject(hdc, oldFont);
\r
8222 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8228 if( count <= 0 ) {
\r
8229 if (appData.debugMode) {
\r
8230 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8233 return ERROR_INVALID_USER_BUFFER;
\r
8236 ResetEvent(ovl->hEvent);
\r
8237 ovl->Offset = ovl->OffsetHigh = 0;
\r
8238 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8242 err = GetLastError();
\r
8243 if (err == ERROR_IO_PENDING) {
\r
8244 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8248 err = GetLastError();
\r
8255 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8260 ResetEvent(ovl->hEvent);
\r
8261 ovl->Offset = ovl->OffsetHigh = 0;
\r
8262 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8266 err = GetLastError();
\r
8267 if (err == ERROR_IO_PENDING) {
\r
8268 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8272 err = GetLastError();
\r
8278 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8279 void CheckForInputBufferFull( InputSource * is )
\r
8281 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8282 /* Look for end of line */
\r
8283 char * p = is->buf;
\r
8285 while( p < is->next && *p != '\n' ) {
\r
8289 if( p >= is->next ) {
\r
8290 if (appData.debugMode) {
\r
8291 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
\r
8294 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8295 is->count = (DWORD) -1;
\r
8296 is->next = is->buf;
\r
8302 InputThread(LPVOID arg)
\r
8307 is = (InputSource *) arg;
\r
8308 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8309 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8310 while (is->hThread != NULL) {
\r
8311 is->error = DoReadFile(is->hFile, is->next,
\r
8312 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8313 &is->count, &ovl);
\r
8314 if (is->error == NO_ERROR) {
\r
8315 is->next += is->count;
\r
8317 if (is->error == ERROR_BROKEN_PIPE) {
\r
8318 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8321 is->count = (DWORD) -1;
\r
8322 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8327 CheckForInputBufferFull( is );
\r
8329 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8331 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8333 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8336 CloseHandle(ovl.hEvent);
\r
8337 CloseHandle(is->hFile);
\r
8339 if (appData.debugMode) {
\r
8340 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
\r
8347 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8349 NonOvlInputThread(LPVOID arg)
\r
8356 is = (InputSource *) arg;
\r
8357 while (is->hThread != NULL) {
\r
8358 is->error = ReadFile(is->hFile, is->next,
\r
8359 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8360 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8361 if (is->error == NO_ERROR) {
\r
8362 /* Change CRLF to LF */
\r
8363 if (is->next > is->buf) {
\r
8365 i = is->count + 1;
\r
8373 if (prev == '\r' && *p == '\n') {
\r
8385 if (is->error == ERROR_BROKEN_PIPE) {
\r
8386 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8389 is->count = (DWORD) -1;
\r
8393 CheckForInputBufferFull( is );
\r
8395 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8397 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8399 if (is->count < 0) break; /* Quit on error */
\r
8401 CloseHandle(is->hFile);
\r
8406 SocketInputThread(LPVOID arg)
\r
8410 is = (InputSource *) arg;
\r
8411 while (is->hThread != NULL) {
\r
8412 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8413 if ((int)is->count == SOCKET_ERROR) {
\r
8414 is->count = (DWORD) -1;
\r
8415 is->error = WSAGetLastError();
\r
8417 is->error = NO_ERROR;
\r
8418 is->next += is->count;
\r
8419 if (is->count == 0 && is->second == is) {
\r
8420 /* End of file on stderr; quit with no message */
\r
8424 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8426 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8428 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8434 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8438 is = (InputSource *) lParam;
\r
8439 if (is->lineByLine) {
\r
8440 /* Feed in lines one by one */
\r
8441 char *p = is->buf;
\r
8443 while (q < is->next) {
\r
8444 if (*q++ == '\n') {
\r
8445 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8450 /* Move any partial line to the start of the buffer */
\r
8452 while (p < is->next) {
\r
8457 if (is->error != NO_ERROR || is->count == 0) {
\r
8458 /* Notify backend of the error. Note: If there was a partial
\r
8459 line at the end, it is not flushed through. */
\r
8460 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8463 /* Feed in the whole chunk of input at once */
\r
8464 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8465 is->next = is->buf;
\r
8469 /*---------------------------------------------------------------------------*\
\r
8471 * Menu enables. Used when setting various modes.
\r
8473 \*---------------------------------------------------------------------------*/
\r
8481 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8483 while (enab->item > 0) {
\r
8484 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8489 Enables gnuEnables[] = {
\r
8490 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8491 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8492 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8493 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8494 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8495 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8496 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8497 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8498 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8499 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8503 Enables icsEnables[] = {
\r
8504 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8505 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8506 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8507 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8508 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8509 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8510 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8511 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8512 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8513 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8514 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8515 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8520 Enables zippyEnables[] = {
\r
8521 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8522 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8523 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8528 Enables ncpEnables[] = {
\r
8529 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8530 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8531 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8532 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8533 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8534 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8535 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8536 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8537 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8538 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8539 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8540 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8541 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8542 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8543 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8547 Enables trainingOnEnables[] = {
\r
8548 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8549 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8550 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8551 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8552 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8553 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8554 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8555 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8559 Enables trainingOffEnables[] = {
\r
8560 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8561 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8562 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8563 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8564 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8565 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8566 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8567 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8571 /* These modify either ncpEnables or gnuEnables */
\r
8572 Enables cmailEnables[] = {
\r
8573 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8574 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8575 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8576 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8577 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8578 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8579 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8583 Enables machineThinkingEnables[] = {
\r
8584 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8585 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8586 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8587 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8588 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8589 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8590 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8591 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8592 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8593 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8594 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8595 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8596 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8597 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8598 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8602 Enables userThinkingEnables[] = {
\r
8603 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8604 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8605 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8606 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8607 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8608 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8609 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8610 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8611 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8612 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8613 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8614 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8615 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8616 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8617 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8621 /*---------------------------------------------------------------------------*\
\r
8623 * Front-end interface functions exported by XBoard.
\r
8624 * Functions appear in same order as prototypes in frontend.h.
\r
8626 \*---------------------------------------------------------------------------*/
\r
8630 static UINT prevChecked = 0;
\r
8631 static int prevPausing = 0;
\r
8634 if (pausing != prevPausing) {
\r
8635 prevPausing = pausing;
\r
8636 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8637 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8638 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8641 switch (gameMode) {
\r
8642 case BeginningOfGame:
\r
8643 if (appData.icsActive)
\r
8644 nowChecked = IDM_IcsClient;
\r
8645 else if (appData.noChessProgram)
\r
8646 nowChecked = IDM_EditGame;
\r
8648 nowChecked = IDM_MachineBlack;
\r
8650 case MachinePlaysBlack:
\r
8651 nowChecked = IDM_MachineBlack;
\r
8653 case MachinePlaysWhite:
\r
8654 nowChecked = IDM_MachineWhite;
\r
8656 case TwoMachinesPlay:
\r
8657 nowChecked = IDM_TwoMachines;
\r
8660 nowChecked = IDM_AnalysisMode;
\r
8663 nowChecked = IDM_AnalyzeFile;
\r
8666 nowChecked = IDM_EditGame;
\r
8668 case PlayFromGameFile:
\r
8669 nowChecked = IDM_LoadGame;
\r
8671 case EditPosition:
\r
8672 nowChecked = IDM_EditPosition;
\r
8675 nowChecked = IDM_Training;
\r
8677 case IcsPlayingWhite:
\r
8678 case IcsPlayingBlack:
\r
8679 case IcsObserving:
\r
8681 nowChecked = IDM_IcsClient;
\r
8688 if (prevChecked != 0)
\r
8689 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8690 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8691 if (nowChecked != 0)
\r
8692 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8693 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8695 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8696 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8697 MF_BYCOMMAND|MF_ENABLED);
\r
8699 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8700 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8703 prevChecked = nowChecked;
\r
8705 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8706 if (appData.icsActive) {
\r
8707 if (appData.icsEngineAnalyze) {
\r
8708 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8709 MF_BYCOMMAND|MF_CHECKED);
\r
8711 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8712 MF_BYCOMMAND|MF_UNCHECKED);
\r
8720 HMENU hmenu = GetMenu(hwndMain);
\r
8721 SetMenuEnables(hmenu, icsEnables);
\r
8722 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8723 MF_BYPOSITION|MF_ENABLED);
\r
8725 if (appData.zippyPlay) {
\r
8726 SetMenuEnables(hmenu, zippyEnables);
\r
8727 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8728 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8729 MF_BYCOMMAND|MF_ENABLED);
\r
8737 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8743 HMENU hmenu = GetMenu(hwndMain);
\r
8744 SetMenuEnables(hmenu, ncpEnables);
\r
8745 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8746 MF_BYPOSITION|MF_GRAYED);
\r
8747 DrawMenuBar(hwndMain);
\r
8753 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8757 SetTrainingModeOn()
\r
8760 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8761 for (i = 0; i < N_BUTTONS; i++) {
\r
8762 if (buttonDesc[i].hwnd != NULL)
\r
8763 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8768 VOID SetTrainingModeOff()
\r
8771 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8772 for (i = 0; i < N_BUTTONS; i++) {
\r
8773 if (buttonDesc[i].hwnd != NULL)
\r
8774 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8780 SetUserThinkingEnables()
\r
8782 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8786 SetMachineThinkingEnables()
\r
8788 HMENU hMenu = GetMenu(hwndMain);
\r
8789 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8791 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8793 if (gameMode == MachinePlaysBlack) {
\r
8794 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8795 } else if (gameMode == MachinePlaysWhite) {
\r
8796 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8797 } else if (gameMode == TwoMachinesPlay) {
\r
8798 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8804 DisplayTitle(char *str)
\r
8806 char title[MSG_SIZ], *host;
\r
8807 if (str[0] != NULLCHAR) {
\r
8808 strcpy(title, str);
\r
8809 } else if (appData.icsActive) {
\r
8810 if (appData.icsCommPort[0] != NULLCHAR)
\r
8813 host = appData.icsHost;
\r
8814 sprintf(title, "%s: %s", szTitle, host);
\r
8815 } else if (appData.noChessProgram) {
\r
8816 strcpy(title, szTitle);
\r
8818 strcpy(title, szTitle);
\r
8819 strcat(title, ": ");
\r
8820 strcat(title, first.tidy);
\r
8822 SetWindowText(hwndMain, title);
\r
8827 DisplayMessage(char *str1, char *str2)
\r
8831 int remain = MESSAGE_TEXT_MAX - 1;
\r
8834 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8835 messageText[0] = NULLCHAR;
\r
8837 len = strlen(str1);
\r
8838 if (len > remain) len = remain;
\r
8839 strncpy(messageText, str1, len);
\r
8840 messageText[len] = NULLCHAR;
\r
8843 if (*str2 && remain >= 2) {
\r
8845 strcat(messageText, " ");
\r
8848 len = strlen(str2);
\r
8849 if (len > remain) len = remain;
\r
8850 strncat(messageText, str2, len);
\r
8852 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8854 if (IsIconic(hwndMain)) return;
\r
8855 hdc = GetDC(hwndMain);
\r
8856 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8857 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8858 &messageRect, messageText, strlen(messageText), NULL);
\r
8859 (void) SelectObject(hdc, oldFont);
\r
8860 (void) ReleaseDC(hwndMain, hdc);
\r
8864 DisplayError(char *str, int error)
\r
8866 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8872 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8873 NULL, error, LANG_NEUTRAL,
\r
8874 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8876 sprintf(buf, "%s:\n%s", str, buf2);
\r
8878 ErrorMap *em = errmap;
\r
8879 while (em->err != 0 && em->err != error) em++;
\r
8880 if (em->err != 0) {
\r
8881 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8883 sprintf(buf, "%s:\nError code %d", str, error);
\r
8888 ErrorPopUp("Error", buf);
\r
8893 DisplayMoveError(char *str)
\r
8895 fromX = fromY = -1;
\r
8896 ClearHighlights();
\r
8897 DrawPosition(FALSE, NULL);
\r
8898 if (appData.popupMoveErrors) {
\r
8899 ErrorPopUp("Error", str);
\r
8901 DisplayMessage(str, "");
\r
8902 moveErrorMessageUp = TRUE;
\r
8907 DisplayFatalError(char *str, int error, int exitStatus)
\r
8909 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8911 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8914 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8915 NULL, error, LANG_NEUTRAL,
\r
8916 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8918 sprintf(buf, "%s:\n%s", str, buf2);
\r
8920 ErrorMap *em = errmap;
\r
8921 while (em->err != 0 && em->err != error) em++;
\r
8922 if (em->err != 0) {
\r
8923 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8925 sprintf(buf, "%s:\nError code %d", str, error);
\r
8930 if (appData.debugMode) {
\r
8931 fprintf(debugFP, "%s: %s\n", label, str);
\r
8933 if (appData.popupExitMessage) {
\r
8934 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8935 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8937 ExitEvent(exitStatus);
\r
8942 DisplayInformation(char *str)
\r
8944 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8949 DisplayNote(char *str)
\r
8951 ErrorPopUp("Note", str);
\r
8956 char *title, *question, *replyPrefix;
\r
8961 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8963 static QuestionParams *qp;
\r
8964 char reply[MSG_SIZ];
\r
8967 switch (message) {
\r
8968 case WM_INITDIALOG:
\r
8969 qp = (QuestionParams *) lParam;
\r
8970 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8971 SetWindowText(hDlg, qp->title);
\r
8972 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8973 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8977 switch (LOWORD(wParam)) {
\r
8979 strcpy(reply, qp->replyPrefix);
\r
8980 if (*reply) strcat(reply, " ");
\r
8981 len = strlen(reply);
\r
8982 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8983 strcat(reply, "\n");
\r
8984 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8985 EndDialog(hDlg, TRUE);
\r
8986 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
8989 EndDialog(hDlg, FALSE);
\r
9000 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9002 QuestionParams qp;
\r
9006 qp.question = question;
\r
9007 qp.replyPrefix = replyPrefix;
\r
9009 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9010 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9011 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9012 FreeProcInstance(lpProc);
\r
9015 /* [AS] Pick FRC position */
\r
9016 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9018 static int * lpIndexFRC;
\r
9024 case WM_INITDIALOG:
\r
9025 lpIndexFRC = (int *) lParam;
\r
9027 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9029 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9030 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9031 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9032 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9037 switch( LOWORD(wParam) ) {
\r
9039 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9040 EndDialog( hDlg, 0 );
\r
9041 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9044 EndDialog( hDlg, 1 );
\r
9046 case IDC_NFG_Edit:
\r
9047 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9048 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9050 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9053 case IDC_NFG_Random:
\r
9054 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9055 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9068 int index = appData.defaultFrcPosition;
\r
9069 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9071 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9073 if( result == 0 ) {
\r
9074 appData.defaultFrcPosition = index;
\r
9080 /* [AS] Game list options */
\r
9086 static GLT_Item GLT_ItemInfo[] = {
\r
9087 { GLT_EVENT, "Event" },
\r
9088 { GLT_SITE, "Site" },
\r
9089 { GLT_DATE, "Date" },
\r
9090 { GLT_ROUND, "Round" },
\r
9091 { GLT_PLAYERS, "Players" },
\r
9092 { GLT_RESULT, "Result" },
\r
9093 { GLT_WHITE_ELO, "White Rating" },
\r
9094 { GLT_BLACK_ELO, "Black Rating" },
\r
9095 { GLT_TIME_CONTROL,"Time Control" },
\r
9096 { GLT_VARIANT, "Variant" },
\r
9097 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9101 const char * GLT_FindItem( char id )
\r
9103 const char * result = 0;
\r
9105 GLT_Item * list = GLT_ItemInfo;
\r
9107 while( list->id != 0 ) {
\r
9108 if( list->id == id ) {
\r
9109 result = list->name;
\r
9119 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9121 const char * name = GLT_FindItem( id );
\r
9124 if( index >= 0 ) {
\r
9125 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9128 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9133 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9137 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9140 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9144 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9146 pc = GLT_ALL_TAGS;
\r
9149 if( strchr( tags, *pc ) == 0 ) {
\r
9150 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9155 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9158 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9160 char result = '\0';
\r
9163 GLT_Item * list = GLT_ItemInfo;
\r
9165 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9166 while( list->id != 0 ) {
\r
9167 if( strcmp( list->name, name ) == 0 ) {
\r
9168 result = list->id;
\r
9179 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9181 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9182 int idx2 = idx1 + delta;
\r
9183 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9185 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9188 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9189 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9190 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9191 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9195 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9197 static char glt[64];
\r
9198 static char * lpUserGLT;
\r
9202 case WM_INITDIALOG:
\r
9203 lpUserGLT = (char *) lParam;
\r
9205 strcpy( glt, lpUserGLT );
\r
9207 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9209 /* Initialize list */
\r
9210 GLT_TagsToList( hDlg, glt );
\r
9212 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9217 switch( LOWORD(wParam) ) {
\r
9220 char * pc = lpUserGLT;
\r
9222 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9226 id = GLT_ListItemToTag( hDlg, idx );
\r
9230 } while( id != '\0' );
\r
9232 EndDialog( hDlg, 0 );
\r
9235 EndDialog( hDlg, 1 );
\r
9238 case IDC_GLT_Default:
\r
9239 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9240 GLT_TagsToList( hDlg, glt );
\r
9243 case IDC_GLT_Restore:
\r
9244 strcpy( glt, lpUserGLT );
\r
9245 GLT_TagsToList( hDlg, glt );
\r
9249 GLT_MoveSelection( hDlg, -1 );
\r
9252 case IDC_GLT_Down:
\r
9253 GLT_MoveSelection( hDlg, +1 );
\r
9263 int GameListOptions()
\r
9267 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9269 strcpy( glt, appData.gameListTags );
\r
9271 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9273 if( result == 0 ) {
\r
9274 /* [AS] Memory leak here! */
\r
9275 appData.gameListTags = strdup( glt );
\r
9283 DisplayIcsInteractionTitle(char *str)
\r
9285 char consoleTitle[MSG_SIZ];
\r
9287 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9288 SetWindowText(hwndConsole, consoleTitle);
\r
9292 DrawPosition(int fullRedraw, Board board)
\r
9294 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9301 fromX = fromY = -1;
\r
9302 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9303 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9304 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9305 dragInfo.lastpos = dragInfo.pos;
\r
9306 dragInfo.start.x = dragInfo.start.y = -1;
\r
9307 dragInfo.from = dragInfo.start;
\r
9309 DrawPosition(TRUE, NULL);
\r
9315 CommentPopUp(char *title, char *str)
\r
9317 HWND hwnd = GetActiveWindow();
\r
9318 EitherCommentPopUp(0, title, str, FALSE);
\r
9319 SetActiveWindow(hwnd);
\r
9323 CommentPopDown(void)
\r
9325 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9326 if (commentDialog) {
\r
9327 ShowWindow(commentDialog, SW_HIDE);
\r
9329 commentDialogUp = FALSE;
\r
9333 EditCommentPopUp(int index, char *title, char *str)
\r
9335 EitherCommentPopUp(index, title, str, TRUE);
\r
9342 MyPlaySound(&sounds[(int)SoundMove]);
\r
9345 VOID PlayIcsWinSound()
\r
9347 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9350 VOID PlayIcsLossSound()
\r
9352 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9355 VOID PlayIcsDrawSound()
\r
9357 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9360 VOID PlayIcsUnfinishedSound()
\r
9362 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9368 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9376 consoleEcho = TRUE;
\r
9377 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9378 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9379 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9388 consoleEcho = FALSE;
\r
9389 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9390 /* This works OK: set text and background both to the same color */
\r
9392 cf.crTextColor = COLOR_ECHOOFF;
\r
9393 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9394 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9397 /* No Raw()...? */
\r
9399 void Colorize(ColorClass cc, int continuation)
\r
9401 currentColorClass = cc;
\r
9402 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9403 consoleCF.crTextColor = textAttribs[cc].color;
\r
9404 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9405 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9411 static char buf[MSG_SIZ];
\r
9412 DWORD bufsiz = MSG_SIZ;
\r
9414 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9415 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9417 if (!GetUserName(buf, &bufsiz)) {
\r
9418 /*DisplayError("Error getting user name", GetLastError());*/
\r
9419 strcpy(buf, "User");
\r
9427 static char buf[MSG_SIZ];
\r
9428 DWORD bufsiz = MSG_SIZ;
\r
9430 if (!GetComputerName(buf, &bufsiz)) {
\r
9431 /*DisplayError("Error getting host name", GetLastError());*/
\r
9432 strcpy(buf, "Unknown");
\r
9439 ClockTimerRunning()
\r
9441 return clockTimerEvent != 0;
\r
9447 if (clockTimerEvent == 0) return FALSE;
\r
9448 KillTimer(hwndMain, clockTimerEvent);
\r
9449 clockTimerEvent = 0;
\r
9454 StartClockTimer(long millisec)
\r
9456 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9457 (UINT) millisec, NULL);
\r
9461 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9464 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9466 if(appData.noGUI) return;
\r
9467 hdc = GetDC(hwndMain);
\r
9468 if (!IsIconic(hwndMain)) {
\r
9469 DisplayAClock(hdc, timeRemaining, highlight,
\r
9470 (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);
\r
9472 if (highlight && iconCurrent == iconBlack) {
\r
9473 iconCurrent = iconWhite;
\r
9474 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9475 if (IsIconic(hwndMain)) {
\r
9476 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9479 (void) ReleaseDC(hwndMain, hdc);
\r
9481 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9485 DisplayBlackClock(long timeRemaining, int highlight)
\r
9488 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9490 if(appData.noGUI) return;
\r
9491 hdc = GetDC(hwndMain);
\r
9492 if (!IsIconic(hwndMain)) {
\r
9493 DisplayAClock(hdc, timeRemaining, highlight,
\r
9494 (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);
\r
9496 if (highlight && iconCurrent == iconWhite) {
\r
9497 iconCurrent = iconBlack;
\r
9498 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9499 if (IsIconic(hwndMain)) {
\r
9500 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9503 (void) ReleaseDC(hwndMain, hdc);
\r
9505 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9510 LoadGameTimerRunning()
\r
9512 return loadGameTimerEvent != 0;
\r
9516 StopLoadGameTimer()
\r
9518 if (loadGameTimerEvent == 0) return FALSE;
\r
9519 KillTimer(hwndMain, loadGameTimerEvent);
\r
9520 loadGameTimerEvent = 0;
\r
9525 StartLoadGameTimer(long millisec)
\r
9527 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9528 (UINT) millisec, NULL);
\r
9536 char fileTitle[MSG_SIZ];
\r
9538 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9539 f = OpenFileDialog(hwndMain, "a", defName,
\r
9540 appData.oldSaveStyle ? "gam" : "pgn",
\r
9542 "Save Game to File", NULL, fileTitle, NULL);
\r
9544 SaveGame(f, 0, "");
\r
9551 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9553 if (delayedTimerEvent != 0) {
\r
9554 if (appData.debugMode) {
\r
9555 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9557 KillTimer(hwndMain, delayedTimerEvent);
\r
9558 delayedTimerEvent = 0;
\r
9559 delayedTimerCallback();
\r
9561 delayedTimerCallback = cb;
\r
9562 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9563 (UINT) millisec, NULL);
\r
9566 DelayedEventCallback
\r
9569 if (delayedTimerEvent) {
\r
9570 return delayedTimerCallback;
\r
9577 CancelDelayedEvent()
\r
9579 if (delayedTimerEvent) {
\r
9580 KillTimer(hwndMain, delayedTimerEvent);
\r
9581 delayedTimerEvent = 0;
\r
9585 DWORD GetWin32Priority(int nice)
\r
9586 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9588 REALTIME_PRIORITY_CLASS 0x00000100
\r
9589 HIGH_PRIORITY_CLASS 0x00000080
\r
9590 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9591 NORMAL_PRIORITY_CLASS 0x00000020
\r
9592 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9593 IDLE_PRIORITY_CLASS 0x00000040
\r
9595 if (nice < -15) return 0x00000080;
\r
9596 if (nice < 0) return 0x00008000;
\r
9597 if (nice == 0) return 0x00000020;
\r
9598 if (nice < 15) return 0x00004000;
\r
9599 return 0x00000040;
\r
9602 /* Start a child process running the given program.
\r
9603 The process's standard output can be read from "from", and its
\r
9604 standard input can be written to "to".
\r
9605 Exit with fatal error if anything goes wrong.
\r
9606 Returns an opaque pointer that can be used to destroy the process
\r
9610 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9612 #define BUFSIZE 4096
\r
9614 HANDLE hChildStdinRd, hChildStdinWr,
\r
9615 hChildStdoutRd, hChildStdoutWr;
\r
9616 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9617 SECURITY_ATTRIBUTES saAttr;
\r
9619 PROCESS_INFORMATION piProcInfo;
\r
9620 STARTUPINFO siStartInfo;
\r
9622 char buf[MSG_SIZ];
\r
9625 if (appData.debugMode) {
\r
9626 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9631 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9632 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9633 saAttr.bInheritHandle = TRUE;
\r
9634 saAttr.lpSecurityDescriptor = NULL;
\r
9637 * The steps for redirecting child's STDOUT:
\r
9638 * 1. Create anonymous pipe to be STDOUT for child.
\r
9639 * 2. Create a noninheritable duplicate of read handle,
\r
9640 * and close the inheritable read handle.
\r
9643 /* Create a pipe for the child's STDOUT. */
\r
9644 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9645 return GetLastError();
\r
9648 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9649 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9650 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9651 FALSE, /* not inherited */
\r
9652 DUPLICATE_SAME_ACCESS);
\r
9654 return GetLastError();
\r
9656 CloseHandle(hChildStdoutRd);
\r
9659 * The steps for redirecting child's STDIN:
\r
9660 * 1. Create anonymous pipe to be STDIN for child.
\r
9661 * 2. Create a noninheritable duplicate of write handle,
\r
9662 * and close the inheritable write handle.
\r
9665 /* Create a pipe for the child's STDIN. */
\r
9666 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9667 return GetLastError();
\r
9670 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9671 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9672 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9673 FALSE, /* not inherited */
\r
9674 DUPLICATE_SAME_ACCESS);
\r
9676 return GetLastError();
\r
9678 CloseHandle(hChildStdinWr);
\r
9680 /* Arrange to (1) look in dir for the child .exe file, and
\r
9681 * (2) have dir be the child's working directory. Interpret
\r
9682 * dir relative to the directory WinBoard loaded from. */
\r
9683 GetCurrentDirectory(MSG_SIZ, buf);
\r
9684 SetCurrentDirectory(installDir);
\r
9685 SetCurrentDirectory(dir);
\r
9687 /* Now create the child process. */
\r
9689 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9690 siStartInfo.lpReserved = NULL;
\r
9691 siStartInfo.lpDesktop = NULL;
\r
9692 siStartInfo.lpTitle = NULL;
\r
9693 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9694 siStartInfo.cbReserved2 = 0;
\r
9695 siStartInfo.lpReserved2 = NULL;
\r
9696 siStartInfo.hStdInput = hChildStdinRd;
\r
9697 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9698 siStartInfo.hStdError = hChildStdoutWr;
\r
9700 fSuccess = CreateProcess(NULL,
\r
9701 cmdLine, /* command line */
\r
9702 NULL, /* process security attributes */
\r
9703 NULL, /* primary thread security attrs */
\r
9704 TRUE, /* handles are inherited */
\r
9705 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9706 NULL, /* use parent's environment */
\r
9708 &siStartInfo, /* STARTUPINFO pointer */
\r
9709 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9711 err = GetLastError();
\r
9712 SetCurrentDirectory(buf); /* return to prev directory */
\r
9717 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9718 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9719 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9722 /* Close the handles we don't need in the parent */
\r
9723 CloseHandle(piProcInfo.hThread);
\r
9724 CloseHandle(hChildStdinRd);
\r
9725 CloseHandle(hChildStdoutWr);
\r
9727 /* Prepare return value */
\r
9728 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9729 cp->kind = CPReal;
\r
9730 cp->hProcess = piProcInfo.hProcess;
\r
9731 cp->pid = piProcInfo.dwProcessId;
\r
9732 cp->hFrom = hChildStdoutRdDup;
\r
9733 cp->hTo = hChildStdinWrDup;
\r
9735 *pr = (void *) cp;
\r
9737 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9738 2000 where engines sometimes don't see the initial command(s)
\r
9739 from WinBoard and hang. I don't understand how that can happen,
\r
9740 but the Sleep is harmless, so I've put it in. Others have also
\r
9741 reported what may be the same problem, so hopefully this will fix
\r
9742 it for them too. */
\r
9750 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9752 ChildProc *cp; int result;
\r
9754 cp = (ChildProc *) pr;
\r
9755 if (cp == NULL) return;
\r
9757 switch (cp->kind) {
\r
9759 /* TerminateProcess is considered harmful, so... */
\r
9760 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9761 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9762 /* The following doesn't work because the chess program
\r
9763 doesn't "have the same console" as WinBoard. Maybe
\r
9764 we could arrange for this even though neither WinBoard
\r
9765 nor the chess program uses a console for stdio? */
\r
9766 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9768 /* [AS] Special termination modes for misbehaving programs... */
\r
9769 if( signal == 9 ) {
\r
9770 result = TerminateProcess( cp->hProcess, 0 );
\r
9772 if ( appData.debugMode) {
\r
9773 fprintf( debugFP, "Terminating process %u, result=%d\n", cp->pid, result );
\r
9776 else if( signal == 10 ) {
\r
9777 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9779 if( dw != WAIT_OBJECT_0 ) {
\r
9780 result = TerminateProcess( cp->hProcess, 0 );
\r
9782 if ( appData.debugMode) {
\r
9783 fprintf( debugFP, "Process %u still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9789 CloseHandle(cp->hProcess);
\r
9793 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9797 closesocket(cp->sock);
\r
9802 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9803 closesocket(cp->sock);
\r
9804 closesocket(cp->sock2);
\r
9812 InterruptChildProcess(ProcRef pr)
\r
9816 cp = (ChildProc *) pr;
\r
9817 if (cp == NULL) return;
\r
9818 switch (cp->kind) {
\r
9820 /* The following doesn't work because the chess program
\r
9821 doesn't "have the same console" as WinBoard. Maybe
\r
9822 we could arrange for this even though neither WinBoard
\r
9823 nor the chess program uses a console for stdio */
\r
9824 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9829 /* Can't interrupt */
\r
9833 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9840 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9842 char cmdLine[MSG_SIZ];
\r
9844 if (port[0] == NULLCHAR) {
\r
9845 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9847 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9849 return StartChildProcess(cmdLine, "", pr);
\r
9853 /* Code to open TCP sockets */
\r
9856 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9861 struct sockaddr_in sa, mysa;
\r
9862 struct hostent FAR *hp;
\r
9863 unsigned short uport;
\r
9864 WORD wVersionRequested;
\r
9867 /* Initialize socket DLL */
\r
9868 wVersionRequested = MAKEWORD(1, 1);
\r
9869 err = WSAStartup(wVersionRequested, &wsaData);
\r
9870 if (err != 0) return err;
\r
9873 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9874 err = WSAGetLastError();
\r
9879 /* Bind local address using (mostly) don't-care values.
\r
9881 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9882 mysa.sin_family = AF_INET;
\r
9883 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9884 uport = (unsigned short) 0;
\r
9885 mysa.sin_port = htons(uport);
\r
9886 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9887 == SOCKET_ERROR) {
\r
9888 err = WSAGetLastError();
\r
9893 /* Resolve remote host name */
\r
9894 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9895 if (!(hp = gethostbyname(host))) {
\r
9896 unsigned int b0, b1, b2, b3;
\r
9898 err = WSAGetLastError();
\r
9900 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9901 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9902 hp->h_addrtype = AF_INET;
\r
9904 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9905 hp->h_addr_list[0] = (char *) malloc(4);
\r
9906 hp->h_addr_list[0][0] = (char) b0;
\r
9907 hp->h_addr_list[0][1] = (char) b1;
\r
9908 hp->h_addr_list[0][2] = (char) b2;
\r
9909 hp->h_addr_list[0][3] = (char) b3;
\r
9915 sa.sin_family = hp->h_addrtype;
\r
9916 uport = (unsigned short) atoi(port);
\r
9917 sa.sin_port = htons(uport);
\r
9918 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9920 /* Make connection */
\r
9921 if (connect(s, (struct sockaddr *) &sa,
\r
9922 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9923 err = WSAGetLastError();
\r
9928 /* Prepare return value */
\r
9929 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9930 cp->kind = CPSock;
\r
9932 *pr = (ProcRef *) cp;
\r
9938 OpenCommPort(char *name, ProcRef *pr)
\r
9943 char fullname[MSG_SIZ];
\r
9945 if (*name != '\\')
\r
9946 sprintf(fullname, "\\\\.\\%s", name);
\r
9948 strcpy(fullname, name);
\r
9950 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9951 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9952 if (h == (HANDLE) -1) {
\r
9953 return GetLastError();
\r
9957 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9959 /* Accumulate characters until a 100ms pause, then parse */
\r
9960 ct.ReadIntervalTimeout = 100;
\r
9961 ct.ReadTotalTimeoutMultiplier = 0;
\r
9962 ct.ReadTotalTimeoutConstant = 0;
\r
9963 ct.WriteTotalTimeoutMultiplier = 0;
\r
9964 ct.WriteTotalTimeoutConstant = 0;
\r
9965 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9967 /* Prepare return value */
\r
9968 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9969 cp->kind = CPComm;
\r
9972 *pr = (ProcRef *) cp;
\r
9978 OpenLoopback(ProcRef *pr)
\r
9980 DisplayFatalError("Not implemented", 0, 1);
\r
9986 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9991 struct sockaddr_in sa, mysa;
\r
9992 struct hostent FAR *hp;
\r
9993 unsigned short uport;
\r
9994 WORD wVersionRequested;
\r
9997 char stderrPortStr[MSG_SIZ];
\r
9999 /* Initialize socket DLL */
\r
10000 wVersionRequested = MAKEWORD(1, 1);
\r
10001 err = WSAStartup(wVersionRequested, &wsaData);
\r
10002 if (err != 0) return err;
\r
10004 /* Resolve remote host name */
\r
10005 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10006 if (!(hp = gethostbyname(host))) {
\r
10007 unsigned int b0, b1, b2, b3;
\r
10009 err = WSAGetLastError();
\r
10011 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10012 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10013 hp->h_addrtype = AF_INET;
\r
10014 hp->h_length = 4;
\r
10015 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10016 hp->h_addr_list[0] = (char *) malloc(4);
\r
10017 hp->h_addr_list[0][0] = (char) b0;
\r
10018 hp->h_addr_list[0][1] = (char) b1;
\r
10019 hp->h_addr_list[0][2] = (char) b2;
\r
10020 hp->h_addr_list[0][3] = (char) b3;
\r
10026 sa.sin_family = hp->h_addrtype;
\r
10027 uport = (unsigned short) 514;
\r
10028 sa.sin_port = htons(uport);
\r
10029 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10031 /* Bind local socket to unused "privileged" port address
\r
10033 s = INVALID_SOCKET;
\r
10034 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10035 mysa.sin_family = AF_INET;
\r
10036 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10037 for (fromPort = 1023;; fromPort--) {
\r
10038 if (fromPort < 0) {
\r
10040 return WSAEADDRINUSE;
\r
10042 if (s == INVALID_SOCKET) {
\r
10043 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10044 err = WSAGetLastError();
\r
10049 uport = (unsigned short) fromPort;
\r
10050 mysa.sin_port = htons(uport);
\r
10051 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10052 == SOCKET_ERROR) {
\r
10053 err = WSAGetLastError();
\r
10054 if (err == WSAEADDRINUSE) continue;
\r
10058 if (connect(s, (struct sockaddr *) &sa,
\r
10059 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10060 err = WSAGetLastError();
\r
10061 if (err == WSAEADDRINUSE) {
\r
10072 /* Bind stderr local socket to unused "privileged" port address
\r
10074 s2 = INVALID_SOCKET;
\r
10075 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10076 mysa.sin_family = AF_INET;
\r
10077 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10078 for (fromPort = 1023;; fromPort--) {
\r
10079 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10080 if (fromPort < 0) {
\r
10081 (void) closesocket(s);
\r
10083 return WSAEADDRINUSE;
\r
10085 if (s2 == INVALID_SOCKET) {
\r
10086 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10087 err = WSAGetLastError();
\r
10093 uport = (unsigned short) fromPort;
\r
10094 mysa.sin_port = htons(uport);
\r
10095 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10096 == SOCKET_ERROR) {
\r
10097 err = WSAGetLastError();
\r
10098 if (err == WSAEADDRINUSE) continue;
\r
10099 (void) closesocket(s);
\r
10103 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10104 err = WSAGetLastError();
\r
10105 if (err == WSAEADDRINUSE) {
\r
10107 s2 = INVALID_SOCKET;
\r
10110 (void) closesocket(s);
\r
10111 (void) closesocket(s2);
\r
10117 prevStderrPort = fromPort; // remember port used
\r
10118 sprintf(stderrPortStr, "%d", fromPort);
\r
10120 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10121 err = WSAGetLastError();
\r
10122 (void) closesocket(s);
\r
10123 (void) closesocket(s2);
\r
10128 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10129 err = WSAGetLastError();
\r
10130 (void) closesocket(s);
\r
10131 (void) closesocket(s2);
\r
10135 if (*user == NULLCHAR) user = UserName();
\r
10136 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10137 err = WSAGetLastError();
\r
10138 (void) closesocket(s);
\r
10139 (void) closesocket(s2);
\r
10143 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10144 err = WSAGetLastError();
\r
10145 (void) closesocket(s);
\r
10146 (void) closesocket(s2);
\r
10151 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10152 err = WSAGetLastError();
\r
10153 (void) closesocket(s);
\r
10154 (void) closesocket(s2);
\r
10158 (void) closesocket(s2); /* Stop listening */
\r
10160 /* Prepare return value */
\r
10161 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10162 cp->kind = CPRcmd;
\r
10165 *pr = (ProcRef *) cp;
\r
10172 AddInputSource(ProcRef pr, int lineByLine,
\r
10173 InputCallback func, VOIDSTAR closure)
\r
10175 InputSource *is, *is2 = NULL;
\r
10176 ChildProc *cp = (ChildProc *) pr;
\r
10178 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10179 is->lineByLine = lineByLine;
\r
10181 is->closure = closure;
\r
10182 is->second = NULL;
\r
10183 is->next = is->buf;
\r
10184 if (pr == NoProc) {
\r
10185 is->kind = CPReal;
\r
10186 consoleInputSource = is;
\r
10188 is->kind = cp->kind;
\r
10190 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10191 we create all threads suspended so that the is->hThread variable can be
\r
10192 safely assigned, then let the threads start with ResumeThread.
\r
10194 switch (cp->kind) {
\r
10196 is->hFile = cp->hFrom;
\r
10197 cp->hFrom = NULL; /* now owned by InputThread */
\r
10199 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10200 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10204 is->hFile = cp->hFrom;
\r
10205 cp->hFrom = NULL; /* now owned by InputThread */
\r
10207 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10208 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10212 is->sock = cp->sock;
\r
10214 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10215 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10219 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10221 is->sock = cp->sock;
\r
10222 is->second = is2;
\r
10223 is2->sock = cp->sock2;
\r
10224 is2->second = is2;
\r
10226 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10227 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10229 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10230 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10234 if( is->hThread != NULL ) {
\r
10235 ResumeThread( is->hThread );
\r
10238 if( is2 != NULL && is2->hThread != NULL ) {
\r
10239 ResumeThread( is2->hThread );
\r
10243 return (InputSourceRef) is;
\r
10247 RemoveInputSource(InputSourceRef isr)
\r
10251 is = (InputSource *) isr;
\r
10252 is->hThread = NULL; /* tell thread to stop */
\r
10253 CloseHandle(is->hThread);
\r
10254 if (is->second != NULL) {
\r
10255 is->second->hThread = NULL;
\r
10256 CloseHandle(is->second->hThread);
\r
10262 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10265 int outCount = SOCKET_ERROR;
\r
10266 ChildProc *cp = (ChildProc *) pr;
\r
10267 static OVERLAPPED ovl;
\r
10269 if (pr == NoProc) {
\r
10270 ConsoleOutput(message, count, FALSE);
\r
10274 if (ovl.hEvent == NULL) {
\r
10275 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10277 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10279 switch (cp->kind) {
\r
10282 outCount = send(cp->sock, message, count, 0);
\r
10283 if (outCount == SOCKET_ERROR) {
\r
10284 *outError = WSAGetLastError();
\r
10286 *outError = NO_ERROR;
\r
10291 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10292 &dOutCount, NULL)) {
\r
10293 *outError = NO_ERROR;
\r
10294 outCount = (int) dOutCount;
\r
10296 *outError = GetLastError();
\r
10301 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10302 &dOutCount, &ovl);
\r
10303 if (*outError == NO_ERROR) {
\r
10304 outCount = (int) dOutCount;
\r
10312 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10315 /* Ignore delay, not implemented for WinBoard */
\r
10316 return OutputToProcess(pr, message, count, outError);
\r
10321 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10322 char *buf, int count, int error)
\r
10324 DisplayFatalError("Not implemented", 0, 1);
\r
10327 /* see wgamelist.c for Game List functions */
\r
10328 /* see wedittags.c for Edit Tags functions */
\r
10335 char buf[MSG_SIZ];
\r
10338 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10339 f = fopen(buf, "r");
\r
10341 ProcessICSInitScript(f);
\r
10349 StartAnalysisClock()
\r
10351 if (analysisTimerEvent) return;
\r
10352 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10353 (UINT) 2000, NULL);
\r
10357 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10359 static HANDLE hwndText;
\r
10361 static int sizeX, sizeY;
\r
10362 int newSizeX, newSizeY, flags;
\r
10365 switch (message) {
\r
10366 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10367 /* Initialize the dialog items */
\r
10368 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10369 SetWindowText(hDlg, analysisTitle);
\r
10370 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10371 /* Size and position the dialog */
\r
10372 if (!analysisDialog) {
\r
10373 analysisDialog = hDlg;
\r
10374 flags = SWP_NOZORDER;
\r
10375 GetClientRect(hDlg, &rect);
\r
10376 sizeX = rect.right;
\r
10377 sizeY = rect.bottom;
\r
10378 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10379 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10380 WINDOWPLACEMENT wp;
\r
10381 EnsureOnScreen(&analysisX, &analysisY);
\r
10382 wp.length = sizeof(WINDOWPLACEMENT);
\r
10384 wp.showCmd = SW_SHOW;
\r
10385 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10386 wp.rcNormalPosition.left = analysisX;
\r
10387 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10388 wp.rcNormalPosition.top = analysisY;
\r
10389 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10390 SetWindowPlacement(hDlg, &wp);
\r
10392 GetClientRect(hDlg, &rect);
\r
10393 newSizeX = rect.right;
\r
10394 newSizeY = rect.bottom;
\r
10395 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10396 newSizeX, newSizeY);
\r
10397 sizeX = newSizeX;
\r
10398 sizeY = newSizeY;
\r
10403 case WM_COMMAND: /* message: received a command */
\r
10404 switch (LOWORD(wParam)) {
\r
10406 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10407 ExitAnalyzeMode();
\r
10419 newSizeX = LOWORD(lParam);
\r
10420 newSizeY = HIWORD(lParam);
\r
10421 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10422 sizeX = newSizeX;
\r
10423 sizeY = newSizeY;
\r
10426 case WM_GETMINMAXINFO:
\r
10427 /* Prevent resizing window too small */
\r
10428 mmi = (MINMAXINFO *) lParam;
\r
10429 mmi->ptMinTrackSize.x = 100;
\r
10430 mmi->ptMinTrackSize.y = 100;
\r
10437 AnalysisPopUp(char* title, char* str)
\r
10443 EngineOutputPopUp();
\r
10446 if (str == NULL) str = "";
\r
10447 p = (char *) malloc(2 * strlen(str) + 2);
\r
10450 if (*str == '\n') *q++ = '\r';
\r
10454 if (analysisText != NULL) free(analysisText);
\r
10455 analysisText = p;
\r
10457 if (analysisDialog) {
\r
10458 SetWindowText(analysisDialog, title);
\r
10459 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10460 ShowWindow(analysisDialog, SW_SHOW);
\r
10462 analysisTitle = title;
\r
10463 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10464 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10465 hwndMain, (DLGPROC)lpProc);
\r
10466 FreeProcInstance(lpProc);
\r
10468 analysisDialogUp = TRUE;
\r
10472 AnalysisPopDown()
\r
10474 if (analysisDialog) {
\r
10475 ShowWindow(analysisDialog, SW_HIDE);
\r
10477 analysisDialogUp = FALSE;
\r
10482 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10484 highlightInfo.sq[0].x = fromX;
\r
10485 highlightInfo.sq[0].y = fromY;
\r
10486 highlightInfo.sq[1].x = toX;
\r
10487 highlightInfo.sq[1].y = toY;
\r
10491 ClearHighlights()
\r
10493 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10494 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10498 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10500 premoveHighlightInfo.sq[0].x = fromX;
\r
10501 premoveHighlightInfo.sq[0].y = fromY;
\r
10502 premoveHighlightInfo.sq[1].x = toX;
\r
10503 premoveHighlightInfo.sq[1].y = toY;
\r
10507 ClearPremoveHighlights()
\r
10509 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10510 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10514 ShutDownFrontEnd()
\r
10516 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10517 DeleteClipboardTempFiles();
\r
10523 if (IsIconic(hwndMain))
\r
10524 ShowWindow(hwndMain, SW_RESTORE);
\r
10526 SetActiveWindow(hwndMain);
\r
10530 * Prototypes for animation support routines
\r
10532 static void ScreenSquare(int column, int row, POINT * pt);
\r
10533 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10534 POINT frames[], int * nFrames);
\r
10537 #define kFactor 4
\r
10540 AnimateMove(board, fromX, fromY, toX, toY)
\r
10547 ChessSquare piece;
\r
10548 POINT start, finish, mid;
\r
10549 POINT frames[kFactor * 2 + 1];
\r
10552 if (!appData.animate) return;
\r
10553 if (doingSizing) return;
\r
10554 if (fromY < 0 || fromX < 0) return;
\r
10555 piece = board[fromY][fromX];
\r
10556 if (piece >= EmptySquare) return;
\r
10558 ScreenSquare(fromX, fromY, &start);
\r
10559 ScreenSquare(toX, toY, &finish);
\r
10561 /* All pieces except knights move in straight line */
\r
10562 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10563 mid.x = start.x + (finish.x - start.x) / 2;
\r
10564 mid.y = start.y + (finish.y - start.y) / 2;
\r
10566 /* Knight: make diagonal movement then straight */
\r
10567 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10568 mid.x = start.x + (finish.x - start.x) / 2;
\r
10569 mid.y = finish.y;
\r
10571 mid.x = finish.x;
\r
10572 mid.y = start.y + (finish.y - start.y) / 2;
\r
10576 /* Don't use as many frames for very short moves */
\r
10577 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10578 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10580 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10582 animInfo.from.x = fromX;
\r
10583 animInfo.from.y = fromY;
\r
10584 animInfo.to.x = toX;
\r
10585 animInfo.to.y = toY;
\r
10586 animInfo.lastpos = start;
\r
10587 animInfo.piece = piece;
\r
10588 for (n = 0; n < nFrames; n++) {
\r
10589 animInfo.pos = frames[n];
\r
10590 DrawPosition(FALSE, NULL);
\r
10591 animInfo.lastpos = animInfo.pos;
\r
10592 Sleep(appData.animSpeed);
\r
10594 animInfo.pos = finish;
\r
10595 DrawPosition(FALSE, NULL);
\r
10596 animInfo.piece = EmptySquare;
\r
10599 /* Convert board position to corner of screen rect and color */
\r
10602 ScreenSquare(column, row, pt)
\r
10603 int column; int row; POINT * pt;
\r
10606 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10607 pt->y = lineGap + row * (squareSize + lineGap);
\r
10609 pt->x = lineGap + column * (squareSize + lineGap);
\r
10610 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10614 /* Generate a series of frame coords from start->mid->finish.
\r
10615 The movement rate doubles until the half way point is
\r
10616 reached, then halves back down to the final destination,
\r
10617 which gives a nice slow in/out effect. The algorithmn
\r
10618 may seem to generate too many intermediates for short
\r
10619 moves, but remember that the purpose is to attract the
\r
10620 viewers attention to the piece about to be moved and
\r
10621 then to where it ends up. Too few frames would be less
\r
10625 Tween(start, mid, finish, factor, frames, nFrames)
\r
10626 POINT * start; POINT * mid;
\r
10627 POINT * finish; int factor;
\r
10628 POINT frames[]; int * nFrames;
\r
10630 int n, fraction = 1, count = 0;
\r
10632 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10633 for (n = 0; n < factor; n++)
\r
10635 for (n = 0; n < factor; n++) {
\r
10636 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10637 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10639 fraction = fraction / 2;
\r
10643 frames[count] = *mid;
\r
10646 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10648 for (n = 0; n < factor; n++) {
\r
10649 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10650 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10652 fraction = fraction * 2;
\r
10654 *nFrames = count;
\r
10658 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10663 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10664 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10666 OutputDebugString( buf );
\r
10669 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10671 EvalGraphSet( first, last, current, pvInfoList );
\r
10674 void SetProgramStats( FrontEndProgramStats * stats )
\r
10679 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10680 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10682 OutputDebugString( buf );
\r
10685 EngineOutputUpdate( stats );
\r