2 * WinBoard.c -- Windows NT front end to XBoard
\r
3 * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
\r
5 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
6 * Massachusetts. Enhancements Copyright
\r
7 * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software
\r
10 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
11 * which was written and is copyrighted by Wayne Christopher.
\r
13 * The following terms apply to Digital Equipment Corporation's copyright
\r
14 * interest in XBoard:
\r
15 * ------------------------------------------------------------------------
\r
16 * All Rights Reserved
\r
18 * Permission to use, copy, modify, and distribute this software and its
\r
19 * documentation for any purpose and without fee is hereby granted,
\r
20 * provided that the above copyright notice appear in all copies and that
\r
21 * both that copyright notice and this permission notice appear in
\r
22 * supporting documentation, and that the name of Digital not be
\r
23 * used in advertising or publicity pertaining to distribution of the
\r
24 * software without specific, written prior permission.
\r
26 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
27 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
28 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
29 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
30 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
31 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
33 * ------------------------------------------------------------------------
\r
35 * The following terms apply to the enhanced version of XBoard
\r
36 * distributed by the Free Software Foundation:
\r
37 * ------------------------------------------------------------------------
\r
39 * GNU XBoard is free software: you can redistribute it and/or modify
\r
40 * it under the terms of the GNU General Public License as published by
\r
41 * the Free Software Foundation, either version 3 of the License, or (at
\r
42 * your option) any later version.
\r
44 * GNU XBoard is distributed in the hope that it will be useful, but
\r
45 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
46 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
47 * General Public License for more details.
\r
49 * You should have received a copy of the GNU General Public License
\r
50 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
52 *------------------------------------------------------------------------
\r
53 ** See the file ChangeLog for a revision history. */
\r
57 #include <windows.h>
\r
58 #include <winuser.h>
\r
59 #include <winsock.h>
\r
60 #include <commctrl.h>
\r
66 #include <sys/stat.h>
\r
69 #include <commdlg.h>
\r
71 #include <richedit.h>
\r
72 #include <mmsystem.h>
\r
81 #include "winboard.h"
\r
82 #include "frontend.h"
\r
83 #include "backend.h"
\r
85 #include "wclipbrd.h"
\r
86 #include "wgamelist.h"
\r
87 #include "wedittags.h"
\r
88 #include "woptions.h"
\r
89 #include "wsockerr.h"
\r
90 #include "defaults.h"
\r
94 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
97 void mysrandom(unsigned int seed);
\r
99 extern int whiteFlag, blackFlag;
\r
100 Boolean flipClock = FALSE;
\r
102 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
103 VOID NewVariantPopup(HWND hwnd);
\r
104 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
105 /*char*/int promoChar));
\r
108 ChessSquare piece;
\r
109 POINT pos; /* window coordinates of current pos */
\r
110 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
111 POINT from; /* board coordinates of the piece's orig pos */
\r
112 POINT to; /* board coordinates of the piece's new pos */
\r
115 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
118 POINT start; /* window coordinates of start pos */
\r
119 POINT pos; /* window coordinates of current pos */
\r
120 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
121 POINT from; /* board coordinates of the piece's orig pos */
\r
124 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
127 POINT sq[2]; /* board coordinates of from, to squares */
\r
130 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
131 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
133 /* Window class names */
\r
134 char szAppName[] = "WinBoard";
\r
135 char szConsoleName[] = "WBConsole";
\r
137 /* Title bar text */
\r
138 char szTitle[] = "WinBoard";
\r
139 char szConsoleTitle[] = "ICS Interaction";
\r
142 char *settingsFileName;
\r
143 BOOLEAN saveSettingsOnExit;
\r
144 char installDir[MSG_SIZ];
\r
146 BoardSize boardSize;
\r
147 BOOLEAN chessProgram;
\r
148 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
149 static int squareSize, lineGap, minorSize;
\r
150 static int winWidth, winHeight;
\r
151 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
152 static int logoHeight = 0;
\r
153 static char messageText[MESSAGE_TEXT_MAX];
\r
154 static int clockTimerEvent = 0;
\r
155 static int loadGameTimerEvent = 0;
\r
156 static int analysisTimerEvent = 0;
\r
157 static DelayedEventCallback delayedTimerCallback;
\r
158 static int delayedTimerEvent = 0;
\r
159 static int buttonCount = 2;
\r
160 char *icsTextMenuString;
\r
162 char *firstChessProgramNames;
\r
163 char *secondChessProgramNames;
\r
165 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
167 #define PALETTESIZE 256
\r
169 HINSTANCE hInst; /* current instance */
\r
170 HWND hwndMain = NULL; /* root window*/
\r
171 HWND hwndConsole = NULL;
\r
172 BOOLEAN alwaysOnTop = FALSE;
\r
174 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
175 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
177 ColorClass currentColorClass;
\r
179 HWND hCommPort = NULL; /* currently open comm port */
\r
180 static HWND hwndPause; /* pause button */
\r
181 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
182 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
183 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
184 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
185 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
186 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
187 static HPEN gridPen = NULL;
\r
188 static HPEN highlightPen = NULL;
\r
189 static HPEN premovePen = NULL;
\r
190 static NPLOGPALETTE pLogPal;
\r
191 static BOOL paletteChanged = FALSE;
\r
192 static HICON iconWhite, iconBlack, iconCurrent;
\r
193 static int doingSizing = FALSE;
\r
194 static int lastSizing = 0;
\r
195 static int prevStderrPort;
\r
197 /* [AS] Support for background textures */
\r
198 #define BACK_TEXTURE_MODE_DISABLED 0
\r
199 #define BACK_TEXTURE_MODE_PLAIN 1
\r
200 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
202 static HBITMAP liteBackTexture = NULL;
\r
203 static HBITMAP darkBackTexture = NULL;
\r
204 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
205 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
206 static int backTextureSquareSize = 0;
\r
207 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
209 #if __GNUC__ && !defined(_winmajor)
\r
210 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
212 #define oldDialog (_winmajor < 4)
\r
215 char *defaultTextAttribs[] =
\r
217 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
218 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
228 int cliWidth, cliHeight;
\r
231 SizeInfo sizeInfo[] =
\r
233 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
234 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
235 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
236 { "petite", 33, 1, 1, 1, 0, 0 },
\r
237 { "slim", 37, 2, 1, 0, 0, 0 },
\r
238 { "small", 40, 2, 1, 0, 0, 0 },
\r
239 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
240 { "middling", 49, 2, 0, 0, 0, 0 },
\r
241 { "average", 54, 2, 0, 0, 0, 0 },
\r
242 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
243 { "medium", 64, 3, 0, 0, 0, 0 },
\r
244 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
245 { "large", 80, 3, 0, 0, 0, 0 },
\r
246 { "big", 87, 3, 0, 0, 0, 0 },
\r
247 { "huge", 95, 3, 0, 0, 0, 0 },
\r
248 { "giant", 108, 3, 0, 0, 0, 0 },
\r
249 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
250 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
251 { NULL, 0, 0, 0, 0, 0, 0 }
\r
254 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
255 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
257 { 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
258 { 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
259 { 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
260 { 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
261 { 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
262 { 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
263 { 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
264 { 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
265 { 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
266 { 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
267 { 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
268 { 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
269 { 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
270 { 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
271 { 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
272 { 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
273 { 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
274 { 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
277 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
286 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
287 #define N_BUTTONS 5
\r
289 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
291 {"<<", IDM_ToStart, NULL, NULL},
\r
292 {"<", IDM_Backward, NULL, NULL},
\r
293 {"P", IDM_Pause, NULL, NULL},
\r
294 {">", IDM_Forward, NULL, NULL},
\r
295 {">>", IDM_ToEnd, NULL, NULL},
\r
298 int tinyLayout = 0, smallLayout = 0;
\r
299 #define MENU_BAR_ITEMS 6
\r
300 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
301 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
302 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
306 MySound sounds[(int)NSoundClasses];
\r
307 MyTextAttribs textAttribs[(int)NColorClasses];
\r
309 MyColorizeAttribs colorizeAttribs[] = {
\r
310 { (COLORREF)0, 0, "Shout Text" },
\r
311 { (COLORREF)0, 0, "SShout/CShout" },
\r
312 { (COLORREF)0, 0, "Channel 1 Text" },
\r
313 { (COLORREF)0, 0, "Channel Text" },
\r
314 { (COLORREF)0, 0, "Kibitz Text" },
\r
315 { (COLORREF)0, 0, "Tell Text" },
\r
316 { (COLORREF)0, 0, "Challenge Text" },
\r
317 { (COLORREF)0, 0, "Request Text" },
\r
318 { (COLORREF)0, 0, "Seek Text" },
\r
319 { (COLORREF)0, 0, "Normal Text" },
\r
320 { (COLORREF)0, 0, "None" }
\r
325 static char *commentTitle;
\r
326 static char *commentText;
\r
327 static int commentIndex;
\r
328 static Boolean editComment = FALSE;
\r
329 HWND commentDialog = NULL;
\r
330 BOOLEAN commentDialogUp = FALSE;
\r
331 static int commentX, commentY, commentH, commentW;
\r
333 static char *analysisTitle;
\r
334 static char *analysisText;
\r
335 HWND analysisDialog = NULL;
\r
336 BOOLEAN analysisDialogUp = FALSE;
\r
337 static int analysisX, analysisY, analysisH, analysisW;
\r
339 char errorTitle[MSG_SIZ];
\r
340 char errorMessage[2*MSG_SIZ];
\r
341 HWND errorDialog = NULL;
\r
342 BOOLEAN moveErrorMessageUp = FALSE;
\r
343 BOOLEAN consoleEcho = TRUE;
\r
344 CHARFORMAT consoleCF;
\r
345 COLORREF consoleBackgroundColor;
\r
347 char *programVersion;
\r
353 typedef int CPKind;
\r
362 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
365 #define INPUT_SOURCE_BUF_SIZE 4096
\r
367 typedef struct _InputSource {
\r
374 char buf[INPUT_SOURCE_BUF_SIZE];
\r
378 InputCallback func;
\r
379 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
383 InputSource *consoleInputSource;
\r
388 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
389 VOID ConsoleCreate();
\r
391 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
392 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
393 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
394 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
396 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
397 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
398 void ParseIcsTextMenu(char *icsTextMenuString);
\r
399 VOID PopUpMoveDialog(char firstchar);
\r
400 VOID PopUpNameDialog(char firstchar);
\r
401 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
405 int GameListOptions();
\r
407 HWND moveHistoryDialog = NULL;
\r
408 BOOLEAN moveHistoryDialogUp = FALSE;
\r
410 WindowPlacement wpMoveHistory;
\r
412 HWND evalGraphDialog = NULL;
\r
413 BOOLEAN evalGraphDialogUp = FALSE;
\r
415 WindowPlacement wpEvalGraph;
\r
417 HWND engineOutputDialog = NULL;
\r
418 BOOLEAN engineOutputDialogUp = FALSE;
\r
420 WindowPlacement wpEngineOutput;
\r
422 VOID MoveHistoryPopUp();
\r
423 VOID MoveHistoryPopDown();
\r
424 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
425 BOOL MoveHistoryIsUp();
\r
427 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
428 VOID EvalGraphPopUp();
\r
429 VOID EvalGraphPopDown();
\r
430 BOOL EvalGraphIsUp();
\r
432 VOID EngineOutputPopUp();
\r
433 VOID EngineOutputPopDown();
\r
434 BOOL EngineOutputIsUp();
\r
435 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
437 VOID GothicPopUp(char *title, VariantClass variant);
\r
439 * Setting "frozen" should disable all user input other than deleting
\r
440 * the window. We do this while engines are initializing themselves.
\r
442 static int frozen = 0;
\r
443 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
449 if (frozen) return;
\r
451 hmenu = GetMenu(hwndMain);
\r
452 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
453 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
455 DrawMenuBar(hwndMain);
\r
458 /* Undo a FreezeUI */
\r
464 if (!frozen) return;
\r
466 hmenu = GetMenu(hwndMain);
\r
467 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
468 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
470 DrawMenuBar(hwndMain);
\r
473 /*---------------------------------------------------------------------------*\
\r
477 \*---------------------------------------------------------------------------*/
\r
480 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
481 LPSTR lpCmdLine, int nCmdShow)
\r
484 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
485 // INITCOMMONCONTROLSEX ex;
\r
489 LoadLibrary("RICHED32.DLL");
\r
490 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
492 if (!InitApplication(hInstance)) {
\r
495 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
499 // InitCommonControlsEx(&ex);
\r
500 InitCommonControls();
\r
502 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
503 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
504 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
506 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
508 while (GetMessage(&msg, /* message structure */
\r
509 NULL, /* handle of window receiving the message */
\r
510 0, /* lowest message to examine */
\r
511 0)) /* highest message to examine */
\r
513 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
514 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
515 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
516 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
517 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
518 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
519 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
520 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
521 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
522 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
523 TranslateMessage(&msg); /* Translates virtual key codes */
\r
524 DispatchMessage(&msg); /* Dispatches message to window */
\r
529 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
532 /*---------------------------------------------------------------------------*\
\r
534 * Initialization functions
\r
536 \*---------------------------------------------------------------------------*/
\r
539 InitApplication(HINSTANCE hInstance)
\r
543 /* Fill in window class structure with parameters that describe the */
\r
546 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
547 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
548 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
549 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
550 wc.hInstance = hInstance; /* Owner of this class */
\r
551 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
552 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
553 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
554 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
555 wc.lpszClassName = szAppName; /* Name to register as */
\r
557 /* Register the window class and return success/failure code. */
\r
558 if (!RegisterClass(&wc)) return FALSE;
\r
560 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
561 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
563 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
564 wc.hInstance = hInstance;
\r
565 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
566 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
567 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
568 wc.lpszMenuName = NULL;
\r
569 wc.lpszClassName = szConsoleName;
\r
571 if (!RegisterClass(&wc)) return FALSE;
\r
576 /* Set by InitInstance, used by EnsureOnScreen */
\r
577 int screenHeight, screenWidth;
\r
580 EnsureOnScreen(int *x, int *y)
\r
582 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
583 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
584 if (*x > screenWidth - 32) *x = 0;
\r
585 if (*y > screenHeight - 32) *y = 0;
\r
586 if (*x < 0) *x = 0;
\r
587 if (*y < 0) *y = 0;
\r
588 // if (*x < 10) *x = 10;
\r
589 // if (*y < gap) *y = gap;
\r
593 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
595 HWND hwnd; /* Main window handle. */
\r
597 WINDOWPLACEMENT wp;
\r
600 hInst = hInstance; /* Store instance handle in our global variable */
\r
602 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
603 *filepart = NULLCHAR;
\r
605 GetCurrentDirectory(MSG_SIZ, installDir);
\r
607 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
608 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
609 if (appData.debugMode) {
\r
610 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
611 setbuf(debugFP, NULL);
\r
616 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
617 // InitEngineUCI( installDir, &second );
\r
619 /* Create a main window for this application instance. */
\r
620 hwnd = CreateWindow(szAppName, szTitle,
\r
621 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
622 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
623 NULL, NULL, hInstance, NULL);
\r
626 /* If window could not be created, return "failure" */
\r
631 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
632 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
633 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
635 if (first.programLogo == NULL && appData.debugMode) {
\r
636 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
638 } else if(appData.autoLogo) {
\r
639 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
641 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
642 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
646 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
647 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
649 if (second.programLogo == NULL && appData.debugMode) {
\r
650 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
652 } else if(appData.autoLogo) {
\r
653 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
655 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
656 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
660 iconWhite = LoadIcon(hInstance, "icon_white");
\r
661 iconBlack = LoadIcon(hInstance, "icon_black");
\r
662 iconCurrent = iconWhite;
\r
663 InitDrawingColors();
\r
664 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
665 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
666 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
667 /* Compute window size for each board size, and use the largest
\r
668 size that fits on this screen as the default. */
\r
669 InitDrawingSizes((BoardSize)ibs, 0);
\r
670 if (boardSize == (BoardSize)-1 &&
\r
671 winHeight <= screenHeight
\r
672 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
673 && winWidth <= screenWidth) {
\r
674 boardSize = (BoardSize)ibs;
\r
678 InitDrawingSizes(boardSize, 0);
\r
680 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
682 /* [AS] Load textures if specified */
\r
683 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
685 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
686 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
687 liteBackTextureMode = appData.liteBackTextureMode;
\r
689 if (liteBackTexture == NULL && appData.debugMode) {
\r
690 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
694 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
695 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
696 darkBackTextureMode = appData.darkBackTextureMode;
\r
698 if (darkBackTexture == NULL && appData.debugMode) {
\r
699 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
703 mysrandom( (unsigned) time(NULL) );
\r
705 /* [AS] Restore layout */
\r
706 if( wpMoveHistory.visible ) {
\r
707 MoveHistoryPopUp();
\r
710 if( wpEvalGraph.visible ) {
\r
714 if( wpEngineOutput.visible ) {
\r
715 EngineOutputPopUp();
\r
720 /* Make the window visible; update its client area; and return "success" */
\r
721 EnsureOnScreen(&boardX, &boardY);
\r
722 wp.length = sizeof(WINDOWPLACEMENT);
\r
724 wp.showCmd = nCmdShow;
\r
725 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
726 wp.rcNormalPosition.left = boardX;
\r
727 wp.rcNormalPosition.right = boardX + winWidth;
\r
728 wp.rcNormalPosition.top = boardY;
\r
729 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
730 SetWindowPlacement(hwndMain, &wp);
\r
732 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
733 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
736 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
737 if( gameInfo.variant != VariantFischeRandom ) {
\r
738 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
743 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
744 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
746 ShowWindow(hwndConsole, nCmdShow);
\r
748 UpdateWindow(hwnd);
\r
756 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
757 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
758 ArgSettingsFilename
\r
766 String *pString; // ArgString
\r
767 int *pInt; // ArgInt
\r
768 float *pFloat; // ArgFloat
\r
769 Boolean *pBoolean; // ArgBoolean
\r
770 COLORREF *pColor; // ArgColor
\r
771 ColorClass cc; // ArgAttribs
\r
772 String *pFilename; // ArgFilename
\r
773 BoardSize *pBoardSize; // ArgBoardSize
\r
774 int whichFont; // ArgFont
\r
775 DCB *pDCB; // ArgCommSettings
\r
776 String *pFilename; // ArgSettingsFilename
\r
784 ArgDescriptor argDescriptors[] = {
\r
785 /* positional arguments */
\r
786 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
787 { "", ArgNone, NULL },
\r
788 /* keyword arguments */
\r
789 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
790 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
791 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
792 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
793 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
794 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
795 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
796 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
797 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
798 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
799 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
800 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
801 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
802 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
803 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
804 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
805 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
806 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
808 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
810 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
812 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
813 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
815 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
816 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
817 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
818 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
819 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
820 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
821 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
822 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
823 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
824 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
825 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
826 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
827 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
828 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
829 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
830 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
831 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
832 /*!!bitmapDirectory?*/
\r
833 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
834 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
835 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
836 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
837 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
838 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
839 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
840 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
841 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
842 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
843 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
844 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
845 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
846 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
847 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
848 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
849 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
850 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
851 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
852 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
853 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
854 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
855 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
856 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
857 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
858 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
859 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
860 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
861 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
862 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
863 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
864 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
865 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
866 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
867 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
868 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
869 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
870 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
871 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
872 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
873 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
874 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
875 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
876 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
877 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
878 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
879 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
880 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
881 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
882 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
883 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
884 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
885 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
886 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
887 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
888 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
889 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
890 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
891 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
892 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
893 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
894 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
895 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
896 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
897 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
898 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
899 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
900 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
901 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
902 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
903 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
904 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
905 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
906 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
907 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
908 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
909 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
910 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
911 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
912 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
913 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
914 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
915 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
916 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
917 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
918 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
919 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
920 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
921 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
922 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
923 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
924 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
925 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
926 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
927 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
928 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
929 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
930 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
931 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
932 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
933 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
934 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
935 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
936 TRUE }, /* must come after all fonts */
\r
937 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
938 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
939 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
940 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
941 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
942 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
943 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
944 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
945 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
946 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
947 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
948 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
949 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
950 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
951 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
952 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
953 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
954 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
955 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
956 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
957 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
958 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
959 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
960 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
961 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
962 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
963 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
964 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
965 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
966 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
967 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
969 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
970 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
972 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
973 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
974 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
975 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
976 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
977 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
978 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
979 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
980 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
981 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
982 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
983 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
984 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
985 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
986 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
987 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
988 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
989 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
990 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
991 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
992 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
993 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
994 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
995 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
996 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
997 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
998 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
999 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1000 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1001 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1002 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1003 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1004 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1005 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1006 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1007 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1008 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1009 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1010 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1011 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1012 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1013 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1014 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1015 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1016 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1017 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1018 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1019 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1020 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1021 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1022 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1023 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1024 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1025 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1026 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1027 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1028 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1029 { "highlightLastMove", ArgBoolean,
\r
1030 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1031 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1032 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1033 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1034 { "highlightDragging", ArgBoolean,
\r
1035 (LPVOID) &appData.highlightDragging, TRUE },
\r
1036 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1037 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1038 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1039 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1040 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1041 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1042 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1043 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1044 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1045 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1046 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1047 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1048 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1049 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1050 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1051 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1052 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1053 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1054 { "soundShout", ArgFilename,
\r
1055 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1056 { "soundSShout", ArgFilename,
\r
1057 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1058 { "soundChannel1", ArgFilename,
\r
1059 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1060 { "soundChannel", ArgFilename,
\r
1061 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1062 { "soundKibitz", ArgFilename,
\r
1063 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1064 { "soundTell", ArgFilename,
\r
1065 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1066 { "soundChallenge", ArgFilename,
\r
1067 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1068 { "soundRequest", ArgFilename,
\r
1069 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1070 { "soundSeek", ArgFilename,
\r
1071 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1072 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1073 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1074 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1075 { "soundIcsLoss", ArgFilename,
\r
1076 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1077 { "soundIcsDraw", ArgFilename,
\r
1078 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1079 { "soundIcsUnfinished", ArgFilename,
\r
1080 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1081 { "soundIcsAlarm", ArgFilename,
\r
1082 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1083 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1084 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1085 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1086 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1087 { "reuseChessPrograms", ArgBoolean,
\r
1088 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1089 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1090 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1091 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1092 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1093 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1094 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1095 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1096 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1097 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1098 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1099 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1100 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1101 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1102 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1103 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1104 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1105 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1106 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1107 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1108 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1109 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1110 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1111 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1112 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1113 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1114 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1115 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1116 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1117 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1118 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1119 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1120 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1121 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1122 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1123 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1124 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1125 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1127 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1129 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1130 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1131 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1132 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1133 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1134 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1135 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1136 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1137 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1138 /* [AS] New features */
\r
1139 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1140 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1141 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1142 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1143 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1144 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1145 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1146 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1147 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1148 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1149 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1150 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1151 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1152 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1153 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1154 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1155 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1156 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1157 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1158 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1159 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1160 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1161 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1162 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1163 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1164 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1165 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1166 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1167 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1168 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1169 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1170 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1171 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1172 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1173 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1174 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1175 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1176 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1177 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1178 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1179 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1180 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1181 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1182 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1183 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1184 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1185 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1186 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1187 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1188 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1190 /* [AS] Layout stuff */
\r
1191 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1192 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1193 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1194 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1195 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1197 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1198 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1199 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1200 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1201 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1203 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1204 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1205 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1206 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1207 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1209 /* [HGM] board-size, adjudication and misc. options */
\r
1210 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1211 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1212 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1213 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1214 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1215 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1216 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1217 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1218 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1219 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1220 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1221 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1222 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1223 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1224 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1225 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1226 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1227 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1228 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1229 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1230 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1231 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1232 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1233 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1234 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1235 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1236 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1237 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1238 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1241 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1242 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1243 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1244 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1245 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1246 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1247 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1248 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1249 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1250 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1251 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1252 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1253 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1255 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1256 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1257 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1258 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1259 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1260 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1261 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1263 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1264 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1265 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1266 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1267 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1268 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1269 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1270 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1271 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1272 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1273 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1274 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1275 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1276 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1277 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1278 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1279 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1280 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1282 /* [HGM] options for broadcasting and time odds */
\r
1283 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1284 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1285 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1286 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1287 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1288 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1289 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1290 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1291 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1292 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1293 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1294 { NULL, ArgNone, NULL, FALSE }
\r
1298 /* Kludge for indirection files on command line */
\r
1299 char* lastIndirectionFilename;
\r
1300 ArgDescriptor argDescriptorIndirection =
\r
1301 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1305 ExitArgError(char *msg, char *badArg)
\r
1307 char buf[MSG_SIZ];
\r
1309 sprintf(buf, "%s %s", msg, badArg);
\r
1310 DisplayFatalError(buf, 0, 2);
\r
1314 /* Command line font name parser. NULL name means do nothing.
\r
1315 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1316 For backward compatibility, syntax without the colon is also
\r
1317 accepted, but font names with digits in them won't work in that case.
\r
1320 ParseFontName(char *name, MyFontParams *mfp)
\r
1323 if (name == NULL) return;
\r
1325 q = strchr(p, ':');
\r
1327 if (q - p >= sizeof(mfp->faceName))
\r
1328 ExitArgError("Font name too long:", name);
\r
1329 memcpy(mfp->faceName, p, q - p);
\r
1330 mfp->faceName[q - p] = NULLCHAR;
\r
1333 q = mfp->faceName;
\r
1334 while (*p && !isdigit(*p)) {
\r
1336 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1337 ExitArgError("Font name too long:", name);
\r
1339 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1342 if (!*p) ExitArgError("Font point size missing:", name);
\r
1343 mfp->pointSize = (float) atof(p);
\r
1344 mfp->bold = (strchr(p, 'b') != NULL);
\r
1345 mfp->italic = (strchr(p, 'i') != NULL);
\r
1346 mfp->underline = (strchr(p, 'u') != NULL);
\r
1347 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1350 /* Color name parser.
\r
1351 X version accepts X color names, but this one
\r
1352 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1354 ParseColorName(char *name)
\r
1356 int red, green, blue, count;
\r
1357 char buf[MSG_SIZ];
\r
1359 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1361 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1362 &red, &green, &blue);
\r
1365 sprintf(buf, "Can't parse color name %s", name);
\r
1366 DisplayError(buf, 0);
\r
1367 return RGB(0, 0, 0);
\r
1369 return PALETTERGB(red, green, blue);
\r
1373 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1375 char *e = argValue;
\r
1379 if (*e == 'b') eff |= CFE_BOLD;
\r
1380 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1381 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1382 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1383 else if (*e == '#' || isdigit(*e)) break;
\r
1387 *color = ParseColorName(e);
\r
1392 ParseBoardSize(char *name)
\r
1394 BoardSize bs = SizeTiny;
\r
1395 while (sizeInfo[bs].name != NULL) {
\r
1396 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1399 ExitArgError("Unrecognized board size value", name);
\r
1400 return bs; /* not reached */
\r
1405 StringGet(void *getClosure)
\r
1407 char **p = (char **) getClosure;
\r
1412 FileGet(void *getClosure)
\r
1415 FILE* f = (FILE*) getClosure;
\r
1418 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1425 /* Parse settings file named "name". If file found, return the
\r
1426 full name in fullname and return TRUE; else return FALSE */
\r
1428 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1432 int ok; char buf[MSG_SIZ];
\r
1434 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1435 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1436 sprintf(buf, "%s.ini", name);
\r
1437 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1440 f = fopen(fullname, "r");
\r
1442 ParseArgs(FileGet, f);
\r
1451 ParseArgs(GetFunc get, void *cl)
\r
1453 char argName[ARG_MAX];
\r
1454 char argValue[ARG_MAX];
\r
1455 ArgDescriptor *ad;
\r
1464 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1465 if (ch == NULLCHAR) break;
\r
1467 /* Comment to end of line */
\r
1469 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1471 } else if (ch == '/' || ch == '-') {
\r
1474 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1475 ch != '\n' && ch != '\t') {
\r
1481 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1482 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1484 if (ad->argName == NULL)
\r
1485 ExitArgError("Unrecognized argument", argName);
\r
1487 } else if (ch == '@') {
\r
1488 /* Indirection file */
\r
1489 ad = &argDescriptorIndirection;
\r
1492 /* Positional argument */
\r
1493 ad = &argDescriptors[posarg++];
\r
1494 strcpy(argName, ad->argName);
\r
1497 if (ad->argType == ArgTrue) {
\r
1498 *(Boolean *) ad->argLoc = TRUE;
\r
1501 if (ad->argType == ArgFalse) {
\r
1502 *(Boolean *) ad->argLoc = FALSE;
\r
1506 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1507 if (ch == NULLCHAR || ch == '\n') {
\r
1508 ExitArgError("No value provided for argument", argName);
\r
1512 // Quoting with { }. No characters have to (or can) be escaped.
\r
1513 // Thus the string cannot contain a '}' character.
\r
1533 } else if (ch == '\'' || ch == '"') {
\r
1534 // Quoting with ' ' or " ", with \ as escape character.
\r
1535 // Inconvenient for long strings that may contain Windows filenames.
\r
1552 if (ch == start) {
\r
1561 if (ad->argType == ArgFilename
\r
1562 || ad->argType == ArgSettingsFilename) {
\r
1568 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1592 for (i = 0; i < 3; i++) {
\r
1593 if (ch >= '0' && ch <= '7') {
\r
1594 octval = octval*8 + (ch - '0');
\r
1601 *q++ = (char) octval;
\r
1612 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1619 switch (ad->argType) {
\r
1621 *(int *) ad->argLoc = atoi(argValue);
\r
1625 *(float *) ad->argLoc = (float) atof(argValue);
\r
1630 *(char **) ad->argLoc = strdup(argValue);
\r
1633 case ArgSettingsFilename:
\r
1635 char fullname[MSG_SIZ];
\r
1636 if (ParseSettingsFile(argValue, fullname)) {
\r
1637 if (ad->argLoc != NULL) {
\r
1638 *(char **) ad->argLoc = strdup(fullname);
\r
1641 if (ad->argLoc != NULL) {
\r
1643 ExitArgError("Failed to open indirection file", argValue);
\r
1650 switch (argValue[0]) {
\r
1653 *(Boolean *) ad->argLoc = TRUE;
\r
1657 *(Boolean *) ad->argLoc = FALSE;
\r
1660 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1666 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1669 case ArgAttribs: {
\r
1670 ColorClass cc = (ColorClass)ad->argLoc;
\r
1671 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1675 case ArgBoardSize:
\r
1676 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1680 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1683 case ArgCommSettings:
\r
1684 ParseCommSettings(argValue, &dcb);
\r
1688 ExitArgError("Unrecognized argument", argValue);
\r
1697 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1699 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1700 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1703 lf->lfEscapement = 0;
\r
1704 lf->lfOrientation = 0;
\r
1705 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1706 lf->lfItalic = mfp->italic;
\r
1707 lf->lfUnderline = mfp->underline;
\r
1708 lf->lfStrikeOut = mfp->strikeout;
\r
1709 lf->lfCharSet = DEFAULT_CHARSET;
\r
1710 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1711 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1712 lf->lfQuality = DEFAULT_QUALITY;
\r
1713 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1714 strcpy(lf->lfFaceName, mfp->faceName);
\r
1718 CreateFontInMF(MyFont *mf)
\r
1720 LFfromMFP(&mf->lf, &mf->mfp);
\r
1721 if (mf->hf) DeleteObject(mf->hf);
\r
1722 mf->hf = CreateFontIndirect(&mf->lf);
\r
1726 SetDefaultTextAttribs()
\r
1729 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1730 ParseAttribs(&textAttribs[cc].color,
\r
1731 &textAttribs[cc].effects,
\r
1732 defaultTextAttribs[cc]);
\r
1737 SetDefaultSounds()
\r
1741 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1742 textAttribs[cc].sound.name = strdup("");
\r
1743 textAttribs[cc].sound.data = NULL;
\r
1745 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1746 sounds[sc].name = strdup("");
\r
1747 sounds[sc].data = NULL;
\r
1749 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1757 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1758 MyLoadSound(&textAttribs[cc].sound);
\r
1760 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1761 MyLoadSound(&sounds[sc]);
\r
1766 InitAppData(LPSTR lpCmdLine)
\r
1769 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1772 programName = szAppName;
\r
1774 /* Initialize to defaults */
\r
1775 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1776 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1777 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1778 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1779 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1780 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1781 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1782 SetDefaultTextAttribs();
\r
1783 SetDefaultSounds();
\r
1784 appData.movesPerSession = MOVES_PER_SESSION;
\r
1785 appData.initString = INIT_STRING;
\r
1786 appData.secondInitString = INIT_STRING;
\r
1787 appData.firstComputerString = COMPUTER_STRING;
\r
1788 appData.secondComputerString = COMPUTER_STRING;
\r
1789 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1790 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1791 appData.firstPlaysBlack = FALSE;
\r
1792 appData.noChessProgram = FALSE;
\r
1793 chessProgram = FALSE;
\r
1794 appData.firstHost = FIRST_HOST;
\r
1795 appData.secondHost = SECOND_HOST;
\r
1796 appData.firstDirectory = FIRST_DIRECTORY;
\r
1797 appData.secondDirectory = SECOND_DIRECTORY;
\r
1798 appData.bitmapDirectory = "";
\r
1799 appData.remoteShell = REMOTE_SHELL;
\r
1800 appData.remoteUser = "";
\r
1801 appData.timeDelay = TIME_DELAY;
\r
1802 appData.timeControl = TIME_CONTROL;
\r
1803 appData.timeIncrement = TIME_INCREMENT;
\r
1804 appData.icsActive = FALSE;
\r
1805 appData.icsHost = "";
\r
1806 appData.icsPort = ICS_PORT;
\r
1807 appData.icsCommPort = ICS_COMM_PORT;
\r
1808 appData.icsLogon = ICS_LOGON;
\r
1809 appData.icsHelper = "";
\r
1810 appData.useTelnet = FALSE;
\r
1811 appData.telnetProgram = TELNET_PROGRAM;
\r
1812 appData.gateway = "";
\r
1813 appData.loadGameFile = "";
\r
1814 appData.loadGameIndex = 0;
\r
1815 appData.saveGameFile = "";
\r
1816 appData.autoSaveGames = FALSE;
\r
1817 appData.loadPositionFile = "";
\r
1818 appData.loadPositionIndex = 1;
\r
1819 appData.savePositionFile = "";
\r
1820 appData.matchMode = FALSE;
\r
1821 appData.matchGames = 0;
\r
1822 appData.monoMode = FALSE;
\r
1823 appData.debugMode = FALSE;
\r
1824 appData.clockMode = TRUE;
\r
1825 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1826 appData.Iconic = FALSE; /*unused*/
\r
1827 appData.searchTime = "";
\r
1828 appData.searchDepth = 0;
\r
1829 appData.showCoords = FALSE;
\r
1830 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1831 appData.autoCallFlag = FALSE;
\r
1832 appData.flipView = FALSE;
\r
1833 appData.autoFlipView = TRUE;
\r
1834 appData.cmailGameName = "";
\r
1835 appData.alwaysPromoteToQueen = FALSE;
\r
1836 appData.oldSaveStyle = FALSE;
\r
1837 appData.quietPlay = FALSE;
\r
1838 appData.showThinking = FALSE;
\r
1839 appData.ponderNextMove = TRUE;
\r
1840 appData.periodicUpdates = TRUE;
\r
1841 appData.popupExitMessage = TRUE;
\r
1842 appData.popupMoveErrors = FALSE;
\r
1843 appData.autoObserve = FALSE;
\r
1844 appData.autoComment = FALSE;
\r
1845 appData.animate = TRUE;
\r
1846 appData.animSpeed = 10;
\r
1847 appData.animateDragging = TRUE;
\r
1848 appData.highlightLastMove = TRUE;
\r
1849 appData.getMoveList = TRUE;
\r
1850 appData.testLegality = TRUE;
\r
1851 appData.premove = TRUE;
\r
1852 appData.premoveWhite = FALSE;
\r
1853 appData.premoveWhiteText = "";
\r
1854 appData.premoveBlack = FALSE;
\r
1855 appData.premoveBlackText = "";
\r
1856 appData.icsAlarm = TRUE;
\r
1857 appData.icsAlarmTime = 5000;
\r
1858 appData.autoRaiseBoard = TRUE;
\r
1859 appData.localLineEditing = TRUE;
\r
1860 appData.colorize = TRUE;
\r
1861 appData.reuseFirst = TRUE;
\r
1862 appData.reuseSecond = TRUE;
\r
1863 appData.blindfold = FALSE;
\r
1864 appData.icsEngineAnalyze = FALSE;
\r
1865 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1866 dcb.DCBlength = sizeof(DCB);
\r
1867 dcb.BaudRate = 9600;
\r
1868 dcb.fBinary = TRUE;
\r
1869 dcb.fParity = FALSE;
\r
1870 dcb.fOutxCtsFlow = FALSE;
\r
1871 dcb.fOutxDsrFlow = FALSE;
\r
1872 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1873 dcb.fDsrSensitivity = FALSE;
\r
1874 dcb.fTXContinueOnXoff = TRUE;
\r
1875 dcb.fOutX = FALSE;
\r
1877 dcb.fNull = FALSE;
\r
1878 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1879 dcb.fAbortOnError = FALSE;
\r
1881 dcb.Parity = SPACEPARITY;
\r
1882 dcb.StopBits = ONESTOPBIT;
\r
1883 settingsFileName = SETTINGS_FILE;
\r
1884 saveSettingsOnExit = TRUE;
\r
1885 boardX = CW_USEDEFAULT;
\r
1886 boardY = CW_USEDEFAULT;
\r
1887 consoleX = CW_USEDEFAULT;
\r
1888 consoleY = CW_USEDEFAULT;
\r
1889 consoleW = CW_USEDEFAULT;
\r
1890 consoleH = CW_USEDEFAULT;
\r
1891 analysisX = CW_USEDEFAULT;
\r
1892 analysisY = CW_USEDEFAULT;
\r
1893 analysisW = CW_USEDEFAULT;
\r
1894 analysisH = CW_USEDEFAULT;
\r
1895 commentX = CW_USEDEFAULT;
\r
1896 commentY = CW_USEDEFAULT;
\r
1897 commentW = CW_USEDEFAULT;
\r
1898 commentH = CW_USEDEFAULT;
\r
1899 editTagsX = CW_USEDEFAULT;
\r
1900 editTagsY = CW_USEDEFAULT;
\r
1901 editTagsW = CW_USEDEFAULT;
\r
1902 editTagsH = CW_USEDEFAULT;
\r
1903 gameListX = CW_USEDEFAULT;
\r
1904 gameListY = CW_USEDEFAULT;
\r
1905 gameListW = CW_USEDEFAULT;
\r
1906 gameListH = CW_USEDEFAULT;
\r
1907 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1908 icsNames = ICS_NAMES;
\r
1909 firstChessProgramNames = FCP_NAMES;
\r
1910 secondChessProgramNames = SCP_NAMES;
\r
1911 appData.initialMode = "";
\r
1912 appData.variant = "normal";
\r
1913 appData.firstProtocolVersion = PROTOVER;
\r
1914 appData.secondProtocolVersion = PROTOVER;
\r
1915 appData.showButtonBar = TRUE;
\r
1917 /* [AS] New properties (see comments in header file) */
\r
1918 appData.firstScoreIsAbsolute = FALSE;
\r
1919 appData.secondScoreIsAbsolute = FALSE;
\r
1920 appData.saveExtendedInfoInPGN = FALSE;
\r
1921 appData.hideThinkingFromHuman = FALSE;
\r
1922 appData.liteBackTextureFile = "";
\r
1923 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1924 appData.darkBackTextureFile = "";
\r
1925 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1926 appData.renderPiecesWithFont = "";
\r
1927 appData.fontToPieceTable = "";
\r
1928 appData.fontBackColorWhite = 0;
\r
1929 appData.fontForeColorWhite = 0;
\r
1930 appData.fontBackColorBlack = 0;
\r
1931 appData.fontForeColorBlack = 0;
\r
1932 appData.fontPieceSize = 80;
\r
1933 appData.overrideLineGap = 1;
\r
1934 appData.adjudicateLossThreshold = 0;
\r
1935 appData.delayBeforeQuit = 0;
\r
1936 appData.delayAfterQuit = 0;
\r
1937 appData.nameOfDebugFile = "winboard.debug";
\r
1938 appData.pgnEventHeader = "Computer Chess Game";
\r
1939 appData.defaultFrcPosition = -1;
\r
1940 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1941 appData.saveOutOfBookInfo = TRUE;
\r
1942 appData.showEvalInMoveHistory = TRUE;
\r
1943 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1944 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1945 appData.highlightMoveWithArrow = FALSE;
\r
1946 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1947 appData.useStickyWindows = TRUE;
\r
1948 appData.adjudicateDrawMoves = 0;
\r
1949 appData.autoDisplayComment = TRUE;
\r
1950 appData.autoDisplayTags = TRUE;
\r
1951 appData.firstIsUCI = FALSE;
\r
1952 appData.secondIsUCI = FALSE;
\r
1953 appData.firstHasOwnBookUCI = TRUE;
\r
1954 appData.secondHasOwnBookUCI = TRUE;
\r
1955 appData.polyglotDir = "";
\r
1956 appData.usePolyglotBook = FALSE;
\r
1957 appData.polyglotBook = "";
\r
1958 appData.defaultHashSize = 64;
\r
1959 appData.defaultCacheSizeEGTB = 4;
\r
1960 appData.defaultPathEGTB = "c:\\egtb";
\r
1961 appData.firstOptions = "";
\r
1962 appData.secondOptions = "";
\r
1964 InitWindowPlacement( &wpMoveHistory );
\r
1965 InitWindowPlacement( &wpEvalGraph );
\r
1966 InitWindowPlacement( &wpEngineOutput );
\r
1968 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1969 appData.NrFiles = -1;
\r
1970 appData.NrRanks = -1;
\r
1971 appData.holdingsSize = -1;
\r
1972 appData.testClaims = FALSE;
\r
1973 appData.checkMates = FALSE;
\r
1974 appData.materialDraws= FALSE;
\r
1975 appData.trivialDraws = FALSE;
\r
1976 appData.ruleMoves = 51;
\r
1977 appData.drawRepeats = 6;
\r
1978 appData.matchPause = 10000;
\r
1979 appData.alphaRank = FALSE;
\r
1980 appData.allWhite = FALSE;
\r
1981 appData.upsideDown = FALSE;
\r
1982 appData.serverPause = 15;
\r
1983 appData.serverMovesName = NULL;
\r
1984 appData.suppressLoadMoves = FALSE;
\r
1985 appData.firstTimeOdds = 1;
\r
1986 appData.secondTimeOdds = 1;
\r
1987 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
1988 appData.secondAccumulateTC = 1;
\r
1989 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
1990 appData.secondNPS = -1;
\r
1991 appData.engineComments = 1;
\r
1992 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
1993 appData.egtFormats = "";
\r
1996 appData.zippyTalk = ZIPPY_TALK;
\r
1997 appData.zippyPlay = ZIPPY_PLAY;
\r
1998 appData.zippyLines = ZIPPY_LINES;
\r
1999 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2000 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2001 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2002 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2003 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2004 appData.zippyUseI = ZIPPY_USE_I;
\r
2005 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2006 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2007 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2008 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2009 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2010 appData.zippyAbort = ZIPPY_ABORT;
\r
2011 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2012 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2013 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2016 /* Point font array elements to structures and
\r
2017 parse default font names */
\r
2018 for (i=0; i<NUM_FONTS; i++) {
\r
2019 for (j=0; j<NUM_SIZES; j++) {
\r
2020 font[j][i] = &fontRec[j][i];
\r
2021 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2025 /* Parse default settings file if any */
\r
2026 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2027 settingsFileName = strdup(buf);
\r
2030 /* Parse command line */
\r
2031 ParseArgs(StringGet, &lpCmdLine);
\r
2033 /* [HGM] make sure board size is acceptable */
\r
2034 if(appData.NrFiles > BOARD_SIZE ||
\r
2035 appData.NrRanks > BOARD_SIZE )
\r
2036 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2038 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2039 * with options from the command line, we now make an even higher priority
\r
2040 * overrule by WB options attached to the engine command line. This so that
\r
2041 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2044 if(appData.firstChessProgram != NULL) {
\r
2045 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2046 static char *f = "first";
\r
2047 char buf[MSG_SIZ], *q = buf;
\r
2048 if(p != NULL) { // engine command line contains WinBoard options
\r
2049 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2050 ParseArgs(StringGet, &q);
\r
2051 p[-1] = 0; // cut them offengine command line
\r
2054 // now do same for second chess program
\r
2055 if(appData.secondChessProgram != NULL) {
\r
2056 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2057 static char *s = "second";
\r
2058 char buf[MSG_SIZ], *q = buf;
\r
2059 if(p != NULL) { // engine command line contains WinBoard options
\r
2060 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2061 ParseArgs(StringGet, &q);
\r
2062 p[-1] = 0; // cut them offengine command line
\r
2067 /* Propagate options that affect others */
\r
2068 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2069 if (appData.icsActive || appData.noChessProgram) {
\r
2070 chessProgram = FALSE; /* not local chess program mode */
\r
2073 /* Open startup dialog if needed */
\r
2074 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2075 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2076 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2077 *appData.secondChessProgram == NULLCHAR))) {
\r
2080 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2081 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2082 FreeProcInstance(lpProc);
\r
2085 /* Make sure save files land in the right (?) directory */
\r
2086 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2087 appData.saveGameFile = strdup(buf);
\r
2089 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2090 appData.savePositionFile = strdup(buf);
\r
2093 /* Finish initialization for fonts and sounds */
\r
2094 for (i=0; i<NUM_FONTS; i++) {
\r
2095 for (j=0; j<NUM_SIZES; j++) {
\r
2096 CreateFontInMF(font[j][i]);
\r
2099 /* xboard, and older WinBoards, controlled the move sound with the
\r
2100 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2101 always turn the option on (so that the backend will call us),
\r
2102 then let the user turn the sound off by setting it to silence if
\r
2103 desired. To accommodate old winboard.ini files saved by old
\r
2104 versions of WinBoard, we also turn off the sound if the option
\r
2105 was initially set to false. */
\r
2106 if (!appData.ringBellAfterMoves) {
\r
2107 sounds[(int)SoundMove].name = strdup("");
\r
2108 appData.ringBellAfterMoves = TRUE;
\r
2110 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2111 SetCurrentDirectory(installDir);
\r
2113 SetCurrentDirectory(currDir);
\r
2115 p = icsTextMenuString;
\r
2116 if (p[0] == '@') {
\r
2117 FILE* f = fopen(p + 1, "r");
\r
2119 DisplayFatalError(p + 1, errno, 2);
\r
2122 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2124 buf[i] = NULLCHAR;
\r
2127 ParseIcsTextMenu(strdup(p));
\r
2134 HMENU hmenu = GetMenu(hwndMain);
\r
2136 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2137 MF_BYCOMMAND|((appData.icsActive &&
\r
2138 *appData.icsCommPort != NULLCHAR) ?
\r
2139 MF_ENABLED : MF_GRAYED));
\r
2140 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2141 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2142 MF_CHECKED : MF_UNCHECKED));
\r
2147 SaveSettings(char* name)
\r
2150 ArgDescriptor *ad;
\r
2151 WINDOWPLACEMENT wp;
\r
2152 char dir[MSG_SIZ];
\r
2154 if (!hwndMain) return;
\r
2156 GetCurrentDirectory(MSG_SIZ, dir);
\r
2157 SetCurrentDirectory(installDir);
\r
2158 f = fopen(name, "w");
\r
2159 SetCurrentDirectory(dir);
\r
2161 DisplayError(name, errno);
\r
2164 fprintf(f, ";\n");
\r
2165 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2166 fprintf(f, ";\n");
\r
2167 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2168 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2169 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2170 fprintf(f, ";\n");
\r
2172 wp.length = sizeof(WINDOWPLACEMENT);
\r
2173 GetWindowPlacement(hwndMain, &wp);
\r
2174 boardX = wp.rcNormalPosition.left;
\r
2175 boardY = wp.rcNormalPosition.top;
\r
2177 if (hwndConsole) {
\r
2178 GetWindowPlacement(hwndConsole, &wp);
\r
2179 consoleX = wp.rcNormalPosition.left;
\r
2180 consoleY = wp.rcNormalPosition.top;
\r
2181 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2182 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2185 if (analysisDialog) {
\r
2186 GetWindowPlacement(analysisDialog, &wp);
\r
2187 analysisX = wp.rcNormalPosition.left;
\r
2188 analysisY = wp.rcNormalPosition.top;
\r
2189 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2190 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2193 if (commentDialog) {
\r
2194 GetWindowPlacement(commentDialog, &wp);
\r
2195 commentX = wp.rcNormalPosition.left;
\r
2196 commentY = wp.rcNormalPosition.top;
\r
2197 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2198 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2201 if (editTagsDialog) {
\r
2202 GetWindowPlacement(editTagsDialog, &wp);
\r
2203 editTagsX = wp.rcNormalPosition.left;
\r
2204 editTagsY = wp.rcNormalPosition.top;
\r
2205 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2206 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2209 if (gameListDialog) {
\r
2210 GetWindowPlacement(gameListDialog, &wp);
\r
2211 gameListX = wp.rcNormalPosition.left;
\r
2212 gameListY = wp.rcNormalPosition.top;
\r
2213 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2214 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2217 /* [AS] Move history */
\r
2218 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2220 if( moveHistoryDialog ) {
\r
2221 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2222 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2223 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2224 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2225 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2228 /* [AS] Eval graph */
\r
2229 wpEvalGraph.visible = EvalGraphIsUp();
\r
2231 if( evalGraphDialog ) {
\r
2232 GetWindowPlacement(evalGraphDialog, &wp);
\r
2233 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2234 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2235 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2236 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2239 /* [AS] Engine output */
\r
2240 wpEngineOutput.visible = EngineOutputIsUp();
\r
2242 if( engineOutputDialog ) {
\r
2243 GetWindowPlacement(engineOutputDialog, &wp);
\r
2244 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2245 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2246 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2247 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2250 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2251 if (!ad->save) continue;
\r
2252 switch (ad->argType) {
\r
2255 char *p = *(char **)ad->argLoc;
\r
2256 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2257 /* Quote multiline values or \-containing values
\r
2258 with { } if possible */
\r
2259 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2261 /* Else quote with " " */
\r
2262 fprintf(f, "/%s=\"", ad->argName);
\r
2264 if (*p == '\n') fprintf(f, "\n");
\r
2265 else if (*p == '\r') fprintf(f, "\\r");
\r
2266 else if (*p == '\t') fprintf(f, "\\t");
\r
2267 else if (*p == '\b') fprintf(f, "\\b");
\r
2268 else if (*p == '\f') fprintf(f, "\\f");
\r
2269 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2270 else if (*p == '\"') fprintf(f, "\\\"");
\r
2271 else if (*p == '\\') fprintf(f, "\\\\");
\r
2275 fprintf(f, "\"\n");
\r
2280 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2283 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2286 fprintf(f, "/%s=%s\n", ad->argName,
\r
2287 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2290 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2293 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2297 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2298 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2299 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2304 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2305 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2306 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2307 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2308 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2309 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2310 (ta->effects) ? " " : "",
\r
2311 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2315 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2316 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2318 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2321 case ArgBoardSize:
\r
2322 fprintf(f, "/%s=%s\n", ad->argName,
\r
2323 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2328 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2329 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2330 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2331 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2332 ad->argName, mfp->faceName, mfp->pointSize,
\r
2333 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2334 mfp->bold ? "b" : "",
\r
2335 mfp->italic ? "i" : "",
\r
2336 mfp->underline ? "u" : "",
\r
2337 mfp->strikeout ? "s" : "");
\r
2341 case ArgCommSettings:
\r
2342 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2344 case ArgSettingsFilename: ;
\r
2352 /*---------------------------------------------------------------------------*\
\r
2354 * GDI board drawing routines
\r
2356 \*---------------------------------------------------------------------------*/
\r
2358 /* [AS] Draw square using background texture */
\r
2359 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2364 return; /* Should never happen! */
\r
2367 SetGraphicsMode( dst, GM_ADVANCED );
\r
2374 /* X reflection */
\r
2379 x.eDx = (FLOAT) dw + dx - 1;
\r
2382 SetWorldTransform( dst, &x );
\r
2385 /* Y reflection */
\r
2391 x.eDy = (FLOAT) dh + dy - 1;
\r
2393 SetWorldTransform( dst, &x );
\r
2401 x.eDx = (FLOAT) dx;
\r
2402 x.eDy = (FLOAT) dy;
\r
2405 SetWorldTransform( dst, &x );
\r
2409 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2417 SetWorldTransform( dst, &x );
\r
2419 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2422 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2424 PM_WP = (int) WhitePawn,
\r
2425 PM_WN = (int) WhiteKnight,
\r
2426 PM_WB = (int) WhiteBishop,
\r
2427 PM_WR = (int) WhiteRook,
\r
2428 PM_WQ = (int) WhiteQueen,
\r
2429 PM_WF = (int) WhiteFerz,
\r
2430 PM_WW = (int) WhiteWazir,
\r
2431 PM_WE = (int) WhiteAlfil,
\r
2432 PM_WM = (int) WhiteMan,
\r
2433 PM_WO = (int) WhiteCannon,
\r
2434 PM_WU = (int) WhiteUnicorn,
\r
2435 PM_WH = (int) WhiteNightrider,
\r
2436 PM_WA = (int) WhiteAngel,
\r
2437 PM_WC = (int) WhiteMarshall,
\r
2438 PM_WAB = (int) WhiteCardinal,
\r
2439 PM_WD = (int) WhiteDragon,
\r
2440 PM_WL = (int) WhiteLance,
\r
2441 PM_WS = (int) WhiteCobra,
\r
2442 PM_WV = (int) WhiteFalcon,
\r
2443 PM_WSG = (int) WhiteSilver,
\r
2444 PM_WG = (int) WhiteGrasshopper,
\r
2445 PM_WK = (int) WhiteKing,
\r
2446 PM_BP = (int) BlackPawn,
\r
2447 PM_BN = (int) BlackKnight,
\r
2448 PM_BB = (int) BlackBishop,
\r
2449 PM_BR = (int) BlackRook,
\r
2450 PM_BQ = (int) BlackQueen,
\r
2451 PM_BF = (int) BlackFerz,
\r
2452 PM_BW = (int) BlackWazir,
\r
2453 PM_BE = (int) BlackAlfil,
\r
2454 PM_BM = (int) BlackMan,
\r
2455 PM_BO = (int) BlackCannon,
\r
2456 PM_BU = (int) BlackUnicorn,
\r
2457 PM_BH = (int) BlackNightrider,
\r
2458 PM_BA = (int) BlackAngel,
\r
2459 PM_BC = (int) BlackMarshall,
\r
2460 PM_BG = (int) BlackGrasshopper,
\r
2461 PM_BAB = (int) BlackCardinal,
\r
2462 PM_BD = (int) BlackDragon,
\r
2463 PM_BL = (int) BlackLance,
\r
2464 PM_BS = (int) BlackCobra,
\r
2465 PM_BV = (int) BlackFalcon,
\r
2466 PM_BSG = (int) BlackSilver,
\r
2467 PM_BK = (int) BlackKing
\r
2470 static HFONT hPieceFont = NULL;
\r
2471 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2472 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2473 static int fontBitmapSquareSize = 0;
\r
2474 static char pieceToFontChar[(int) EmptySquare] =
\r
2475 { 'p', 'n', 'b', 'r', 'q',
\r
2476 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2477 'k', 'o', 'm', 'v', 't', 'w',
\r
2478 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2481 extern BOOL SetCharTable( char *table, const char * map );
\r
2482 /* [HGM] moved to backend.c */
\r
2484 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2487 BYTE r1 = GetRValue( color );
\r
2488 BYTE g1 = GetGValue( color );
\r
2489 BYTE b1 = GetBValue( color );
\r
2495 /* Create a uniform background first */
\r
2496 hbrush = CreateSolidBrush( color );
\r
2497 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2498 FillRect( hdc, &rc, hbrush );
\r
2499 DeleteObject( hbrush );
\r
2502 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2503 int steps = squareSize / 2;
\r
2506 for( i=0; i<steps; i++ ) {
\r
2507 BYTE r = r1 - (r1-r2) * i / steps;
\r
2508 BYTE g = g1 - (g1-g2) * i / steps;
\r
2509 BYTE b = b1 - (b1-b2) * i / steps;
\r
2511 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2512 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2513 FillRect( hdc, &rc, hbrush );
\r
2514 DeleteObject(hbrush);
\r
2517 else if( mode == 2 ) {
\r
2518 /* Diagonal gradient, good more or less for every piece */
\r
2519 POINT triangle[3];
\r
2520 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2521 HBRUSH hbrush_old;
\r
2522 int steps = squareSize;
\r
2525 triangle[0].x = squareSize - steps;
\r
2526 triangle[0].y = squareSize;
\r
2527 triangle[1].x = squareSize;
\r
2528 triangle[1].y = squareSize;
\r
2529 triangle[2].x = squareSize;
\r
2530 triangle[2].y = squareSize - steps;
\r
2532 for( i=0; i<steps; i++ ) {
\r
2533 BYTE r = r1 - (r1-r2) * i / steps;
\r
2534 BYTE g = g1 - (g1-g2) * i / steps;
\r
2535 BYTE b = b1 - (b1-b2) * i / steps;
\r
2537 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2538 hbrush_old = SelectObject( hdc, hbrush );
\r
2539 Polygon( hdc, triangle, 3 );
\r
2540 SelectObject( hdc, hbrush_old );
\r
2541 DeleteObject(hbrush);
\r
2546 SelectObject( hdc, hpen );
\r
2551 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2552 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2553 piece: follow the steps as explained below.
\r
2555 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2559 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2563 int backColor = whitePieceColor;
\r
2564 int foreColor = blackPieceColor;
\r
2566 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2567 backColor = appData.fontBackColorWhite;
\r
2568 foreColor = appData.fontForeColorWhite;
\r
2570 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2571 backColor = appData.fontBackColorBlack;
\r
2572 foreColor = appData.fontForeColorBlack;
\r
2576 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2578 hbm_old = SelectObject( hdc, hbm );
\r
2582 rc.right = squareSize;
\r
2583 rc.bottom = squareSize;
\r
2585 /* Step 1: background is now black */
\r
2586 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2588 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2590 pt.x = (squareSize - sz.cx) / 2;
\r
2591 pt.y = (squareSize - sz.cy) / 2;
\r
2593 SetBkMode( hdc, TRANSPARENT );
\r
2594 SetTextColor( hdc, chroma );
\r
2595 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2596 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2598 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2599 /* Step 3: the area outside the piece is filled with white */
\r
2600 // FloodFill( hdc, 0, 0, chroma );
\r
2601 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2602 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2603 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2604 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2605 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2607 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2608 but if the start point is not inside the piece we're lost!
\r
2609 There should be a better way to do this... if we could create a region or path
\r
2610 from the fill operation we would be fine for example.
\r
2612 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2613 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2615 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2616 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2617 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2619 SelectObject( dc2, bm2 );
\r
2620 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2621 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2622 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2623 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2624 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2627 DeleteObject( bm2 );
\r
2630 SetTextColor( hdc, 0 );
\r
2632 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2633 draw the piece again in black for safety.
\r
2635 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2637 SelectObject( hdc, hbm_old );
\r
2639 if( hPieceMask[index] != NULL ) {
\r
2640 DeleteObject( hPieceMask[index] );
\r
2643 hPieceMask[index] = hbm;
\r
2646 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2648 SelectObject( hdc, hbm );
\r
2651 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2652 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2653 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2655 SelectObject( dc1, hPieceMask[index] );
\r
2656 SelectObject( dc2, bm2 );
\r
2657 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2658 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2661 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2662 the piece background and deletes (makes transparent) the rest.
\r
2663 Thanks to that mask, we are free to paint the background with the greates
\r
2664 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2665 We use this, to make gradients and give the pieces a "roundish" look.
\r
2667 SetPieceBackground( hdc, backColor, 2 );
\r
2668 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2672 DeleteObject( bm2 );
\r
2675 SetTextColor( hdc, foreColor );
\r
2676 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2678 SelectObject( hdc, hbm_old );
\r
2680 if( hPieceFace[index] != NULL ) {
\r
2681 DeleteObject( hPieceFace[index] );
\r
2684 hPieceFace[index] = hbm;
\r
2687 static int TranslatePieceToFontPiece( int piece )
\r
2717 case BlackMarshall:
\r
2721 case BlackNightrider:
\r
2727 case BlackUnicorn:
\r
2731 case BlackGrasshopper:
\r
2743 case BlackCardinal:
\r
2750 case WhiteMarshall:
\r
2754 case WhiteNightrider:
\r
2760 case WhiteUnicorn:
\r
2764 case WhiteGrasshopper:
\r
2776 case WhiteCardinal:
\r
2785 void CreatePiecesFromFont()
\r
2788 HDC hdc_window = NULL;
\r
2794 if( fontBitmapSquareSize < 0 ) {
\r
2795 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2799 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2800 fontBitmapSquareSize = -1;
\r
2804 if( fontBitmapSquareSize != squareSize ) {
\r
2805 hdc_window = GetDC( hwndMain );
\r
2806 hdc = CreateCompatibleDC( hdc_window );
\r
2808 if( hPieceFont != NULL ) {
\r
2809 DeleteObject( hPieceFont );
\r
2812 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2813 hPieceMask[i] = NULL;
\r
2814 hPieceFace[i] = NULL;
\r
2820 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2821 fontHeight = appData.fontPieceSize;
\r
2824 fontHeight = (fontHeight * squareSize) / 100;
\r
2826 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2828 lf.lfEscapement = 0;
\r
2829 lf.lfOrientation = 0;
\r
2830 lf.lfWeight = FW_NORMAL;
\r
2832 lf.lfUnderline = 0;
\r
2833 lf.lfStrikeOut = 0;
\r
2834 lf.lfCharSet = DEFAULT_CHARSET;
\r
2835 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2836 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2837 lf.lfQuality = PROOF_QUALITY;
\r
2838 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2839 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2840 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2842 hPieceFont = CreateFontIndirect( &lf );
\r
2844 if( hPieceFont == NULL ) {
\r
2845 fontBitmapSquareSize = -2;
\r
2848 /* Setup font-to-piece character table */
\r
2849 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2850 /* No (or wrong) global settings, try to detect the font */
\r
2851 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2853 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2855 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2856 /* DiagramTT* family */
\r
2857 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2859 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2860 /* Fairy symbols */
\r
2861 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2863 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2864 /* Good Companion (Some characters get warped as literal :-( */
\r
2865 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2866 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2867 SetCharTable(pieceToFontChar, s);
\r
2870 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2871 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2875 /* Create bitmaps */
\r
2876 hfont_old = SelectObject( hdc, hPieceFont );
\r
2878 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2879 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2880 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2881 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2882 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2883 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2884 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2885 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2886 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2887 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2888 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2889 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2891 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2892 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2893 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2894 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2895 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2896 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2897 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2898 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2899 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2900 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2901 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
2902 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
2903 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
2904 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
2905 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
2906 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
2907 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2908 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2909 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2910 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2911 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2912 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2913 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2914 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2915 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2916 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2917 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
2918 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
2919 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
2920 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
2921 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
2922 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
2924 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2925 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2926 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2928 SelectObject( hdc, hfont_old );
\r
2930 fontBitmapSquareSize = squareSize;
\r
2934 if( hdc != NULL ) {
\r
2938 if( hdc_window != NULL ) {
\r
2939 ReleaseDC( hwndMain, hdc_window );
\r
2944 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2948 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2949 if (gameInfo.event &&
\r
2950 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2951 strcmp(name, "k80s") == 0) {
\r
2952 strcpy(name, "tim");
\r
2954 return LoadBitmap(hinst, name);
\r
2958 /* Insert a color into the program's logical palette
\r
2959 structure. This code assumes the given color is
\r
2960 the result of the RGB or PALETTERGB macro, and it
\r
2961 knows how those macros work (which is documented).
\r
2964 InsertInPalette(COLORREF color)
\r
2966 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2968 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2969 DisplayFatalError("Too many colors", 0, 1);
\r
2970 pLogPal->palNumEntries--;
\r
2974 pe->peFlags = (char) 0;
\r
2975 pe->peRed = (char) (0xFF & color);
\r
2976 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2977 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2983 InitDrawingColors()
\r
2985 if (pLogPal == NULL) {
\r
2986 /* Allocate enough memory for a logical palette with
\r
2987 * PALETTESIZE entries and set the size and version fields
\r
2988 * of the logical palette structure.
\r
2990 pLogPal = (NPLOGPALETTE)
\r
2991 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2992 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2993 pLogPal->palVersion = 0x300;
\r
2995 pLogPal->palNumEntries = 0;
\r
2997 InsertInPalette(lightSquareColor);
\r
2998 InsertInPalette(darkSquareColor);
\r
2999 InsertInPalette(whitePieceColor);
\r
3000 InsertInPalette(blackPieceColor);
\r
3001 InsertInPalette(highlightSquareColor);
\r
3002 InsertInPalette(premoveHighlightColor);
\r
3004 /* create a logical color palette according the information
\r
3005 * in the LOGPALETTE structure.
\r
3007 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3009 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3010 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3011 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3012 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3013 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3014 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3016 /* [AS] Force rendering of the font-based pieces */
\r
3017 if( fontBitmapSquareSize > 0 ) {
\r
3018 fontBitmapSquareSize = 0;
\r
3024 BoardWidth(int boardSize, int n)
\r
3025 { /* [HGM] argument n added to allow different width and height */
\r
3026 int lineGap = sizeInfo[boardSize].lineGap;
\r
3028 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3029 lineGap = appData.overrideLineGap;
\r
3032 return (n + 1) * lineGap +
\r
3033 n * sizeInfo[boardSize].squareSize;
\r
3036 /* Respond to board resize by dragging edge */
\r
3038 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3040 BoardSize newSize = NUM_SIZES - 1;
\r
3041 static int recurse = 0;
\r
3042 if (IsIconic(hwndMain)) return;
\r
3043 if (recurse > 0) return;
\r
3045 while (newSize > 0) {
\r
3046 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3047 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3048 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3051 boardSize = newSize;
\r
3052 InitDrawingSizes(boardSize, flags);
\r
3059 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3061 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3062 ChessSquare piece;
\r
3063 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3065 SIZE clockSize, messageSize;
\r
3067 char buf[MSG_SIZ];
\r
3069 HMENU hmenu = GetMenu(hwndMain);
\r
3070 RECT crect, wrect;
\r
3072 LOGBRUSH logbrush;
\r
3074 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3075 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3077 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3078 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3080 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3081 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3082 squareSize = sizeInfo[boardSize].squareSize;
\r
3083 lineGap = sizeInfo[boardSize].lineGap;
\r
3084 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3086 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3087 lineGap = appData.overrideLineGap;
\r
3090 if (tinyLayout != oldTinyLayout) {
\r
3091 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3093 style &= ~WS_SYSMENU;
\r
3094 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3095 "&Minimize\tCtrl+F4");
\r
3097 style |= WS_SYSMENU;
\r
3098 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3100 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3102 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3103 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3104 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3106 DrawMenuBar(hwndMain);
\r
3109 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3110 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3112 /* Get text area sizes */
\r
3113 hdc = GetDC(hwndMain);
\r
3114 if (appData.clockMode) {
\r
3115 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3117 sprintf(buf, "White");
\r
3119 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3120 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3121 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3122 str = "We only care about the height here";
\r
3123 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3124 SelectObject(hdc, oldFont);
\r
3125 ReleaseDC(hwndMain, hdc);
\r
3127 /* Compute where everything goes */
\r
3128 if(first.programLogo || second.programLogo) {
\r
3129 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3130 logoHeight = 2*clockSize.cy;
\r
3131 leftLogoRect.left = OUTER_MARGIN;
\r
3132 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3133 leftLogoRect.top = OUTER_MARGIN;
\r
3134 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3136 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3137 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3138 rightLogoRect.top = OUTER_MARGIN;
\r
3139 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3142 blackRect.left = leftLogoRect.right;
\r
3143 blackRect.right = rightLogoRect.left;
\r
3144 blackRect.top = OUTER_MARGIN;
\r
3145 blackRect.bottom = blackRect.top + clockSize.cy;
\r
3147 whiteRect.left = blackRect.left ;
\r
3148 whiteRect.right = blackRect.right;
\r
3149 whiteRect.top = blackRect.bottom;
\r
3150 whiteRect.bottom = leftLogoRect.bottom;
\r
3152 whiteRect.left = OUTER_MARGIN;
\r
3153 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3154 whiteRect.top = OUTER_MARGIN + logoHeight;
\r
3155 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3157 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3158 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3159 blackRect.top = whiteRect.top;
\r
3160 blackRect.bottom = whiteRect.bottom;
\r
3163 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3164 if (appData.showButtonBar) {
\r
3165 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3166 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3168 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3170 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3171 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3173 boardRect.left = OUTER_MARGIN;
\r
3174 boardRect.right = boardRect.left + boardWidth;
\r
3175 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3176 boardRect.bottom = boardRect.top + boardHeight;
\r
3178 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3179 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3180 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3181 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3182 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3183 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3184 GetWindowRect(hwndMain, &wrect);
\r
3185 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3186 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3187 /* compensate if menu bar wrapped */
\r
3188 GetClientRect(hwndMain, &crect);
\r
3189 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3190 winHeight += offby;
\r
3192 case WMSZ_TOPLEFT:
\r
3193 SetWindowPos(hwndMain, NULL,
\r
3194 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3195 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3198 case WMSZ_TOPRIGHT:
\r
3200 SetWindowPos(hwndMain, NULL,
\r
3201 wrect.left, wrect.bottom - winHeight,
\r
3202 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3205 case WMSZ_BOTTOMLEFT:
\r
3207 SetWindowPos(hwndMain, NULL,
\r
3208 wrect.right - winWidth, wrect.top,
\r
3209 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3212 case WMSZ_BOTTOMRIGHT:
\r
3216 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3217 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3222 for (i = 0; i < N_BUTTONS; i++) {
\r
3223 if (buttonDesc[i].hwnd != NULL) {
\r
3224 DestroyWindow(buttonDesc[i].hwnd);
\r
3225 buttonDesc[i].hwnd = NULL;
\r
3227 if (appData.showButtonBar) {
\r
3228 buttonDesc[i].hwnd =
\r
3229 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3230 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3231 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3232 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3233 (HMENU) buttonDesc[i].id,
\r
3234 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3236 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3237 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3238 MAKELPARAM(FALSE, 0));
\r
3240 if (buttonDesc[i].id == IDM_Pause)
\r
3241 hwndPause = buttonDesc[i].hwnd;
\r
3242 buttonDesc[i].wndproc = (WNDPROC)
\r
3243 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3246 if (gridPen != NULL) DeleteObject(gridPen);
\r
3247 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3248 if (premovePen != NULL) DeleteObject(premovePen);
\r
3249 if (lineGap != 0) {
\r
3250 logbrush.lbStyle = BS_SOLID;
\r
3251 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3253 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3254 lineGap, &logbrush, 0, NULL);
\r
3255 logbrush.lbColor = highlightSquareColor;
\r
3257 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3258 lineGap, &logbrush, 0, NULL);
\r
3260 logbrush.lbColor = premoveHighlightColor;
\r
3262 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3263 lineGap, &logbrush, 0, NULL);
\r
3265 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3266 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3267 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3268 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3269 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3270 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3271 BOARD_WIDTH * (squareSize + lineGap);
\r
3272 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3274 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3275 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3276 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3277 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3278 lineGap / 2 + (i * (squareSize + lineGap));
\r
3279 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3280 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3281 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3285 /* [HGM] Licensing requirement */
\r
3287 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3290 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3292 GothicPopUp( "", VariantNormal);
\r
3295 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3296 oldBoardSize = boardSize;
\r
3297 oldTinyLayout = tinyLayout;
\r
3299 /* Load piece bitmaps for this board size */
\r
3300 for (i=0; i<=2; i++) {
\r
3301 for (piece = WhitePawn;
\r
3302 (int) piece < (int) BlackPawn;
\r
3303 piece = (ChessSquare) ((int) piece + 1)) {
\r
3304 if (pieceBitmap[i][piece] != NULL)
\r
3305 DeleteObject(pieceBitmap[i][piece]);
\r
3309 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3310 // Orthodox Chess pieces
\r
3311 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3312 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3313 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3314 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3315 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3316 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3317 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3318 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3319 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3320 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3321 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3322 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3323 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3324 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3325 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3326 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3327 // in Shogi, Hijack the unused Queen for Lance
\r
3328 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3329 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3330 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3332 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3333 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3334 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3337 if(squareSize <= 72 && squareSize >= 33) {
\r
3338 /* A & C are available in most sizes now */
\r
3339 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3340 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3341 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3342 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3343 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3344 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3345 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3346 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3347 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3348 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3349 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3350 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3351 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3352 } else { // Smirf-like
\r
3353 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3354 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3355 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3357 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3358 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3359 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3360 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3361 } else { // WinBoard standard
\r
3362 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3363 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3364 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3369 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3370 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3371 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3372 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3373 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3374 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3375 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3376 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3377 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3378 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3379 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3380 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3381 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3382 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3383 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3384 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3385 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3386 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3387 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3388 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3389 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3390 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3391 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3392 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3393 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3394 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3395 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3396 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3397 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3398 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3399 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3401 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3402 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3403 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3404 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3405 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3406 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3407 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3408 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3409 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3410 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3411 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3412 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3413 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3415 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3416 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3417 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3418 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3419 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3420 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3421 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3422 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3423 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3424 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3425 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3426 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3429 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3430 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3431 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3432 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3433 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3434 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3435 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3436 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3437 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3438 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3439 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3440 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3441 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3442 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3443 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3447 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3448 /* special Shogi support in this size */
\r
3449 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3450 for (piece = WhitePawn;
\r
3451 (int) piece < (int) BlackPawn;
\r
3452 piece = (ChessSquare) ((int) piece + 1)) {
\r
3453 if (pieceBitmap[i][piece] != NULL)
\r
3454 DeleteObject(pieceBitmap[i][piece]);
\r
3457 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3458 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3459 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3460 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3461 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3462 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3463 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3464 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3465 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3466 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3467 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3468 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3469 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3470 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3471 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3472 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3473 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3474 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3475 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3476 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3477 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3478 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3479 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3480 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3481 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3482 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3483 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3484 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3485 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3486 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3487 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3488 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3489 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3490 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3491 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3492 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3493 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3494 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3495 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3496 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3497 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3498 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3504 PieceBitmap(ChessSquare p, int kind)
\r
3506 if ((int) p >= (int) BlackPawn)
\r
3507 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3509 return pieceBitmap[kind][(int) p];
\r
3512 /***************************************************************/
\r
3514 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3515 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3517 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3518 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3522 SquareToPos(int row, int column, int * x, int * y)
\r
3525 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3526 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3528 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3529 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3534 DrawCoordsOnDC(HDC hdc)
\r
3536 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
3537 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
3538 char str[2] = { NULLCHAR, NULLCHAR };
\r
3539 int oldMode, oldAlign, x, y, start, i;
\r
3543 if (!appData.showCoords)
\r
3546 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3548 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3549 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3550 oldAlign = GetTextAlign(hdc);
\r
3551 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3553 y = boardRect.top + lineGap;
\r
3554 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3556 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3557 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3558 str[0] = files[start + i];
\r
3559 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3560 y += squareSize + lineGap;
\r
3563 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3565 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3566 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3567 str[0] = ranks[start + i];
\r
3568 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3569 x += squareSize + lineGap;
\r
3572 SelectObject(hdc, oldBrush);
\r
3573 SetBkMode(hdc, oldMode);
\r
3574 SetTextAlign(hdc, oldAlign);
\r
3575 SelectObject(hdc, oldFont);
\r
3579 DrawGridOnDC(HDC hdc)
\r
3583 if (lineGap != 0) {
\r
3584 oldPen = SelectObject(hdc, gridPen);
\r
3585 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3586 SelectObject(hdc, oldPen);
\r
3590 #define HIGHLIGHT_PEN 0
\r
3591 #define PREMOVE_PEN 1
\r
3594 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3597 HPEN oldPen, hPen;
\r
3598 if (lineGap == 0) return;
\r
3600 x1 = boardRect.left +
\r
3601 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3602 y1 = boardRect.top +
\r
3603 lineGap/2 + y * (squareSize + lineGap);
\r
3605 x1 = boardRect.left +
\r
3606 lineGap/2 + x * (squareSize + lineGap);
\r
3607 y1 = boardRect.top +
\r
3608 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3610 hPen = pen ? premovePen : highlightPen;
\r
3611 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3612 MoveToEx(hdc, x1, y1, NULL);
\r
3613 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3614 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3615 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3616 LineTo(hdc, x1, y1);
\r
3617 SelectObject(hdc, oldPen);
\r
3621 DrawHighlightsOnDC(HDC hdc)
\r
3624 for (i=0; i<2; i++) {
\r
3625 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3626 DrawHighlightOnDC(hdc, TRUE,
\r
3627 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3630 for (i=0; i<2; i++) {
\r
3631 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3632 premoveHighlightInfo.sq[i].y >= 0) {
\r
3633 DrawHighlightOnDC(hdc, TRUE,
\r
3634 premoveHighlightInfo.sq[i].x,
\r
3635 premoveHighlightInfo.sq[i].y,
\r
3641 /* Note: sqcolor is used only in monoMode */
\r
3642 /* Note that this code is largely duplicated in woptions.c,
\r
3643 function DrawSampleSquare, so that needs to be updated too */
\r
3645 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3647 HBITMAP oldBitmap;
\r
3651 if (appData.blindfold) return;
\r
3653 /* [AS] Use font-based pieces if needed */
\r
3654 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3655 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3656 CreatePiecesFromFont();
\r
3658 if( fontBitmapSquareSize == squareSize ) {
\r
3659 int index = TranslatePieceToFontPiece(piece);
\r
3661 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3665 squareSize, squareSize,
\r
3670 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3674 squareSize, squareSize,
\r
3683 if (appData.monoMode) {
\r
3684 SelectObject(tmphdc, PieceBitmap(piece,
\r
3685 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3686 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3687 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3689 tmpSize = squareSize;
\r
3691 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3692 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3693 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3694 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3695 x += (squareSize - minorSize)>>1;
\r
3696 y += squareSize - minorSize - 2;
\r
3697 tmpSize = minorSize;
\r
3699 if (color || appData.allWhite ) {
\r
3700 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3702 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3703 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3704 if(appData.upsideDown && color==flipView)
\r
3705 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3707 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3709 /* Use black piece color for outline of white pieces */
\r
3710 /* Not sure this looks really good (though xboard does it).
\r
3711 Maybe better to have another selectable color, default black */
\r
3712 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3713 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3714 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3716 /* Use black for outline of white pieces */
\r
3717 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3718 if(appData.upsideDown && color==flipView)
\r
3719 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3721 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3725 /* Use white piece color for details of black pieces */
\r
3726 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3727 WHITE_PIECE ones aren't always the right shape. */
\r
3728 /* Not sure this looks really good (though xboard does it).
\r
3729 Maybe better to have another selectable color, default medium gray? */
\r
3730 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3731 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3732 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3733 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3734 SelectObject(hdc, blackPieceBrush);
\r
3735 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3737 /* Use square color for details of black pieces */
\r
3738 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3739 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3740 if(appData.upsideDown && !flipView)
\r
3741 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3743 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3746 SelectObject(hdc, oldBrush);
\r
3747 SelectObject(tmphdc, oldBitmap);
\r
3751 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3752 int GetBackTextureMode( int algo )
\r
3754 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3758 case BACK_TEXTURE_MODE_PLAIN:
\r
3759 result = 1; /* Always use identity map */
\r
3761 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3762 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3770 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3771 to handle redraws cleanly (as random numbers would always be different).
\r
3773 VOID RebuildTextureSquareInfo()
\r
3783 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3785 if( liteBackTexture != NULL ) {
\r
3786 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3787 lite_w = bi.bmWidth;
\r
3788 lite_h = bi.bmHeight;
\r
3792 if( darkBackTexture != NULL ) {
\r
3793 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3794 dark_w = bi.bmWidth;
\r
3795 dark_h = bi.bmHeight;
\r
3799 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3800 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3801 if( (col + row) & 1 ) {
\r
3803 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3804 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3805 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3806 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3811 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3812 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3813 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3814 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3821 /* [AS] Arrow highlighting support */
\r
3823 static int A_WIDTH = 5; /* Width of arrow body */
\r
3825 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3826 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3828 static double Sqr( double x )
\r
3833 static int Round( double x )
\r
3835 return (int) (x + 0.5);
\r
3838 /* Draw an arrow between two points using current settings */
\r
3839 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3842 double dx, dy, j, k, x, y;
\r
3844 if( d_x == s_x ) {
\r
3845 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3847 arrow[0].x = s_x + A_WIDTH;
\r
3850 arrow[1].x = s_x + A_WIDTH;
\r
3851 arrow[1].y = d_y - h;
\r
3853 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3854 arrow[2].y = d_y - h;
\r
3859 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3860 arrow[4].y = d_y - h;
\r
3862 arrow[5].x = s_x - A_WIDTH;
\r
3863 arrow[5].y = d_y - h;
\r
3865 arrow[6].x = s_x - A_WIDTH;
\r
3868 else if( d_y == s_y ) {
\r
3869 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3872 arrow[0].y = s_y + A_WIDTH;
\r
3874 arrow[1].x = d_x - w;
\r
3875 arrow[1].y = s_y + A_WIDTH;
\r
3877 arrow[2].x = d_x - w;
\r
3878 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3883 arrow[4].x = d_x - w;
\r
3884 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3886 arrow[5].x = d_x - w;
\r
3887 arrow[5].y = s_y - A_WIDTH;
\r
3890 arrow[6].y = s_y - A_WIDTH;
\r
3893 /* [AS] Needed a lot of paper for this! :-) */
\r
3894 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3895 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3897 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3899 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3904 arrow[0].x = Round(x - j);
\r
3905 arrow[0].y = Round(y + j*dx);
\r
3907 arrow[1].x = Round(x + j);
\r
3908 arrow[1].y = Round(y - j*dx);
\r
3911 x = (double) d_x - k;
\r
3912 y = (double) d_y - k*dy;
\r
3915 x = (double) d_x + k;
\r
3916 y = (double) d_y + k*dy;
\r
3919 arrow[2].x = Round(x + j);
\r
3920 arrow[2].y = Round(y - j*dx);
\r
3922 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3923 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3928 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3929 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3931 arrow[6].x = Round(x - j);
\r
3932 arrow[6].y = Round(y + j*dx);
\r
3935 Polygon( hdc, arrow, 7 );
\r
3938 /* [AS] Draw an arrow between two squares */
\r
3939 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3941 int s_x, s_y, d_x, d_y;
\r
3948 if( s_col == d_col && s_row == d_row ) {
\r
3952 /* Get source and destination points */
\r
3953 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3954 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3957 d_y += squareSize / 4;
\r
3959 else if( d_y < s_y ) {
\r
3960 d_y += 3 * squareSize / 4;
\r
3963 d_y += squareSize / 2;
\r
3967 d_x += squareSize / 4;
\r
3969 else if( d_x < s_x ) {
\r
3970 d_x += 3 * squareSize / 4;
\r
3973 d_x += squareSize / 2;
\r
3976 s_x += squareSize / 2;
\r
3977 s_y += squareSize / 2;
\r
3979 /* Adjust width */
\r
3980 A_WIDTH = squareSize / 14;
\r
3983 stLB.lbStyle = BS_SOLID;
\r
3984 stLB.lbColor = appData.highlightArrowColor;
\r
3987 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3988 holdpen = SelectObject( hdc, hpen );
\r
3989 hbrush = CreateBrushIndirect( &stLB );
\r
3990 holdbrush = SelectObject( hdc, hbrush );
\r
3992 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3994 SelectObject( hdc, holdpen );
\r
3995 SelectObject( hdc, holdbrush );
\r
3996 DeleteObject( hpen );
\r
3997 DeleteObject( hbrush );
\r
4000 BOOL HasHighlightInfo()
\r
4002 BOOL result = FALSE;
\r
4004 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4005 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4013 BOOL IsDrawArrowEnabled()
\r
4015 BOOL result = FALSE;
\r
4017 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4024 VOID DrawArrowHighlight( HDC hdc )
\r
4026 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4027 DrawArrowBetweenSquares( hdc,
\r
4028 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4029 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4033 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4035 HRGN result = NULL;
\r
4037 if( HasHighlightInfo() ) {
\r
4038 int x1, y1, x2, y2;
\r
4039 int sx, sy, dx, dy;
\r
4041 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4042 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4044 sx = MIN( x1, x2 );
\r
4045 sy = MIN( y1, y2 );
\r
4046 dx = MAX( x1, x2 ) + squareSize;
\r
4047 dy = MAX( y1, y2 ) + squareSize;
\r
4049 result = CreateRectRgn( sx, sy, dx, dy );
\r
4056 Warning: this function modifies the behavior of several other functions.
\r
4058 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4059 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4060 repaint is scattered all over the place, which is not good for features such as
\r
4061 "arrow highlighting" that require a full repaint of the board.
\r
4063 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4064 user interaction, when speed is not so important) but especially to avoid errors
\r
4065 in the displayed graphics.
\r
4067 In such patched places, I always try refer to this function so there is a single
\r
4068 place to maintain knowledge.
\r
4070 To restore the original behavior, just return FALSE unconditionally.
\r
4072 BOOL IsFullRepaintPreferrable()
\r
4074 BOOL result = FALSE;
\r
4076 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4077 /* Arrow may appear on the board */
\r
4085 This function is called by DrawPosition to know whether a full repaint must
\r
4088 Only DrawPosition may directly call this function, which makes use of
\r
4089 some state information. Other function should call DrawPosition specifying
\r
4090 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4092 BOOL DrawPositionNeedsFullRepaint()
\r
4094 BOOL result = FALSE;
\r
4097 Probably a slightly better policy would be to trigger a full repaint
\r
4098 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4099 but animation is fast enough that it's difficult to notice.
\r
4101 if( animInfo.piece == EmptySquare ) {
\r
4102 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4111 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4113 int row, column, x, y, square_color, piece_color;
\r
4114 ChessSquare piece;
\r
4116 HDC texture_hdc = NULL;
\r
4118 /* [AS] Initialize background textures if needed */
\r
4119 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4120 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4121 if( backTextureSquareSize != squareSize
\r
4122 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4123 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4124 backTextureSquareSize = squareSize;
\r
4125 RebuildTextureSquareInfo();
\r
4128 texture_hdc = CreateCompatibleDC( hdc );
\r
4131 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4132 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4134 SquareToPos(row, column, &x, &y);
\r
4136 piece = board[row][column];
\r
4138 square_color = ((column + row) % 2) == 1;
\r
4139 if( gameInfo.variant == VariantXiangqi ) {
\r
4140 square_color = !InPalace(row, column);
\r
4141 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4142 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4144 piece_color = (int) piece < (int) BlackPawn;
\r
4147 /* [HGM] holdings file: light square or black */
\r
4148 if(column == BOARD_LEFT-2) {
\r
4149 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4152 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4156 if(column == BOARD_RGHT + 1 ) {
\r
4157 if( row < gameInfo.holdingsSize )
\r
4160 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4164 if(column == BOARD_LEFT-1 ) /* left align */
\r
4165 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4166 else if( column == BOARD_RGHT) /* right align */
\r
4167 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4169 if (appData.monoMode) {
\r
4170 if (piece == EmptySquare) {
\r
4171 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4172 square_color ? WHITENESS : BLACKNESS);
\r
4174 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4177 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4178 /* [AS] Draw the square using a texture bitmap */
\r
4179 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4180 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4181 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4184 squareSize, squareSize,
\r
4187 backTextureSquareInfo[r][c].mode,
\r
4188 backTextureSquareInfo[r][c].x,
\r
4189 backTextureSquareInfo[r][c].y );
\r
4191 SelectObject( texture_hdc, hbm );
\r
4193 if (piece != EmptySquare) {
\r
4194 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4198 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4200 oldBrush = SelectObject(hdc, brush );
\r
4201 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4202 SelectObject(hdc, oldBrush);
\r
4203 if (piece != EmptySquare)
\r
4204 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4209 if( texture_hdc != NULL ) {
\r
4210 DeleteDC( texture_hdc );
\r
4214 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4215 void fputDW(FILE *f, int x)
\r
4217 fputc(x & 255, f);
\r
4218 fputc(x>>8 & 255, f);
\r
4219 fputc(x>>16 & 255, f);
\r
4220 fputc(x>>24 & 255, f);
\r
4223 #define MAX_CLIPS 200 /* more than enough */
\r
4226 DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)
\r
4228 // HBITMAP bufferBitmap;
\r
4233 int w = 100, h = 50;
\r
4235 if(cps->programLogo == NULL) return;
\r
4236 // GetClientRect(hwndMain, &Rect);
\r
4237 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4238 // Rect.bottom-Rect.top+1);
\r
4239 tmphdc = CreateCompatibleDC(hdc);
\r
4240 hbm = SelectObject(tmphdc, (HBITMAP) cps->programLogo);
\r
4241 if( GetObject( cps->programLogo, sizeof(bi), &bi ) > 0 ) {
\r
4245 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4246 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4247 SelectObject(tmphdc, hbm);
\r
4252 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4254 static Board lastReq, lastDrawn;
\r
4255 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4256 static int lastDrawnFlipView = 0;
\r
4257 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4258 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4261 HBITMAP bufferBitmap;
\r
4262 HBITMAP oldBitmap;
\r
4264 HRGN clips[MAX_CLIPS];
\r
4265 ChessSquare dragged_piece = EmptySquare;
\r
4267 /* I'm undecided on this - this function figures out whether a full
\r
4268 * repaint is necessary on its own, so there's no real reason to have the
\r
4269 * caller tell it that. I think this can safely be set to FALSE - but
\r
4270 * if we trust the callers not to request full repaints unnessesarily, then
\r
4271 * we could skip some clipping work. In other words, only request a full
\r
4272 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4273 * gamestart and similar) --Hawk
\r
4275 Boolean fullrepaint = repaint;
\r
4277 if( DrawPositionNeedsFullRepaint() ) {
\r
4278 fullrepaint = TRUE;
\r
4282 if( fullrepaint ) {
\r
4283 static int repaint_count = 0;
\r
4287 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4288 OutputDebugString( buf );
\r
4292 if (board == NULL) {
\r
4293 if (!lastReqValid) {
\r
4298 CopyBoard(lastReq, board);
\r
4302 if (doingSizing) {
\r
4306 if (IsIconic(hwndMain)) {
\r
4310 if (hdc == NULL) {
\r
4311 hdc = GetDC(hwndMain);
\r
4312 if (!appData.monoMode) {
\r
4313 SelectPalette(hdc, hPal, FALSE);
\r
4314 RealizePalette(hdc);
\r
4318 releaseDC = FALSE;
\r
4322 fprintf(debugFP, "*******************************\n"
\r
4324 "dragInfo.from (%d,%d)\n"
\r
4325 "dragInfo.start (%d,%d)\n"
\r
4326 "dragInfo.pos (%d,%d)\n"
\r
4327 "dragInfo.lastpos (%d,%d)\n",
\r
4328 repaint ? "TRUE" : "FALSE",
\r
4329 dragInfo.from.x, dragInfo.from.y,
\r
4330 dragInfo.start.x, dragInfo.start.y,
\r
4331 dragInfo.pos.x, dragInfo.pos.y,
\r
4332 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4333 fprintf(debugFP, "prev: ");
\r
4334 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4335 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4336 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4339 fprintf(debugFP, "\n");
\r
4340 fprintf(debugFP, "board: ");
\r
4341 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4342 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4343 fprintf(debugFP, "%d ", board[row][column]);
\r
4346 fprintf(debugFP, "\n");
\r
4350 /* Create some work-DCs */
\r
4351 hdcmem = CreateCompatibleDC(hdc);
\r
4352 tmphdc = CreateCompatibleDC(hdc);
\r
4354 /* If dragging is in progress, we temporarely remove the piece */
\r
4355 /* [HGM] or temporarily decrease count if stacked */
\r
4356 /* !! Moved to before board compare !! */
\r
4357 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4358 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4359 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4360 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4361 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4363 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4364 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4365 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4367 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4370 /* Figure out which squares need updating by comparing the
\r
4371 * newest board with the last drawn board and checking if
\r
4372 * flipping has changed.
\r
4374 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4375 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4376 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4377 if (lastDrawn[row][column] != board[row][column]) {
\r
4378 SquareToPos(row, column, &x, &y);
\r
4379 clips[num_clips++] =
\r
4380 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4384 for (i=0; i<2; i++) {
\r
4385 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4386 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4387 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4388 lastDrawnHighlight.sq[i].y >= 0) {
\r
4389 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4390 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4391 clips[num_clips++] =
\r
4392 CreateRectRgn(x - lineGap, y - lineGap,
\r
4393 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4395 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4396 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4397 clips[num_clips++] =
\r
4398 CreateRectRgn(x - lineGap, y - lineGap,
\r
4399 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4403 for (i=0; i<2; i++) {
\r
4404 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4405 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4406 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4407 lastDrawnPremove.sq[i].y >= 0) {
\r
4408 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4409 lastDrawnPremove.sq[i].x, &x, &y);
\r
4410 clips[num_clips++] =
\r
4411 CreateRectRgn(x - lineGap, y - lineGap,
\r
4412 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4414 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4415 premoveHighlightInfo.sq[i].y >= 0) {
\r
4416 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4417 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4418 clips[num_clips++] =
\r
4419 CreateRectRgn(x - lineGap, y - lineGap,
\r
4420 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4425 fullrepaint = TRUE;
\r
4428 /* Create a buffer bitmap - this is the actual bitmap
\r
4429 * being written to. When all the work is done, we can
\r
4430 * copy it to the real DC (the screen). This avoids
\r
4431 * the problems with flickering.
\r
4433 GetClientRect(hwndMain, &Rect);
\r
4434 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4435 Rect.bottom-Rect.top+1);
\r
4436 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4437 if (!appData.monoMode) {
\r
4438 SelectPalette(hdcmem, hPal, FALSE);
\r
4441 /* Create clips for dragging */
\r
4442 if (!fullrepaint) {
\r
4443 if (dragInfo.from.x >= 0) {
\r
4444 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4445 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4447 if (dragInfo.start.x >= 0) {
\r
4448 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4449 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4451 if (dragInfo.pos.x >= 0) {
\r
4452 x = dragInfo.pos.x - squareSize / 2;
\r
4453 y = dragInfo.pos.y - squareSize / 2;
\r
4454 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4456 if (dragInfo.lastpos.x >= 0) {
\r
4457 x = dragInfo.lastpos.x - squareSize / 2;
\r
4458 y = dragInfo.lastpos.y - squareSize / 2;
\r
4459 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4463 /* Are we animating a move?
\r
4465 * - remove the piece from the board (temporarely)
\r
4466 * - calculate the clipping region
\r
4468 if (!fullrepaint) {
\r
4469 if (animInfo.piece != EmptySquare) {
\r
4470 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4471 x = boardRect.left + animInfo.lastpos.x;
\r
4472 y = boardRect.top + animInfo.lastpos.y;
\r
4473 x2 = boardRect.left + animInfo.pos.x;
\r
4474 y2 = boardRect.top + animInfo.pos.y;
\r
4475 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4476 /* Slight kludge. The real problem is that after AnimateMove is
\r
4477 done, the position on the screen does not match lastDrawn.
\r
4478 This currently causes trouble only on e.p. captures in
\r
4479 atomic, where the piece moves to an empty square and then
\r
4480 explodes. The old and new positions both had an empty square
\r
4481 at the destination, but animation has drawn a piece there and
\r
4482 we have to remember to erase it. */
\r
4483 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4487 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4488 if (num_clips == 0)
\r
4489 fullrepaint = TRUE;
\r
4491 /* Set clipping on the memory DC */
\r
4492 if (!fullrepaint) {
\r
4493 SelectClipRgn(hdcmem, clips[0]);
\r
4494 for (x = 1; x < num_clips; x++) {
\r
4495 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4496 abort(); // this should never ever happen!
\r
4500 /* Do all the drawing to the memory DC */
\r
4501 DrawGridOnDC(hdcmem);
\r
4502 DrawHighlightsOnDC(hdcmem);
\r
4503 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4506 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);
\r
4507 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);
\r
4510 if( appData.highlightMoveWithArrow ) {
\r
4511 DrawArrowHighlight(hdcmem);
\r
4514 DrawCoordsOnDC(hdcmem);
\r
4516 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4517 /* to make sure lastDrawn contains what is actually drawn */
\r
4519 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4520 if (dragged_piece != EmptySquare) {
\r
4521 /* [HGM] or restack */
\r
4522 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4523 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4525 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4526 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4527 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4528 x = dragInfo.pos.x - squareSize / 2;
\r
4529 y = dragInfo.pos.y - squareSize / 2;
\r
4530 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4531 ((int) dragged_piece < (int) BlackPawn),
\r
4532 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4535 /* Put the animated piece back into place and draw it */
\r
4536 if (animInfo.piece != EmptySquare) {
\r
4537 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4538 x = boardRect.left + animInfo.pos.x;
\r
4539 y = boardRect.top + animInfo.pos.y;
\r
4540 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4541 ((int) animInfo.piece < (int) BlackPawn),
\r
4542 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4545 /* Release the bufferBitmap by selecting in the old bitmap
\r
4546 * and delete the memory DC
\r
4548 SelectObject(hdcmem, oldBitmap);
\r
4551 /* Set clipping on the target DC */
\r
4552 if (!fullrepaint) {
\r
4553 SelectClipRgn(hdc, clips[0]);
\r
4554 for (x = 1; x < num_clips; x++) {
\r
4555 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4556 abort(); // this should never ever happen!
\r
4560 /* Copy the new bitmap onto the screen in one go.
\r
4561 * This way we avoid any flickering
\r
4563 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4564 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4565 boardRect.right - boardRect.left,
\r
4566 boardRect.bottom - boardRect.top,
\r
4567 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4568 if(saveDiagFlag) {
\r
4569 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4570 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4572 GetObject(bufferBitmap, sizeof(b), &b);
\r
4573 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4574 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4575 bih.biWidth = b.bmWidth;
\r
4576 bih.biHeight = b.bmHeight;
\r
4578 bih.biBitCount = b.bmBitsPixel;
\r
4579 bih.biCompression = 0;
\r
4580 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4581 bih.biXPelsPerMeter = 0;
\r
4582 bih.biYPelsPerMeter = 0;
\r
4583 bih.biClrUsed = 0;
\r
4584 bih.biClrImportant = 0;
\r
4585 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4586 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4587 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4588 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4591 wb = b.bmWidthBytes;
\r
4593 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4594 int k = ((int*) pData)[i];
\r
4595 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4596 if(j >= 16) break;
\r
4598 if(j >= nrColors) nrColors = j+1;
\r
4600 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4602 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4603 for(w=0; w<(wb>>2); w+=2) {
\r
4604 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4605 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4606 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4607 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4608 pData[p++] = m | j<<4;
\r
4610 while(p&3) pData[p++] = 0;
\r
4613 wb = ((wb+31)>>5)<<2;
\r
4615 // write BITMAPFILEHEADER
\r
4616 fprintf(diagFile, "BM");
\r
4617 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4618 fputDW(diagFile, 0);
\r
4619 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4620 // write BITMAPINFOHEADER
\r
4621 fputDW(diagFile, 40);
\r
4622 fputDW(diagFile, b.bmWidth);
\r
4623 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4624 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4625 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4626 fputDW(diagFile, 0);
\r
4627 fputDW(diagFile, 0);
\r
4628 fputDW(diagFile, 0);
\r
4629 fputDW(diagFile, 0);
\r
4630 fputDW(diagFile, 0);
\r
4631 fputDW(diagFile, 0);
\r
4632 // write color table
\r
4634 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4635 // write bitmap data
\r
4636 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4637 fputc(pData[i], diagFile);
\r
4642 SelectObject(tmphdc, oldBitmap);
\r
4644 /* Massive cleanup */
\r
4645 for (x = 0; x < num_clips; x++)
\r
4646 DeleteObject(clips[x]);
\r
4649 DeleteObject(bufferBitmap);
\r
4652 ReleaseDC(hwndMain, hdc);
\r
4654 if (lastDrawnFlipView != flipView) {
\r
4656 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4658 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4661 /* CopyBoard(lastDrawn, board);*/
\r
4662 lastDrawnHighlight = highlightInfo;
\r
4663 lastDrawnPremove = premoveHighlightInfo;
\r
4664 lastDrawnFlipView = flipView;
\r
4665 lastDrawnValid = 1;
\r
4668 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4673 saveDiagFlag = 1; diagFile = f;
\r
4674 HDCDrawPosition(NULL, TRUE, NULL);
\r
4678 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4685 /*---------------------------------------------------------------------------*\
\r
4686 | CLIENT PAINT PROCEDURE
\r
4687 | This is the main event-handler for the WM_PAINT message.
\r
4689 \*---------------------------------------------------------------------------*/
\r
4691 PaintProc(HWND hwnd)
\r
4697 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4698 if (IsIconic(hwnd)) {
\r
4699 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4701 if (!appData.monoMode) {
\r
4702 SelectPalette(hdc, hPal, FALSE);
\r
4703 RealizePalette(hdc);
\r
4705 HDCDrawPosition(hdc, 1, NULL);
\r
4707 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4708 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4709 ETO_CLIPPED|ETO_OPAQUE,
\r
4710 &messageRect, messageText, strlen(messageText), NULL);
\r
4711 SelectObject(hdc, oldFont);
\r
4712 DisplayBothClocks();
\r
4714 EndPaint(hwnd,&ps);
\r
4722 * If the user selects on a border boundary, return -1; if off the board,
\r
4723 * return -2. Otherwise map the event coordinate to the square.
\r
4724 * The offset boardRect.left or boardRect.top must already have been
\r
4725 * subtracted from x.
\r
4728 EventToSquare(int x)
\r
4735 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4737 x /= (squareSize + lineGap);
\r
4738 if (x >= BOARD_SIZE)
\r
4749 DropEnable dropEnables[] = {
\r
4750 { 'P', DP_Pawn, "Pawn" },
\r
4751 { 'N', DP_Knight, "Knight" },
\r
4752 { 'B', DP_Bishop, "Bishop" },
\r
4753 { 'R', DP_Rook, "Rook" },
\r
4754 { 'Q', DP_Queen, "Queen" },
\r
4758 SetupDropMenu(HMENU hmenu)
\r
4760 int i, count, enable;
\r
4762 extern char white_holding[], black_holding[];
\r
4763 char item[MSG_SIZ];
\r
4765 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4766 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4767 dropEnables[i].piece);
\r
4769 while (p && *p++ == dropEnables[i].piece) count++;
\r
4770 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4771 enable = count > 0 || !appData.testLegality
\r
4772 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4773 && !appData.icsActive);
\r
4774 ModifyMenu(hmenu, dropEnables[i].command,
\r
4775 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4776 dropEnables[i].command, item);
\r
4780 static int fromX = -1, fromY = -1, toX, toY;
\r
4782 /* Event handler for mouse messages */
\r
4784 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4788 static int recursive = 0;
\r
4790 // BOOLEAN needsRedraw = FALSE;
\r
4791 BOOLEAN saveAnimate;
\r
4792 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4793 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4794 ChessMove moveType;
\r
4797 if (message == WM_MBUTTONUP) {
\r
4798 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4799 to the middle button: we simulate pressing the left button too!
\r
4801 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4802 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4808 pt.x = LOWORD(lParam);
\r
4809 pt.y = HIWORD(lParam);
\r
4810 x = EventToSquare(pt.x - boardRect.left);
\r
4811 y = EventToSquare(pt.y - boardRect.top);
\r
4812 if (!flipView && y >= 0) {
\r
4813 y = BOARD_HEIGHT - 1 - y;
\r
4815 if (flipView && x >= 0) {
\r
4816 x = BOARD_WIDTH - 1 - x;
\r
4819 switch (message) {
\r
4820 case WM_LBUTTONDOWN:
\r
4821 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4822 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4823 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4824 if(gameInfo.holdingsWidth &&
\r
4825 (WhiteOnMove(currentMove)
\r
4826 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4827 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4828 // click in right holdings, for determining promotion piece
\r
4829 ChessSquare p = boards[currentMove][y][x];
\r
4830 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4831 if(p != EmptySquare) {
\r
4832 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4833 fromX = fromY = -1;
\r
4837 DrawPosition(FALSE, boards[currentMove]);
\r
4841 sameAgain = FALSE;
\r
4843 /* Downclick vertically off board; check if on clock */
\r
4844 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4845 if (gameMode == EditPosition) {
\r
4846 SetWhiteToPlayEvent();
\r
4847 } else if (gameMode == IcsPlayingBlack ||
\r
4848 gameMode == MachinePlaysWhite) {
\r
4850 } else if (gameMode == EditGame) {
\r
4851 AdjustClock((logoHeight > 0 ? flipView: flipClock), -1);
\r
4853 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4854 if (gameMode == EditPosition) {
\r
4855 SetBlackToPlayEvent();
\r
4856 } else if (gameMode == IcsPlayingWhite ||
\r
4857 gameMode == MachinePlaysBlack) {
\r
4859 } else if (gameMode == EditGame) {
\r
4860 AdjustClock(!(logoHeight > 0 ? flipView: flipClock), -1);
\r
4863 if (!appData.highlightLastMove) {
\r
4864 ClearHighlights();
\r
4865 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4867 fromX = fromY = -1;
\r
4868 dragInfo.start.x = dragInfo.start.y = -1;
\r
4869 dragInfo.from = dragInfo.start;
\r
4871 } else if (x < 0 || y < 0
\r
4872 /* [HGM] block clicks between board and holdings */
\r
4873 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4874 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4875 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4876 /* EditPosition, empty square, or different color piece;
\r
4877 click-click move is possible */
\r
4880 } else if (fromX == x && fromY == y) {
\r
4881 /* Downclick on same square again */
\r
4882 ClearHighlights();
\r
4883 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4884 sameAgain = TRUE;
\r
4885 } else if (fromX != -1 &&
\r
4886 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4888 /* Downclick on different square. */
\r
4889 /* [HGM] if on holdings file, should count as new first click ! */
\r
4890 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4893 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4894 to make sure move is legal before showing promotion popup */
\r
4895 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4896 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4897 fromX = fromY = -1;
\r
4898 ClearHighlights();
\r
4899 DrawPosition(FALSE, boards[currentMove]);
\r
4902 if(moveType != ImpossibleMove) {
\r
4903 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4904 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4905 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4906 appData.alwaysPromoteToQueen)) {
\r
4907 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4908 if (!appData.highlightLastMove) {
\r
4909 ClearHighlights();
\r
4910 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4913 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4914 SetHighlights(fromX, fromY, toX, toY);
\r
4915 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4916 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4917 If promotion to Q is legal, all are legal! */
\r
4918 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4919 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4920 // kludge to temporarily execute move on display, wthout promotng yet
\r
4921 promotionChoice = TRUE;
\r
4922 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4923 boards[currentMove][toY][toX] = p;
\r
4924 DrawPosition(FALSE, boards[currentMove]);
\r
4925 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4926 boards[currentMove][toY][toX] = q;
\r
4928 PromotionPopup(hwnd);
\r
4929 } else { /* not a promotion */
\r
4930 if (appData.animate || appData.highlightLastMove) {
\r
4931 SetHighlights(fromX, fromY, toX, toY);
\r
4933 ClearHighlights();
\r
4935 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4936 fromX = fromY = -1;
\r
4937 if (appData.animate && !appData.highlightLastMove) {
\r
4938 ClearHighlights();
\r
4939 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4945 /* [HGM] it seemed that braces were missing here */
\r
4946 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4947 fromX = fromY = -1;
\r
4951 ClearHighlights();
\r
4952 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4954 /* First downclick, or restart on a square with same color piece */
\r
4955 if (!frozen && OKToStartUserMove(x, y)) {
\r
4958 dragInfo.lastpos = pt;
\r
4959 dragInfo.from.x = fromX;
\r
4960 dragInfo.from.y = fromY;
\r
4961 dragInfo.start = dragInfo.from;
\r
4962 SetCapture(hwndMain);
\r
4964 fromX = fromY = -1;
\r
4965 dragInfo.start.x = dragInfo.start.y = -1;
\r
4966 dragInfo.from = dragInfo.start;
\r
4967 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4971 case WM_LBUTTONUP:
\r
4973 if (fromX == -1) break;
\r
4974 if (x == fromX && y == fromY) {
\r
4975 dragInfo.from.x = dragInfo.from.y = -1;
\r
4976 /* Upclick on same square */
\r
4978 /* Clicked same square twice: abort click-click move */
\r
4979 fromX = fromY = -1;
\r
4981 ClearPremoveHighlights();
\r
4983 /* First square clicked: start click-click move */
\r
4984 SetHighlights(fromX, fromY, -1, -1);
\r
4986 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4987 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4988 /* Errant click; ignore */
\r
4991 /* Finish drag move. */
\r
4992 if (appData.debugMode) {
\r
4993 fprintf(debugFP, "release\n");
\r
4995 dragInfo.from.x = dragInfo.from.y = -1;
\r
4998 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4999 appData.animate = appData.animate && !appData.animateDragging;
\r
5000 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5001 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5002 fromX = fromY = -1;
\r
5003 ClearHighlights();
\r
5004 DrawPosition(FALSE, boards[currentMove]);
\r
5007 if(moveType != ImpossibleMove) {
\r
5008 /* [HGM] use move type to determine if move is promotion.
\r
5009 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5010 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5011 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5012 appData.alwaysPromoteToQueen))
\r
5013 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5015 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5016 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5017 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5018 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5019 // kludge to temporarily execute move on display, wthout promotng yet
\r
5020 promotionChoice = TRUE;
\r
5021 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5022 boards[currentMove][toY][toX] = p;
\r
5023 DrawPosition(FALSE, boards[currentMove]);
\r
5024 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5025 boards[currentMove][toY][toX] = q;
\r
5028 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5029 } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5031 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5032 appData.animate = saveAnimate;
\r
5033 fromX = fromY = -1;
\r
5034 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5035 ClearHighlights();
\r
5037 if (appData.animate || appData.animateDragging ||
\r
5038 appData.highlightDragging || gotPremove) {
\r
5039 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5042 dragInfo.start.x = dragInfo.start.y = -1;
\r
5043 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5046 case WM_MOUSEMOVE:
\r
5047 if ((appData.animateDragging || appData.highlightDragging)
\r
5048 && (wParam & MK_LBUTTON)
\r
5049 && dragInfo.from.x >= 0)
\r
5051 BOOL full_repaint = FALSE;
\r
5053 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5054 if (appData.animateDragging) {
\r
5055 dragInfo.pos = pt;
\r
5057 if (appData.highlightDragging) {
\r
5058 SetHighlights(fromX, fromY, x, y);
\r
5059 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5060 full_repaint = TRUE;
\r
5064 DrawPosition( full_repaint, NULL);
\r
5066 dragInfo.lastpos = dragInfo.pos;
\r
5070 case WM_MOUSEWHEEL: // [DM]
\r
5071 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5072 /* Mouse Wheel is being rolled forward
\r
5073 * Play moves forward
\r
5075 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5076 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5077 /* Mouse Wheel is being rolled backward
\r
5078 * Play moves backward
\r
5080 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5081 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5085 case WM_MBUTTONDOWN:
\r
5086 case WM_RBUTTONDOWN:
\r
5089 fromX = fromY = -1;
\r
5090 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5091 dragInfo.start.x = dragInfo.start.y = -1;
\r
5092 dragInfo.from = dragInfo.start;
\r
5093 dragInfo.lastpos = dragInfo.pos;
\r
5094 if (appData.highlightDragging) {
\r
5095 ClearHighlights();
\r
5098 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5099 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5100 if (gameMode == EditGame) AdjustClock((logoHeight > 0 ? flipView: flipClock), 1);
\r
5101 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5102 if (gameMode == EditGame) AdjustClock(!(logoHeight > 0 ? flipView: flipClock), 1);
\r
5105 DrawPosition(TRUE, NULL);
\r
5107 switch (gameMode) {
\r
5108 case EditPosition:
\r
5109 case IcsExamining:
\r
5110 if (x < 0 || y < 0) break;
\r
5113 if (message == WM_MBUTTONDOWN) {
\r
5114 buttonCount = 3; /* even if system didn't think so */
\r
5115 if (wParam & MK_SHIFT)
\r
5116 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5118 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5119 } else { /* message == WM_RBUTTONDOWN */
\r
5121 if (buttonCount == 3) {
\r
5122 if (wParam & MK_SHIFT)
\r
5123 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5125 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5127 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5130 /* Just have one menu, on the right button. Windows users don't
\r
5131 think to try the middle one, and sometimes other software steals
\r
5132 it, or it doesn't really exist. */
\r
5133 if(gameInfo.variant != VariantShogi)
\r
5134 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5136 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5140 case IcsPlayingWhite:
\r
5141 case IcsPlayingBlack:
\r
5143 case MachinePlaysWhite:
\r
5144 case MachinePlaysBlack:
\r
5145 if (appData.testLegality &&
\r
5146 gameInfo.variant != VariantBughouse &&
\r
5147 gameInfo.variant != VariantCrazyhouse) break;
\r
5148 if (x < 0 || y < 0) break;
\r
5151 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5152 SetupDropMenu(hmenu);
\r
5153 MenuPopup(hwnd, pt, hmenu, -1);
\r
5164 /* Preprocess messages for buttons in main window */
\r
5166 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5168 int id = GetWindowLong(hwnd, GWL_ID);
\r
5171 for (i=0; i<N_BUTTONS; i++) {
\r
5172 if (buttonDesc[i].id == id) break;
\r
5174 if (i == N_BUTTONS) return 0;
\r
5175 switch (message) {
\r
5180 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5181 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5188 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5191 if (appData.icsActive) {
\r
5192 if (GetKeyState(VK_SHIFT) < 0) {
\r
5194 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5195 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5199 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5200 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5207 if (appData.icsActive) {
\r
5208 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5209 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5211 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5213 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5214 PopUpMoveDialog((char)wParam);
\r
5220 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5223 /* Process messages for Promotion dialog box */
\r
5225 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5229 switch (message) {
\r
5230 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5231 /* Center the dialog over the application window */
\r
5232 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5233 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5234 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5235 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5236 SW_SHOW : SW_HIDE);
\r
5237 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5238 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5239 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5240 PieceToChar(WhiteAngel) != '~') ||
\r
5241 (PieceToChar(BlackAngel) >= 'A' &&
\r
5242 PieceToChar(BlackAngel) != '~') ) ?
\r
5243 SW_SHOW : SW_HIDE);
\r
5244 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5245 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5246 PieceToChar(WhiteMarshall) != '~') ||
\r
5247 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5248 PieceToChar(BlackMarshall) != '~') ) ?
\r
5249 SW_SHOW : SW_HIDE);
\r
5250 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5251 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5252 gameInfo.variant != VariantShogi ?
\r
5253 SW_SHOW : SW_HIDE);
\r
5254 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5255 gameInfo.variant != VariantShogi ?
\r
5256 SW_SHOW : SW_HIDE);
\r
5257 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5258 gameInfo.variant == VariantShogi ?
\r
5259 SW_SHOW : SW_HIDE);
\r
5260 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5261 gameInfo.variant == VariantShogi ?
\r
5262 SW_SHOW : SW_HIDE);
\r
5263 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5264 gameInfo.variant == VariantSuper ?
\r
5265 SW_SHOW : SW_HIDE);
\r
5268 case WM_COMMAND: /* message: received a command */
\r
5269 switch (LOWORD(wParam)) {
\r
5271 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5272 ClearHighlights();
\r
5273 DrawPosition(FALSE, NULL);
\r
5276 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5279 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5282 promoChar = PieceToChar(BlackRook);
\r
5285 promoChar = PieceToChar(BlackBishop);
\r
5287 case PB_Chancellor:
\r
5288 promoChar = PieceToChar(BlackMarshall);
\r
5290 case PB_Archbishop:
\r
5291 promoChar = PieceToChar(BlackAngel);
\r
5294 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5299 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5300 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5301 only show the popup when we are already sure the move is valid or
\r
5302 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5303 will figure out it is a promotion from the promoChar. */
\r
5304 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5305 if (!appData.highlightLastMove) {
\r
5306 ClearHighlights();
\r
5307 DrawPosition(FALSE, NULL);
\r
5314 /* Pop up promotion dialog */
\r
5316 PromotionPopup(HWND hwnd)
\r
5320 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5321 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5322 hwnd, (DLGPROC)lpProc);
\r
5323 FreeProcInstance(lpProc);
\r
5326 /* Toggle ShowThinking */
\r
5328 ToggleShowThinking()
\r
5330 appData.showThinking = !appData.showThinking;
\r
5331 ShowThinkingEvent();
\r
5335 LoadGameDialog(HWND hwnd, char* title)
\r
5339 char fileTitle[MSG_SIZ];
\r
5340 f = OpenFileDialog(hwnd, "rb", "",
\r
5341 appData.oldSaveStyle ? "gam" : "pgn",
\r
5343 title, &number, fileTitle, NULL);
\r
5345 cmailMsgLoaded = FALSE;
\r
5346 if (number == 0) {
\r
5347 int error = GameListBuild(f);
\r
5349 DisplayError("Cannot build game list", error);
\r
5350 } else if (!ListEmpty(&gameList) &&
\r
5351 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5352 GameListPopUp(f, fileTitle);
\r
5355 GameListDestroy();
\r
5358 LoadGame(f, number, fileTitle, FALSE);
\r
5363 ChangedConsoleFont()
\r
5366 CHARRANGE tmpsel, sel;
\r
5367 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5368 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5369 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5372 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5373 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5374 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5375 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5376 * size. This was undocumented in the version of MSVC++ that I had
\r
5377 * when I wrote the code, but is apparently documented now.
\r
5379 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5380 cfmt.bCharSet = f->lf.lfCharSet;
\r
5381 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5382 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5383 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5384 /* Why are the following seemingly needed too? */
\r
5385 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5386 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5387 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5389 tmpsel.cpMax = -1; /*999999?*/
\r
5390 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5391 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5392 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5393 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5395 paraf.cbSize = sizeof(paraf);
\r
5396 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5397 paraf.dxStartIndent = 0;
\r
5398 paraf.dxOffset = WRAP_INDENT;
\r
5399 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5400 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5403 /*---------------------------------------------------------------------------*\
\r
5405 * Window Proc for main window
\r
5407 \*---------------------------------------------------------------------------*/
\r
5409 /* Process messages for main window, etc. */
\r
5411 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5414 int wmId, wmEvent;
\r
5418 char fileTitle[MSG_SIZ];
\r
5419 char buf[MSG_SIZ];
\r
5420 static SnapData sd;
\r
5422 switch (message) {
\r
5424 case WM_PAINT: /* message: repaint portion of window */
\r
5428 case WM_ERASEBKGND:
\r
5429 if (IsIconic(hwnd)) {
\r
5430 /* Cheat; change the message */
\r
5431 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5433 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5437 case WM_LBUTTONDOWN:
\r
5438 case WM_MBUTTONDOWN:
\r
5439 case WM_RBUTTONDOWN:
\r
5440 case WM_LBUTTONUP:
\r
5441 case WM_MBUTTONUP:
\r
5442 case WM_RBUTTONUP:
\r
5443 case WM_MOUSEMOVE:
\r
5444 case WM_MOUSEWHEEL:
\r
5445 MouseEvent(hwnd, message, wParam, lParam);
\r
5450 if (appData.icsActive) {
\r
5451 if (wParam == '\t') {
\r
5452 if (GetKeyState(VK_SHIFT) < 0) {
\r
5454 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5455 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5459 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5460 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5464 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5465 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5467 SendMessage(h, message, wParam, lParam);
\r
5469 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5470 PopUpMoveDialog((char)wParam);
\r
5474 case WM_PALETTECHANGED:
\r
5475 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5477 HDC hdc = GetDC(hwndMain);
\r
5478 SelectPalette(hdc, hPal, TRUE);
\r
5479 nnew = RealizePalette(hdc);
\r
5481 paletteChanged = TRUE;
\r
5483 UpdateColors(hdc);
\r
5485 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5488 ReleaseDC(hwnd, hdc);
\r
5492 case WM_QUERYNEWPALETTE:
\r
5493 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5495 HDC hdc = GetDC(hwndMain);
\r
5496 paletteChanged = FALSE;
\r
5497 SelectPalette(hdc, hPal, FALSE);
\r
5498 nnew = RealizePalette(hdc);
\r
5500 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5502 ReleaseDC(hwnd, hdc);
\r
5507 case WM_COMMAND: /* message: command from application menu */
\r
5508 wmId = LOWORD(wParam);
\r
5509 wmEvent = HIWORD(wParam);
\r
5514 AnalysisPopDown();
\r
5517 case IDM_NewGameFRC:
\r
5518 if( NewGameFRC() == 0 ) {
\r
5520 AnalysisPopDown();
\r
5524 case IDM_NewVariant:
\r
5525 NewVariantPopup(hwnd);
\r
5528 case IDM_LoadGame:
\r
5529 LoadGameDialog(hwnd, "Load Game from File");
\r
5532 case IDM_LoadNextGame:
\r
5536 case IDM_LoadPrevGame:
\r
5540 case IDM_ReloadGame:
\r
5544 case IDM_LoadPosition:
\r
5545 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5546 Reset(FALSE, TRUE);
\r
5549 f = OpenFileDialog(hwnd, "rb", "",
\r
5550 appData.oldSaveStyle ? "pos" : "fen",
\r
5552 "Load Position from File", &number, fileTitle, NULL);
\r
5554 LoadPosition(f, number, fileTitle);
\r
5558 case IDM_LoadNextPosition:
\r
5559 ReloadPosition(1);
\r
5562 case IDM_LoadPrevPosition:
\r
5563 ReloadPosition(-1);
\r
5566 case IDM_ReloadPosition:
\r
5567 ReloadPosition(0);
\r
5570 case IDM_SaveGame:
\r
5571 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5572 f = OpenFileDialog(hwnd, "a", defName,
\r
5573 appData.oldSaveStyle ? "gam" : "pgn",
\r
5575 "Save Game to File", NULL, fileTitle, NULL);
\r
5577 SaveGame(f, 0, "");
\r
5581 case IDM_SavePosition:
\r
5582 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5583 f = OpenFileDialog(hwnd, "a", defName,
\r
5584 appData.oldSaveStyle ? "pos" : "fen",
\r
5586 "Save Position to File", NULL, fileTitle, NULL);
\r
5588 SavePosition(f, 0, "");
\r
5592 case IDM_SaveDiagram:
\r
5593 defName = "diagram";
\r
5594 f = OpenFileDialog(hwnd, "wb", defName,
\r
5597 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5603 case IDM_CopyGame:
\r
5604 CopyGameToClipboard();
\r
5607 case IDM_PasteGame:
\r
5608 PasteGameFromClipboard();
\r
5611 case IDM_CopyGameListToClipboard:
\r
5612 CopyGameListToClipboard();
\r
5615 /* [AS] Autodetect FEN or PGN data */
\r
5616 case IDM_PasteAny:
\r
5617 PasteGameOrFENFromClipboard();
\r
5620 /* [AS] Move history */
\r
5621 case IDM_ShowMoveHistory:
\r
5622 if( MoveHistoryIsUp() ) {
\r
5623 MoveHistoryPopDown();
\r
5626 MoveHistoryPopUp();
\r
5630 /* [AS] Eval graph */
\r
5631 case IDM_ShowEvalGraph:
\r
5632 if( EvalGraphIsUp() ) {
\r
5633 EvalGraphPopDown();
\r
5640 /* [AS] Engine output */
\r
5641 case IDM_ShowEngineOutput:
\r
5642 if( EngineOutputIsUp() ) {
\r
5643 EngineOutputPopDown();
\r
5646 EngineOutputPopUp();
\r
5650 /* [AS] User adjudication */
\r
5651 case IDM_UserAdjudication_White:
\r
5652 UserAdjudicationEvent( +1 );
\r
5655 case IDM_UserAdjudication_Black:
\r
5656 UserAdjudicationEvent( -1 );
\r
5659 case IDM_UserAdjudication_Draw:
\r
5660 UserAdjudicationEvent( 0 );
\r
5663 /* [AS] Game list options dialog */
\r
5664 case IDM_GameListOptions:
\r
5665 GameListOptions();
\r
5668 case IDM_CopyPosition:
\r
5669 CopyFENToClipboard();
\r
5672 case IDM_PastePosition:
\r
5673 PasteFENFromClipboard();
\r
5676 case IDM_MailMove:
\r
5680 case IDM_ReloadCMailMsg:
\r
5681 Reset(TRUE, TRUE);
\r
5682 ReloadCmailMsgEvent(FALSE);
\r
5685 case IDM_Minimize:
\r
5686 ShowWindow(hwnd, SW_MINIMIZE);
\r
5693 case IDM_MachineWhite:
\r
5694 MachineWhiteEvent();
\r
5696 * refresh the tags dialog only if it's visible
\r
5698 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5700 tags = PGNTags(&gameInfo);
\r
5701 TagsPopUp(tags, CmailMsg());
\r
5706 case IDM_MachineBlack:
\r
5707 MachineBlackEvent();
\r
5709 * refresh the tags dialog only if it's visible
\r
5711 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5713 tags = PGNTags(&gameInfo);
\r
5714 TagsPopUp(tags, CmailMsg());
\r
5719 case IDM_TwoMachines:
\r
5720 TwoMachinesEvent();
\r
5722 * refresh the tags dialog only if it's visible
\r
5724 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5726 tags = PGNTags(&gameInfo);
\r
5727 TagsPopUp(tags, CmailMsg());
\r
5732 case IDM_AnalysisMode:
\r
5733 if (!first.analysisSupport) {
\r
5734 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5735 DisplayError(buf, 0);
\r
5737 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5738 if (appData.icsActive) {
\r
5739 if (gameMode != IcsObserving) {
\r
5740 sprintf(buf, "You are not observing a game");
\r
5741 DisplayError(buf, 0);
\r
5742 /* secure check */
\r
5743 if (appData.icsEngineAnalyze) {
\r
5744 if (appData.debugMode)
\r
5745 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5746 ExitAnalyzeMode();
\r
5752 /* if enable, user want disable icsEngineAnalyze */
\r
5753 if (appData.icsEngineAnalyze) {
\r
5754 ExitAnalyzeMode();
\r
5758 appData.icsEngineAnalyze = TRUE;
\r
5759 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5762 if (!appData.showThinking) ToggleShowThinking();
\r
5763 AnalyzeModeEvent();
\r
5767 case IDM_AnalyzeFile:
\r
5768 if (!first.analysisSupport) {
\r
5769 char buf[MSG_SIZ];
\r
5770 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5771 DisplayError(buf, 0);
\r
5773 if (!appData.showThinking) ToggleShowThinking();
\r
5774 AnalyzeFileEvent();
\r
5775 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5776 AnalysisPeriodicEvent(1);
\r
5780 case IDM_IcsClient:
\r
5784 case IDM_EditGame:
\r
5788 case IDM_EditPosition:
\r
5789 EditPositionEvent();
\r
5792 case IDM_Training:
\r
5796 case IDM_ShowGameList:
\r
5797 ShowGameListProc();
\r
5800 case IDM_EditTags:
\r
5804 case IDM_EditComment:
\r
5805 if (commentDialogUp && editComment) {
\r
5808 EditCommentEvent();
\r
5828 case IDM_CallFlag:
\r
5848 case IDM_StopObserving:
\r
5849 StopObservingEvent();
\r
5852 case IDM_StopExamining:
\r
5853 StopExaminingEvent();
\r
5856 case IDM_TypeInMove:
\r
5857 PopUpMoveDialog('\000');
\r
5860 case IDM_TypeInName:
\r
5861 PopUpNameDialog('\000');
\r
5864 case IDM_Backward:
\r
5866 SetFocus(hwndMain);
\r
5871 SetFocus(hwndMain);
\r
5876 SetFocus(hwndMain);
\r
5881 SetFocus(hwndMain);
\r
5888 case IDM_TruncateGame:
\r
5889 TruncateGameEvent();
\r
5896 case IDM_RetractMove:
\r
5897 RetractMoveEvent();
\r
5900 case IDM_FlipView:
\r
5901 flipView = !flipView;
\r
5902 DrawPosition(FALSE, NULL);
\r
5905 case IDM_FlipClock:
\r
5906 flipClock = !flipClock;
\r
5907 DisplayBothClocks();
\r
5910 case IDM_GeneralOptions:
\r
5911 GeneralOptionsPopup(hwnd);
\r
5912 DrawPosition(TRUE, NULL);
\r
5915 case IDM_BoardOptions:
\r
5916 BoardOptionsPopup(hwnd);
\r
5919 case IDM_EnginePlayOptions:
\r
5920 EnginePlayOptionsPopup(hwnd);
\r
5923 case IDM_OptionsUCI:
\r
5924 UciOptionsPopup(hwnd);
\r
5927 case IDM_IcsOptions:
\r
5928 IcsOptionsPopup(hwnd);
\r
5932 FontsOptionsPopup(hwnd);
\r
5936 SoundOptionsPopup(hwnd);
\r
5939 case IDM_CommPort:
\r
5940 CommPortOptionsPopup(hwnd);
\r
5943 case IDM_LoadOptions:
\r
5944 LoadOptionsPopup(hwnd);
\r
5947 case IDM_SaveOptions:
\r
5948 SaveOptionsPopup(hwnd);
\r
5951 case IDM_TimeControl:
\r
5952 TimeControlOptionsPopup(hwnd);
\r
5955 case IDM_SaveSettings:
\r
5956 SaveSettings(settingsFileName);
\r
5959 case IDM_SaveSettingsOnExit:
\r
5960 saveSettingsOnExit = !saveSettingsOnExit;
\r
5961 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5962 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5963 MF_CHECKED : MF_UNCHECKED));
\r
5974 case IDM_AboutGame:
\r
5979 appData.debugMode = !appData.debugMode;
\r
5980 if (appData.debugMode) {
\r
5981 char dir[MSG_SIZ];
\r
5982 GetCurrentDirectory(MSG_SIZ, dir);
\r
5983 SetCurrentDirectory(installDir);
\r
5984 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5985 SetCurrentDirectory(dir);
\r
5986 setbuf(debugFP, NULL);
\r
5993 case IDM_HELPCONTENTS:
\r
5994 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5995 MessageBox (GetFocus(),
\r
5996 "Unable to activate help",
\r
5997 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6001 case IDM_HELPSEARCH:
\r
6002 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
6003 MessageBox (GetFocus(),
\r
6004 "Unable to activate help",
\r
6005 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6009 case IDM_HELPHELP:
\r
6010 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6011 MessageBox (GetFocus(),
\r
6012 "Unable to activate help",
\r
6013 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6018 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6020 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6021 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6022 FreeProcInstance(lpProc);
\r
6025 case IDM_DirectCommand1:
\r
6026 AskQuestionEvent("Direct Command",
\r
6027 "Send to chess program:", "", "1");
\r
6029 case IDM_DirectCommand2:
\r
6030 AskQuestionEvent("Direct Command",
\r
6031 "Send to second chess program:", "", "2");
\r
6034 case EP_WhitePawn:
\r
6035 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6036 fromX = fromY = -1;
\r
6039 case EP_WhiteKnight:
\r
6040 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6041 fromX = fromY = -1;
\r
6044 case EP_WhiteBishop:
\r
6045 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6046 fromX = fromY = -1;
\r
6049 case EP_WhiteRook:
\r
6050 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6051 fromX = fromY = -1;
\r
6054 case EP_WhiteQueen:
\r
6055 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6056 fromX = fromY = -1;
\r
6059 case EP_WhiteFerz:
\r
6060 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6061 fromX = fromY = -1;
\r
6064 case EP_WhiteWazir:
\r
6065 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6066 fromX = fromY = -1;
\r
6069 case EP_WhiteAlfil:
\r
6070 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6071 fromX = fromY = -1;
\r
6074 case EP_WhiteCannon:
\r
6075 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6076 fromX = fromY = -1;
\r
6079 case EP_WhiteCardinal:
\r
6080 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6081 fromX = fromY = -1;
\r
6084 case EP_WhiteMarshall:
\r
6085 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6086 fromX = fromY = -1;
\r
6089 case EP_WhiteKing:
\r
6090 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6091 fromX = fromY = -1;
\r
6094 case EP_BlackPawn:
\r
6095 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6096 fromX = fromY = -1;
\r
6099 case EP_BlackKnight:
\r
6100 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6101 fromX = fromY = -1;
\r
6104 case EP_BlackBishop:
\r
6105 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6106 fromX = fromY = -1;
\r
6109 case EP_BlackRook:
\r
6110 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6111 fromX = fromY = -1;
\r
6114 case EP_BlackQueen:
\r
6115 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6116 fromX = fromY = -1;
\r
6119 case EP_BlackFerz:
\r
6120 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6121 fromX = fromY = -1;
\r
6124 case EP_BlackWazir:
\r
6125 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6126 fromX = fromY = -1;
\r
6129 case EP_BlackAlfil:
\r
6130 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6131 fromX = fromY = -1;
\r
6134 case EP_BlackCannon:
\r
6135 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6136 fromX = fromY = -1;
\r
6139 case EP_BlackCardinal:
\r
6140 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6141 fromX = fromY = -1;
\r
6144 case EP_BlackMarshall:
\r
6145 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6146 fromX = fromY = -1;
\r
6149 case EP_BlackKing:
\r
6150 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6151 fromX = fromY = -1;
\r
6154 case EP_EmptySquare:
\r
6155 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6156 fromX = fromY = -1;
\r
6159 case EP_ClearBoard:
\r
6160 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6161 fromX = fromY = -1;
\r
6165 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6166 fromX = fromY = -1;
\r
6170 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6171 fromX = fromY = -1;
\r
6175 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6176 fromX = fromY = -1;
\r
6180 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6181 fromX = fromY = -1;
\r
6185 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6186 fromX = fromY = -1;
\r
6190 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6191 fromX = fromY = -1;
\r
6195 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6196 fromX = fromY = -1;
\r
6200 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6201 fromX = fromY = -1;
\r
6205 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6206 fromX = fromY = -1;
\r
6210 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6216 case CLOCK_TIMER_ID:
\r
6217 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6218 clockTimerEvent = 0;
\r
6219 DecrementClocks(); /* call into back end */
\r
6221 case LOAD_GAME_TIMER_ID:
\r
6222 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6223 loadGameTimerEvent = 0;
\r
6224 AutoPlayGameLoop(); /* call into back end */
\r
6226 case ANALYSIS_TIMER_ID:
\r
6227 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6228 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6229 AnalysisPeriodicEvent(0);
\r
6231 KillTimer(hwnd, analysisTimerEvent);
\r
6232 analysisTimerEvent = 0;
\r
6235 case DELAYED_TIMER_ID:
\r
6236 KillTimer(hwnd, delayedTimerEvent);
\r
6237 delayedTimerEvent = 0;
\r
6238 delayedTimerCallback();
\r
6243 case WM_USER_Input:
\r
6244 InputEvent(hwnd, message, wParam, lParam);
\r
6247 /* [AS] Also move "attached" child windows */
\r
6248 case WM_WINDOWPOSCHANGING:
\r
6249 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6250 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6252 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6253 /* Window is moving */
\r
6256 GetWindowRect( hwnd, &rcMain );
\r
6258 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6259 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6260 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6265 /* [AS] Snapping */
\r
6266 case WM_ENTERSIZEMOVE:
\r
6267 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6268 if (hwnd == hwndMain) {
\r
6269 doingSizing = TRUE;
\r
6272 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6276 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6277 if (hwnd == hwndMain) {
\r
6278 lastSizing = wParam;
\r
6283 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6284 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6286 case WM_EXITSIZEMOVE:
\r
6287 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6288 if (hwnd == hwndMain) {
\r
6290 doingSizing = FALSE;
\r
6291 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6292 GetClientRect(hwnd, &client);
\r
6293 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6295 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6297 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6300 case WM_DESTROY: /* message: window being destroyed */
\r
6301 PostQuitMessage(0);
\r
6305 if (hwnd == hwndMain) {
\r
6310 default: /* Passes it on if unprocessed */
\r
6311 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6316 /*---------------------------------------------------------------------------*\
\r
6318 * Misc utility routines
\r
6320 \*---------------------------------------------------------------------------*/
\r
6323 * Decent random number generator, at least not as bad as Windows
\r
6324 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6326 unsigned int randstate;
\r
6331 randstate = randstate * 1664525 + 1013904223;
\r
6332 return (int) randstate & 0x7fffffff;
\r
6336 mysrandom(unsigned int seed)
\r
6343 * returns TRUE if user selects a different color, FALSE otherwise
\r
6347 ChangeColor(HWND hwnd, COLORREF *which)
\r
6349 static BOOL firstTime = TRUE;
\r
6350 static DWORD customColors[16];
\r
6352 COLORREF newcolor;
\r
6357 /* Make initial colors in use available as custom colors */
\r
6358 /* Should we put the compiled-in defaults here instead? */
\r
6360 customColors[i++] = lightSquareColor & 0xffffff;
\r
6361 customColors[i++] = darkSquareColor & 0xffffff;
\r
6362 customColors[i++] = whitePieceColor & 0xffffff;
\r
6363 customColors[i++] = blackPieceColor & 0xffffff;
\r
6364 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6365 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6367 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6368 customColors[i++] = textAttribs[ccl].color;
\r
6370 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6371 firstTime = FALSE;
\r
6374 cc.lStructSize = sizeof(cc);
\r
6375 cc.hwndOwner = hwnd;
\r
6376 cc.hInstance = NULL;
\r
6377 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6378 cc.lpCustColors = (LPDWORD) customColors;
\r
6379 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6381 if (!ChooseColor(&cc)) return FALSE;
\r
6383 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6384 if (newcolor == *which) return FALSE;
\r
6385 *which = newcolor;
\r
6389 InitDrawingColors();
\r
6390 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6395 MyLoadSound(MySound *ms)
\r
6401 if (ms->data) free(ms->data);
\r
6404 switch (ms->name[0]) {
\r
6410 /* System sound from Control Panel. Don't preload here. */
\r
6414 if (ms->name[1] == NULLCHAR) {
\r
6415 /* "!" alone = silence */
\r
6418 /* Builtin wave resource. Error if not found. */
\r
6419 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6420 if (h == NULL) break;
\r
6421 ms->data = (void *)LoadResource(hInst, h);
\r
6422 if (h == NULL) break;
\r
6427 /* .wav file. Error if not found. */
\r
6428 f = fopen(ms->name, "rb");
\r
6429 if (f == NULL) break;
\r
6430 if (fstat(fileno(f), &st) < 0) break;
\r
6431 ms->data = malloc(st.st_size);
\r
6432 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6438 char buf[MSG_SIZ];
\r
6439 sprintf(buf, "Error loading sound %s", ms->name);
\r
6440 DisplayError(buf, GetLastError());
\r
6446 MyPlaySound(MySound *ms)
\r
6448 BOOLEAN ok = FALSE;
\r
6449 switch (ms->name[0]) {
\r
6455 /* System sound from Control Panel (deprecated feature).
\r
6456 "$" alone or an unset sound name gets default beep (still in use). */
\r
6457 if (ms->name[1]) {
\r
6458 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6460 if (!ok) ok = MessageBeep(MB_OK);
\r
6463 /* Builtin wave resource, or "!" alone for silence */
\r
6464 if (ms->name[1]) {
\r
6465 if (ms->data == NULL) return FALSE;
\r
6466 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6472 /* .wav file. Error if not found. */
\r
6473 if (ms->data == NULL) return FALSE;
\r
6474 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6477 /* Don't print an error: this can happen innocently if the sound driver
\r
6478 is busy; for instance, if another instance of WinBoard is playing
\r
6479 a sound at about the same time. */
\r
6482 char buf[MSG_SIZ];
\r
6483 sprintf(buf, "Error playing sound %s", ms->name);
\r
6484 DisplayError(buf, GetLastError());
\r
6492 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6495 OPENFILENAME *ofn;
\r
6496 static UINT *number; /* gross that this is static */
\r
6498 switch (message) {
\r
6499 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6500 /* Center the dialog over the application window */
\r
6501 ofn = (OPENFILENAME *) lParam;
\r
6502 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6503 number = (UINT *) ofn->lCustData;
\r
6504 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6508 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6509 return FALSE; /* Allow for further processing */
\r
6512 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6513 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6515 return FALSE; /* Allow for further processing */
\r
6521 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6523 static UINT *number;
\r
6524 OPENFILENAME *ofname;
\r
6527 case WM_INITDIALOG:
\r
6528 ofname = (OPENFILENAME *)lParam;
\r
6529 number = (UINT *)(ofname->lCustData);
\r
6532 ofnot = (OFNOTIFY *)lParam;
\r
6533 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6534 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6543 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6544 char *nameFilt, char *dlgTitle, UINT *number,
\r
6545 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6547 OPENFILENAME openFileName;
\r
6548 char buf1[MSG_SIZ];
\r
6551 if (fileName == NULL) fileName = buf1;
\r
6552 if (defName == NULL) {
\r
6553 strcpy(fileName, "*.");
\r
6554 strcat(fileName, defExt);
\r
6556 strcpy(fileName, defName);
\r
6558 if (fileTitle) strcpy(fileTitle, "");
\r
6559 if (number) *number = 0;
\r
6561 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6562 openFileName.hwndOwner = hwnd;
\r
6563 openFileName.hInstance = (HANDLE) hInst;
\r
6564 openFileName.lpstrFilter = nameFilt;
\r
6565 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6566 openFileName.nMaxCustFilter = 0L;
\r
6567 openFileName.nFilterIndex = 1L;
\r
6568 openFileName.lpstrFile = fileName;
\r
6569 openFileName.nMaxFile = MSG_SIZ;
\r
6570 openFileName.lpstrFileTitle = fileTitle;
\r
6571 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6572 openFileName.lpstrInitialDir = NULL;
\r
6573 openFileName.lpstrTitle = dlgTitle;
\r
6574 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6575 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6576 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6577 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6578 openFileName.nFileOffset = 0;
\r
6579 openFileName.nFileExtension = 0;
\r
6580 openFileName.lpstrDefExt = defExt;
\r
6581 openFileName.lCustData = (LONG) number;
\r
6582 openFileName.lpfnHook = oldDialog ?
\r
6583 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6584 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6586 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6587 GetOpenFileName(&openFileName)) {
\r
6588 /* open the file */
\r
6589 f = fopen(openFileName.lpstrFile, write);
\r
6591 MessageBox(hwnd, "File open failed", NULL,
\r
6592 MB_OK|MB_ICONEXCLAMATION);
\r
6596 int err = CommDlgExtendedError();
\r
6597 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6606 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6608 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6611 * Get the first pop-up menu in the menu template. This is the
\r
6612 * menu that TrackPopupMenu displays.
\r
6614 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6616 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6619 * TrackPopup uses screen coordinates, so convert the
\r
6620 * coordinates of the mouse click to screen coordinates.
\r
6622 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6624 /* Draw and track the floating pop-up menu. */
\r
6625 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6626 pt.x, pt.y, 0, hwnd, NULL);
\r
6628 /* Destroy the menu.*/
\r
6629 DestroyMenu(hmenu);
\r
6634 int sizeX, sizeY, newSizeX, newSizeY;
\r
6636 } ResizeEditPlusButtonsClosure;
\r
6639 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6641 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6645 if (hChild == cl->hText) return TRUE;
\r
6646 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6647 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6648 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6649 ScreenToClient(cl->hDlg, &pt);
\r
6650 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6651 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6655 /* Resize a dialog that has a (rich) edit field filling most of
\r
6656 the top, with a row of buttons below */
\r
6658 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6661 int newTextHeight, newTextWidth;
\r
6662 ResizeEditPlusButtonsClosure cl;
\r
6664 /*if (IsIconic(hDlg)) return;*/
\r
6665 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6667 cl.hdwp = BeginDeferWindowPos(8);
\r
6669 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6670 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6671 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6672 if (newTextHeight < 0) {
\r
6673 newSizeY += -newTextHeight;
\r
6674 newTextHeight = 0;
\r
6676 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6677 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6683 cl.newSizeX = newSizeX;
\r
6684 cl.newSizeY = newSizeY;
\r
6685 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6687 EndDeferWindowPos(cl.hdwp);
\r
6690 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6692 RECT rChild, rParent;
\r
6693 int wChild, hChild, wParent, hParent;
\r
6694 int wScreen, hScreen, xNew, yNew;
\r
6697 /* Get the Height and Width of the child window */
\r
6698 GetWindowRect (hwndChild, &rChild);
\r
6699 wChild = rChild.right - rChild.left;
\r
6700 hChild = rChild.bottom - rChild.top;
\r
6702 /* Get the Height and Width of the parent window */
\r
6703 GetWindowRect (hwndParent, &rParent);
\r
6704 wParent = rParent.right - rParent.left;
\r
6705 hParent = rParent.bottom - rParent.top;
\r
6707 /* Get the display limits */
\r
6708 hdc = GetDC (hwndChild);
\r
6709 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6710 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6711 ReleaseDC(hwndChild, hdc);
\r
6713 /* Calculate new X position, then adjust for screen */
\r
6714 xNew = rParent.left + ((wParent - wChild) /2);
\r
6717 } else if ((xNew+wChild) > wScreen) {
\r
6718 xNew = wScreen - wChild;
\r
6721 /* Calculate new Y position, then adjust for screen */
\r
6723 yNew = rParent.top + ((hParent - hChild) /2);
\r
6726 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6731 } else if ((yNew+hChild) > hScreen) {
\r
6732 yNew = hScreen - hChild;
\r
6735 /* Set it, and return */
\r
6736 return SetWindowPos (hwndChild, NULL,
\r
6737 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6740 /* Center one window over another */
\r
6741 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6743 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6746 /*---------------------------------------------------------------------------*\
\r
6748 * Startup Dialog functions
\r
6750 \*---------------------------------------------------------------------------*/
\r
6752 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6754 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6756 while (*cd != NULL) {
\r
6757 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6763 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6765 char buf1[ARG_MAX];
\r
6768 if (str[0] == '@') {
\r
6769 FILE* f = fopen(str + 1, "r");
\r
6771 DisplayFatalError(str + 1, errno, 2);
\r
6774 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6776 buf1[len] = NULLCHAR;
\r
6780 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6783 char buf[MSG_SIZ];
\r
6784 char *end = strchr(str, '\n');
\r
6785 if (end == NULL) return;
\r
6786 memcpy(buf, str, end - str);
\r
6787 buf[end - str] = NULLCHAR;
\r
6788 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6794 SetStartupDialogEnables(HWND hDlg)
\r
6796 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6797 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6798 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6799 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6800 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6801 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6802 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6803 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6804 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6805 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6806 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6807 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6808 IsDlgButtonChecked(hDlg, OPT_View));
\r
6812 QuoteForFilename(char *filename)
\r
6814 int dquote, space;
\r
6815 dquote = strchr(filename, '"') != NULL;
\r
6816 space = strchr(filename, ' ') != NULL;
\r
6817 if (dquote || space) {
\r
6829 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6831 char buf[MSG_SIZ];
\r
6834 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6835 q = QuoteForFilename(nthcp);
\r
6836 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6837 if (*nthdir != NULLCHAR) {
\r
6838 q = QuoteForFilename(nthdir);
\r
6839 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6841 if (*nthcp == NULLCHAR) {
\r
6842 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6843 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6844 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6845 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6850 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6852 char buf[MSG_SIZ];
\r
6856 switch (message) {
\r
6857 case WM_INITDIALOG:
\r
6858 /* Center the dialog */
\r
6859 CenterWindow (hDlg, GetDesktopWindow());
\r
6860 /* Initialize the dialog items */
\r
6861 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6862 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6863 firstChessProgramNames);
\r
6864 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6865 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6866 secondChessProgramNames);
\r
6867 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6868 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6869 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6870 if (*appData.icsHelper != NULLCHAR) {
\r
6871 char *q = QuoteForFilename(appData.icsHelper);
\r
6872 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6874 if (*appData.icsHost == NULLCHAR) {
\r
6875 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6876 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6877 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6878 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6879 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6882 if (appData.icsActive) {
\r
6883 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6885 else if (appData.noChessProgram) {
\r
6886 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6889 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6892 SetStartupDialogEnables(hDlg);
\r
6896 switch (LOWORD(wParam)) {
\r
6898 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6899 strcpy(buf, "/fcp=");
\r
6900 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6902 ParseArgs(StringGet, &p);
\r
6903 strcpy(buf, "/scp=");
\r
6904 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6906 ParseArgs(StringGet, &p);
\r
6907 appData.noChessProgram = FALSE;
\r
6908 appData.icsActive = FALSE;
\r
6909 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6910 strcpy(buf, "/ics /icshost=");
\r
6911 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6913 ParseArgs(StringGet, &p);
\r
6914 if (appData.zippyPlay) {
\r
6915 strcpy(buf, "/fcp=");
\r
6916 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6918 ParseArgs(StringGet, &p);
\r
6920 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6921 appData.noChessProgram = TRUE;
\r
6922 appData.icsActive = FALSE;
\r
6924 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6925 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6928 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6929 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6931 ParseArgs(StringGet, &p);
\r
6933 EndDialog(hDlg, TRUE);
\r
6940 case IDM_HELPCONTENTS:
\r
6941 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6942 MessageBox (GetFocus(),
\r
6943 "Unable to activate help",
\r
6944 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6949 SetStartupDialogEnables(hDlg);
\r
6957 /*---------------------------------------------------------------------------*\
\r
6959 * About box dialog functions
\r
6961 \*---------------------------------------------------------------------------*/
\r
6963 /* Process messages for "About" dialog box */
\r
6965 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6967 switch (message) {
\r
6968 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6969 /* Center the dialog over the application window */
\r
6970 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6971 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6974 case WM_COMMAND: /* message: received a command */
\r
6975 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6976 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6977 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6985 /*---------------------------------------------------------------------------*\
\r
6987 * Comment Dialog functions
\r
6989 \*---------------------------------------------------------------------------*/
\r
6992 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6994 static HANDLE hwndText = NULL;
\r
6995 int len, newSizeX, newSizeY, flags;
\r
6996 static int sizeX, sizeY;
\r
7001 switch (message) {
\r
7002 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7003 /* Initialize the dialog items */
\r
7004 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7005 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7006 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7007 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7008 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7009 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7010 SetWindowText(hDlg, commentTitle);
\r
7011 if (editComment) {
\r
7012 SetFocus(hwndText);
\r
7014 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7016 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7017 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7018 MAKELPARAM(FALSE, 0));
\r
7019 /* Size and position the dialog */
\r
7020 if (!commentDialog) {
\r
7021 commentDialog = hDlg;
\r
7022 flags = SWP_NOZORDER;
\r
7023 GetClientRect(hDlg, &rect);
\r
7024 sizeX = rect.right;
\r
7025 sizeY = rect.bottom;
\r
7026 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7027 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7028 WINDOWPLACEMENT wp;
\r
7029 EnsureOnScreen(&commentX, &commentY);
\r
7030 wp.length = sizeof(WINDOWPLACEMENT);
\r
7032 wp.showCmd = SW_SHOW;
\r
7033 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7034 wp.rcNormalPosition.left = commentX;
\r
7035 wp.rcNormalPosition.right = commentX + commentW;
\r
7036 wp.rcNormalPosition.top = commentY;
\r
7037 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7038 SetWindowPlacement(hDlg, &wp);
\r
7040 GetClientRect(hDlg, &rect);
\r
7041 newSizeX = rect.right;
\r
7042 newSizeY = rect.bottom;
\r
7043 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7044 newSizeX, newSizeY);
\r
7051 case WM_COMMAND: /* message: received a command */
\r
7052 switch (LOWORD(wParam)) {
\r
7054 if (editComment) {
\r
7056 /* Read changed options from the dialog box */
\r
7057 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7058 len = GetWindowTextLength(hwndText);
\r
7059 str = (char *) malloc(len + 1);
\r
7060 GetWindowText(hwndText, str, len + 1);
\r
7069 ReplaceComment(commentIndex, str);
\r
7076 case OPT_CancelComment:
\r
7080 case OPT_ClearComment:
\r
7081 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7084 case OPT_EditComment:
\r
7085 EditCommentEvent();
\r
7094 newSizeX = LOWORD(lParam);
\r
7095 newSizeY = HIWORD(lParam);
\r
7096 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7101 case WM_GETMINMAXINFO:
\r
7102 /* Prevent resizing window too small */
\r
7103 mmi = (MINMAXINFO *) lParam;
\r
7104 mmi->ptMinTrackSize.x = 100;
\r
7105 mmi->ptMinTrackSize.y = 100;
\r
7112 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7117 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7119 if (str == NULL) str = "";
\r
7120 p = (char *) malloc(2 * strlen(str) + 2);
\r
7123 if (*str == '\n') *q++ = '\r';
\r
7127 if (commentText != NULL) free(commentText);
\r
7129 commentIndex = index;
\r
7130 commentTitle = title;
\r
7132 editComment = edit;
\r
7134 if (commentDialog) {
\r
7135 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7136 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7138 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7139 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7140 hwndMain, (DLGPROC)lpProc);
\r
7141 FreeProcInstance(lpProc);
\r
7143 commentDialogUp = TRUE;
\r
7147 /*---------------------------------------------------------------------------*\
\r
7149 * Type-in move dialog functions
\r
7151 \*---------------------------------------------------------------------------*/
\r
7154 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7156 char move[MSG_SIZ];
\r
7158 ChessMove moveType;
\r
7159 int fromX, fromY, toX, toY;
\r
7162 switch (message) {
\r
7163 case WM_INITDIALOG:
\r
7164 move[0] = (char) lParam;
\r
7165 move[1] = NULLCHAR;
\r
7166 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7167 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7168 SetWindowText(hInput, move);
\r
7170 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7174 switch (LOWORD(wParam)) {
\r
7176 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7177 gameMode != Training) {
\r
7178 DisplayMoveError("Displayed move is not current");
\r
7180 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7181 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7182 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7183 if (gameMode != Training)
\r
7184 forwardMostMove = currentMove;
\r
7185 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7187 DisplayMoveError("Could not parse move");
\r
7190 EndDialog(hDlg, TRUE);
\r
7193 EndDialog(hDlg, FALSE);
\r
7204 PopUpMoveDialog(char firstchar)
\r
7208 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7209 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7210 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7211 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7212 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7213 gameMode == Training) {
\r
7214 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7215 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7216 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7217 FreeProcInstance(lpProc);
\r
7221 /*---------------------------------------------------------------------------*\
\r
7223 * Type-in name dialog functions
\r
7225 \*---------------------------------------------------------------------------*/
\r
7228 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7230 char move[MSG_SIZ];
\r
7233 switch (message) {
\r
7234 case WM_INITDIALOG:
\r
7235 move[0] = (char) lParam;
\r
7236 move[1] = NULLCHAR;
\r
7237 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7238 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7239 SetWindowText(hInput, move);
\r
7241 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7245 switch (LOWORD(wParam)) {
\r
7247 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7248 appData.userName = strdup(move);
\r
7250 EndDialog(hDlg, TRUE);
\r
7253 EndDialog(hDlg, FALSE);
\r
7264 PopUpNameDialog(char firstchar)
\r
7268 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7269 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7270 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7271 FreeProcInstance(lpProc);
\r
7274 /*---------------------------------------------------------------------------*\
\r
7278 \*---------------------------------------------------------------------------*/
\r
7280 /* Nonmodal error box */
\r
7281 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7282 WPARAM wParam, LPARAM lParam);
\r
7285 ErrorPopUp(char *title, char *content)
\r
7289 BOOLEAN modal = hwndMain == NULL;
\r
7307 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7308 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7311 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7313 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7314 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7315 hwndMain, (DLGPROC)lpProc);
\r
7316 FreeProcInstance(lpProc);
\r
7323 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7324 if (errorDialog == NULL) return;
\r
7325 DestroyWindow(errorDialog);
\r
7326 errorDialog = NULL;
\r
7330 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7335 switch (message) {
\r
7336 case WM_INITDIALOG:
\r
7337 GetWindowRect(hDlg, &rChild);
\r
7340 SetWindowPos(hDlg, NULL, rChild.left,
\r
7341 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7342 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7346 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7347 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7348 and it doesn't work when you resize the dialog.
\r
7349 For now, just give it a default position.
\r
7351 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7353 errorDialog = hDlg;
\r
7354 SetWindowText(hDlg, errorTitle);
\r
7355 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7356 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7360 switch (LOWORD(wParam)) {
\r
7363 if (errorDialog == hDlg) errorDialog = NULL;
\r
7364 DestroyWindow(hDlg);
\r
7376 HWND gothicDialog = NULL;
\r
7379 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7383 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7385 switch (message) {
\r
7386 case WM_INITDIALOG:
\r
7387 GetWindowRect(hDlg, &rChild);
\r
7389 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7393 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7394 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7395 and it doesn't work when you resize the dialog.
\r
7396 For now, just give it a default position.
\r
7398 gothicDialog = hDlg;
\r
7399 SetWindowText(hDlg, errorTitle);
\r
7400 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7401 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7405 switch (LOWORD(wParam)) {
\r
7408 if (errorDialog == hDlg) errorDialog = NULL;
\r
7409 DestroyWindow(hDlg);
\r
7421 GothicPopUp(char *title, VariantClass variant)
\r
7424 static char *lastTitle;
\r
7426 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7427 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7429 if(lastTitle != title && gothicDialog != NULL) {
\r
7430 DestroyWindow(gothicDialog);
\r
7431 gothicDialog = NULL;
\r
7433 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7434 title = lastTitle;
\r
7435 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7436 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7437 hwndMain, (DLGPROC)lpProc);
\r
7438 FreeProcInstance(lpProc);
\r
7443 /*---------------------------------------------------------------------------*\
\r
7445 * Ics Interaction console functions
\r
7447 \*---------------------------------------------------------------------------*/
\r
7449 #define HISTORY_SIZE 64
\r
7450 static char *history[HISTORY_SIZE];
\r
7451 int histIn = 0, histP = 0;
\r
7454 SaveInHistory(char *cmd)
\r
7456 if (history[histIn] != NULL) {
\r
7457 free(history[histIn]);
\r
7458 history[histIn] = NULL;
\r
7460 if (*cmd == NULLCHAR) return;
\r
7461 history[histIn] = StrSave(cmd);
\r
7462 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7463 if (history[histIn] != NULL) {
\r
7464 free(history[histIn]);
\r
7465 history[histIn] = NULL;
\r
7471 PrevInHistory(char *cmd)
\r
7474 if (histP == histIn) {
\r
7475 if (history[histIn] != NULL) free(history[histIn]);
\r
7476 history[histIn] = StrSave(cmd);
\r
7478 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7479 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7481 return history[histP];
\r
7487 if (histP == histIn) return NULL;
\r
7488 histP = (histP + 1) % HISTORY_SIZE;
\r
7489 return history[histP];
\r
7496 BOOLEAN immediate;
\r
7497 } IcsTextMenuEntry;
\r
7498 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7499 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7502 ParseIcsTextMenu(char *icsTextMenuString)
\r
7505 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7506 char *p = icsTextMenuString;
\r
7507 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7510 if (e->command != NULL) {
\r
7512 e->command = NULL;
\r
7516 e = icsTextMenuEntry;
\r
7517 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7518 if (*p == ';' || *p == '\n') {
\r
7519 e->item = strdup("-");
\r
7520 e->command = NULL;
\r
7522 } else if (*p == '-') {
\r
7523 e->item = strdup("-");
\r
7524 e->command = NULL;
\r
7528 char *q, *r, *s, *t;
\r
7530 q = strchr(p, ',');
\r
7531 if (q == NULL) break;
\r
7533 r = strchr(q + 1, ',');
\r
7534 if (r == NULL) break;
\r
7536 s = strchr(r + 1, ',');
\r
7537 if (s == NULL) break;
\r
7540 t = strchr(s + 1, c);
\r
7543 t = strchr(s + 1, c);
\r
7545 if (t != NULL) *t = NULLCHAR;
\r
7546 e->item = strdup(p);
\r
7547 e->command = strdup(q + 1);
\r
7548 e->getname = *(r + 1) != '0';
\r
7549 e->immediate = *(s + 1) != '0';
\r
7553 if (t == NULL) break;
\r
7562 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7566 hmenu = LoadMenu(hInst, "TextMenu");
\r
7567 h = GetSubMenu(hmenu, 0);
\r
7569 if (strcmp(e->item, "-") == 0) {
\r
7570 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7572 if (e->item[0] == '|') {
\r
7573 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7574 IDM_CommandX + i, &e->item[1]);
\r
7576 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7585 WNDPROC consoleTextWindowProc;
\r
7588 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7590 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7591 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7595 SetWindowText(hInput, command);
\r
7597 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7599 sel.cpMin = 999999;
\r
7600 sel.cpMax = 999999;
\r
7601 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7606 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7607 if (sel.cpMin == sel.cpMax) {
\r
7608 /* Expand to surrounding word */
\r
7611 tr.chrg.cpMax = sel.cpMin;
\r
7612 tr.chrg.cpMin = --sel.cpMin;
\r
7613 if (sel.cpMin < 0) break;
\r
7614 tr.lpstrText = name;
\r
7615 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7616 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7620 tr.chrg.cpMin = sel.cpMax;
\r
7621 tr.chrg.cpMax = ++sel.cpMax;
\r
7622 tr.lpstrText = name;
\r
7623 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7624 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7627 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7628 MessageBeep(MB_ICONEXCLAMATION);
\r
7632 tr.lpstrText = name;
\r
7633 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7635 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7636 MessageBeep(MB_ICONEXCLAMATION);
\r
7639 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7642 sprintf(buf, "%s %s", command, name);
\r
7643 SetWindowText(hInput, buf);
\r
7644 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7646 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7647 SetWindowText(hInput, buf);
\r
7648 sel.cpMin = 999999;
\r
7649 sel.cpMax = 999999;
\r
7650 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7656 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7661 switch (message) {
\r
7663 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7666 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7669 sel.cpMin = 999999;
\r
7670 sel.cpMax = 999999;
\r
7671 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7672 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7677 if (wParam == '\t') {
\r
7678 if (GetKeyState(VK_SHIFT) < 0) {
\r
7680 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7681 if (buttonDesc[0].hwnd) {
\r
7682 SetFocus(buttonDesc[0].hwnd);
\r
7684 SetFocus(hwndMain);
\r
7688 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7691 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7693 SendMessage(hInput, message, wParam, lParam);
\r
7697 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7699 return SendMessage(hInput, message, wParam, lParam);
\r
7700 case WM_MBUTTONDOWN:
\r
7701 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7702 case WM_RBUTTONDOWN:
\r
7703 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7704 /* Move selection here if it was empty */
\r
7706 pt.x = LOWORD(lParam);
\r
7707 pt.y = HIWORD(lParam);
\r
7708 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7709 if (sel.cpMin == sel.cpMax) {
\r
7710 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7711 sel.cpMax = sel.cpMin;
\r
7712 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7714 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7717 case WM_RBUTTONUP:
\r
7718 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7719 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7720 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7723 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7724 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7725 if (sel.cpMin == sel.cpMax) {
\r
7726 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7727 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7729 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7730 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7732 pt.x = LOWORD(lParam);
\r
7733 pt.y = HIWORD(lParam);
\r
7734 MenuPopup(hwnd, pt, hmenu, -1);
\r
7738 switch (LOWORD(wParam)) {
\r
7739 case IDM_QuickPaste:
\r
7741 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7742 if (sel.cpMin == sel.cpMax) {
\r
7743 MessageBeep(MB_ICONEXCLAMATION);
\r
7746 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7747 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7748 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7753 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7756 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7759 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7763 int i = LOWORD(wParam) - IDM_CommandX;
\r
7764 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7765 icsTextMenuEntry[i].command != NULL) {
\r
7766 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7767 icsTextMenuEntry[i].getname,
\r
7768 icsTextMenuEntry[i].immediate);
\r
7776 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7779 WNDPROC consoleInputWindowProc;
\r
7782 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7784 char buf[MSG_SIZ];
\r
7786 static BOOL sendNextChar = FALSE;
\r
7787 static BOOL quoteNextChar = FALSE;
\r
7788 InputSource *is = consoleInputSource;
\r
7792 switch (message) {
\r
7794 if (!appData.localLineEditing || sendNextChar) {
\r
7795 is->buf[0] = (CHAR) wParam;
\r
7797 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7798 sendNextChar = FALSE;
\r
7801 if (quoteNextChar) {
\r
7802 buf[0] = (char) wParam;
\r
7803 buf[1] = NULLCHAR;
\r
7804 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7805 quoteNextChar = FALSE;
\r
7809 case '\r': /* Enter key */
\r
7810 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7811 if (consoleEcho) SaveInHistory(is->buf);
\r
7812 is->buf[is->count++] = '\n';
\r
7813 is->buf[is->count] = NULLCHAR;
\r
7814 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7815 if (consoleEcho) {
\r
7816 ConsoleOutput(is->buf, is->count, TRUE);
\r
7817 } else if (appData.localLineEditing) {
\r
7818 ConsoleOutput("\n", 1, TRUE);
\r
7821 case '\033': /* Escape key */
\r
7822 SetWindowText(hwnd, "");
\r
7823 cf.cbSize = sizeof(CHARFORMAT);
\r
7824 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7825 if (consoleEcho) {
\r
7826 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7828 cf.crTextColor = COLOR_ECHOOFF;
\r
7830 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7831 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7833 case '\t': /* Tab key */
\r
7834 if (GetKeyState(VK_SHIFT) < 0) {
\r
7836 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7839 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7840 if (buttonDesc[0].hwnd) {
\r
7841 SetFocus(buttonDesc[0].hwnd);
\r
7843 SetFocus(hwndMain);
\r
7847 case '\023': /* Ctrl+S */
\r
7848 sendNextChar = TRUE;
\r
7850 case '\021': /* Ctrl+Q */
\r
7851 quoteNextChar = TRUE;
\r
7860 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7861 p = PrevInHistory(buf);
\r
7863 SetWindowText(hwnd, p);
\r
7864 sel.cpMin = 999999;
\r
7865 sel.cpMax = 999999;
\r
7866 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7871 p = NextInHistory();
\r
7873 SetWindowText(hwnd, p);
\r
7874 sel.cpMin = 999999;
\r
7875 sel.cpMax = 999999;
\r
7876 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7882 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7886 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7890 case WM_MBUTTONDOWN:
\r
7891 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7892 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7894 case WM_RBUTTONUP:
\r
7895 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7896 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7897 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7901 hmenu = LoadMenu(hInst, "InputMenu");
\r
7902 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7903 if (sel.cpMin == sel.cpMax) {
\r
7904 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7905 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7907 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7908 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7910 pt.x = LOWORD(lParam);
\r
7911 pt.y = HIWORD(lParam);
\r
7912 MenuPopup(hwnd, pt, hmenu, -1);
\r
7916 switch (LOWORD(wParam)) {
\r
7918 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7920 case IDM_SelectAll:
\r
7922 sel.cpMax = -1; /*999999?*/
\r
7923 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7926 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7929 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7932 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7937 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7940 #define CO_MAX 100000
\r
7941 #define CO_TRIM 1000
\r
7944 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7946 static SnapData sd;
\r
7947 static HWND hText, hInput /*, hFocus*/;
\r
7948 // InputSource *is = consoleInputSource;
\r
7950 static int sizeX, sizeY;
\r
7951 int newSizeX, newSizeY;
\r
7954 switch (message) {
\r
7955 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7956 hwndConsole = hDlg;
\r
7957 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7958 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7960 consoleTextWindowProc = (WNDPROC)
\r
7961 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7962 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7963 consoleInputWindowProc = (WNDPROC)
\r
7964 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7965 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7966 Colorize(ColorNormal, TRUE);
\r
7967 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7968 ChangedConsoleFont();
\r
7969 GetClientRect(hDlg, &rect);
\r
7970 sizeX = rect.right;
\r
7971 sizeY = rect.bottom;
\r
7972 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7973 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7974 WINDOWPLACEMENT wp;
\r
7975 EnsureOnScreen(&consoleX, &consoleY);
\r
7976 wp.length = sizeof(WINDOWPLACEMENT);
\r
7978 wp.showCmd = SW_SHOW;
\r
7979 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7980 wp.rcNormalPosition.left = consoleX;
\r
7981 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7982 wp.rcNormalPosition.top = consoleY;
\r
7983 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7984 SetWindowPlacement(hDlg, &wp);
\r
7987 // [HGM] Chessknight's change 2004-07-13
\r
7988 else { /* Determine Defaults */
\r
7989 WINDOWPLACEMENT wp;
\r
7990 consoleX = winWidth + 1;
\r
7991 consoleY = boardY;
\r
7992 consoleW = screenWidth - winWidth;
\r
7993 consoleH = winHeight;
\r
7994 EnsureOnScreen(&consoleX, &consoleY);
\r
7995 wp.length = sizeof(WINDOWPLACEMENT);
\r
7997 wp.showCmd = SW_SHOW;
\r
7998 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7999 wp.rcNormalPosition.left = consoleX;
\r
8000 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8001 wp.rcNormalPosition.top = consoleY;
\r
8002 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8003 SetWindowPlacement(hDlg, &wp);
\r
8018 if (IsIconic(hDlg)) break;
\r
8019 newSizeX = LOWORD(lParam);
\r
8020 newSizeY = HIWORD(lParam);
\r
8021 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8022 RECT rectText, rectInput;
\r
8024 int newTextHeight, newTextWidth;
\r
8025 GetWindowRect(hText, &rectText);
\r
8026 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8027 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8028 if (newTextHeight < 0) {
\r
8029 newSizeY += -newTextHeight;
\r
8030 newTextHeight = 0;
\r
8032 SetWindowPos(hText, NULL, 0, 0,
\r
8033 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8034 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8035 pt.x = rectInput.left;
\r
8036 pt.y = rectInput.top + newSizeY - sizeY;
\r
8037 ScreenToClient(hDlg, &pt);
\r
8038 SetWindowPos(hInput, NULL,
\r
8039 pt.x, pt.y, /* needs client coords */
\r
8040 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8041 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8047 case WM_GETMINMAXINFO:
\r
8048 /* Prevent resizing window too small */
\r
8049 mmi = (MINMAXINFO *) lParam;
\r
8050 mmi->ptMinTrackSize.x = 100;
\r
8051 mmi->ptMinTrackSize.y = 100;
\r
8054 /* [AS] Snapping */
\r
8055 case WM_ENTERSIZEMOVE:
\r
8056 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8059 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8062 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8064 case WM_EXITSIZEMOVE:
\r
8065 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8068 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8076 if (hwndConsole) return;
\r
8077 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8078 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8083 ConsoleOutput(char* data, int length, int forceVisible)
\r
8088 char buf[CO_MAX+1];
\r
8091 static int delayLF = 0;
\r
8092 CHARRANGE savesel, sel;
\r
8094 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8102 while (length--) {
\r
8110 } else if (*p == '\007') {
\r
8111 MyPlaySound(&sounds[(int)SoundBell]);
\r
8118 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8119 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8120 /* Save current selection */
\r
8121 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8122 exlen = GetWindowTextLength(hText);
\r
8123 /* Find out whether current end of text is visible */
\r
8124 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8125 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8126 /* Trim existing text if it's too long */
\r
8127 if (exlen + (q - buf) > CO_MAX) {
\r
8128 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8131 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8132 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8134 savesel.cpMin -= trim;
\r
8135 savesel.cpMax -= trim;
\r
8136 if (exlen < 0) exlen = 0;
\r
8137 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8138 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8140 /* Append the new text */
\r
8141 sel.cpMin = exlen;
\r
8142 sel.cpMax = exlen;
\r
8143 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8144 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8145 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8146 if (forceVisible || exlen == 0 ||
\r
8147 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8148 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8149 /* Scroll to make new end of text visible if old end of text
\r
8150 was visible or new text is an echo of user typein */
\r
8151 sel.cpMin = 9999999;
\r
8152 sel.cpMax = 9999999;
\r
8153 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8154 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8155 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8156 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8158 if (savesel.cpMax == exlen || forceVisible) {
\r
8159 /* Move insert point to new end of text if it was at the old
\r
8160 end of text or if the new text is an echo of user typein */
\r
8161 sel.cpMin = 9999999;
\r
8162 sel.cpMax = 9999999;
\r
8163 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8165 /* Restore previous selection */
\r
8166 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8168 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8175 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8179 COLORREF oldFg, oldBg;
\r
8183 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8185 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8186 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8187 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8190 rect.right = x + squareSize;
\r
8192 rect.bottom = y + squareSize;
\r
8195 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8196 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8197 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8198 &rect, str, strlen(str), NULL);
\r
8200 (void) SetTextColor(hdc, oldFg);
\r
8201 (void) SetBkColor(hdc, oldBg);
\r
8202 (void) SelectObject(hdc, oldFont);
\r
8206 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8207 RECT *rect, char *color, char *flagFell)
\r
8211 COLORREF oldFg, oldBg;
\r
8214 if (appData.clockMode) {
\r
8216 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8218 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
8225 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8226 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8228 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8229 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8231 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8233 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8234 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8235 rect, str, strlen(str), NULL);
\r
8237 (void) SetTextColor(hdc, oldFg);
\r
8238 (void) SetBkColor(hdc, oldBg);
\r
8239 (void) SelectObject(hdc, oldFont);
\r
8244 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8250 if( count <= 0 ) {
\r
8251 if (appData.debugMode) {
\r
8252 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8255 return ERROR_INVALID_USER_BUFFER;
\r
8258 ResetEvent(ovl->hEvent);
\r
8259 ovl->Offset = ovl->OffsetHigh = 0;
\r
8260 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8264 err = GetLastError();
\r
8265 if (err == ERROR_IO_PENDING) {
\r
8266 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8270 err = GetLastError();
\r
8277 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8282 ResetEvent(ovl->hEvent);
\r
8283 ovl->Offset = ovl->OffsetHigh = 0;
\r
8284 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8288 err = GetLastError();
\r
8289 if (err == ERROR_IO_PENDING) {
\r
8290 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8294 err = GetLastError();
\r
8300 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8301 void CheckForInputBufferFull( InputSource * is )
\r
8303 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8304 /* Look for end of line */
\r
8305 char * p = is->buf;
\r
8307 while( p < is->next && *p != '\n' ) {
\r
8311 if( p >= is->next ) {
\r
8312 if (appData.debugMode) {
\r
8313 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8316 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8317 is->count = (DWORD) -1;
\r
8318 is->next = is->buf;
\r
8324 InputThread(LPVOID arg)
\r
8329 is = (InputSource *) arg;
\r
8330 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8331 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8332 while (is->hThread != NULL) {
\r
8333 is->error = DoReadFile(is->hFile, is->next,
\r
8334 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8335 &is->count, &ovl);
\r
8336 if (is->error == NO_ERROR) {
\r
8337 is->next += is->count;
\r
8339 if (is->error == ERROR_BROKEN_PIPE) {
\r
8340 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8343 is->count = (DWORD) -1;
\r
8344 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8349 CheckForInputBufferFull( is );
\r
8351 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8353 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8355 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8358 CloseHandle(ovl.hEvent);
\r
8359 CloseHandle(is->hFile);
\r
8361 if (appData.debugMode) {
\r
8362 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8369 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8371 NonOvlInputThread(LPVOID arg)
\r
8378 is = (InputSource *) arg;
\r
8379 while (is->hThread != NULL) {
\r
8380 is->error = ReadFile(is->hFile, is->next,
\r
8381 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8382 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8383 if (is->error == NO_ERROR) {
\r
8384 /* Change CRLF to LF */
\r
8385 if (is->next > is->buf) {
\r
8387 i = is->count + 1;
\r
8395 if (prev == '\r' && *p == '\n') {
\r
8407 if (is->error == ERROR_BROKEN_PIPE) {
\r
8408 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8411 is->count = (DWORD) -1;
\r
8415 CheckForInputBufferFull( is );
\r
8417 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8419 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8421 if (is->count < 0) break; /* Quit on error */
\r
8423 CloseHandle(is->hFile);
\r
8428 SocketInputThread(LPVOID arg)
\r
8432 is = (InputSource *) arg;
\r
8433 while (is->hThread != NULL) {
\r
8434 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8435 if ((int)is->count == SOCKET_ERROR) {
\r
8436 is->count = (DWORD) -1;
\r
8437 is->error = WSAGetLastError();
\r
8439 is->error = NO_ERROR;
\r
8440 is->next += is->count;
\r
8441 if (is->count == 0 && is->second == is) {
\r
8442 /* End of file on stderr; quit with no message */
\r
8446 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8448 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8450 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8456 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8460 is = (InputSource *) lParam;
\r
8461 if (is->lineByLine) {
\r
8462 /* Feed in lines one by one */
\r
8463 char *p = is->buf;
\r
8465 while (q < is->next) {
\r
8466 if (*q++ == '\n') {
\r
8467 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8472 /* Move any partial line to the start of the buffer */
\r
8474 while (p < is->next) {
\r
8479 if (is->error != NO_ERROR || is->count == 0) {
\r
8480 /* Notify backend of the error. Note: If there was a partial
\r
8481 line at the end, it is not flushed through. */
\r
8482 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8485 /* Feed in the whole chunk of input at once */
\r
8486 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8487 is->next = is->buf;
\r
8491 /*---------------------------------------------------------------------------*\
\r
8493 * Menu enables. Used when setting various modes.
\r
8495 \*---------------------------------------------------------------------------*/
\r
8503 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8505 while (enab->item > 0) {
\r
8506 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8511 Enables gnuEnables[] = {
\r
8512 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8513 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8514 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8515 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8516 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8517 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8518 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8519 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8520 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8521 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8525 Enables icsEnables[] = {
\r
8526 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8527 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8528 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8529 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8530 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8531 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8532 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8533 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8534 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8535 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8536 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8537 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8542 Enables zippyEnables[] = {
\r
8543 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8544 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8545 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8550 Enables ncpEnables[] = {
\r
8551 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8552 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8553 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8554 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8555 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8556 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8557 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8558 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8559 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8560 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8561 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8562 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8563 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8564 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8565 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8569 Enables trainingOnEnables[] = {
\r
8570 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8571 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8572 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8573 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8574 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8575 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8576 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8577 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8581 Enables trainingOffEnables[] = {
\r
8582 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8583 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8584 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8585 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8586 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8587 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8588 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8589 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8593 /* These modify either ncpEnables or gnuEnables */
\r
8594 Enables cmailEnables[] = {
\r
8595 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8596 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8597 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8598 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8599 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8600 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8601 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8605 Enables machineThinkingEnables[] = {
\r
8606 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8607 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8608 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8609 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8610 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8611 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8612 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8613 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8614 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8615 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8616 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8617 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8618 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8619 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8620 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8624 Enables userThinkingEnables[] = {
\r
8625 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8626 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8627 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8628 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8629 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8630 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8631 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8632 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8633 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8634 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8635 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8636 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8637 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8638 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8639 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8643 /*---------------------------------------------------------------------------*\
\r
8645 * Front-end interface functions exported by XBoard.
\r
8646 * Functions appear in same order as prototypes in frontend.h.
\r
8648 \*---------------------------------------------------------------------------*/
\r
8652 static UINT prevChecked = 0;
\r
8653 static int prevPausing = 0;
\r
8656 if (pausing != prevPausing) {
\r
8657 prevPausing = pausing;
\r
8658 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8659 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8660 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8663 switch (gameMode) {
\r
8664 case BeginningOfGame:
\r
8665 if (appData.icsActive)
\r
8666 nowChecked = IDM_IcsClient;
\r
8667 else if (appData.noChessProgram)
\r
8668 nowChecked = IDM_EditGame;
\r
8670 nowChecked = IDM_MachineBlack;
\r
8672 case MachinePlaysBlack:
\r
8673 nowChecked = IDM_MachineBlack;
\r
8675 case MachinePlaysWhite:
\r
8676 nowChecked = IDM_MachineWhite;
\r
8678 case TwoMachinesPlay:
\r
8679 nowChecked = IDM_TwoMachines;
\r
8682 nowChecked = IDM_AnalysisMode;
\r
8685 nowChecked = IDM_AnalyzeFile;
\r
8688 nowChecked = IDM_EditGame;
\r
8690 case PlayFromGameFile:
\r
8691 nowChecked = IDM_LoadGame;
\r
8693 case EditPosition:
\r
8694 nowChecked = IDM_EditPosition;
\r
8697 nowChecked = IDM_Training;
\r
8699 case IcsPlayingWhite:
\r
8700 case IcsPlayingBlack:
\r
8701 case IcsObserving:
\r
8703 nowChecked = IDM_IcsClient;
\r
8710 if (prevChecked != 0)
\r
8711 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8712 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8713 if (nowChecked != 0)
\r
8714 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8715 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8717 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8718 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8719 MF_BYCOMMAND|MF_ENABLED);
\r
8721 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8722 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8725 prevChecked = nowChecked;
\r
8727 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8728 if (appData.icsActive) {
\r
8729 if (appData.icsEngineAnalyze) {
\r
8730 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8731 MF_BYCOMMAND|MF_CHECKED);
\r
8733 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8734 MF_BYCOMMAND|MF_UNCHECKED);
\r
8742 HMENU hmenu = GetMenu(hwndMain);
\r
8743 SetMenuEnables(hmenu, icsEnables);
\r
8744 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8745 MF_BYPOSITION|MF_ENABLED);
\r
8747 if (appData.zippyPlay) {
\r
8748 SetMenuEnables(hmenu, zippyEnables);
\r
8749 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8750 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8751 MF_BYCOMMAND|MF_ENABLED);
\r
8759 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8765 HMENU hmenu = GetMenu(hwndMain);
\r
8766 SetMenuEnables(hmenu, ncpEnables);
\r
8767 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8768 MF_BYPOSITION|MF_GRAYED);
\r
8769 DrawMenuBar(hwndMain);
\r
8775 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8779 SetTrainingModeOn()
\r
8782 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8783 for (i = 0; i < N_BUTTONS; i++) {
\r
8784 if (buttonDesc[i].hwnd != NULL)
\r
8785 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8790 VOID SetTrainingModeOff()
\r
8793 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8794 for (i = 0; i < N_BUTTONS; i++) {
\r
8795 if (buttonDesc[i].hwnd != NULL)
\r
8796 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8802 SetUserThinkingEnables()
\r
8804 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8808 SetMachineThinkingEnables()
\r
8810 HMENU hMenu = GetMenu(hwndMain);
\r
8811 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8813 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8815 if (gameMode == MachinePlaysBlack) {
\r
8816 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8817 } else if (gameMode == MachinePlaysWhite) {
\r
8818 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8819 } else if (gameMode == TwoMachinesPlay) {
\r
8820 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8826 DisplayTitle(char *str)
\r
8828 char title[MSG_SIZ], *host;
\r
8829 if (str[0] != NULLCHAR) {
\r
8830 strcpy(title, str);
\r
8831 } else if (appData.icsActive) {
\r
8832 if (appData.icsCommPort[0] != NULLCHAR)
\r
8835 host = appData.icsHost;
\r
8836 sprintf(title, "%s: %s", szTitle, host);
\r
8837 } else if (appData.noChessProgram) {
\r
8838 strcpy(title, szTitle);
\r
8840 strcpy(title, szTitle);
\r
8841 strcat(title, ": ");
\r
8842 strcat(title, first.tidy);
\r
8844 SetWindowText(hwndMain, title);
\r
8849 DisplayMessage(char *str1, char *str2)
\r
8853 int remain = MESSAGE_TEXT_MAX - 1;
\r
8856 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8857 messageText[0] = NULLCHAR;
\r
8859 len = strlen(str1);
\r
8860 if (len > remain) len = remain;
\r
8861 strncpy(messageText, str1, len);
\r
8862 messageText[len] = NULLCHAR;
\r
8865 if (*str2 && remain >= 2) {
\r
8867 strcat(messageText, " ");
\r
8870 len = strlen(str2);
\r
8871 if (len > remain) len = remain;
\r
8872 strncat(messageText, str2, len);
\r
8874 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8876 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8877 hdc = GetDC(hwndMain);
\r
8878 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8879 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8880 &messageRect, messageText, strlen(messageText), NULL);
\r
8881 (void) SelectObject(hdc, oldFont);
\r
8882 (void) ReleaseDC(hwndMain, hdc);
\r
8886 DisplayError(char *str, int error)
\r
8888 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8894 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8895 NULL, error, LANG_NEUTRAL,
\r
8896 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8898 sprintf(buf, "%s:\n%s", str, buf2);
\r
8900 ErrorMap *em = errmap;
\r
8901 while (em->err != 0 && em->err != error) em++;
\r
8902 if (em->err != 0) {
\r
8903 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8905 sprintf(buf, "%s:\nError code %d", str, error);
\r
8910 ErrorPopUp("Error", buf);
\r
8915 DisplayMoveError(char *str)
\r
8917 fromX = fromY = -1;
\r
8918 ClearHighlights();
\r
8919 DrawPosition(FALSE, NULL);
\r
8920 if (appData.popupMoveErrors) {
\r
8921 ErrorPopUp("Error", str);
\r
8923 DisplayMessage(str, "");
\r
8924 moveErrorMessageUp = TRUE;
\r
8929 DisplayFatalError(char *str, int error, int exitStatus)
\r
8931 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8933 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8936 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8937 NULL, error, LANG_NEUTRAL,
\r
8938 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8940 sprintf(buf, "%s:\n%s", str, buf2);
\r
8942 ErrorMap *em = errmap;
\r
8943 while (em->err != 0 && em->err != error) em++;
\r
8944 if (em->err != 0) {
\r
8945 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8947 sprintf(buf, "%s:\nError code %d", str, error);
\r
8952 if (appData.debugMode) {
\r
8953 fprintf(debugFP, "%s: %s\n", label, str);
\r
8955 if (appData.popupExitMessage) {
\r
8956 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8957 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8959 ExitEvent(exitStatus);
\r
8964 DisplayInformation(char *str)
\r
8966 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8971 DisplayNote(char *str)
\r
8973 ErrorPopUp("Note", str);
\r
8978 char *title, *question, *replyPrefix;
\r
8983 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8985 static QuestionParams *qp;
\r
8986 char reply[MSG_SIZ];
\r
8989 switch (message) {
\r
8990 case WM_INITDIALOG:
\r
8991 qp = (QuestionParams *) lParam;
\r
8992 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8993 SetWindowText(hDlg, qp->title);
\r
8994 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8995 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8999 switch (LOWORD(wParam)) {
\r
9001 strcpy(reply, qp->replyPrefix);
\r
9002 if (*reply) strcat(reply, " ");
\r
9003 len = strlen(reply);
\r
9004 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9005 strcat(reply, "\n");
\r
9006 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9007 EndDialog(hDlg, TRUE);
\r
9008 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9011 EndDialog(hDlg, FALSE);
\r
9022 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9024 QuestionParams qp;
\r
9028 qp.question = question;
\r
9029 qp.replyPrefix = replyPrefix;
\r
9031 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9032 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9033 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9034 FreeProcInstance(lpProc);
\r
9037 /* [AS] Pick FRC position */
\r
9038 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9040 static int * lpIndexFRC;
\r
9046 case WM_INITDIALOG:
\r
9047 lpIndexFRC = (int *) lParam;
\r
9049 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9051 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9052 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9053 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9054 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9059 switch( LOWORD(wParam) ) {
\r
9061 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9062 EndDialog( hDlg, 0 );
\r
9063 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9066 EndDialog( hDlg, 1 );
\r
9068 case IDC_NFG_Edit:
\r
9069 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9070 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9072 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9075 case IDC_NFG_Random:
\r
9076 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9077 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9090 int index = appData.defaultFrcPosition;
\r
9091 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9093 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9095 if( result == 0 ) {
\r
9096 appData.defaultFrcPosition = index;
\r
9102 /* [AS] Game list options */
\r
9108 static GLT_Item GLT_ItemInfo[] = {
\r
9109 { GLT_EVENT, "Event" },
\r
9110 { GLT_SITE, "Site" },
\r
9111 { GLT_DATE, "Date" },
\r
9112 { GLT_ROUND, "Round" },
\r
9113 { GLT_PLAYERS, "Players" },
\r
9114 { GLT_RESULT, "Result" },
\r
9115 { GLT_WHITE_ELO, "White Rating" },
\r
9116 { GLT_BLACK_ELO, "Black Rating" },
\r
9117 { GLT_TIME_CONTROL,"Time Control" },
\r
9118 { GLT_VARIANT, "Variant" },
\r
9119 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9123 const char * GLT_FindItem( char id )
\r
9125 const char * result = 0;
\r
9127 GLT_Item * list = GLT_ItemInfo;
\r
9129 while( list->id != 0 ) {
\r
9130 if( list->id == id ) {
\r
9131 result = list->name;
\r
9141 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9143 const char * name = GLT_FindItem( id );
\r
9146 if( index >= 0 ) {
\r
9147 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9150 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9155 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9159 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9162 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9166 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9168 pc = GLT_ALL_TAGS;
\r
9171 if( strchr( tags, *pc ) == 0 ) {
\r
9172 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9177 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9180 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9182 char result = '\0';
\r
9185 GLT_Item * list = GLT_ItemInfo;
\r
9187 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9188 while( list->id != 0 ) {
\r
9189 if( strcmp( list->name, name ) == 0 ) {
\r
9190 result = list->id;
\r
9201 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9203 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9204 int idx2 = idx1 + delta;
\r
9205 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9207 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9210 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9211 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9212 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9213 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9217 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9219 static char glt[64];
\r
9220 static char * lpUserGLT;
\r
9224 case WM_INITDIALOG:
\r
9225 lpUserGLT = (char *) lParam;
\r
9227 strcpy( glt, lpUserGLT );
\r
9229 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9231 /* Initialize list */
\r
9232 GLT_TagsToList( hDlg, glt );
\r
9234 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9239 switch( LOWORD(wParam) ) {
\r
9242 char * pc = lpUserGLT;
\r
9244 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9248 id = GLT_ListItemToTag( hDlg, idx );
\r
9252 } while( id != '\0' );
\r
9254 EndDialog( hDlg, 0 );
\r
9257 EndDialog( hDlg, 1 );
\r
9260 case IDC_GLT_Default:
\r
9261 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9262 GLT_TagsToList( hDlg, glt );
\r
9265 case IDC_GLT_Restore:
\r
9266 strcpy( glt, lpUserGLT );
\r
9267 GLT_TagsToList( hDlg, glt );
\r
9271 GLT_MoveSelection( hDlg, -1 );
\r
9274 case IDC_GLT_Down:
\r
9275 GLT_MoveSelection( hDlg, +1 );
\r
9285 int GameListOptions()
\r
9289 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9291 strcpy( glt, appData.gameListTags );
\r
9293 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9295 if( result == 0 ) {
\r
9296 /* [AS] Memory leak here! */
\r
9297 appData.gameListTags = strdup( glt );
\r
9305 DisplayIcsInteractionTitle(char *str)
\r
9307 char consoleTitle[MSG_SIZ];
\r
9309 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9310 SetWindowText(hwndConsole, consoleTitle);
\r
9314 DrawPosition(int fullRedraw, Board board)
\r
9316 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9323 fromX = fromY = -1;
\r
9324 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9325 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9326 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9327 dragInfo.lastpos = dragInfo.pos;
\r
9328 dragInfo.start.x = dragInfo.start.y = -1;
\r
9329 dragInfo.from = dragInfo.start;
\r
9331 DrawPosition(TRUE, NULL);
\r
9337 CommentPopUp(char *title, char *str)
\r
9339 HWND hwnd = GetActiveWindow();
\r
9340 EitherCommentPopUp(0, title, str, FALSE);
\r
9341 SetActiveWindow(hwnd);
\r
9345 CommentPopDown(void)
\r
9347 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9348 if (commentDialog) {
\r
9349 ShowWindow(commentDialog, SW_HIDE);
\r
9351 commentDialogUp = FALSE;
\r
9355 EditCommentPopUp(int index, char *title, char *str)
\r
9357 EitherCommentPopUp(index, title, str, TRUE);
\r
9364 MyPlaySound(&sounds[(int)SoundMove]);
\r
9367 VOID PlayIcsWinSound()
\r
9369 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9372 VOID PlayIcsLossSound()
\r
9374 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9377 VOID PlayIcsDrawSound()
\r
9379 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9382 VOID PlayIcsUnfinishedSound()
\r
9384 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9390 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9398 consoleEcho = TRUE;
\r
9399 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9400 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9401 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9410 consoleEcho = FALSE;
\r
9411 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9412 /* This works OK: set text and background both to the same color */
\r
9414 cf.crTextColor = COLOR_ECHOOFF;
\r
9415 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9416 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9419 /* No Raw()...? */
\r
9421 void Colorize(ColorClass cc, int continuation)
\r
9423 currentColorClass = cc;
\r
9424 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9425 consoleCF.crTextColor = textAttribs[cc].color;
\r
9426 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9427 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9433 static char buf[MSG_SIZ];
\r
9434 DWORD bufsiz = MSG_SIZ;
\r
9436 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9437 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9439 if (!GetUserName(buf, &bufsiz)) {
\r
9440 /*DisplayError("Error getting user name", GetLastError());*/
\r
9441 strcpy(buf, "User");
\r
9449 static char buf[MSG_SIZ];
\r
9450 DWORD bufsiz = MSG_SIZ;
\r
9452 if (!GetComputerName(buf, &bufsiz)) {
\r
9453 /*DisplayError("Error getting host name", GetLastError());*/
\r
9454 strcpy(buf, "Unknown");
\r
9461 ClockTimerRunning()
\r
9463 return clockTimerEvent != 0;
\r
9469 if (clockTimerEvent == 0) return FALSE;
\r
9470 KillTimer(hwndMain, clockTimerEvent);
\r
9471 clockTimerEvent = 0;
\r
9476 StartClockTimer(long millisec)
\r
9478 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9479 (UINT) millisec, NULL);
\r
9483 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9486 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9488 if(appData.noGUI) return;
\r
9489 hdc = GetDC(hwndMain);
\r
9490 if (!IsIconic(hwndMain)) {
\r
9491 DisplayAClock(hdc, timeRemaining, highlight,
\r
9492 (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);
\r
9494 if (highlight && iconCurrent == iconBlack) {
\r
9495 iconCurrent = iconWhite;
\r
9496 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9497 if (IsIconic(hwndMain)) {
\r
9498 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9501 (void) ReleaseDC(hwndMain, hdc);
\r
9503 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9507 DisplayBlackClock(long timeRemaining, int highlight)
\r
9510 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9512 if(appData.noGUI) return;
\r
9513 hdc = GetDC(hwndMain);
\r
9514 if (!IsIconic(hwndMain)) {
\r
9515 DisplayAClock(hdc, timeRemaining, highlight,
\r
9516 (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);
\r
9518 if (highlight && iconCurrent == iconWhite) {
\r
9519 iconCurrent = iconBlack;
\r
9520 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9521 if (IsIconic(hwndMain)) {
\r
9522 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9525 (void) ReleaseDC(hwndMain, hdc);
\r
9527 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9532 LoadGameTimerRunning()
\r
9534 return loadGameTimerEvent != 0;
\r
9538 StopLoadGameTimer()
\r
9540 if (loadGameTimerEvent == 0) return FALSE;
\r
9541 KillTimer(hwndMain, loadGameTimerEvent);
\r
9542 loadGameTimerEvent = 0;
\r
9547 StartLoadGameTimer(long millisec)
\r
9549 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9550 (UINT) millisec, NULL);
\r
9558 char fileTitle[MSG_SIZ];
\r
9560 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9561 f = OpenFileDialog(hwndMain, "a", defName,
\r
9562 appData.oldSaveStyle ? "gam" : "pgn",
\r
9564 "Save Game to File", NULL, fileTitle, NULL);
\r
9566 SaveGame(f, 0, "");
\r
9573 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9575 if (delayedTimerEvent != 0) {
\r
9576 if (appData.debugMode) {
\r
9577 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9579 KillTimer(hwndMain, delayedTimerEvent);
\r
9580 delayedTimerEvent = 0;
\r
9581 delayedTimerCallback();
\r
9583 delayedTimerCallback = cb;
\r
9584 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9585 (UINT) millisec, NULL);
\r
9588 DelayedEventCallback
\r
9591 if (delayedTimerEvent) {
\r
9592 return delayedTimerCallback;
\r
9599 CancelDelayedEvent()
\r
9601 if (delayedTimerEvent) {
\r
9602 KillTimer(hwndMain, delayedTimerEvent);
\r
9603 delayedTimerEvent = 0;
\r
9607 DWORD GetWin32Priority(int nice)
\r
9608 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9610 REALTIME_PRIORITY_CLASS 0x00000100
\r
9611 HIGH_PRIORITY_CLASS 0x00000080
\r
9612 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9613 NORMAL_PRIORITY_CLASS 0x00000020
\r
9614 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9615 IDLE_PRIORITY_CLASS 0x00000040
\r
9617 if (nice < -15) return 0x00000080;
\r
9618 if (nice < 0) return 0x00008000;
\r
9619 if (nice == 0) return 0x00000020;
\r
9620 if (nice < 15) return 0x00004000;
\r
9621 return 0x00000040;
\r
9624 /* Start a child process running the given program.
\r
9625 The process's standard output can be read from "from", and its
\r
9626 standard input can be written to "to".
\r
9627 Exit with fatal error if anything goes wrong.
\r
9628 Returns an opaque pointer that can be used to destroy the process
\r
9632 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9634 #define BUFSIZE 4096
\r
9636 HANDLE hChildStdinRd, hChildStdinWr,
\r
9637 hChildStdoutRd, hChildStdoutWr;
\r
9638 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9639 SECURITY_ATTRIBUTES saAttr;
\r
9641 PROCESS_INFORMATION piProcInfo;
\r
9642 STARTUPINFO siStartInfo;
\r
9644 char buf[MSG_SIZ];
\r
9647 if (appData.debugMode) {
\r
9648 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9653 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9654 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9655 saAttr.bInheritHandle = TRUE;
\r
9656 saAttr.lpSecurityDescriptor = NULL;
\r
9659 * The steps for redirecting child's STDOUT:
\r
9660 * 1. Create anonymous pipe to be STDOUT for child.
\r
9661 * 2. Create a noninheritable duplicate of read handle,
\r
9662 * and close the inheritable read handle.
\r
9665 /* Create a pipe for the child's STDOUT. */
\r
9666 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9667 return GetLastError();
\r
9670 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9671 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9672 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9673 FALSE, /* not inherited */
\r
9674 DUPLICATE_SAME_ACCESS);
\r
9676 return GetLastError();
\r
9678 CloseHandle(hChildStdoutRd);
\r
9681 * The steps for redirecting child's STDIN:
\r
9682 * 1. Create anonymous pipe to be STDIN for child.
\r
9683 * 2. Create a noninheritable duplicate of write handle,
\r
9684 * and close the inheritable write handle.
\r
9687 /* Create a pipe for the child's STDIN. */
\r
9688 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9689 return GetLastError();
\r
9692 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9693 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9694 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9695 FALSE, /* not inherited */
\r
9696 DUPLICATE_SAME_ACCESS);
\r
9698 return GetLastError();
\r
9700 CloseHandle(hChildStdinWr);
\r
9702 /* Arrange to (1) look in dir for the child .exe file, and
\r
9703 * (2) have dir be the child's working directory. Interpret
\r
9704 * dir relative to the directory WinBoard loaded from. */
\r
9705 GetCurrentDirectory(MSG_SIZ, buf);
\r
9706 SetCurrentDirectory(installDir);
\r
9707 SetCurrentDirectory(dir);
\r
9709 /* Now create the child process. */
\r
9711 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9712 siStartInfo.lpReserved = NULL;
\r
9713 siStartInfo.lpDesktop = NULL;
\r
9714 siStartInfo.lpTitle = NULL;
\r
9715 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9716 siStartInfo.cbReserved2 = 0;
\r
9717 siStartInfo.lpReserved2 = NULL;
\r
9718 siStartInfo.hStdInput = hChildStdinRd;
\r
9719 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9720 siStartInfo.hStdError = hChildStdoutWr;
\r
9722 fSuccess = CreateProcess(NULL,
\r
9723 cmdLine, /* command line */
\r
9724 NULL, /* process security attributes */
\r
9725 NULL, /* primary thread security attrs */
\r
9726 TRUE, /* handles are inherited */
\r
9727 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9728 NULL, /* use parent's environment */
\r
9730 &siStartInfo, /* STARTUPINFO pointer */
\r
9731 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9733 err = GetLastError();
\r
9734 SetCurrentDirectory(buf); /* return to prev directory */
\r
9739 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9740 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9741 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9744 /* Close the handles we don't need in the parent */
\r
9745 CloseHandle(piProcInfo.hThread);
\r
9746 CloseHandle(hChildStdinRd);
\r
9747 CloseHandle(hChildStdoutWr);
\r
9749 /* Prepare return value */
\r
9750 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9751 cp->kind = CPReal;
\r
9752 cp->hProcess = piProcInfo.hProcess;
\r
9753 cp->pid = piProcInfo.dwProcessId;
\r
9754 cp->hFrom = hChildStdoutRdDup;
\r
9755 cp->hTo = hChildStdinWrDup;
\r
9757 *pr = (void *) cp;
\r
9759 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9760 2000 where engines sometimes don't see the initial command(s)
\r
9761 from WinBoard and hang. I don't understand how that can happen,
\r
9762 but the Sleep is harmless, so I've put it in. Others have also
\r
9763 reported what may be the same problem, so hopefully this will fix
\r
9764 it for them too. */
\r
9772 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9774 ChildProc *cp; int result;
\r
9776 cp = (ChildProc *) pr;
\r
9777 if (cp == NULL) return;
\r
9779 switch (cp->kind) {
\r
9781 /* TerminateProcess is considered harmful, so... */
\r
9782 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9783 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9784 /* The following doesn't work because the chess program
\r
9785 doesn't "have the same console" as WinBoard. Maybe
\r
9786 we could arrange for this even though neither WinBoard
\r
9787 nor the chess program uses a console for stdio? */
\r
9788 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9790 /* [AS] Special termination modes for misbehaving programs... */
\r
9791 if( signal == 9 ) {
\r
9792 result = TerminateProcess( cp->hProcess, 0 );
\r
9794 if ( appData.debugMode) {
\r
9795 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9798 else if( signal == 10 ) {
\r
9799 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9801 if( dw != WAIT_OBJECT_0 ) {
\r
9802 result = TerminateProcess( cp->hProcess, 0 );
\r
9804 if ( appData.debugMode) {
\r
9805 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9811 CloseHandle(cp->hProcess);
\r
9815 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9819 closesocket(cp->sock);
\r
9824 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9825 closesocket(cp->sock);
\r
9826 closesocket(cp->sock2);
\r
9834 InterruptChildProcess(ProcRef pr)
\r
9838 cp = (ChildProc *) pr;
\r
9839 if (cp == NULL) return;
\r
9840 switch (cp->kind) {
\r
9842 /* The following doesn't work because the chess program
\r
9843 doesn't "have the same console" as WinBoard. Maybe
\r
9844 we could arrange for this even though neither WinBoard
\r
9845 nor the chess program uses a console for stdio */
\r
9846 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9851 /* Can't interrupt */
\r
9855 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9862 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9864 char cmdLine[MSG_SIZ];
\r
9866 if (port[0] == NULLCHAR) {
\r
9867 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9869 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9871 return StartChildProcess(cmdLine, "", pr);
\r
9875 /* Code to open TCP sockets */
\r
9878 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9883 struct sockaddr_in sa, mysa;
\r
9884 struct hostent FAR *hp;
\r
9885 unsigned short uport;
\r
9886 WORD wVersionRequested;
\r
9889 /* Initialize socket DLL */
\r
9890 wVersionRequested = MAKEWORD(1, 1);
\r
9891 err = WSAStartup(wVersionRequested, &wsaData);
\r
9892 if (err != 0) return err;
\r
9895 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9896 err = WSAGetLastError();
\r
9901 /* Bind local address using (mostly) don't-care values.
\r
9903 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9904 mysa.sin_family = AF_INET;
\r
9905 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9906 uport = (unsigned short) 0;
\r
9907 mysa.sin_port = htons(uport);
\r
9908 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9909 == SOCKET_ERROR) {
\r
9910 err = WSAGetLastError();
\r
9915 /* Resolve remote host name */
\r
9916 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9917 if (!(hp = gethostbyname(host))) {
\r
9918 unsigned int b0, b1, b2, b3;
\r
9920 err = WSAGetLastError();
\r
9922 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9923 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9924 hp->h_addrtype = AF_INET;
\r
9926 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9927 hp->h_addr_list[0] = (char *) malloc(4);
\r
9928 hp->h_addr_list[0][0] = (char) b0;
\r
9929 hp->h_addr_list[0][1] = (char) b1;
\r
9930 hp->h_addr_list[0][2] = (char) b2;
\r
9931 hp->h_addr_list[0][3] = (char) b3;
\r
9937 sa.sin_family = hp->h_addrtype;
\r
9938 uport = (unsigned short) atoi(port);
\r
9939 sa.sin_port = htons(uport);
\r
9940 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9942 /* Make connection */
\r
9943 if (connect(s, (struct sockaddr *) &sa,
\r
9944 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9945 err = WSAGetLastError();
\r
9950 /* Prepare return value */
\r
9951 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9952 cp->kind = CPSock;
\r
9954 *pr = (ProcRef *) cp;
\r
9960 OpenCommPort(char *name, ProcRef *pr)
\r
9965 char fullname[MSG_SIZ];
\r
9967 if (*name != '\\')
\r
9968 sprintf(fullname, "\\\\.\\%s", name);
\r
9970 strcpy(fullname, name);
\r
9972 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9973 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9974 if (h == (HANDLE) -1) {
\r
9975 return GetLastError();
\r
9979 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9981 /* Accumulate characters until a 100ms pause, then parse */
\r
9982 ct.ReadIntervalTimeout = 100;
\r
9983 ct.ReadTotalTimeoutMultiplier = 0;
\r
9984 ct.ReadTotalTimeoutConstant = 0;
\r
9985 ct.WriteTotalTimeoutMultiplier = 0;
\r
9986 ct.WriteTotalTimeoutConstant = 0;
\r
9987 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9989 /* Prepare return value */
\r
9990 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9991 cp->kind = CPComm;
\r
9994 *pr = (ProcRef *) cp;
\r
10000 OpenLoopback(ProcRef *pr)
\r
10002 DisplayFatalError("Not implemented", 0, 1);
\r
10008 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10012 SOCKET s, s2, s3;
\r
10013 struct sockaddr_in sa, mysa;
\r
10014 struct hostent FAR *hp;
\r
10015 unsigned short uport;
\r
10016 WORD wVersionRequested;
\r
10019 char stderrPortStr[MSG_SIZ];
\r
10021 /* Initialize socket DLL */
\r
10022 wVersionRequested = MAKEWORD(1, 1);
\r
10023 err = WSAStartup(wVersionRequested, &wsaData);
\r
10024 if (err != 0) return err;
\r
10026 /* Resolve remote host name */
\r
10027 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10028 if (!(hp = gethostbyname(host))) {
\r
10029 unsigned int b0, b1, b2, b3;
\r
10031 err = WSAGetLastError();
\r
10033 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10034 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10035 hp->h_addrtype = AF_INET;
\r
10036 hp->h_length = 4;
\r
10037 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10038 hp->h_addr_list[0] = (char *) malloc(4);
\r
10039 hp->h_addr_list[0][0] = (char) b0;
\r
10040 hp->h_addr_list[0][1] = (char) b1;
\r
10041 hp->h_addr_list[0][2] = (char) b2;
\r
10042 hp->h_addr_list[0][3] = (char) b3;
\r
10048 sa.sin_family = hp->h_addrtype;
\r
10049 uport = (unsigned short) 514;
\r
10050 sa.sin_port = htons(uport);
\r
10051 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10053 /* Bind local socket to unused "privileged" port address
\r
10055 s = INVALID_SOCKET;
\r
10056 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10057 mysa.sin_family = AF_INET;
\r
10058 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10059 for (fromPort = 1023;; fromPort--) {
\r
10060 if (fromPort < 0) {
\r
10062 return WSAEADDRINUSE;
\r
10064 if (s == INVALID_SOCKET) {
\r
10065 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10066 err = WSAGetLastError();
\r
10071 uport = (unsigned short) fromPort;
\r
10072 mysa.sin_port = htons(uport);
\r
10073 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10074 == SOCKET_ERROR) {
\r
10075 err = WSAGetLastError();
\r
10076 if (err == WSAEADDRINUSE) continue;
\r
10080 if (connect(s, (struct sockaddr *) &sa,
\r
10081 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10082 err = WSAGetLastError();
\r
10083 if (err == WSAEADDRINUSE) {
\r
10094 /* Bind stderr local socket to unused "privileged" port address
\r
10096 s2 = INVALID_SOCKET;
\r
10097 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10098 mysa.sin_family = AF_INET;
\r
10099 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10100 for (fromPort = 1023;; fromPort--) {
\r
10101 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10102 if (fromPort < 0) {
\r
10103 (void) closesocket(s);
\r
10105 return WSAEADDRINUSE;
\r
10107 if (s2 == INVALID_SOCKET) {
\r
10108 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10109 err = WSAGetLastError();
\r
10115 uport = (unsigned short) fromPort;
\r
10116 mysa.sin_port = htons(uport);
\r
10117 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10118 == SOCKET_ERROR) {
\r
10119 err = WSAGetLastError();
\r
10120 if (err == WSAEADDRINUSE) continue;
\r
10121 (void) closesocket(s);
\r
10125 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10126 err = WSAGetLastError();
\r
10127 if (err == WSAEADDRINUSE) {
\r
10129 s2 = INVALID_SOCKET;
\r
10132 (void) closesocket(s);
\r
10133 (void) closesocket(s2);
\r
10139 prevStderrPort = fromPort; // remember port used
\r
10140 sprintf(stderrPortStr, "%d", fromPort);
\r
10142 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10143 err = WSAGetLastError();
\r
10144 (void) closesocket(s);
\r
10145 (void) closesocket(s2);
\r
10150 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10151 err = WSAGetLastError();
\r
10152 (void) closesocket(s);
\r
10153 (void) closesocket(s2);
\r
10157 if (*user == NULLCHAR) user = UserName();
\r
10158 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10159 err = WSAGetLastError();
\r
10160 (void) closesocket(s);
\r
10161 (void) closesocket(s2);
\r
10165 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10166 err = WSAGetLastError();
\r
10167 (void) closesocket(s);
\r
10168 (void) closesocket(s2);
\r
10173 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10174 err = WSAGetLastError();
\r
10175 (void) closesocket(s);
\r
10176 (void) closesocket(s2);
\r
10180 (void) closesocket(s2); /* Stop listening */
\r
10182 /* Prepare return value */
\r
10183 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10184 cp->kind = CPRcmd;
\r
10187 *pr = (ProcRef *) cp;
\r
10194 AddInputSource(ProcRef pr, int lineByLine,
\r
10195 InputCallback func, VOIDSTAR closure)
\r
10197 InputSource *is, *is2 = NULL;
\r
10198 ChildProc *cp = (ChildProc *) pr;
\r
10200 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10201 is->lineByLine = lineByLine;
\r
10203 is->closure = closure;
\r
10204 is->second = NULL;
\r
10205 is->next = is->buf;
\r
10206 if (pr == NoProc) {
\r
10207 is->kind = CPReal;
\r
10208 consoleInputSource = is;
\r
10210 is->kind = cp->kind;
\r
10212 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10213 we create all threads suspended so that the is->hThread variable can be
\r
10214 safely assigned, then let the threads start with ResumeThread.
\r
10216 switch (cp->kind) {
\r
10218 is->hFile = cp->hFrom;
\r
10219 cp->hFrom = NULL; /* now owned by InputThread */
\r
10221 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10222 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10226 is->hFile = cp->hFrom;
\r
10227 cp->hFrom = NULL; /* now owned by InputThread */
\r
10229 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10230 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10234 is->sock = cp->sock;
\r
10236 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10237 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10241 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10243 is->sock = cp->sock;
\r
10244 is->second = is2;
\r
10245 is2->sock = cp->sock2;
\r
10246 is2->second = is2;
\r
10248 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10249 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10251 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10252 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10256 if( is->hThread != NULL ) {
\r
10257 ResumeThread( is->hThread );
\r
10260 if( is2 != NULL && is2->hThread != NULL ) {
\r
10261 ResumeThread( is2->hThread );
\r
10265 return (InputSourceRef) is;
\r
10269 RemoveInputSource(InputSourceRef isr)
\r
10273 is = (InputSource *) isr;
\r
10274 is->hThread = NULL; /* tell thread to stop */
\r
10275 CloseHandle(is->hThread);
\r
10276 if (is->second != NULL) {
\r
10277 is->second->hThread = NULL;
\r
10278 CloseHandle(is->second->hThread);
\r
10284 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10287 int outCount = SOCKET_ERROR;
\r
10288 ChildProc *cp = (ChildProc *) pr;
\r
10289 static OVERLAPPED ovl;
\r
10291 if (pr == NoProc) {
\r
10292 ConsoleOutput(message, count, FALSE);
\r
10296 if (ovl.hEvent == NULL) {
\r
10297 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10299 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10301 switch (cp->kind) {
\r
10304 outCount = send(cp->sock, message, count, 0);
\r
10305 if (outCount == SOCKET_ERROR) {
\r
10306 *outError = WSAGetLastError();
\r
10308 *outError = NO_ERROR;
\r
10313 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10314 &dOutCount, NULL)) {
\r
10315 *outError = NO_ERROR;
\r
10316 outCount = (int) dOutCount;
\r
10318 *outError = GetLastError();
\r
10323 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10324 &dOutCount, &ovl);
\r
10325 if (*outError == NO_ERROR) {
\r
10326 outCount = (int) dOutCount;
\r
10334 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10337 /* Ignore delay, not implemented for WinBoard */
\r
10338 return OutputToProcess(pr, message, count, outError);
\r
10343 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10344 char *buf, int count, int error)
\r
10346 DisplayFatalError("Not implemented", 0, 1);
\r
10349 /* see wgamelist.c for Game List functions */
\r
10350 /* see wedittags.c for Edit Tags functions */
\r
10357 char buf[MSG_SIZ];
\r
10360 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10361 f = fopen(buf, "r");
\r
10363 ProcessICSInitScript(f);
\r
10371 StartAnalysisClock()
\r
10373 if (analysisTimerEvent) return;
\r
10374 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10375 (UINT) 2000, NULL);
\r
10379 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10381 static HANDLE hwndText;
\r
10383 static int sizeX, sizeY;
\r
10384 int newSizeX, newSizeY, flags;
\r
10387 switch (message) {
\r
10388 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10389 /* Initialize the dialog items */
\r
10390 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10391 SetWindowText(hDlg, analysisTitle);
\r
10392 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10393 /* Size and position the dialog */
\r
10394 if (!analysisDialog) {
\r
10395 analysisDialog = hDlg;
\r
10396 flags = SWP_NOZORDER;
\r
10397 GetClientRect(hDlg, &rect);
\r
10398 sizeX = rect.right;
\r
10399 sizeY = rect.bottom;
\r
10400 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10401 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10402 WINDOWPLACEMENT wp;
\r
10403 EnsureOnScreen(&analysisX, &analysisY);
\r
10404 wp.length = sizeof(WINDOWPLACEMENT);
\r
10406 wp.showCmd = SW_SHOW;
\r
10407 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10408 wp.rcNormalPosition.left = analysisX;
\r
10409 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10410 wp.rcNormalPosition.top = analysisY;
\r
10411 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10412 SetWindowPlacement(hDlg, &wp);
\r
10414 GetClientRect(hDlg, &rect);
\r
10415 newSizeX = rect.right;
\r
10416 newSizeY = rect.bottom;
\r
10417 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10418 newSizeX, newSizeY);
\r
10419 sizeX = newSizeX;
\r
10420 sizeY = newSizeY;
\r
10425 case WM_COMMAND: /* message: received a command */
\r
10426 switch (LOWORD(wParam)) {
\r
10428 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10429 ExitAnalyzeMode();
\r
10441 newSizeX = LOWORD(lParam);
\r
10442 newSizeY = HIWORD(lParam);
\r
10443 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10444 sizeX = newSizeX;
\r
10445 sizeY = newSizeY;
\r
10448 case WM_GETMINMAXINFO:
\r
10449 /* Prevent resizing window too small */
\r
10450 mmi = (MINMAXINFO *) lParam;
\r
10451 mmi->ptMinTrackSize.x = 100;
\r
10452 mmi->ptMinTrackSize.y = 100;
\r
10459 AnalysisPopUp(char* title, char* str)
\r
10465 EngineOutputPopUp();
\r
10468 if (str == NULL) str = "";
\r
10469 p = (char *) malloc(2 * strlen(str) + 2);
\r
10472 if (*str == '\n') *q++ = '\r';
\r
10476 if (analysisText != NULL) free(analysisText);
\r
10477 analysisText = p;
\r
10479 if (analysisDialog) {
\r
10480 SetWindowText(analysisDialog, title);
\r
10481 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10482 ShowWindow(analysisDialog, SW_SHOW);
\r
10484 analysisTitle = title;
\r
10485 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10486 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10487 hwndMain, (DLGPROC)lpProc);
\r
10488 FreeProcInstance(lpProc);
\r
10490 analysisDialogUp = TRUE;
\r
10494 AnalysisPopDown()
\r
10496 if (analysisDialog) {
\r
10497 ShowWindow(analysisDialog, SW_HIDE);
\r
10499 analysisDialogUp = FALSE;
\r
10504 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10506 highlightInfo.sq[0].x = fromX;
\r
10507 highlightInfo.sq[0].y = fromY;
\r
10508 highlightInfo.sq[1].x = toX;
\r
10509 highlightInfo.sq[1].y = toY;
\r
10513 ClearHighlights()
\r
10515 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10516 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10520 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10522 premoveHighlightInfo.sq[0].x = fromX;
\r
10523 premoveHighlightInfo.sq[0].y = fromY;
\r
10524 premoveHighlightInfo.sq[1].x = toX;
\r
10525 premoveHighlightInfo.sq[1].y = toY;
\r
10529 ClearPremoveHighlights()
\r
10531 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10532 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10536 ShutDownFrontEnd()
\r
10538 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10539 DeleteClipboardTempFiles();
\r
10545 if (IsIconic(hwndMain))
\r
10546 ShowWindow(hwndMain, SW_RESTORE);
\r
10548 SetActiveWindow(hwndMain);
\r
10552 * Prototypes for animation support routines
\r
10554 static void ScreenSquare(int column, int row, POINT * pt);
\r
10555 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10556 POINT frames[], int * nFrames);
\r
10559 #define kFactor 4
\r
10562 AnimateMove(board, fromX, fromY, toX, toY)
\r
10569 ChessSquare piece;
\r
10570 POINT start, finish, mid;
\r
10571 POINT frames[kFactor * 2 + 1];
\r
10574 if (!appData.animate) return;
\r
10575 if (doingSizing) return;
\r
10576 if (fromY < 0 || fromX < 0) return;
\r
10577 piece = board[fromY][fromX];
\r
10578 if (piece >= EmptySquare) return;
\r
10580 ScreenSquare(fromX, fromY, &start);
\r
10581 ScreenSquare(toX, toY, &finish);
\r
10583 /* All pieces except knights move in straight line */
\r
10584 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10585 mid.x = start.x + (finish.x - start.x) / 2;
\r
10586 mid.y = start.y + (finish.y - start.y) / 2;
\r
10588 /* Knight: make diagonal movement then straight */
\r
10589 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10590 mid.x = start.x + (finish.x - start.x) / 2;
\r
10591 mid.y = finish.y;
\r
10593 mid.x = finish.x;
\r
10594 mid.y = start.y + (finish.y - start.y) / 2;
\r
10598 /* Don't use as many frames for very short moves */
\r
10599 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10600 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10602 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10604 animInfo.from.x = fromX;
\r
10605 animInfo.from.y = fromY;
\r
10606 animInfo.to.x = toX;
\r
10607 animInfo.to.y = toY;
\r
10608 animInfo.lastpos = start;
\r
10609 animInfo.piece = piece;
\r
10610 for (n = 0; n < nFrames; n++) {
\r
10611 animInfo.pos = frames[n];
\r
10612 DrawPosition(FALSE, NULL);
\r
10613 animInfo.lastpos = animInfo.pos;
\r
10614 Sleep(appData.animSpeed);
\r
10616 animInfo.pos = finish;
\r
10617 DrawPosition(FALSE, NULL);
\r
10618 animInfo.piece = EmptySquare;
\r
10621 /* Convert board position to corner of screen rect and color */
\r
10624 ScreenSquare(column, row, pt)
\r
10625 int column; int row; POINT * pt;
\r
10628 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10629 pt->y = lineGap + row * (squareSize + lineGap);
\r
10631 pt->x = lineGap + column * (squareSize + lineGap);
\r
10632 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10636 /* Generate a series of frame coords from start->mid->finish.
\r
10637 The movement rate doubles until the half way point is
\r
10638 reached, then halves back down to the final destination,
\r
10639 which gives a nice slow in/out effect. The algorithmn
\r
10640 may seem to generate too many intermediates for short
\r
10641 moves, but remember that the purpose is to attract the
\r
10642 viewers attention to the piece about to be moved and
\r
10643 then to where it ends up. Too few frames would be less
\r
10647 Tween(start, mid, finish, factor, frames, nFrames)
\r
10648 POINT * start; POINT * mid;
\r
10649 POINT * finish; int factor;
\r
10650 POINT frames[]; int * nFrames;
\r
10652 int n, fraction = 1, count = 0;
\r
10654 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10655 for (n = 0; n < factor; n++)
\r
10657 for (n = 0; n < factor; n++) {
\r
10658 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10659 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10661 fraction = fraction / 2;
\r
10665 frames[count] = *mid;
\r
10668 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10670 for (n = 0; n < factor; n++) {
\r
10671 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10672 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10674 fraction = fraction * 2;
\r
10676 *nFrames = count;
\r
10680 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10685 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10686 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10688 OutputDebugString( buf );
\r
10691 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10693 EvalGraphSet( first, last, current, pvInfoList );
\r
10696 void SetProgramStats( FrontEndProgramStats * stats )
\r
10701 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10702 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10704 OutputDebugString( buf );
\r
10707 EngineOutputUpdate( stats );
\r