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
498 // InitCommonControlsEx(&ex);
\r
499 InitCommonControls();
\r
501 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
502 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
503 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
505 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
507 while (GetMessage(&msg, /* message structure */
\r
508 NULL, /* handle of window receiving the message */
\r
509 0, /* lowest message to examine */
\r
510 0)) /* highest message to examine */
\r
512 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
513 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
514 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
515 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
516 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
517 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
518 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
519 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
520 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
521 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
522 TranslateMessage(&msg); /* Translates virtual key codes */
\r
523 DispatchMessage(&msg); /* Dispatches message to window */
\r
528 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
531 /*---------------------------------------------------------------------------*\
\r
533 * Initialization functions
\r
535 \*---------------------------------------------------------------------------*/
\r
538 InitApplication(HINSTANCE hInstance)
\r
542 /* Fill in window class structure with parameters that describe the */
\r
545 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
546 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
547 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
548 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
549 wc.hInstance = hInstance; /* Owner of this class */
\r
550 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
551 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
552 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
553 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
554 wc.lpszClassName = szAppName; /* Name to register as */
\r
556 /* Register the window class and return success/failure code. */
\r
557 if (!RegisterClass(&wc)) return FALSE;
\r
559 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
560 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
562 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
563 wc.hInstance = hInstance;
\r
564 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
565 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
566 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
567 wc.lpszMenuName = NULL;
\r
568 wc.lpszClassName = szConsoleName;
\r
570 if (!RegisterClass(&wc)) return FALSE;
\r
575 /* Set by InitInstance, used by EnsureOnScreen */
\r
576 int screenHeight, screenWidth;
\r
579 EnsureOnScreen(int *x, int *y)
\r
581 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
582 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
583 if (*x > screenWidth - 32) *x = 0;
\r
584 if (*y > screenHeight - 32) *y = 0;
\r
585 if (*x < 0) *x = 0;
\r
586 if (*y < 0) *y = 0;
\r
587 // if (*x < 10) *x = 10;
\r
588 // if (*y < gap) *y = gap;
\r
592 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
594 HWND hwnd; /* Main window handle. */
\r
596 WINDOWPLACEMENT wp;
\r
599 hInst = hInstance; /* Store instance handle in our global variable */
\r
601 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
602 *filepart = NULLCHAR;
\r
604 GetCurrentDirectory(MSG_SIZ, installDir);
\r
606 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
607 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
608 if (appData.debugMode) {
\r
609 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
610 setbuf(debugFP, NULL);
\r
615 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
616 // InitEngineUCI( installDir, &second );
\r
618 /* Create a main window for this application instance. */
\r
619 hwnd = CreateWindow(szAppName, szTitle,
\r
620 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
621 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
622 NULL, NULL, hInstance, NULL);
\r
625 /* If window could not be created, return "failure" */
\r
630 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
631 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
632 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
634 if (first.programLogo == NULL && appData.debugMode) {
\r
635 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
637 } else if(appData.autoLogo) {
\r
638 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
640 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
641 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
645 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
646 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
648 if (second.programLogo == NULL && appData.debugMode) {
\r
649 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
651 } else if(appData.autoLogo) {
\r
652 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
654 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
655 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
659 iconWhite = LoadIcon(hInstance, "icon_white");
\r
660 iconBlack = LoadIcon(hInstance, "icon_black");
\r
661 iconCurrent = iconWhite;
\r
662 InitDrawingColors();
\r
663 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
664 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
665 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
666 /* Compute window size for each board size, and use the largest
\r
667 size that fits on this screen as the default. */
\r
668 InitDrawingSizes((BoardSize)ibs, 0);
\r
669 if (boardSize == (BoardSize)-1 &&
\r
670 winHeight <= screenHeight
\r
671 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
672 && winWidth <= screenWidth) {
\r
673 boardSize = (BoardSize)ibs;
\r
677 InitDrawingSizes(boardSize, 0);
\r
679 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
681 /* [AS] Load textures if specified */
\r
682 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
684 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
685 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
686 liteBackTextureMode = appData.liteBackTextureMode;
\r
688 if (liteBackTexture == NULL && appData.debugMode) {
\r
689 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
693 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
694 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
695 darkBackTextureMode = appData.darkBackTextureMode;
\r
697 if (darkBackTexture == NULL && appData.debugMode) {
\r
698 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
702 mysrandom( (unsigned) time(NULL) );
\r
704 /* [AS] Restore layout */
\r
705 if( wpMoveHistory.visible ) {
\r
706 MoveHistoryPopUp();
\r
709 if( wpEvalGraph.visible ) {
\r
713 if( wpEngineOutput.visible ) {
\r
714 EngineOutputPopUp();
\r
719 /* Make the window visible; update its client area; and return "success" */
\r
720 EnsureOnScreen(&boardX, &boardY);
\r
721 wp.length = sizeof(WINDOWPLACEMENT);
\r
723 wp.showCmd = nCmdShow;
\r
724 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
725 wp.rcNormalPosition.left = boardX;
\r
726 wp.rcNormalPosition.right = boardX + winWidth;
\r
727 wp.rcNormalPosition.top = boardY;
\r
728 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
729 SetWindowPlacement(hwndMain, &wp);
\r
731 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
732 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
735 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
736 if( gameInfo.variant != VariantFischeRandom ) {
\r
737 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
742 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
743 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
745 ShowWindow(hwndConsole, nCmdShow);
\r
747 UpdateWindow(hwnd);
\r
755 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
756 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
757 ArgSettingsFilename
\r
765 String *pString; // ArgString
\r
766 int *pInt; // ArgInt
\r
767 float *pFloat; // ArgFloat
\r
768 Boolean *pBoolean; // ArgBoolean
\r
769 COLORREF *pColor; // ArgColor
\r
770 ColorClass cc; // ArgAttribs
\r
771 String *pFilename; // ArgFilename
\r
772 BoardSize *pBoardSize; // ArgBoardSize
\r
773 int whichFont; // ArgFont
\r
774 DCB *pDCB; // ArgCommSettings
\r
775 String *pFilename; // ArgSettingsFilename
\r
783 ArgDescriptor argDescriptors[] = {
\r
784 /* positional arguments */
\r
785 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
786 { "", ArgNone, NULL },
\r
787 /* keyword arguments */
\r
788 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
789 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
790 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
791 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
792 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
793 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
794 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
795 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
796 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
797 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
798 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
799 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
800 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
801 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
802 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
803 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
804 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
805 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
807 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
809 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
811 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
812 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
814 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
815 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
816 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
817 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
818 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
819 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
820 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
821 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
822 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
823 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
824 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
825 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
826 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
827 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
828 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
829 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
830 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
831 /*!!bitmapDirectory?*/
\r
832 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
833 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
834 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
835 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
836 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
837 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
838 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
839 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
840 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
841 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
842 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
843 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
844 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
845 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
846 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
847 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
848 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
849 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
850 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
851 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
852 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
853 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
854 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
855 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
856 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
857 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
858 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
859 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
860 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
861 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
862 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
863 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
864 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
865 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
866 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
867 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
868 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
869 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
870 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
871 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
872 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
873 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
874 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
875 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
876 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
877 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
878 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
879 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
880 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
881 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
882 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
883 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
884 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
885 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
886 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
887 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
888 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
889 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
890 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
891 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
892 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
893 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
894 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
895 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
896 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
897 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
898 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
899 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
900 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
901 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
902 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
903 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
904 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
905 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
906 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
907 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
908 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
909 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
910 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
911 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
912 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
913 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
914 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
915 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
916 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
917 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
918 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
919 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
920 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
921 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
922 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
923 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
924 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
925 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
926 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
927 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
928 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
929 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
930 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
931 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
932 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
933 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
934 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
935 TRUE }, /* must come after all fonts */
\r
936 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
937 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
938 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
939 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
940 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
941 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
942 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
943 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
944 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
945 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
946 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
947 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
948 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
949 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
950 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
951 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
952 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
953 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
954 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
955 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
956 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
957 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
958 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
959 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
960 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
961 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
962 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
963 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
964 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
965 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
966 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
968 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
969 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
971 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
972 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
973 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
974 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
975 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
976 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
977 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
978 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
979 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
980 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
981 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
982 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
983 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
984 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
985 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
986 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
987 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
988 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
989 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
990 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
991 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
992 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
993 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
994 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
995 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
996 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
997 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
998 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
999 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1000 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1001 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1002 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1003 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1004 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1005 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1006 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1007 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1008 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1009 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1010 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1011 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1012 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1013 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1014 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1015 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1016 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1017 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1018 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1019 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1020 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1021 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1022 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1023 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1024 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1025 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1026 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1027 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1028 { "highlightLastMove", ArgBoolean,
\r
1029 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1030 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1031 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1032 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1033 { "highlightDragging", ArgBoolean,
\r
1034 (LPVOID) &appData.highlightDragging, TRUE },
\r
1035 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1036 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1037 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1038 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1039 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1040 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1041 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1042 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1043 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1044 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1045 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1046 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1047 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1048 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1049 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1050 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1051 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1052 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1053 { "soundShout", ArgFilename,
\r
1054 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1055 { "soundSShout", ArgFilename,
\r
1056 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1057 { "soundChannel1", ArgFilename,
\r
1058 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1059 { "soundChannel", ArgFilename,
\r
1060 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1061 { "soundKibitz", ArgFilename,
\r
1062 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1063 { "soundTell", ArgFilename,
\r
1064 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1065 { "soundChallenge", ArgFilename,
\r
1066 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1067 { "soundRequest", ArgFilename,
\r
1068 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1069 { "soundSeek", ArgFilename,
\r
1070 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1071 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1072 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1073 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1074 { "soundIcsLoss", ArgFilename,
\r
1075 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1076 { "soundIcsDraw", ArgFilename,
\r
1077 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1078 { "soundIcsUnfinished", ArgFilename,
\r
1079 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1080 { "soundIcsAlarm", ArgFilename,
\r
1081 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1082 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1083 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1084 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1085 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1086 { "reuseChessPrograms", ArgBoolean,
\r
1087 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1088 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1089 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1090 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1091 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1092 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1093 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1094 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1095 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1096 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1097 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1098 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1099 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1100 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1101 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1102 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1103 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1104 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1105 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1106 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1107 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1108 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1109 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1110 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1111 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1112 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1113 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1114 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1115 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1116 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1117 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1118 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1119 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1120 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1121 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1122 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1123 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1124 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1126 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1128 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1129 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1130 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1131 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1132 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1133 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1134 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1135 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1136 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1137 /* [AS] New features */
\r
1138 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1139 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1140 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1141 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1142 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1143 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1144 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1145 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1146 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1147 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1148 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1149 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1150 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1151 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1152 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1153 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1154 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1155 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1156 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1157 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1158 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1159 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1160 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1161 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1162 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1163 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1164 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1165 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1166 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1167 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1168 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1169 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1170 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1171 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1172 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1173 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1174 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1175 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1176 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1177 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1178 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1179 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1180 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1181 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1182 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1183 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1184 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1185 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1186 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1187 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1189 /* [AS] Layout stuff */
\r
1190 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1191 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1192 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1193 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1194 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1196 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1197 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1198 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1199 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1200 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1202 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1203 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1204 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1205 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1206 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1208 /* [HGM] board-size, adjudication and misc. options */
\r
1209 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1210 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1211 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1212 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1213 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1214 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1215 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1216 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1217 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1218 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1219 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1220 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1221 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1222 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1223 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1224 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1225 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1226 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1227 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1228 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1229 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1230 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1231 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1232 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1233 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1234 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1235 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1236 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1237 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1240 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1241 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1242 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1243 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1244 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1245 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1246 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1247 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1248 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1249 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1250 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1251 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1252 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1254 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1255 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1256 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1257 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1258 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1259 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1260 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1262 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1263 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1264 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1265 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1266 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1267 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1268 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1269 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1270 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1271 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1272 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1273 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1274 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1275 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1276 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1277 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1278 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1279 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1281 /* [HGM] options for broadcasting and time odds */
\r
1282 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1283 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1284 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1285 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1286 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1287 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1288 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1289 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1290 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1291 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1292 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1293 { NULL, ArgNone, NULL, FALSE }
\r
1297 /* Kludge for indirection files on command line */
\r
1298 char* lastIndirectionFilename;
\r
1299 ArgDescriptor argDescriptorIndirection =
\r
1300 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1304 ExitArgError(char *msg, char *badArg)
\r
1306 char buf[MSG_SIZ];
\r
1308 sprintf(buf, "%s %s", msg, badArg);
\r
1309 DisplayFatalError(buf, 0, 2);
\r
1313 /* Command line font name parser. NULL name means do nothing.
\r
1314 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1315 For backward compatibility, syntax without the colon is also
\r
1316 accepted, but font names with digits in them won't work in that case.
\r
1319 ParseFontName(char *name, MyFontParams *mfp)
\r
1322 if (name == NULL) return;
\r
1324 q = strchr(p, ':');
\r
1326 if (q - p >= sizeof(mfp->faceName))
\r
1327 ExitArgError("Font name too long:", name);
\r
1328 memcpy(mfp->faceName, p, q - p);
\r
1329 mfp->faceName[q - p] = NULLCHAR;
\r
1332 q = mfp->faceName;
\r
1333 while (*p && !isdigit(*p)) {
\r
1335 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1336 ExitArgError("Font name too long:", name);
\r
1338 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1341 if (!*p) ExitArgError("Font point size missing:", name);
\r
1342 mfp->pointSize = (float) atof(p);
\r
1343 mfp->bold = (strchr(p, 'b') != NULL);
\r
1344 mfp->italic = (strchr(p, 'i') != NULL);
\r
1345 mfp->underline = (strchr(p, 'u') != NULL);
\r
1346 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1349 /* Color name parser.
\r
1350 X version accepts X color names, but this one
\r
1351 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1353 ParseColorName(char *name)
\r
1355 int red, green, blue, count;
\r
1356 char buf[MSG_SIZ];
\r
1358 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1360 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1361 &red, &green, &blue);
\r
1364 sprintf(buf, "Can't parse color name %s", name);
\r
1365 DisplayError(buf, 0);
\r
1366 return RGB(0, 0, 0);
\r
1368 return PALETTERGB(red, green, blue);
\r
1372 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1374 char *e = argValue;
\r
1378 if (*e == 'b') eff |= CFE_BOLD;
\r
1379 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1380 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1381 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1382 else if (*e == '#' || isdigit(*e)) break;
\r
1386 *color = ParseColorName(e);
\r
1391 ParseBoardSize(char *name)
\r
1393 BoardSize bs = SizeTiny;
\r
1394 while (sizeInfo[bs].name != NULL) {
\r
1395 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1398 ExitArgError("Unrecognized board size value", name);
\r
1399 return bs; /* not reached */
\r
1404 StringGet(void *getClosure)
\r
1406 char **p = (char **) getClosure;
\r
1411 FileGet(void *getClosure)
\r
1414 FILE* f = (FILE*) getClosure;
\r
1417 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1424 /* Parse settings file named "name". If file found, return the
\r
1425 full name in fullname and return TRUE; else return FALSE */
\r
1427 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1432 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1433 f = fopen(fullname, "r");
\r
1435 ParseArgs(FileGet, f);
\r
1444 ParseArgs(GetFunc get, void *cl)
\r
1446 char argName[ARG_MAX];
\r
1447 char argValue[ARG_MAX];
\r
1448 ArgDescriptor *ad;
\r
1457 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1458 if (ch == NULLCHAR) break;
\r
1460 /* Comment to end of line */
\r
1462 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1464 } else if (ch == '/' || ch == '-') {
\r
1467 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1468 ch != '\n' && ch != '\t') {
\r
1474 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1475 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1477 if (ad->argName == NULL)
\r
1478 ExitArgError("Unrecognized argument", argName);
\r
1480 } else if (ch == '@') {
\r
1481 /* Indirection file */
\r
1482 ad = &argDescriptorIndirection;
\r
1485 /* Positional argument */
\r
1486 ad = &argDescriptors[posarg++];
\r
1487 strcpy(argName, ad->argName);
\r
1490 if (ad->argType == ArgTrue) {
\r
1491 *(Boolean *) ad->argLoc = TRUE;
\r
1494 if (ad->argType == ArgFalse) {
\r
1495 *(Boolean *) ad->argLoc = FALSE;
\r
1499 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1500 if (ch == NULLCHAR || ch == '\n') {
\r
1501 ExitArgError("No value provided for argument", argName);
\r
1505 // Quoting with { }. No characters have to (or can) be escaped.
\r
1506 // Thus the string cannot contain a '}' character.
\r
1526 } else if (ch == '\'' || ch == '"') {
\r
1527 // Quoting with ' ' or " ", with \ as escape character.
\r
1528 // Inconvenient for long strings that may contain Windows filenames.
\r
1545 if (ch == start) {
\r
1554 if (ad->argType == ArgFilename
\r
1555 || ad->argType == ArgSettingsFilename) {
\r
1561 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1585 for (i = 0; i < 3; i++) {
\r
1586 if (ch >= '0' && ch <= '7') {
\r
1587 octval = octval*8 + (ch - '0');
\r
1594 *q++ = (char) octval;
\r
1605 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1612 switch (ad->argType) {
\r
1614 *(int *) ad->argLoc = atoi(argValue);
\r
1618 *(float *) ad->argLoc = (float) atof(argValue);
\r
1623 *(char **) ad->argLoc = strdup(argValue);
\r
1626 case ArgSettingsFilename:
\r
1628 char fullname[MSG_SIZ];
\r
1629 if (ParseSettingsFile(argValue, fullname)) {
\r
1630 if (ad->argLoc != NULL) {
\r
1631 *(char **) ad->argLoc = strdup(fullname);
\r
1634 if (ad->argLoc != NULL) {
\r
1636 ExitArgError("Failed to open indirection file", argValue);
\r
1643 switch (argValue[0]) {
\r
1646 *(Boolean *) ad->argLoc = TRUE;
\r
1650 *(Boolean *) ad->argLoc = FALSE;
\r
1653 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1659 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1662 case ArgAttribs: {
\r
1663 ColorClass cc = (ColorClass)ad->argLoc;
\r
1664 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1668 case ArgBoardSize:
\r
1669 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1673 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1676 case ArgCommSettings:
\r
1677 ParseCommSettings(argValue, &dcb);
\r
1681 ExitArgError("Unrecognized argument", argValue);
\r
1690 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1692 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1693 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1696 lf->lfEscapement = 0;
\r
1697 lf->lfOrientation = 0;
\r
1698 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1699 lf->lfItalic = mfp->italic;
\r
1700 lf->lfUnderline = mfp->underline;
\r
1701 lf->lfStrikeOut = mfp->strikeout;
\r
1702 lf->lfCharSet = DEFAULT_CHARSET;
\r
1703 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1704 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1705 lf->lfQuality = DEFAULT_QUALITY;
\r
1706 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1707 strcpy(lf->lfFaceName, mfp->faceName);
\r
1711 CreateFontInMF(MyFont *mf)
\r
1713 LFfromMFP(&mf->lf, &mf->mfp);
\r
1714 if (mf->hf) DeleteObject(mf->hf);
\r
1715 mf->hf = CreateFontIndirect(&mf->lf);
\r
1719 SetDefaultTextAttribs()
\r
1722 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1723 ParseAttribs(&textAttribs[cc].color,
\r
1724 &textAttribs[cc].effects,
\r
1725 defaultTextAttribs[cc]);
\r
1730 SetDefaultSounds()
\r
1734 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1735 textAttribs[cc].sound.name = strdup("");
\r
1736 textAttribs[cc].sound.data = NULL;
\r
1738 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1739 sounds[sc].name = strdup("");
\r
1740 sounds[sc].data = NULL;
\r
1742 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1750 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1751 MyLoadSound(&textAttribs[cc].sound);
\r
1753 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1754 MyLoadSound(&sounds[sc]);
\r
1759 InitAppData(LPSTR lpCmdLine)
\r
1762 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1765 programName = szAppName;
\r
1767 /* Initialize to defaults */
\r
1768 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1769 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1770 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1771 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1772 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1773 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1774 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1775 SetDefaultTextAttribs();
\r
1776 SetDefaultSounds();
\r
1777 appData.movesPerSession = MOVES_PER_SESSION;
\r
1778 appData.initString = INIT_STRING;
\r
1779 appData.secondInitString = INIT_STRING;
\r
1780 appData.firstComputerString = COMPUTER_STRING;
\r
1781 appData.secondComputerString = COMPUTER_STRING;
\r
1782 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1783 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1784 appData.firstPlaysBlack = FALSE;
\r
1785 appData.noChessProgram = FALSE;
\r
1786 chessProgram = FALSE;
\r
1787 appData.firstHost = FIRST_HOST;
\r
1788 appData.secondHost = SECOND_HOST;
\r
1789 appData.firstDirectory = FIRST_DIRECTORY;
\r
1790 appData.secondDirectory = SECOND_DIRECTORY;
\r
1791 appData.bitmapDirectory = "";
\r
1792 appData.remoteShell = REMOTE_SHELL;
\r
1793 appData.remoteUser = "";
\r
1794 appData.timeDelay = TIME_DELAY;
\r
1795 appData.timeControl = TIME_CONTROL;
\r
1796 appData.timeIncrement = TIME_INCREMENT;
\r
1797 appData.icsActive = FALSE;
\r
1798 appData.icsHost = "";
\r
1799 appData.icsPort = ICS_PORT;
\r
1800 appData.icsCommPort = ICS_COMM_PORT;
\r
1801 appData.icsLogon = ICS_LOGON;
\r
1802 appData.icsHelper = "";
\r
1803 appData.useTelnet = FALSE;
\r
1804 appData.telnetProgram = TELNET_PROGRAM;
\r
1805 appData.gateway = "";
\r
1806 appData.loadGameFile = "";
\r
1807 appData.loadGameIndex = 0;
\r
1808 appData.saveGameFile = "";
\r
1809 appData.autoSaveGames = FALSE;
\r
1810 appData.loadPositionFile = "";
\r
1811 appData.loadPositionIndex = 1;
\r
1812 appData.savePositionFile = "";
\r
1813 appData.matchMode = FALSE;
\r
1814 appData.matchGames = 0;
\r
1815 appData.monoMode = FALSE;
\r
1816 appData.debugMode = FALSE;
\r
1817 appData.clockMode = TRUE;
\r
1818 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1819 appData.Iconic = FALSE; /*unused*/
\r
1820 appData.searchTime = "";
\r
1821 appData.searchDepth = 0;
\r
1822 appData.showCoords = FALSE;
\r
1823 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1824 appData.autoCallFlag = FALSE;
\r
1825 appData.flipView = FALSE;
\r
1826 appData.autoFlipView = TRUE;
\r
1827 appData.cmailGameName = "";
\r
1828 appData.alwaysPromoteToQueen = FALSE;
\r
1829 appData.oldSaveStyle = FALSE;
\r
1830 appData.quietPlay = FALSE;
\r
1831 appData.showThinking = FALSE;
\r
1832 appData.ponderNextMove = TRUE;
\r
1833 appData.periodicUpdates = TRUE;
\r
1834 appData.popupExitMessage = TRUE;
\r
1835 appData.popupMoveErrors = FALSE;
\r
1836 appData.autoObserve = FALSE;
\r
1837 appData.autoComment = FALSE;
\r
1838 appData.animate = TRUE;
\r
1839 appData.animSpeed = 10;
\r
1840 appData.animateDragging = TRUE;
\r
1841 appData.highlightLastMove = TRUE;
\r
1842 appData.getMoveList = TRUE;
\r
1843 appData.testLegality = TRUE;
\r
1844 appData.premove = TRUE;
\r
1845 appData.premoveWhite = FALSE;
\r
1846 appData.premoveWhiteText = "";
\r
1847 appData.premoveBlack = FALSE;
\r
1848 appData.premoveBlackText = "";
\r
1849 appData.icsAlarm = TRUE;
\r
1850 appData.icsAlarmTime = 5000;
\r
1851 appData.autoRaiseBoard = TRUE;
\r
1852 appData.localLineEditing = TRUE;
\r
1853 appData.colorize = TRUE;
\r
1854 appData.reuseFirst = TRUE;
\r
1855 appData.reuseSecond = TRUE;
\r
1856 appData.blindfold = FALSE;
\r
1857 appData.icsEngineAnalyze = FALSE;
\r
1858 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1859 dcb.DCBlength = sizeof(DCB);
\r
1860 dcb.BaudRate = 9600;
\r
1861 dcb.fBinary = TRUE;
\r
1862 dcb.fParity = FALSE;
\r
1863 dcb.fOutxCtsFlow = FALSE;
\r
1864 dcb.fOutxDsrFlow = FALSE;
\r
1865 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1866 dcb.fDsrSensitivity = FALSE;
\r
1867 dcb.fTXContinueOnXoff = TRUE;
\r
1868 dcb.fOutX = FALSE;
\r
1870 dcb.fNull = FALSE;
\r
1871 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1872 dcb.fAbortOnError = FALSE;
\r
1874 dcb.Parity = SPACEPARITY;
\r
1875 dcb.StopBits = ONESTOPBIT;
\r
1876 settingsFileName = SETTINGS_FILE;
\r
1877 saveSettingsOnExit = TRUE;
\r
1878 boardX = CW_USEDEFAULT;
\r
1879 boardY = CW_USEDEFAULT;
\r
1880 consoleX = CW_USEDEFAULT;
\r
1881 consoleY = CW_USEDEFAULT;
\r
1882 consoleW = CW_USEDEFAULT;
\r
1883 consoleH = CW_USEDEFAULT;
\r
1884 analysisX = CW_USEDEFAULT;
\r
1885 analysisY = CW_USEDEFAULT;
\r
1886 analysisW = CW_USEDEFAULT;
\r
1887 analysisH = CW_USEDEFAULT;
\r
1888 commentX = CW_USEDEFAULT;
\r
1889 commentY = CW_USEDEFAULT;
\r
1890 commentW = CW_USEDEFAULT;
\r
1891 commentH = CW_USEDEFAULT;
\r
1892 editTagsX = CW_USEDEFAULT;
\r
1893 editTagsY = CW_USEDEFAULT;
\r
1894 editTagsW = CW_USEDEFAULT;
\r
1895 editTagsH = CW_USEDEFAULT;
\r
1896 gameListX = CW_USEDEFAULT;
\r
1897 gameListY = CW_USEDEFAULT;
\r
1898 gameListW = CW_USEDEFAULT;
\r
1899 gameListH = CW_USEDEFAULT;
\r
1900 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1901 icsNames = ICS_NAMES;
\r
1902 firstChessProgramNames = FCP_NAMES;
\r
1903 secondChessProgramNames = SCP_NAMES;
\r
1904 appData.initialMode = "";
\r
1905 appData.variant = "normal";
\r
1906 appData.firstProtocolVersion = PROTOVER;
\r
1907 appData.secondProtocolVersion = PROTOVER;
\r
1908 appData.showButtonBar = TRUE;
\r
1910 /* [AS] New properties (see comments in header file) */
\r
1911 appData.firstScoreIsAbsolute = FALSE;
\r
1912 appData.secondScoreIsAbsolute = FALSE;
\r
1913 appData.saveExtendedInfoInPGN = FALSE;
\r
1914 appData.hideThinkingFromHuman = FALSE;
\r
1915 appData.liteBackTextureFile = "";
\r
1916 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1917 appData.darkBackTextureFile = "";
\r
1918 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1919 appData.renderPiecesWithFont = "";
\r
1920 appData.fontToPieceTable = "";
\r
1921 appData.fontBackColorWhite = 0;
\r
1922 appData.fontForeColorWhite = 0;
\r
1923 appData.fontBackColorBlack = 0;
\r
1924 appData.fontForeColorBlack = 0;
\r
1925 appData.fontPieceSize = 80;
\r
1926 appData.overrideLineGap = 1;
\r
1927 appData.adjudicateLossThreshold = 0;
\r
1928 appData.delayBeforeQuit = 0;
\r
1929 appData.delayAfterQuit = 0;
\r
1930 appData.nameOfDebugFile = "winboard.debug";
\r
1931 appData.pgnEventHeader = "Computer Chess Game";
\r
1932 appData.defaultFrcPosition = -1;
\r
1933 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1934 appData.saveOutOfBookInfo = TRUE;
\r
1935 appData.showEvalInMoveHistory = TRUE;
\r
1936 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1937 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1938 appData.highlightMoveWithArrow = FALSE;
\r
1939 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1940 appData.useStickyWindows = TRUE;
\r
1941 appData.adjudicateDrawMoves = 0;
\r
1942 appData.autoDisplayComment = TRUE;
\r
1943 appData.autoDisplayTags = TRUE;
\r
1944 appData.firstIsUCI = FALSE;
\r
1945 appData.secondIsUCI = FALSE;
\r
1946 appData.firstHasOwnBookUCI = TRUE;
\r
1947 appData.secondHasOwnBookUCI = TRUE;
\r
1948 appData.polyglotDir = "";
\r
1949 appData.usePolyglotBook = FALSE;
\r
1950 appData.polyglotBook = "";
\r
1951 appData.defaultHashSize = 64;
\r
1952 appData.defaultCacheSizeEGTB = 4;
\r
1953 appData.defaultPathEGTB = "c:\\egtb";
\r
1954 appData.firstOptions = "";
\r
1955 appData.secondOptions = "";
\r
1957 InitWindowPlacement( &wpMoveHistory );
\r
1958 InitWindowPlacement( &wpEvalGraph );
\r
1959 InitWindowPlacement( &wpEngineOutput );
\r
1961 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1962 appData.NrFiles = -1;
\r
1963 appData.NrRanks = -1;
\r
1964 appData.holdingsSize = -1;
\r
1965 appData.testClaims = FALSE;
\r
1966 appData.checkMates = FALSE;
\r
1967 appData.materialDraws= FALSE;
\r
1968 appData.trivialDraws = FALSE;
\r
1969 appData.ruleMoves = 51;
\r
1970 appData.drawRepeats = 6;
\r
1971 appData.matchPause = 10000;
\r
1972 appData.alphaRank = FALSE;
\r
1973 appData.allWhite = FALSE;
\r
1974 appData.upsideDown = FALSE;
\r
1975 appData.serverPause = 15;
\r
1976 appData.serverMovesName = NULL;
\r
1977 appData.suppressLoadMoves = FALSE;
\r
1978 appData.firstTimeOdds = 1;
\r
1979 appData.secondTimeOdds = 1;
\r
1980 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
1981 appData.secondAccumulateTC = 1;
\r
1982 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
1983 appData.secondNPS = -1;
\r
1984 appData.engineComments = 1;
\r
1985 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
1986 appData.egtFormats = "";
\r
1989 appData.zippyTalk = ZIPPY_TALK;
\r
1990 appData.zippyPlay = ZIPPY_PLAY;
\r
1991 appData.zippyLines = ZIPPY_LINES;
\r
1992 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1993 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1994 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1995 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1996 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1997 appData.zippyUseI = ZIPPY_USE_I;
\r
1998 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1999 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2000 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2001 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2002 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2003 appData.zippyAbort = ZIPPY_ABORT;
\r
2004 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2005 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2006 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2009 /* Point font array elements to structures and
\r
2010 parse default font names */
\r
2011 for (i=0; i<NUM_FONTS; i++) {
\r
2012 for (j=0; j<NUM_SIZES; j++) {
\r
2013 font[j][i] = &fontRec[j][i];
\r
2014 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2018 /* Parse default settings file if any */
\r
2019 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2020 settingsFileName = strdup(buf);
\r
2023 /* Parse command line */
\r
2024 ParseArgs(StringGet, &lpCmdLine);
\r
2026 /* [HGM] make sure board size is acceptable */
\r
2027 if(appData.NrFiles > BOARD_SIZE ||
\r
2028 appData.NrRanks > BOARD_SIZE )
\r
2029 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2031 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2032 * with options from the command line, we now make an even higher priority
\r
2033 * overrule by WB options attached to the engine command line. This so that
\r
2034 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2037 if(appData.firstChessProgram != NULL) {
\r
2038 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2039 static char *f = "first";
\r
2040 char buf[MSG_SIZ], *q = buf;
\r
2041 if(p != NULL) { // engine command line contains WinBoard options
\r
2042 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2043 ParseArgs(StringGet, &q);
\r
2044 p[-1] = 0; // cut them offengine command line
\r
2047 // now do same for second chess program
\r
2048 if(appData.secondChessProgram != NULL) {
\r
2049 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2050 static char *s = "second";
\r
2051 char buf[MSG_SIZ], *q = buf;
\r
2052 if(p != NULL) { // engine command line contains WinBoard options
\r
2053 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2054 ParseArgs(StringGet, &q);
\r
2055 p[-1] = 0; // cut them offengine command line
\r
2060 /* Propagate options that affect others */
\r
2061 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2062 if (appData.icsActive || appData.noChessProgram) {
\r
2063 chessProgram = FALSE; /* not local chess program mode */
\r
2066 /* Open startup dialog if needed */
\r
2067 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2068 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2069 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2070 *appData.secondChessProgram == NULLCHAR))) {
\r
2073 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2074 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2075 FreeProcInstance(lpProc);
\r
2078 /* Make sure save files land in the right (?) directory */
\r
2079 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2080 appData.saveGameFile = strdup(buf);
\r
2082 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2083 appData.savePositionFile = strdup(buf);
\r
2086 /* Finish initialization for fonts and sounds */
\r
2087 for (i=0; i<NUM_FONTS; i++) {
\r
2088 for (j=0; j<NUM_SIZES; j++) {
\r
2089 CreateFontInMF(font[j][i]);
\r
2092 /* xboard, and older WinBoards, controlled the move sound with the
\r
2093 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2094 always turn the option on (so that the backend will call us),
\r
2095 then let the user turn the sound off by setting it to silence if
\r
2096 desired. To accommodate old winboard.ini files saved by old
\r
2097 versions of WinBoard, we also turn off the sound if the option
\r
2098 was initially set to false. */
\r
2099 if (!appData.ringBellAfterMoves) {
\r
2100 sounds[(int)SoundMove].name = strdup("");
\r
2101 appData.ringBellAfterMoves = TRUE;
\r
2103 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2104 SetCurrentDirectory(installDir);
\r
2106 SetCurrentDirectory(currDir);
\r
2108 p = icsTextMenuString;
\r
2109 if (p[0] == '@') {
\r
2110 FILE* f = fopen(p + 1, "r");
\r
2112 DisplayFatalError(p + 1, errno, 2);
\r
2115 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2117 buf[i] = NULLCHAR;
\r
2120 ParseIcsTextMenu(strdup(p));
\r
2127 HMENU hmenu = GetMenu(hwndMain);
\r
2129 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2130 MF_BYCOMMAND|((appData.icsActive &&
\r
2131 *appData.icsCommPort != NULLCHAR) ?
\r
2132 MF_ENABLED : MF_GRAYED));
\r
2133 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2134 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2135 MF_CHECKED : MF_UNCHECKED));
\r
2140 SaveSettings(char* name)
\r
2143 ArgDescriptor *ad;
\r
2144 WINDOWPLACEMENT wp;
\r
2145 char dir[MSG_SIZ];
\r
2147 if (!hwndMain) return;
\r
2149 GetCurrentDirectory(MSG_SIZ, dir);
\r
2150 SetCurrentDirectory(installDir);
\r
2151 f = fopen(name, "w");
\r
2152 SetCurrentDirectory(dir);
\r
2154 DisplayError(name, errno);
\r
2157 fprintf(f, ";\n");
\r
2158 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2159 fprintf(f, ";\n");
\r
2160 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2161 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2162 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2163 fprintf(f, ";\n");
\r
2165 wp.length = sizeof(WINDOWPLACEMENT);
\r
2166 GetWindowPlacement(hwndMain, &wp);
\r
2167 boardX = wp.rcNormalPosition.left;
\r
2168 boardY = wp.rcNormalPosition.top;
\r
2170 if (hwndConsole) {
\r
2171 GetWindowPlacement(hwndConsole, &wp);
\r
2172 consoleX = wp.rcNormalPosition.left;
\r
2173 consoleY = wp.rcNormalPosition.top;
\r
2174 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2175 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2178 if (analysisDialog) {
\r
2179 GetWindowPlacement(analysisDialog, &wp);
\r
2180 analysisX = wp.rcNormalPosition.left;
\r
2181 analysisY = wp.rcNormalPosition.top;
\r
2182 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2183 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2186 if (commentDialog) {
\r
2187 GetWindowPlacement(commentDialog, &wp);
\r
2188 commentX = wp.rcNormalPosition.left;
\r
2189 commentY = wp.rcNormalPosition.top;
\r
2190 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2191 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2194 if (editTagsDialog) {
\r
2195 GetWindowPlacement(editTagsDialog, &wp);
\r
2196 editTagsX = wp.rcNormalPosition.left;
\r
2197 editTagsY = wp.rcNormalPosition.top;
\r
2198 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2199 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2202 if (gameListDialog) {
\r
2203 GetWindowPlacement(gameListDialog, &wp);
\r
2204 gameListX = wp.rcNormalPosition.left;
\r
2205 gameListY = wp.rcNormalPosition.top;
\r
2206 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2207 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2210 /* [AS] Move history */
\r
2211 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2213 if( moveHistoryDialog ) {
\r
2214 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2215 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2216 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2217 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2218 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2221 /* [AS] Eval graph */
\r
2222 wpEvalGraph.visible = EvalGraphIsUp();
\r
2224 if( evalGraphDialog ) {
\r
2225 GetWindowPlacement(evalGraphDialog, &wp);
\r
2226 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2227 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2228 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2229 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2232 /* [AS] Engine output */
\r
2233 wpEngineOutput.visible = EngineOutputIsUp();
\r
2235 if( engineOutputDialog ) {
\r
2236 GetWindowPlacement(engineOutputDialog, &wp);
\r
2237 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2238 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2239 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2240 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2243 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2244 if (!ad->save) continue;
\r
2245 switch (ad->argType) {
\r
2248 char *p = *(char **)ad->argLoc;
\r
2249 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2250 /* Quote multiline values or \-containing values
\r
2251 with { } if possible */
\r
2252 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2254 /* Else quote with " " */
\r
2255 fprintf(f, "/%s=\"", ad->argName);
\r
2257 if (*p == '\n') fprintf(f, "\n");
\r
2258 else if (*p == '\r') fprintf(f, "\\r");
\r
2259 else if (*p == '\t') fprintf(f, "\\t");
\r
2260 else if (*p == '\b') fprintf(f, "\\b");
\r
2261 else if (*p == '\f') fprintf(f, "\\f");
\r
2262 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2263 else if (*p == '\"') fprintf(f, "\\\"");
\r
2264 else if (*p == '\\') fprintf(f, "\\\\");
\r
2268 fprintf(f, "\"\n");
\r
2273 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2276 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2279 fprintf(f, "/%s=%s\n", ad->argName,
\r
2280 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2283 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2286 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2290 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2291 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2292 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2297 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2298 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2299 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2300 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2301 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2302 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2303 (ta->effects) ? " " : "",
\r
2304 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2308 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2309 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2311 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2314 case ArgBoardSize:
\r
2315 fprintf(f, "/%s=%s\n", ad->argName,
\r
2316 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2321 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2322 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2323 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2324 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2325 ad->argName, mfp->faceName, mfp->pointSize,
\r
2326 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2327 mfp->bold ? "b" : "",
\r
2328 mfp->italic ? "i" : "",
\r
2329 mfp->underline ? "u" : "",
\r
2330 mfp->strikeout ? "s" : "");
\r
2334 case ArgCommSettings:
\r
2335 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2337 case ArgSettingsFilename: ;
\r
2345 /*---------------------------------------------------------------------------*\
\r
2347 * GDI board drawing routines
\r
2349 \*---------------------------------------------------------------------------*/
\r
2351 /* [AS] Draw square using background texture */
\r
2352 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2357 return; /* Should never happen! */
\r
2360 SetGraphicsMode( dst, GM_ADVANCED );
\r
2367 /* X reflection */
\r
2372 x.eDx = (FLOAT) dw + dx - 1;
\r
2375 SetWorldTransform( dst, &x );
\r
2378 /* Y reflection */
\r
2384 x.eDy = (FLOAT) dh + dy - 1;
\r
2386 SetWorldTransform( dst, &x );
\r
2394 x.eDx = (FLOAT) dx;
\r
2395 x.eDy = (FLOAT) dy;
\r
2398 SetWorldTransform( dst, &x );
\r
2402 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2410 SetWorldTransform( dst, &x );
\r
2412 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2415 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2417 PM_WP = (int) WhitePawn,
\r
2418 PM_WN = (int) WhiteKnight,
\r
2419 PM_WB = (int) WhiteBishop,
\r
2420 PM_WR = (int) WhiteRook,
\r
2421 PM_WQ = (int) WhiteQueen,
\r
2422 PM_WF = (int) WhiteFerz,
\r
2423 PM_WW = (int) WhiteWazir,
\r
2424 PM_WE = (int) WhiteAlfil,
\r
2425 PM_WM = (int) WhiteMan,
\r
2426 PM_WO = (int) WhiteCannon,
\r
2427 PM_WU = (int) WhiteUnicorn,
\r
2428 PM_WH = (int) WhiteNightrider,
\r
2429 PM_WA = (int) WhiteAngel,
\r
2430 PM_WC = (int) WhiteMarshall,
\r
2431 PM_WAB = (int) WhiteCardinal,
\r
2432 PM_WD = (int) WhiteDragon,
\r
2433 PM_WL = (int) WhiteLance,
\r
2434 PM_WS = (int) WhiteCobra,
\r
2435 PM_WV = (int) WhiteFalcon,
\r
2436 PM_WSG = (int) WhiteSilver,
\r
2437 PM_WG = (int) WhiteGrasshopper,
\r
2438 PM_WK = (int) WhiteKing,
\r
2439 PM_BP = (int) BlackPawn,
\r
2440 PM_BN = (int) BlackKnight,
\r
2441 PM_BB = (int) BlackBishop,
\r
2442 PM_BR = (int) BlackRook,
\r
2443 PM_BQ = (int) BlackQueen,
\r
2444 PM_BF = (int) BlackFerz,
\r
2445 PM_BW = (int) BlackWazir,
\r
2446 PM_BE = (int) BlackAlfil,
\r
2447 PM_BM = (int) BlackMan,
\r
2448 PM_BO = (int) BlackCannon,
\r
2449 PM_BU = (int) BlackUnicorn,
\r
2450 PM_BH = (int) BlackNightrider,
\r
2451 PM_BA = (int) BlackAngel,
\r
2452 PM_BC = (int) BlackMarshall,
\r
2453 PM_BG = (int) BlackGrasshopper,
\r
2454 PM_BAB = (int) BlackCardinal,
\r
2455 PM_BD = (int) BlackDragon,
\r
2456 PM_BL = (int) BlackLance,
\r
2457 PM_BS = (int) BlackCobra,
\r
2458 PM_BV = (int) BlackFalcon,
\r
2459 PM_BSG = (int) BlackSilver,
\r
2460 PM_BK = (int) BlackKing
\r
2463 static HFONT hPieceFont = NULL;
\r
2464 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2465 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2466 static int fontBitmapSquareSize = 0;
\r
2467 static char pieceToFontChar[(int) EmptySquare] =
\r
2468 { 'p', 'n', 'b', 'r', 'q',
\r
2469 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2470 'k', 'o', 'm', 'v', 't', 'w',
\r
2471 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2474 extern BOOL SetCharTable( char *table, const char * map );
\r
2475 /* [HGM] moved to backend.c */
\r
2477 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2480 BYTE r1 = GetRValue( color );
\r
2481 BYTE g1 = GetGValue( color );
\r
2482 BYTE b1 = GetBValue( color );
\r
2488 /* Create a uniform background first */
\r
2489 hbrush = CreateSolidBrush( color );
\r
2490 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2491 FillRect( hdc, &rc, hbrush );
\r
2492 DeleteObject( hbrush );
\r
2495 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2496 int steps = squareSize / 2;
\r
2499 for( i=0; i<steps; i++ ) {
\r
2500 BYTE r = r1 - (r1-r2) * i / steps;
\r
2501 BYTE g = g1 - (g1-g2) * i / steps;
\r
2502 BYTE b = b1 - (b1-b2) * i / steps;
\r
2504 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2505 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2506 FillRect( hdc, &rc, hbrush );
\r
2507 DeleteObject(hbrush);
\r
2510 else if( mode == 2 ) {
\r
2511 /* Diagonal gradient, good more or less for every piece */
\r
2512 POINT triangle[3];
\r
2513 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2514 HBRUSH hbrush_old;
\r
2515 int steps = squareSize;
\r
2518 triangle[0].x = squareSize - steps;
\r
2519 triangle[0].y = squareSize;
\r
2520 triangle[1].x = squareSize;
\r
2521 triangle[1].y = squareSize;
\r
2522 triangle[2].x = squareSize;
\r
2523 triangle[2].y = squareSize - steps;
\r
2525 for( i=0; i<steps; i++ ) {
\r
2526 BYTE r = r1 - (r1-r2) * i / steps;
\r
2527 BYTE g = g1 - (g1-g2) * i / steps;
\r
2528 BYTE b = b1 - (b1-b2) * i / steps;
\r
2530 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2531 hbrush_old = SelectObject( hdc, hbrush );
\r
2532 Polygon( hdc, triangle, 3 );
\r
2533 SelectObject( hdc, hbrush_old );
\r
2534 DeleteObject(hbrush);
\r
2539 SelectObject( hdc, hpen );
\r
2544 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2545 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2546 piece: follow the steps as explained below.
\r
2548 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2552 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2556 int backColor = whitePieceColor;
\r
2557 int foreColor = blackPieceColor;
\r
2559 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2560 backColor = appData.fontBackColorWhite;
\r
2561 foreColor = appData.fontForeColorWhite;
\r
2563 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2564 backColor = appData.fontBackColorBlack;
\r
2565 foreColor = appData.fontForeColorBlack;
\r
2569 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2571 hbm_old = SelectObject( hdc, hbm );
\r
2575 rc.right = squareSize;
\r
2576 rc.bottom = squareSize;
\r
2578 /* Step 1: background is now black */
\r
2579 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2581 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2583 pt.x = (squareSize - sz.cx) / 2;
\r
2584 pt.y = (squareSize - sz.cy) / 2;
\r
2586 SetBkMode( hdc, TRANSPARENT );
\r
2587 SetTextColor( hdc, chroma );
\r
2588 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2589 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2591 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2592 /* Step 3: the area outside the piece is filled with white */
\r
2593 // FloodFill( hdc, 0, 0, chroma );
\r
2594 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2595 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2596 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2597 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2598 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2600 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2601 but if the start point is not inside the piece we're lost!
\r
2602 There should be a better way to do this... if we could create a region or path
\r
2603 from the fill operation we would be fine for example.
\r
2605 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2606 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2608 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2609 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2610 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2612 SelectObject( dc2, bm2 );
\r
2613 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2614 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2615 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2616 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2617 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2620 DeleteObject( bm2 );
\r
2623 SetTextColor( hdc, 0 );
\r
2625 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2626 draw the piece again in black for safety.
\r
2628 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2630 SelectObject( hdc, hbm_old );
\r
2632 if( hPieceMask[index] != NULL ) {
\r
2633 DeleteObject( hPieceMask[index] );
\r
2636 hPieceMask[index] = hbm;
\r
2639 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2641 SelectObject( hdc, hbm );
\r
2644 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2645 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2646 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2648 SelectObject( dc1, hPieceMask[index] );
\r
2649 SelectObject( dc2, bm2 );
\r
2650 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2651 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2654 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2655 the piece background and deletes (makes transparent) the rest.
\r
2656 Thanks to that mask, we are free to paint the background with the greates
\r
2657 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2658 We use this, to make gradients and give the pieces a "roundish" look.
\r
2660 SetPieceBackground( hdc, backColor, 2 );
\r
2661 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2665 DeleteObject( bm2 );
\r
2668 SetTextColor( hdc, foreColor );
\r
2669 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2671 SelectObject( hdc, hbm_old );
\r
2673 if( hPieceFace[index] != NULL ) {
\r
2674 DeleteObject( hPieceFace[index] );
\r
2677 hPieceFace[index] = hbm;
\r
2680 static int TranslatePieceToFontPiece( int piece )
\r
2710 case BlackMarshall:
\r
2714 case BlackNightrider:
\r
2720 case BlackUnicorn:
\r
2724 case BlackGrasshopper:
\r
2736 case BlackCardinal:
\r
2743 case WhiteMarshall:
\r
2747 case WhiteNightrider:
\r
2753 case WhiteUnicorn:
\r
2757 case WhiteGrasshopper:
\r
2769 case WhiteCardinal:
\r
2778 void CreatePiecesFromFont()
\r
2781 HDC hdc_window = NULL;
\r
2787 if( fontBitmapSquareSize < 0 ) {
\r
2788 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2792 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2793 fontBitmapSquareSize = -1;
\r
2797 if( fontBitmapSquareSize != squareSize ) {
\r
2798 hdc_window = GetDC( hwndMain );
\r
2799 hdc = CreateCompatibleDC( hdc_window );
\r
2801 if( hPieceFont != NULL ) {
\r
2802 DeleteObject( hPieceFont );
\r
2805 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2806 hPieceMask[i] = NULL;
\r
2807 hPieceFace[i] = NULL;
\r
2813 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2814 fontHeight = appData.fontPieceSize;
\r
2817 fontHeight = (fontHeight * squareSize) / 100;
\r
2819 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2821 lf.lfEscapement = 0;
\r
2822 lf.lfOrientation = 0;
\r
2823 lf.lfWeight = FW_NORMAL;
\r
2825 lf.lfUnderline = 0;
\r
2826 lf.lfStrikeOut = 0;
\r
2827 lf.lfCharSet = DEFAULT_CHARSET;
\r
2828 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2829 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2830 lf.lfQuality = PROOF_QUALITY;
\r
2831 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2832 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2833 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2835 hPieceFont = CreateFontIndirect( &lf );
\r
2837 if( hPieceFont == NULL ) {
\r
2838 fontBitmapSquareSize = -2;
\r
2841 /* Setup font-to-piece character table */
\r
2842 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2843 /* No (or wrong) global settings, try to detect the font */
\r
2844 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2846 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2848 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2849 /* DiagramTT* family */
\r
2850 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2852 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2853 /* Fairy symbols */
\r
2854 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2856 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2857 /* Good Companion (Some characters get warped as literal :-( */
\r
2858 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2859 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2860 SetCharTable(pieceToFontChar, s);
\r
2863 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2864 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2868 /* Create bitmaps */
\r
2869 hfont_old = SelectObject( hdc, hPieceFont );
\r
2871 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2872 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2873 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2874 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2875 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2876 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2877 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2878 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2879 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2880 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2881 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2882 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2884 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2885 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2886 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2887 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2888 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2889 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2890 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2891 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2892 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2893 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2894 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
2895 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
2896 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
2897 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
2898 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
2899 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
2900 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2901 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2902 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2903 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2904 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2905 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2906 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2907 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2908 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2909 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2910 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
2911 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
2912 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
2913 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
2914 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
2915 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
2917 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2918 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2919 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2921 SelectObject( hdc, hfont_old );
\r
2923 fontBitmapSquareSize = squareSize;
\r
2927 if( hdc != NULL ) {
\r
2931 if( hdc_window != NULL ) {
\r
2932 ReleaseDC( hwndMain, hdc_window );
\r
2937 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2941 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2942 if (gameInfo.event &&
\r
2943 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2944 strcmp(name, "k80s") == 0) {
\r
2945 strcpy(name, "tim");
\r
2947 return LoadBitmap(hinst, name);
\r
2951 /* Insert a color into the program's logical palette
\r
2952 structure. This code assumes the given color is
\r
2953 the result of the RGB or PALETTERGB macro, and it
\r
2954 knows how those macros work (which is documented).
\r
2957 InsertInPalette(COLORREF color)
\r
2959 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2961 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2962 DisplayFatalError("Too many colors", 0, 1);
\r
2963 pLogPal->palNumEntries--;
\r
2967 pe->peFlags = (char) 0;
\r
2968 pe->peRed = (char) (0xFF & color);
\r
2969 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2970 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2976 InitDrawingColors()
\r
2978 if (pLogPal == NULL) {
\r
2979 /* Allocate enough memory for a logical palette with
\r
2980 * PALETTESIZE entries and set the size and version fields
\r
2981 * of the logical palette structure.
\r
2983 pLogPal = (NPLOGPALETTE)
\r
2984 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2985 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2986 pLogPal->palVersion = 0x300;
\r
2988 pLogPal->palNumEntries = 0;
\r
2990 InsertInPalette(lightSquareColor);
\r
2991 InsertInPalette(darkSquareColor);
\r
2992 InsertInPalette(whitePieceColor);
\r
2993 InsertInPalette(blackPieceColor);
\r
2994 InsertInPalette(highlightSquareColor);
\r
2995 InsertInPalette(premoveHighlightColor);
\r
2997 /* create a logical color palette according the information
\r
2998 * in the LOGPALETTE structure.
\r
3000 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3002 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3003 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3004 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3005 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3006 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3007 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3009 /* [AS] Force rendering of the font-based pieces */
\r
3010 if( fontBitmapSquareSize > 0 ) {
\r
3011 fontBitmapSquareSize = 0;
\r
3017 BoardWidth(int boardSize, int n)
\r
3018 { /* [HGM] argument n added to allow different width and height */
\r
3019 int lineGap = sizeInfo[boardSize].lineGap;
\r
3021 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3022 lineGap = appData.overrideLineGap;
\r
3025 return (n + 1) * lineGap +
\r
3026 n * sizeInfo[boardSize].squareSize;
\r
3029 /* Respond to board resize by dragging edge */
\r
3031 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3033 BoardSize newSize = NUM_SIZES - 1;
\r
3034 static int recurse = 0;
\r
3035 if (IsIconic(hwndMain)) return;
\r
3036 if (recurse > 0) return;
\r
3038 while (newSize > 0) {
\r
3039 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3040 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3041 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3044 boardSize = newSize;
\r
3045 InitDrawingSizes(boardSize, flags);
\r
3052 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3054 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3055 ChessSquare piece;
\r
3056 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3058 SIZE clockSize, messageSize;
\r
3060 char buf[MSG_SIZ];
\r
3062 HMENU hmenu = GetMenu(hwndMain);
\r
3063 RECT crect, wrect;
\r
3065 LOGBRUSH logbrush;
\r
3067 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3068 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3070 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3071 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3073 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3074 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3075 squareSize = sizeInfo[boardSize].squareSize;
\r
3076 lineGap = sizeInfo[boardSize].lineGap;
\r
3077 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3079 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3080 lineGap = appData.overrideLineGap;
\r
3083 if (tinyLayout != oldTinyLayout) {
\r
3084 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3086 style &= ~WS_SYSMENU;
\r
3087 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3088 "&Minimize\tCtrl+F4");
\r
3090 style |= WS_SYSMENU;
\r
3091 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3093 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3095 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3096 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3097 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3099 DrawMenuBar(hwndMain);
\r
3102 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3103 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3105 /* Get text area sizes */
\r
3106 hdc = GetDC(hwndMain);
\r
3107 if (appData.clockMode) {
\r
3108 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3110 sprintf(buf, "White");
\r
3112 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3113 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3114 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3115 str = "We only care about the height here";
\r
3116 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3117 SelectObject(hdc, oldFont);
\r
3118 ReleaseDC(hwndMain, hdc);
\r
3120 /* Compute where everything goes */
\r
3121 if(first.programLogo || second.programLogo) {
\r
3122 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3123 logoHeight = 2*clockSize.cy;
\r
3124 leftLogoRect.left = OUTER_MARGIN;
\r
3125 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3126 leftLogoRect.top = OUTER_MARGIN;
\r
3127 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3129 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3130 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3131 rightLogoRect.top = OUTER_MARGIN;
\r
3132 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3135 blackRect.left = leftLogoRect.right;
\r
3136 blackRect.right = rightLogoRect.left;
\r
3137 blackRect.top = OUTER_MARGIN;
\r
3138 blackRect.bottom = blackRect.top + clockSize.cy;
\r
3140 whiteRect.left = blackRect.left ;
\r
3141 whiteRect.right = blackRect.right;
\r
3142 whiteRect.top = blackRect.bottom;
\r
3143 whiteRect.bottom = leftLogoRect.bottom;
\r
3145 whiteRect.left = OUTER_MARGIN;
\r
3146 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3147 whiteRect.top = OUTER_MARGIN + logoHeight;
\r
3148 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3150 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3151 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3152 blackRect.top = whiteRect.top;
\r
3153 blackRect.bottom = whiteRect.bottom;
\r
3156 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3157 if (appData.showButtonBar) {
\r
3158 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3159 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3161 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3163 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3164 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3166 boardRect.left = OUTER_MARGIN;
\r
3167 boardRect.right = boardRect.left + boardWidth;
\r
3168 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3169 boardRect.bottom = boardRect.top + boardHeight;
\r
3171 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3172 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3173 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3174 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3175 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3176 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3177 GetWindowRect(hwndMain, &wrect);
\r
3178 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3179 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3180 /* compensate if menu bar wrapped */
\r
3181 GetClientRect(hwndMain, &crect);
\r
3182 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3183 winHeight += offby;
\r
3185 case WMSZ_TOPLEFT:
\r
3186 SetWindowPos(hwndMain, NULL,
\r
3187 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3188 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3191 case WMSZ_TOPRIGHT:
\r
3193 SetWindowPos(hwndMain, NULL,
\r
3194 wrect.left, wrect.bottom - winHeight,
\r
3195 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3198 case WMSZ_BOTTOMLEFT:
\r
3200 SetWindowPos(hwndMain, NULL,
\r
3201 wrect.right - winWidth, wrect.top,
\r
3202 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3205 case WMSZ_BOTTOMRIGHT:
\r
3209 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3210 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3215 for (i = 0; i < N_BUTTONS; i++) {
\r
3216 if (buttonDesc[i].hwnd != NULL) {
\r
3217 DestroyWindow(buttonDesc[i].hwnd);
\r
3218 buttonDesc[i].hwnd = NULL;
\r
3220 if (appData.showButtonBar) {
\r
3221 buttonDesc[i].hwnd =
\r
3222 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3223 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3224 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3225 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3226 (HMENU) buttonDesc[i].id,
\r
3227 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3229 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3230 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3231 MAKELPARAM(FALSE, 0));
\r
3233 if (buttonDesc[i].id == IDM_Pause)
\r
3234 hwndPause = buttonDesc[i].hwnd;
\r
3235 buttonDesc[i].wndproc = (WNDPROC)
\r
3236 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3239 if (gridPen != NULL) DeleteObject(gridPen);
\r
3240 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3241 if (premovePen != NULL) DeleteObject(premovePen);
\r
3242 if (lineGap != 0) {
\r
3243 logbrush.lbStyle = BS_SOLID;
\r
3244 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3246 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3247 lineGap, &logbrush, 0, NULL);
\r
3248 logbrush.lbColor = highlightSquareColor;
\r
3250 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3251 lineGap, &logbrush, 0, NULL);
\r
3253 logbrush.lbColor = premoveHighlightColor;
\r
3255 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3256 lineGap, &logbrush, 0, NULL);
\r
3258 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3259 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3260 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3261 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3262 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3263 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3264 BOARD_WIDTH * (squareSize + lineGap);
\r
3265 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3267 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3268 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3269 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3270 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3271 lineGap / 2 + (i * (squareSize + lineGap));
\r
3272 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3273 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3274 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3278 /* [HGM] Licensing requirement */
\r
3280 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3283 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3285 GothicPopUp( "", VariantNormal);
\r
3288 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3289 oldBoardSize = boardSize;
\r
3290 oldTinyLayout = tinyLayout;
\r
3292 /* Load piece bitmaps for this board size */
\r
3293 for (i=0; i<=2; i++) {
\r
3294 for (piece = WhitePawn;
\r
3295 (int) piece < (int) BlackPawn;
\r
3296 piece = (ChessSquare) ((int) piece + 1)) {
\r
3297 if (pieceBitmap[i][piece] != NULL)
\r
3298 DeleteObject(pieceBitmap[i][piece]);
\r
3302 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3303 // Orthodox Chess pieces
\r
3304 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3305 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3306 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3307 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3308 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3309 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3310 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3311 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3312 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3313 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3314 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3315 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3316 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3317 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3318 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3319 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3320 // in Shogi, Hijack the unused Queen for Lance
\r
3321 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3322 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3323 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3325 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3326 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3327 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3330 if(squareSize <= 72 && squareSize >= 33) {
\r
3331 /* A & C are available in most sizes now */
\r
3332 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3333 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3334 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3335 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3336 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3337 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3338 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3339 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3340 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3341 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3342 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3343 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3344 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3345 } else { // Smirf-like
\r
3346 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3347 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3348 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3350 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3351 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3352 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3353 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3354 } else { // WinBoard standard
\r
3355 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3356 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3357 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3362 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3363 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3364 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3365 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3366 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3367 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3368 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3369 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3370 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3371 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3372 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3373 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3374 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3375 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3376 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3377 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3378 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3379 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3380 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3381 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3382 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3383 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3384 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3385 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3386 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3387 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3388 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3389 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3390 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3391 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3392 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3394 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3395 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3396 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3397 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3398 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3399 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3400 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3401 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3402 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3403 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3404 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3405 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3406 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3408 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3409 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3410 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3411 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3412 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3413 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3414 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3415 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3416 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3417 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3418 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3419 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3422 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3423 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3424 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3425 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3426 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3427 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3428 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3429 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3430 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3431 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3432 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3433 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3434 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3435 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3436 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3440 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3441 /* special Shogi support in this size */
\r
3442 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3443 for (piece = WhitePawn;
\r
3444 (int) piece < (int) BlackPawn;
\r
3445 piece = (ChessSquare) ((int) piece + 1)) {
\r
3446 if (pieceBitmap[i][piece] != NULL)
\r
3447 DeleteObject(pieceBitmap[i][piece]);
\r
3450 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3451 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3452 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3453 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3454 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3455 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3456 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3457 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3458 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3459 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3460 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3461 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3462 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3463 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3464 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3465 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3466 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3467 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3468 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3469 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3470 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3471 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3472 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3473 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3474 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3475 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3476 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3477 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3478 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3479 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3480 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3481 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3482 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3483 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3484 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3485 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3486 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3487 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3488 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3489 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3490 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3491 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3497 PieceBitmap(ChessSquare p, int kind)
\r
3499 if ((int) p >= (int) BlackPawn)
\r
3500 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3502 return pieceBitmap[kind][(int) p];
\r
3505 /***************************************************************/
\r
3507 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3508 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3510 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3511 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3515 SquareToPos(int row, int column, int * x, int * y)
\r
3518 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3519 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3521 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3522 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3527 DrawCoordsOnDC(HDC hdc)
\r
3529 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
3530 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
3531 char str[2] = { NULLCHAR, NULLCHAR };
\r
3532 int oldMode, oldAlign, x, y, start, i;
\r
3536 if (!appData.showCoords)
\r
3539 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3541 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3542 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3543 oldAlign = GetTextAlign(hdc);
\r
3544 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3546 y = boardRect.top + lineGap;
\r
3547 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3549 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3550 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3551 str[0] = files[start + i];
\r
3552 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3553 y += squareSize + lineGap;
\r
3556 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3558 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3559 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3560 str[0] = ranks[start + i];
\r
3561 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3562 x += squareSize + lineGap;
\r
3565 SelectObject(hdc, oldBrush);
\r
3566 SetBkMode(hdc, oldMode);
\r
3567 SetTextAlign(hdc, oldAlign);
\r
3568 SelectObject(hdc, oldFont);
\r
3572 DrawGridOnDC(HDC hdc)
\r
3576 if (lineGap != 0) {
\r
3577 oldPen = SelectObject(hdc, gridPen);
\r
3578 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3579 SelectObject(hdc, oldPen);
\r
3583 #define HIGHLIGHT_PEN 0
\r
3584 #define PREMOVE_PEN 1
\r
3587 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3590 HPEN oldPen, hPen;
\r
3591 if (lineGap == 0) return;
\r
3593 x1 = boardRect.left +
\r
3594 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3595 y1 = boardRect.top +
\r
3596 lineGap/2 + y * (squareSize + lineGap);
\r
3598 x1 = boardRect.left +
\r
3599 lineGap/2 + x * (squareSize + lineGap);
\r
3600 y1 = boardRect.top +
\r
3601 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3603 hPen = pen ? premovePen : highlightPen;
\r
3604 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3605 MoveToEx(hdc, x1, y1, NULL);
\r
3606 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3607 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3608 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3609 LineTo(hdc, x1, y1);
\r
3610 SelectObject(hdc, oldPen);
\r
3614 DrawHighlightsOnDC(HDC hdc)
\r
3617 for (i=0; i<2; i++) {
\r
3618 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3619 DrawHighlightOnDC(hdc, TRUE,
\r
3620 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3623 for (i=0; i<2; i++) {
\r
3624 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3625 premoveHighlightInfo.sq[i].y >= 0) {
\r
3626 DrawHighlightOnDC(hdc, TRUE,
\r
3627 premoveHighlightInfo.sq[i].x,
\r
3628 premoveHighlightInfo.sq[i].y,
\r
3634 /* Note: sqcolor is used only in monoMode */
\r
3635 /* Note that this code is largely duplicated in woptions.c,
\r
3636 function DrawSampleSquare, so that needs to be updated too */
\r
3638 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3640 HBITMAP oldBitmap;
\r
3644 if (appData.blindfold) return;
\r
3646 /* [AS] Use font-based pieces if needed */
\r
3647 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3648 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3649 CreatePiecesFromFont();
\r
3651 if( fontBitmapSquareSize == squareSize ) {
\r
3652 int index = TranslatePieceToFontPiece(piece);
\r
3654 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3658 squareSize, squareSize,
\r
3663 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3667 squareSize, squareSize,
\r
3676 if (appData.monoMode) {
\r
3677 SelectObject(tmphdc, PieceBitmap(piece,
\r
3678 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3679 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3680 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3682 tmpSize = squareSize;
\r
3684 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3685 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3686 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3687 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3688 x += (squareSize - minorSize)>>1;
\r
3689 y += squareSize - minorSize - 2;
\r
3690 tmpSize = minorSize;
\r
3692 if (color || appData.allWhite ) {
\r
3693 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3695 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3696 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3697 if(appData.upsideDown && color==flipView)
\r
3698 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3700 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3702 /* Use black piece color for outline of white pieces */
\r
3703 /* Not sure this looks really good (though xboard does it).
\r
3704 Maybe better to have another selectable color, default black */
\r
3705 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3706 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3707 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3709 /* Use black for outline of white pieces */
\r
3710 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3711 if(appData.upsideDown && color==flipView)
\r
3712 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3714 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3718 /* Use white piece color for details of black pieces */
\r
3719 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3720 WHITE_PIECE ones aren't always the right shape. */
\r
3721 /* Not sure this looks really good (though xboard does it).
\r
3722 Maybe better to have another selectable color, default medium gray? */
\r
3723 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3724 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3725 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3726 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3727 SelectObject(hdc, blackPieceBrush);
\r
3728 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3730 /* Use square color for details of black pieces */
\r
3731 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3732 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3733 if(appData.upsideDown && !flipView)
\r
3734 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3736 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3739 SelectObject(hdc, oldBrush);
\r
3740 SelectObject(tmphdc, oldBitmap);
\r
3744 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3745 int GetBackTextureMode( int algo )
\r
3747 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3751 case BACK_TEXTURE_MODE_PLAIN:
\r
3752 result = 1; /* Always use identity map */
\r
3754 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3755 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3763 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3764 to handle redraws cleanly (as random numbers would always be different).
\r
3766 VOID RebuildTextureSquareInfo()
\r
3776 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3778 if( liteBackTexture != NULL ) {
\r
3779 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3780 lite_w = bi.bmWidth;
\r
3781 lite_h = bi.bmHeight;
\r
3785 if( darkBackTexture != NULL ) {
\r
3786 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3787 dark_w = bi.bmWidth;
\r
3788 dark_h = bi.bmHeight;
\r
3792 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3793 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3794 if( (col + row) & 1 ) {
\r
3796 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3797 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3798 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3799 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3804 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3805 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3806 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3807 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3814 /* [AS] Arrow highlighting support */
\r
3816 static int A_WIDTH = 5; /* Width of arrow body */
\r
3818 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3819 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3821 static double Sqr( double x )
\r
3826 static int Round( double x )
\r
3828 return (int) (x + 0.5);
\r
3831 /* Draw an arrow between two points using current settings */
\r
3832 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3835 double dx, dy, j, k, x, y;
\r
3837 if( d_x == s_x ) {
\r
3838 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3840 arrow[0].x = s_x + A_WIDTH;
\r
3843 arrow[1].x = s_x + A_WIDTH;
\r
3844 arrow[1].y = d_y - h;
\r
3846 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3847 arrow[2].y = d_y - h;
\r
3852 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3853 arrow[4].y = d_y - h;
\r
3855 arrow[5].x = s_x - A_WIDTH;
\r
3856 arrow[5].y = d_y - h;
\r
3858 arrow[6].x = s_x - A_WIDTH;
\r
3861 else if( d_y == s_y ) {
\r
3862 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3865 arrow[0].y = s_y + A_WIDTH;
\r
3867 arrow[1].x = d_x - w;
\r
3868 arrow[1].y = s_y + A_WIDTH;
\r
3870 arrow[2].x = d_x - w;
\r
3871 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3876 arrow[4].x = d_x - w;
\r
3877 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3879 arrow[5].x = d_x - w;
\r
3880 arrow[5].y = s_y - A_WIDTH;
\r
3883 arrow[6].y = s_y - A_WIDTH;
\r
3886 /* [AS] Needed a lot of paper for this! :-) */
\r
3887 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3888 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3890 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3892 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3897 arrow[0].x = Round(x - j);
\r
3898 arrow[0].y = Round(y + j*dx);
\r
3900 arrow[1].x = Round(x + j);
\r
3901 arrow[1].y = Round(y - j*dx);
\r
3904 x = (double) d_x - k;
\r
3905 y = (double) d_y - k*dy;
\r
3908 x = (double) d_x + k;
\r
3909 y = (double) d_y + k*dy;
\r
3912 arrow[2].x = Round(x + j);
\r
3913 arrow[2].y = Round(y - j*dx);
\r
3915 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3916 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3921 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3922 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3924 arrow[6].x = Round(x - j);
\r
3925 arrow[6].y = Round(y + j*dx);
\r
3928 Polygon( hdc, arrow, 7 );
\r
3931 /* [AS] Draw an arrow between two squares */
\r
3932 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3934 int s_x, s_y, d_x, d_y;
\r
3941 if( s_col == d_col && s_row == d_row ) {
\r
3945 /* Get source and destination points */
\r
3946 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3947 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3950 d_y += squareSize / 4;
\r
3952 else if( d_y < s_y ) {
\r
3953 d_y += 3 * squareSize / 4;
\r
3956 d_y += squareSize / 2;
\r
3960 d_x += squareSize / 4;
\r
3962 else if( d_x < s_x ) {
\r
3963 d_x += 3 * squareSize / 4;
\r
3966 d_x += squareSize / 2;
\r
3969 s_x += squareSize / 2;
\r
3970 s_y += squareSize / 2;
\r
3972 /* Adjust width */
\r
3973 A_WIDTH = squareSize / 14;
\r
3976 stLB.lbStyle = BS_SOLID;
\r
3977 stLB.lbColor = appData.highlightArrowColor;
\r
3980 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3981 holdpen = SelectObject( hdc, hpen );
\r
3982 hbrush = CreateBrushIndirect( &stLB );
\r
3983 holdbrush = SelectObject( hdc, hbrush );
\r
3985 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3987 SelectObject( hdc, holdpen );
\r
3988 SelectObject( hdc, holdbrush );
\r
3989 DeleteObject( hpen );
\r
3990 DeleteObject( hbrush );
\r
3993 BOOL HasHighlightInfo()
\r
3995 BOOL result = FALSE;
\r
3997 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3998 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4006 BOOL IsDrawArrowEnabled()
\r
4008 BOOL result = FALSE;
\r
4010 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4017 VOID DrawArrowHighlight( HDC hdc )
\r
4019 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4020 DrawArrowBetweenSquares( hdc,
\r
4021 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4022 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4026 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4028 HRGN result = NULL;
\r
4030 if( HasHighlightInfo() ) {
\r
4031 int x1, y1, x2, y2;
\r
4032 int sx, sy, dx, dy;
\r
4034 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4035 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4037 sx = MIN( x1, x2 );
\r
4038 sy = MIN( y1, y2 );
\r
4039 dx = MAX( x1, x2 ) + squareSize;
\r
4040 dy = MAX( y1, y2 ) + squareSize;
\r
4042 result = CreateRectRgn( sx, sy, dx, dy );
\r
4049 Warning: this function modifies the behavior of several other functions.
\r
4051 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4052 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4053 repaint is scattered all over the place, which is not good for features such as
\r
4054 "arrow highlighting" that require a full repaint of the board.
\r
4056 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4057 user interaction, when speed is not so important) but especially to avoid errors
\r
4058 in the displayed graphics.
\r
4060 In such patched places, I always try refer to this function so there is a single
\r
4061 place to maintain knowledge.
\r
4063 To restore the original behavior, just return FALSE unconditionally.
\r
4065 BOOL IsFullRepaintPreferrable()
\r
4067 BOOL result = FALSE;
\r
4069 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4070 /* Arrow may appear on the board */
\r
4078 This function is called by DrawPosition to know whether a full repaint must
\r
4081 Only DrawPosition may directly call this function, which makes use of
\r
4082 some state information. Other function should call DrawPosition specifying
\r
4083 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4085 BOOL DrawPositionNeedsFullRepaint()
\r
4087 BOOL result = FALSE;
\r
4090 Probably a slightly better policy would be to trigger a full repaint
\r
4091 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4092 but animation is fast enough that it's difficult to notice.
\r
4094 if( animInfo.piece == EmptySquare ) {
\r
4095 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4104 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4106 int row, column, x, y, square_color, piece_color;
\r
4107 ChessSquare piece;
\r
4109 HDC texture_hdc = NULL;
\r
4111 /* [AS] Initialize background textures if needed */
\r
4112 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4113 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4114 if( backTextureSquareSize != squareSize
\r
4115 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4116 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4117 backTextureSquareSize = squareSize;
\r
4118 RebuildTextureSquareInfo();
\r
4121 texture_hdc = CreateCompatibleDC( hdc );
\r
4124 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4125 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4127 SquareToPos(row, column, &x, &y);
\r
4129 piece = board[row][column];
\r
4131 square_color = ((column + row) % 2) == 1;
\r
4132 if( gameInfo.variant == VariantXiangqi ) {
\r
4133 square_color = !InPalace(row, column);
\r
4134 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4135 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4137 piece_color = (int) piece < (int) BlackPawn;
\r
4140 /* [HGM] holdings file: light square or black */
\r
4141 if(column == BOARD_LEFT-2) {
\r
4142 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4145 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4149 if(column == BOARD_RGHT + 1 ) {
\r
4150 if( row < gameInfo.holdingsSize )
\r
4153 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4157 if(column == BOARD_LEFT-1 ) /* left align */
\r
4158 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4159 else if( column == BOARD_RGHT) /* right align */
\r
4160 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4162 if (appData.monoMode) {
\r
4163 if (piece == EmptySquare) {
\r
4164 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4165 square_color ? WHITENESS : BLACKNESS);
\r
4167 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4170 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4171 /* [AS] Draw the square using a texture bitmap */
\r
4172 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4173 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4174 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4177 squareSize, squareSize,
\r
4180 backTextureSquareInfo[r][c].mode,
\r
4181 backTextureSquareInfo[r][c].x,
\r
4182 backTextureSquareInfo[r][c].y );
\r
4184 SelectObject( texture_hdc, hbm );
\r
4186 if (piece != EmptySquare) {
\r
4187 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4191 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4193 oldBrush = SelectObject(hdc, brush );
\r
4194 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4195 SelectObject(hdc, oldBrush);
\r
4196 if (piece != EmptySquare)
\r
4197 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4202 if( texture_hdc != NULL ) {
\r
4203 DeleteDC( texture_hdc );
\r
4207 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4208 void fputDW(FILE *f, int x)
\r
4210 fputc(x & 255, f);
\r
4211 fputc(x>>8 & 255, f);
\r
4212 fputc(x>>16 & 255, f);
\r
4213 fputc(x>>24 & 255, f);
\r
4216 #define MAX_CLIPS 200 /* more than enough */
\r
4219 DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)
\r
4221 // HBITMAP bufferBitmap;
\r
4226 int w = 100, h = 50;
\r
4228 if(cps->programLogo == NULL) return;
\r
4229 // GetClientRect(hwndMain, &Rect);
\r
4230 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4231 // Rect.bottom-Rect.top+1);
\r
4232 tmphdc = CreateCompatibleDC(hdc);
\r
4233 hbm = SelectObject(tmphdc, (HBITMAP) cps->programLogo);
\r
4234 if( GetObject( cps->programLogo, sizeof(bi), &bi ) > 0 ) {
\r
4238 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4239 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4240 SelectObject(tmphdc, hbm);
\r
4245 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4247 static Board lastReq, lastDrawn;
\r
4248 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4249 static int lastDrawnFlipView = 0;
\r
4250 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4251 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4254 HBITMAP bufferBitmap;
\r
4255 HBITMAP oldBitmap;
\r
4257 HRGN clips[MAX_CLIPS];
\r
4258 ChessSquare dragged_piece = EmptySquare;
\r
4260 /* I'm undecided on this - this function figures out whether a full
\r
4261 * repaint is necessary on its own, so there's no real reason to have the
\r
4262 * caller tell it that. I think this can safely be set to FALSE - but
\r
4263 * if we trust the callers not to request full repaints unnessesarily, then
\r
4264 * we could skip some clipping work. In other words, only request a full
\r
4265 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4266 * gamestart and similar) --Hawk
\r
4268 Boolean fullrepaint = repaint;
\r
4270 if( DrawPositionNeedsFullRepaint() ) {
\r
4271 fullrepaint = TRUE;
\r
4275 if( fullrepaint ) {
\r
4276 static int repaint_count = 0;
\r
4280 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4281 OutputDebugString( buf );
\r
4285 if (board == NULL) {
\r
4286 if (!lastReqValid) {
\r
4291 CopyBoard(lastReq, board);
\r
4295 if (doingSizing) {
\r
4299 if (IsIconic(hwndMain)) {
\r
4303 if (hdc == NULL) {
\r
4304 hdc = GetDC(hwndMain);
\r
4305 if (!appData.monoMode) {
\r
4306 SelectPalette(hdc, hPal, FALSE);
\r
4307 RealizePalette(hdc);
\r
4311 releaseDC = FALSE;
\r
4315 fprintf(debugFP, "*******************************\n"
\r
4317 "dragInfo.from (%d,%d)\n"
\r
4318 "dragInfo.start (%d,%d)\n"
\r
4319 "dragInfo.pos (%d,%d)\n"
\r
4320 "dragInfo.lastpos (%d,%d)\n",
\r
4321 repaint ? "TRUE" : "FALSE",
\r
4322 dragInfo.from.x, dragInfo.from.y,
\r
4323 dragInfo.start.x, dragInfo.start.y,
\r
4324 dragInfo.pos.x, dragInfo.pos.y,
\r
4325 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4326 fprintf(debugFP, "prev: ");
\r
4327 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4328 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4329 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4332 fprintf(debugFP, "\n");
\r
4333 fprintf(debugFP, "board: ");
\r
4334 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4335 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4336 fprintf(debugFP, "%d ", board[row][column]);
\r
4339 fprintf(debugFP, "\n");
\r
4343 /* Create some work-DCs */
\r
4344 hdcmem = CreateCompatibleDC(hdc);
\r
4345 tmphdc = CreateCompatibleDC(hdc);
\r
4347 /* If dragging is in progress, we temporarely remove the piece */
\r
4348 /* [HGM] or temporarily decrease count if stacked */
\r
4349 /* !! Moved to before board compare !! */
\r
4350 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4351 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4352 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4353 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4354 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4356 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4357 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4358 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4360 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4363 /* Figure out which squares need updating by comparing the
\r
4364 * newest board with the last drawn board and checking if
\r
4365 * flipping has changed.
\r
4367 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4368 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4369 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4370 if (lastDrawn[row][column] != board[row][column]) {
\r
4371 SquareToPos(row, column, &x, &y);
\r
4372 clips[num_clips++] =
\r
4373 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4377 for (i=0; i<2; i++) {
\r
4378 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4379 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4380 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4381 lastDrawnHighlight.sq[i].y >= 0) {
\r
4382 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4383 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4384 clips[num_clips++] =
\r
4385 CreateRectRgn(x - lineGap, y - lineGap,
\r
4386 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4388 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4389 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4390 clips[num_clips++] =
\r
4391 CreateRectRgn(x - lineGap, y - lineGap,
\r
4392 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4396 for (i=0; i<2; i++) {
\r
4397 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4398 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4399 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4400 lastDrawnPremove.sq[i].y >= 0) {
\r
4401 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4402 lastDrawnPremove.sq[i].x, &x, &y);
\r
4403 clips[num_clips++] =
\r
4404 CreateRectRgn(x - lineGap, y - lineGap,
\r
4405 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4407 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4408 premoveHighlightInfo.sq[i].y >= 0) {
\r
4409 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4410 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4411 clips[num_clips++] =
\r
4412 CreateRectRgn(x - lineGap, y - lineGap,
\r
4413 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4418 fullrepaint = TRUE;
\r
4421 /* Create a buffer bitmap - this is the actual bitmap
\r
4422 * being written to. When all the work is done, we can
\r
4423 * copy it to the real DC (the screen). This avoids
\r
4424 * the problems with flickering.
\r
4426 GetClientRect(hwndMain, &Rect);
\r
4427 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4428 Rect.bottom-Rect.top+1);
\r
4429 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4430 if (!appData.monoMode) {
\r
4431 SelectPalette(hdcmem, hPal, FALSE);
\r
4434 /* Create clips for dragging */
\r
4435 if (!fullrepaint) {
\r
4436 if (dragInfo.from.x >= 0) {
\r
4437 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4438 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4440 if (dragInfo.start.x >= 0) {
\r
4441 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4442 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4444 if (dragInfo.pos.x >= 0) {
\r
4445 x = dragInfo.pos.x - squareSize / 2;
\r
4446 y = dragInfo.pos.y - squareSize / 2;
\r
4447 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4449 if (dragInfo.lastpos.x >= 0) {
\r
4450 x = dragInfo.lastpos.x - squareSize / 2;
\r
4451 y = dragInfo.lastpos.y - squareSize / 2;
\r
4452 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4456 /* Are we animating a move?
\r
4458 * - remove the piece from the board (temporarely)
\r
4459 * - calculate the clipping region
\r
4461 if (!fullrepaint) {
\r
4462 if (animInfo.piece != EmptySquare) {
\r
4463 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4464 x = boardRect.left + animInfo.lastpos.x;
\r
4465 y = boardRect.top + animInfo.lastpos.y;
\r
4466 x2 = boardRect.left + animInfo.pos.x;
\r
4467 y2 = boardRect.top + animInfo.pos.y;
\r
4468 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4469 /* Slight kludge. The real problem is that after AnimateMove is
\r
4470 done, the position on the screen does not match lastDrawn.
\r
4471 This currently causes trouble only on e.p. captures in
\r
4472 atomic, where the piece moves to an empty square and then
\r
4473 explodes. The old and new positions both had an empty square
\r
4474 at the destination, but animation has drawn a piece there and
\r
4475 we have to remember to erase it. */
\r
4476 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4480 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4481 if (num_clips == 0)
\r
4482 fullrepaint = TRUE;
\r
4484 /* Set clipping on the memory DC */
\r
4485 if (!fullrepaint) {
\r
4486 SelectClipRgn(hdcmem, clips[0]);
\r
4487 for (x = 1; x < num_clips; x++) {
\r
4488 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4489 abort(); // this should never ever happen!
\r
4493 /* Do all the drawing to the memory DC */
\r
4494 DrawGridOnDC(hdcmem);
\r
4495 DrawHighlightsOnDC(hdcmem);
\r
4496 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4499 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);
\r
4500 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);
\r
4503 if( appData.highlightMoveWithArrow ) {
\r
4504 DrawArrowHighlight(hdcmem);
\r
4507 DrawCoordsOnDC(hdcmem);
\r
4509 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4510 /* to make sure lastDrawn contains what is actually drawn */
\r
4512 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4513 if (dragged_piece != EmptySquare) {
\r
4514 /* [HGM] or restack */
\r
4515 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4516 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4518 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4519 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4520 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4521 x = dragInfo.pos.x - squareSize / 2;
\r
4522 y = dragInfo.pos.y - squareSize / 2;
\r
4523 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4524 ((int) dragged_piece < (int) BlackPawn),
\r
4525 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4528 /* Put the animated piece back into place and draw it */
\r
4529 if (animInfo.piece != EmptySquare) {
\r
4530 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4531 x = boardRect.left + animInfo.pos.x;
\r
4532 y = boardRect.top + animInfo.pos.y;
\r
4533 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4534 ((int) animInfo.piece < (int) BlackPawn),
\r
4535 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4538 /* Release the bufferBitmap by selecting in the old bitmap
\r
4539 * and delete the memory DC
\r
4541 SelectObject(hdcmem, oldBitmap);
\r
4544 /* Set clipping on the target DC */
\r
4545 if (!fullrepaint) {
\r
4546 SelectClipRgn(hdc, clips[0]);
\r
4547 for (x = 1; x < num_clips; x++) {
\r
4548 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4549 abort(); // this should never ever happen!
\r
4553 /* Copy the new bitmap onto the screen in one go.
\r
4554 * This way we avoid any flickering
\r
4556 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4557 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4558 boardRect.right - boardRect.left,
\r
4559 boardRect.bottom - boardRect.top,
\r
4560 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4561 if(saveDiagFlag) {
\r
4562 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4563 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4565 GetObject(bufferBitmap, sizeof(b), &b);
\r
4566 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4567 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4568 bih.biWidth = b.bmWidth;
\r
4569 bih.biHeight = b.bmHeight;
\r
4571 bih.biBitCount = b.bmBitsPixel;
\r
4572 bih.biCompression = 0;
\r
4573 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4574 bih.biXPelsPerMeter = 0;
\r
4575 bih.biYPelsPerMeter = 0;
\r
4576 bih.biClrUsed = 0;
\r
4577 bih.biClrImportant = 0;
\r
4578 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4579 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4580 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4581 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4584 wb = b.bmWidthBytes;
\r
4586 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4587 int k = ((int*) pData)[i];
\r
4588 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4589 if(j >= 16) break;
\r
4591 if(j >= nrColors) nrColors = j+1;
\r
4593 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4595 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4596 for(w=0; w<(wb>>2); w+=2) {
\r
4597 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4598 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4599 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4600 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4601 pData[p++] = m | j<<4;
\r
4603 while(p&3) pData[p++] = 0;
\r
4606 wb = ((wb+31)>>5)<<2;
\r
4608 // write BITMAPFILEHEADER
\r
4609 fprintf(diagFile, "BM");
\r
4610 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4611 fputDW(diagFile, 0);
\r
4612 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4613 // write BITMAPINFOHEADER
\r
4614 fputDW(diagFile, 40);
\r
4615 fputDW(diagFile, b.bmWidth);
\r
4616 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4617 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4618 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4619 fputDW(diagFile, 0);
\r
4620 fputDW(diagFile, 0);
\r
4621 fputDW(diagFile, 0);
\r
4622 fputDW(diagFile, 0);
\r
4623 fputDW(diagFile, 0);
\r
4624 fputDW(diagFile, 0);
\r
4625 // write color table
\r
4627 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4628 // write bitmap data
\r
4629 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4630 fputc(pData[i], diagFile);
\r
4635 SelectObject(tmphdc, oldBitmap);
\r
4637 /* Massive cleanup */
\r
4638 for (x = 0; x < num_clips; x++)
\r
4639 DeleteObject(clips[x]);
\r
4642 DeleteObject(bufferBitmap);
\r
4645 ReleaseDC(hwndMain, hdc);
\r
4647 if (lastDrawnFlipView != flipView) {
\r
4649 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4651 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4654 /* CopyBoard(lastDrawn, board);*/
\r
4655 lastDrawnHighlight = highlightInfo;
\r
4656 lastDrawnPremove = premoveHighlightInfo;
\r
4657 lastDrawnFlipView = flipView;
\r
4658 lastDrawnValid = 1;
\r
4661 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4666 saveDiagFlag = 1; diagFile = f;
\r
4667 HDCDrawPosition(NULL, TRUE, NULL);
\r
4671 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4678 /*---------------------------------------------------------------------------*\
\r
4679 | CLIENT PAINT PROCEDURE
\r
4680 | This is the main event-handler for the WM_PAINT message.
\r
4682 \*---------------------------------------------------------------------------*/
\r
4684 PaintProc(HWND hwnd)
\r
4690 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4691 if (IsIconic(hwnd)) {
\r
4692 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4694 if (!appData.monoMode) {
\r
4695 SelectPalette(hdc, hPal, FALSE);
\r
4696 RealizePalette(hdc);
\r
4698 HDCDrawPosition(hdc, 1, NULL);
\r
4700 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4701 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4702 ETO_CLIPPED|ETO_OPAQUE,
\r
4703 &messageRect, messageText, strlen(messageText), NULL);
\r
4704 SelectObject(hdc, oldFont);
\r
4705 DisplayBothClocks();
\r
4707 EndPaint(hwnd,&ps);
\r
4715 * If the user selects on a border boundary, return -1; if off the board,
\r
4716 * return -2. Otherwise map the event coordinate to the square.
\r
4717 * The offset boardRect.left or boardRect.top must already have been
\r
4718 * subtracted from x.
\r
4721 EventToSquare(int x)
\r
4728 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4730 x /= (squareSize + lineGap);
\r
4731 if (x >= BOARD_SIZE)
\r
4742 DropEnable dropEnables[] = {
\r
4743 { 'P', DP_Pawn, "Pawn" },
\r
4744 { 'N', DP_Knight, "Knight" },
\r
4745 { 'B', DP_Bishop, "Bishop" },
\r
4746 { 'R', DP_Rook, "Rook" },
\r
4747 { 'Q', DP_Queen, "Queen" },
\r
4751 SetupDropMenu(HMENU hmenu)
\r
4753 int i, count, enable;
\r
4755 extern char white_holding[], black_holding[];
\r
4756 char item[MSG_SIZ];
\r
4758 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4759 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4760 dropEnables[i].piece);
\r
4762 while (p && *p++ == dropEnables[i].piece) count++;
\r
4763 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4764 enable = count > 0 || !appData.testLegality
\r
4765 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4766 && !appData.icsActive);
\r
4767 ModifyMenu(hmenu, dropEnables[i].command,
\r
4768 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4769 dropEnables[i].command, item);
\r
4773 static int fromX = -1, fromY = -1, toX, toY;
\r
4775 /* Event handler for mouse messages */
\r
4777 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4781 static int recursive = 0;
\r
4783 // BOOLEAN needsRedraw = FALSE;
\r
4784 BOOLEAN saveAnimate;
\r
4785 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4786 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4787 ChessMove moveType;
\r
4790 if (message == WM_MBUTTONUP) {
\r
4791 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4792 to the middle button: we simulate pressing the left button too!
\r
4794 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4795 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4801 pt.x = LOWORD(lParam);
\r
4802 pt.y = HIWORD(lParam);
\r
4803 x = EventToSquare(pt.x - boardRect.left);
\r
4804 y = EventToSquare(pt.y - boardRect.top);
\r
4805 if (!flipView && y >= 0) {
\r
4806 y = BOARD_HEIGHT - 1 - y;
\r
4808 if (flipView && x >= 0) {
\r
4809 x = BOARD_WIDTH - 1 - x;
\r
4812 switch (message) {
\r
4813 case WM_LBUTTONDOWN:
\r
4814 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4815 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4816 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4817 if(gameInfo.holdingsWidth &&
\r
4818 (WhiteOnMove(currentMove)
\r
4819 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4820 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4821 // click in right holdings, for determining promotion piece
\r
4822 ChessSquare p = boards[currentMove][y][x];
\r
4823 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4824 if(p != EmptySquare) {
\r
4825 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4826 fromX = fromY = -1;
\r
4830 DrawPosition(FALSE, boards[currentMove]);
\r
4834 sameAgain = FALSE;
\r
4836 /* Downclick vertically off board; check if on clock */
\r
4837 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4838 if (gameMode == EditPosition) {
\r
4839 SetWhiteToPlayEvent();
\r
4840 } else if (gameMode == IcsPlayingBlack ||
\r
4841 gameMode == MachinePlaysWhite) {
\r
4843 } else if (gameMode == EditGame) {
\r
4844 AdjustClock((logoHeight > 0 ? flipView: flipClock), -1);
\r
4846 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4847 if (gameMode == EditPosition) {
\r
4848 SetBlackToPlayEvent();
\r
4849 } else if (gameMode == IcsPlayingWhite ||
\r
4850 gameMode == MachinePlaysBlack) {
\r
4852 } else if (gameMode == EditGame) {
\r
4853 AdjustClock(!(logoHeight > 0 ? flipView: flipClock), -1);
\r
4856 if (!appData.highlightLastMove) {
\r
4857 ClearHighlights();
\r
4858 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4860 fromX = fromY = -1;
\r
4861 dragInfo.start.x = dragInfo.start.y = -1;
\r
4862 dragInfo.from = dragInfo.start;
\r
4864 } else if (x < 0 || y < 0
\r
4865 /* [HGM] block clicks between board and holdings */
\r
4866 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4867 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4868 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4869 /* EditPosition, empty square, or different color piece;
\r
4870 click-click move is possible */
\r
4873 } else if (fromX == x && fromY == y) {
\r
4874 /* Downclick on same square again */
\r
4875 ClearHighlights();
\r
4876 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4877 sameAgain = TRUE;
\r
4878 } else if (fromX != -1 &&
\r
4879 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4881 /* Downclick on different square. */
\r
4882 /* [HGM] if on holdings file, should count as new first click ! */
\r
4883 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4886 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4887 to make sure move is legal before showing promotion popup */
\r
4888 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4889 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4890 fromX = fromY = -1;
\r
4891 ClearHighlights();
\r
4892 DrawPosition(FALSE, boards[currentMove]);
\r
4895 if(moveType != ImpossibleMove) {
\r
4896 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4897 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4898 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4899 appData.alwaysPromoteToQueen)) {
\r
4900 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4901 if (!appData.highlightLastMove) {
\r
4902 ClearHighlights();
\r
4903 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4906 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4907 SetHighlights(fromX, fromY, toX, toY);
\r
4908 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4909 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4910 If promotion to Q is legal, all are legal! */
\r
4911 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4912 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4913 // kludge to temporarily execute move on display, wthout promotng yet
\r
4914 promotionChoice = TRUE;
\r
4915 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4916 boards[currentMove][toY][toX] = p;
\r
4917 DrawPosition(FALSE, boards[currentMove]);
\r
4918 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4919 boards[currentMove][toY][toX] = q;
\r
4921 PromotionPopup(hwnd);
\r
4922 } else { /* not a promotion */
\r
4923 if (appData.animate || appData.highlightLastMove) {
\r
4924 SetHighlights(fromX, fromY, toX, toY);
\r
4926 ClearHighlights();
\r
4928 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4929 fromX = fromY = -1;
\r
4930 if (appData.animate && !appData.highlightLastMove) {
\r
4931 ClearHighlights();
\r
4932 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4938 /* [HGM] it seemed that braces were missing here */
\r
4939 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4940 fromX = fromY = -1;
\r
4944 ClearHighlights();
\r
4945 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4947 /* First downclick, or restart on a square with same color piece */
\r
4948 if (!frozen && OKToStartUserMove(x, y)) {
\r
4951 dragInfo.lastpos = pt;
\r
4952 dragInfo.from.x = fromX;
\r
4953 dragInfo.from.y = fromY;
\r
4954 dragInfo.start = dragInfo.from;
\r
4955 SetCapture(hwndMain);
\r
4957 fromX = fromY = -1;
\r
4958 dragInfo.start.x = dragInfo.start.y = -1;
\r
4959 dragInfo.from = dragInfo.start;
\r
4960 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4964 case WM_LBUTTONUP:
\r
4966 if (fromX == -1) break;
\r
4967 if (x == fromX && y == fromY) {
\r
4968 dragInfo.from.x = dragInfo.from.y = -1;
\r
4969 /* Upclick on same square */
\r
4971 /* Clicked same square twice: abort click-click move */
\r
4972 fromX = fromY = -1;
\r
4974 ClearPremoveHighlights();
\r
4976 /* First square clicked: start click-click move */
\r
4977 SetHighlights(fromX, fromY, -1, -1);
\r
4979 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4980 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4981 /* Errant click; ignore */
\r
4984 /* Finish drag move. */
\r
4985 if (appData.debugMode) {
\r
4986 fprintf(debugFP, "release\n");
\r
4988 dragInfo.from.x = dragInfo.from.y = -1;
\r
4991 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4992 appData.animate = appData.animate && !appData.animateDragging;
\r
4993 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4994 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4995 fromX = fromY = -1;
\r
4996 ClearHighlights();
\r
4997 DrawPosition(FALSE, boards[currentMove]);
\r
5000 if(moveType != ImpossibleMove) {
\r
5001 /* [HGM] use move type to determine if move is promotion.
\r
5002 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5003 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5004 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5005 appData.alwaysPromoteToQueen))
\r
5006 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5008 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5009 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5010 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5011 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5012 // kludge to temporarily execute move on display, wthout promotng yet
\r
5013 promotionChoice = TRUE;
\r
5014 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5015 boards[currentMove][toY][toX] = p;
\r
5016 DrawPosition(FALSE, boards[currentMove]);
\r
5017 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5018 boards[currentMove][toY][toX] = q;
\r
5021 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5022 } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5024 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5025 appData.animate = saveAnimate;
\r
5026 fromX = fromY = -1;
\r
5027 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5028 ClearHighlights();
\r
5030 if (appData.animate || appData.animateDragging ||
\r
5031 appData.highlightDragging || gotPremove) {
\r
5032 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5035 dragInfo.start.x = dragInfo.start.y = -1;
\r
5036 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5039 case WM_MOUSEMOVE:
\r
5040 if ((appData.animateDragging || appData.highlightDragging)
\r
5041 && (wParam & MK_LBUTTON)
\r
5042 && dragInfo.from.x >= 0)
\r
5044 BOOL full_repaint = FALSE;
\r
5046 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5047 if (appData.animateDragging) {
\r
5048 dragInfo.pos = pt;
\r
5050 if (appData.highlightDragging) {
\r
5051 SetHighlights(fromX, fromY, x, y);
\r
5052 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5053 full_repaint = TRUE;
\r
5057 DrawPosition( full_repaint, NULL);
\r
5059 dragInfo.lastpos = dragInfo.pos;
\r
5063 case WM_MOUSEWHEEL: // [DM]
\r
5064 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5065 /* Mouse Wheel is being rolled forward
\r
5066 * Play moves forward
\r
5068 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5069 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5070 /* Mouse Wheel is being rolled backward
\r
5071 * Play moves backward
\r
5073 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5074 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5078 case WM_MBUTTONDOWN:
\r
5079 case WM_RBUTTONDOWN:
\r
5082 fromX = fromY = -1;
\r
5083 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5084 dragInfo.start.x = dragInfo.start.y = -1;
\r
5085 dragInfo.from = dragInfo.start;
\r
5086 dragInfo.lastpos = dragInfo.pos;
\r
5087 if (appData.highlightDragging) {
\r
5088 ClearHighlights();
\r
5091 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5092 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5093 if (gameMode == EditGame) AdjustClock((logoHeight > 0 ? flipView: flipClock), 1);
\r
5094 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5095 if (gameMode == EditGame) AdjustClock(!(logoHeight > 0 ? flipView: flipClock), 1);
\r
5098 DrawPosition(TRUE, NULL);
\r
5100 switch (gameMode) {
\r
5101 case EditPosition:
\r
5102 case IcsExamining:
\r
5103 if (x < 0 || y < 0) break;
\r
5106 if (message == WM_MBUTTONDOWN) {
\r
5107 buttonCount = 3; /* even if system didn't think so */
\r
5108 if (wParam & MK_SHIFT)
\r
5109 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5111 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5112 } else { /* message == WM_RBUTTONDOWN */
\r
5114 if (buttonCount == 3) {
\r
5115 if (wParam & MK_SHIFT)
\r
5116 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5118 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5120 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5123 /* Just have one menu, on the right button. Windows users don't
\r
5124 think to try the middle one, and sometimes other software steals
\r
5125 it, or it doesn't really exist. */
\r
5126 if(gameInfo.variant != VariantShogi)
\r
5127 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5129 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5133 case IcsPlayingWhite:
\r
5134 case IcsPlayingBlack:
\r
5136 case MachinePlaysWhite:
\r
5137 case MachinePlaysBlack:
\r
5138 if (appData.testLegality &&
\r
5139 gameInfo.variant != VariantBughouse &&
\r
5140 gameInfo.variant != VariantCrazyhouse) break;
\r
5141 if (x < 0 || y < 0) break;
\r
5144 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5145 SetupDropMenu(hmenu);
\r
5146 MenuPopup(hwnd, pt, hmenu, -1);
\r
5157 /* Preprocess messages for buttons in main window */
\r
5159 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5161 int id = GetWindowLong(hwnd, GWL_ID);
\r
5164 for (i=0; i<N_BUTTONS; i++) {
\r
5165 if (buttonDesc[i].id == id) break;
\r
5167 if (i == N_BUTTONS) return 0;
\r
5168 switch (message) {
\r
5173 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5174 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5181 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5184 if (appData.icsActive) {
\r
5185 if (GetKeyState(VK_SHIFT) < 0) {
\r
5187 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5188 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5192 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5193 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5200 if (appData.icsActive) {
\r
5201 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5202 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5204 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5206 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5207 PopUpMoveDialog((char)wParam);
\r
5213 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5216 /* Process messages for Promotion dialog box */
\r
5218 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5222 switch (message) {
\r
5223 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5224 /* Center the dialog over the application window */
\r
5225 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5226 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5227 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5228 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5229 SW_SHOW : SW_HIDE);
\r
5230 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5231 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5232 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5233 PieceToChar(WhiteAngel) != '~') ||
\r
5234 (PieceToChar(BlackAngel) >= 'A' &&
\r
5235 PieceToChar(BlackAngel) != '~') ) ?
\r
5236 SW_SHOW : SW_HIDE);
\r
5237 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5238 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5239 PieceToChar(WhiteMarshall) != '~') ||
\r
5240 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5241 PieceToChar(BlackMarshall) != '~') ) ?
\r
5242 SW_SHOW : SW_HIDE);
\r
5243 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5244 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5245 gameInfo.variant != VariantShogi ?
\r
5246 SW_SHOW : SW_HIDE);
\r
5247 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5248 gameInfo.variant != VariantShogi ?
\r
5249 SW_SHOW : SW_HIDE);
\r
5250 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5251 gameInfo.variant == VariantShogi ?
\r
5252 SW_SHOW : SW_HIDE);
\r
5253 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5254 gameInfo.variant == VariantShogi ?
\r
5255 SW_SHOW : SW_HIDE);
\r
5256 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5257 gameInfo.variant == VariantSuper ?
\r
5258 SW_SHOW : SW_HIDE);
\r
5261 case WM_COMMAND: /* message: received a command */
\r
5262 switch (LOWORD(wParam)) {
\r
5264 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5265 ClearHighlights();
\r
5266 DrawPosition(FALSE, NULL);
\r
5269 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5272 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5275 promoChar = PieceToChar(BlackRook);
\r
5278 promoChar = PieceToChar(BlackBishop);
\r
5280 case PB_Chancellor:
\r
5281 promoChar = PieceToChar(BlackMarshall);
\r
5283 case PB_Archbishop:
\r
5284 promoChar = PieceToChar(BlackAngel);
\r
5287 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5292 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5293 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5294 only show the popup when we are already sure the move is valid or
\r
5295 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5296 will figure out it is a promotion from the promoChar. */
\r
5297 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5298 if (!appData.highlightLastMove) {
\r
5299 ClearHighlights();
\r
5300 DrawPosition(FALSE, NULL);
\r
5307 /* Pop up promotion dialog */
\r
5309 PromotionPopup(HWND hwnd)
\r
5313 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5314 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5315 hwnd, (DLGPROC)lpProc);
\r
5316 FreeProcInstance(lpProc);
\r
5319 /* Toggle ShowThinking */
\r
5321 ToggleShowThinking()
\r
5323 appData.showThinking = !appData.showThinking;
\r
5324 ShowThinkingEvent();
\r
5328 LoadGameDialog(HWND hwnd, char* title)
\r
5332 char fileTitle[MSG_SIZ];
\r
5333 f = OpenFileDialog(hwnd, "rb", "",
\r
5334 appData.oldSaveStyle ? "gam" : "pgn",
\r
5336 title, &number, fileTitle, NULL);
\r
5338 cmailMsgLoaded = FALSE;
\r
5339 if (number == 0) {
\r
5340 int error = GameListBuild(f);
\r
5342 DisplayError("Cannot build game list", error);
\r
5343 } else if (!ListEmpty(&gameList) &&
\r
5344 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5345 GameListPopUp(f, fileTitle);
\r
5348 GameListDestroy();
\r
5351 LoadGame(f, number, fileTitle, FALSE);
\r
5356 ChangedConsoleFont()
\r
5359 CHARRANGE tmpsel, sel;
\r
5360 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5361 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5362 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5365 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5366 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5367 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5368 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5369 * size. This was undocumented in the version of MSVC++ that I had
\r
5370 * when I wrote the code, but is apparently documented now.
\r
5372 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5373 cfmt.bCharSet = f->lf.lfCharSet;
\r
5374 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5375 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5376 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5377 /* Why are the following seemingly needed too? */
\r
5378 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5379 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5380 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5382 tmpsel.cpMax = -1; /*999999?*/
\r
5383 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5384 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5385 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5386 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5388 paraf.cbSize = sizeof(paraf);
\r
5389 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5390 paraf.dxStartIndent = 0;
\r
5391 paraf.dxOffset = WRAP_INDENT;
\r
5392 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5393 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5396 /*---------------------------------------------------------------------------*\
\r
5398 * Window Proc for main window
\r
5400 \*---------------------------------------------------------------------------*/
\r
5402 /* Process messages for main window, etc. */
\r
5404 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5407 int wmId, wmEvent;
\r
5411 char fileTitle[MSG_SIZ];
\r
5412 char buf[MSG_SIZ];
\r
5413 static SnapData sd;
\r
5415 switch (message) {
\r
5417 case WM_PAINT: /* message: repaint portion of window */
\r
5421 case WM_ERASEBKGND:
\r
5422 if (IsIconic(hwnd)) {
\r
5423 /* Cheat; change the message */
\r
5424 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5426 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5430 case WM_LBUTTONDOWN:
\r
5431 case WM_MBUTTONDOWN:
\r
5432 case WM_RBUTTONDOWN:
\r
5433 case WM_LBUTTONUP:
\r
5434 case WM_MBUTTONUP:
\r
5435 case WM_RBUTTONUP:
\r
5436 case WM_MOUSEMOVE:
\r
5437 case WM_MOUSEWHEEL:
\r
5438 MouseEvent(hwnd, message, wParam, lParam);
\r
5443 if (appData.icsActive) {
\r
5444 if (wParam == '\t') {
\r
5445 if (GetKeyState(VK_SHIFT) < 0) {
\r
5447 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5448 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5452 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5453 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5457 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5458 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5460 SendMessage(h, message, wParam, lParam);
\r
5462 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5463 PopUpMoveDialog((char)wParam);
\r
5467 case WM_PALETTECHANGED:
\r
5468 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5470 HDC hdc = GetDC(hwndMain);
\r
5471 SelectPalette(hdc, hPal, TRUE);
\r
5472 nnew = RealizePalette(hdc);
\r
5474 paletteChanged = TRUE;
\r
5476 UpdateColors(hdc);
\r
5478 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5481 ReleaseDC(hwnd, hdc);
\r
5485 case WM_QUERYNEWPALETTE:
\r
5486 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5488 HDC hdc = GetDC(hwndMain);
\r
5489 paletteChanged = FALSE;
\r
5490 SelectPalette(hdc, hPal, FALSE);
\r
5491 nnew = RealizePalette(hdc);
\r
5493 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5495 ReleaseDC(hwnd, hdc);
\r
5500 case WM_COMMAND: /* message: command from application menu */
\r
5501 wmId = LOWORD(wParam);
\r
5502 wmEvent = HIWORD(wParam);
\r
5507 AnalysisPopDown();
\r
5510 case IDM_NewGameFRC:
\r
5511 if( NewGameFRC() == 0 ) {
\r
5513 AnalysisPopDown();
\r
5517 case IDM_NewVariant:
\r
5518 NewVariantPopup(hwnd);
\r
5521 case IDM_LoadGame:
\r
5522 LoadGameDialog(hwnd, "Load Game from File");
\r
5525 case IDM_LoadNextGame:
\r
5529 case IDM_LoadPrevGame:
\r
5533 case IDM_ReloadGame:
\r
5537 case IDM_LoadPosition:
\r
5538 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5539 Reset(FALSE, TRUE);
\r
5542 f = OpenFileDialog(hwnd, "rb", "",
\r
5543 appData.oldSaveStyle ? "pos" : "fen",
\r
5545 "Load Position from File", &number, fileTitle, NULL);
\r
5547 LoadPosition(f, number, fileTitle);
\r
5551 case IDM_LoadNextPosition:
\r
5552 ReloadPosition(1);
\r
5555 case IDM_LoadPrevPosition:
\r
5556 ReloadPosition(-1);
\r
5559 case IDM_ReloadPosition:
\r
5560 ReloadPosition(0);
\r
5563 case IDM_SaveGame:
\r
5564 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5565 f = OpenFileDialog(hwnd, "a", defName,
\r
5566 appData.oldSaveStyle ? "gam" : "pgn",
\r
5568 "Save Game to File", NULL, fileTitle, NULL);
\r
5570 SaveGame(f, 0, "");
\r
5574 case IDM_SavePosition:
\r
5575 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5576 f = OpenFileDialog(hwnd, "a", defName,
\r
5577 appData.oldSaveStyle ? "pos" : "fen",
\r
5579 "Save Position to File", NULL, fileTitle, NULL);
\r
5581 SavePosition(f, 0, "");
\r
5585 case IDM_SaveDiagram:
\r
5586 defName = "diagram";
\r
5587 f = OpenFileDialog(hwnd, "wb", defName,
\r
5590 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5596 case IDM_CopyGame:
\r
5597 CopyGameToClipboard();
\r
5600 case IDM_PasteGame:
\r
5601 PasteGameFromClipboard();
\r
5604 case IDM_CopyGameListToClipboard:
\r
5605 CopyGameListToClipboard();
\r
5608 /* [AS] Autodetect FEN or PGN data */
\r
5609 case IDM_PasteAny:
\r
5610 PasteGameOrFENFromClipboard();
\r
5613 /* [AS] Move history */
\r
5614 case IDM_ShowMoveHistory:
\r
5615 if( MoveHistoryIsUp() ) {
\r
5616 MoveHistoryPopDown();
\r
5619 MoveHistoryPopUp();
\r
5623 /* [AS] Eval graph */
\r
5624 case IDM_ShowEvalGraph:
\r
5625 if( EvalGraphIsUp() ) {
\r
5626 EvalGraphPopDown();
\r
5633 /* [AS] Engine output */
\r
5634 case IDM_ShowEngineOutput:
\r
5635 if( EngineOutputIsUp() ) {
\r
5636 EngineOutputPopDown();
\r
5639 EngineOutputPopUp();
\r
5643 /* [AS] User adjudication */
\r
5644 case IDM_UserAdjudication_White:
\r
5645 UserAdjudicationEvent( +1 );
\r
5648 case IDM_UserAdjudication_Black:
\r
5649 UserAdjudicationEvent( -1 );
\r
5652 case IDM_UserAdjudication_Draw:
\r
5653 UserAdjudicationEvent( 0 );
\r
5656 /* [AS] Game list options dialog */
\r
5657 case IDM_GameListOptions:
\r
5658 GameListOptions();
\r
5661 case IDM_CopyPosition:
\r
5662 CopyFENToClipboard();
\r
5665 case IDM_PastePosition:
\r
5666 PasteFENFromClipboard();
\r
5669 case IDM_MailMove:
\r
5673 case IDM_ReloadCMailMsg:
\r
5674 Reset(TRUE, TRUE);
\r
5675 ReloadCmailMsgEvent(FALSE);
\r
5678 case IDM_Minimize:
\r
5679 ShowWindow(hwnd, SW_MINIMIZE);
\r
5686 case IDM_MachineWhite:
\r
5687 MachineWhiteEvent();
\r
5689 * refresh the tags dialog only if it's visible
\r
5691 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5693 tags = PGNTags(&gameInfo);
\r
5694 TagsPopUp(tags, CmailMsg());
\r
5699 case IDM_MachineBlack:
\r
5700 MachineBlackEvent();
\r
5702 * refresh the tags dialog only if it's visible
\r
5704 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5706 tags = PGNTags(&gameInfo);
\r
5707 TagsPopUp(tags, CmailMsg());
\r
5712 case IDM_TwoMachines:
\r
5713 TwoMachinesEvent();
\r
5715 * refresh the tags dialog only if it's visible
\r
5717 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5719 tags = PGNTags(&gameInfo);
\r
5720 TagsPopUp(tags, CmailMsg());
\r
5725 case IDM_AnalysisMode:
\r
5726 if (!first.analysisSupport) {
\r
5727 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5728 DisplayError(buf, 0);
\r
5730 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5731 if (appData.icsActive) {
\r
5732 if (gameMode != IcsObserving) {
\r
5733 sprintf(buf, "You are not observing a game");
\r
5734 DisplayError(buf, 0);
\r
5735 /* secure check */
\r
5736 if (appData.icsEngineAnalyze) {
\r
5737 if (appData.debugMode)
\r
5738 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5739 ExitAnalyzeMode();
\r
5745 /* if enable, user want disable icsEngineAnalyze */
\r
5746 if (appData.icsEngineAnalyze) {
\r
5747 ExitAnalyzeMode();
\r
5751 appData.icsEngineAnalyze = TRUE;
\r
5752 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5755 if (!appData.showThinking) ToggleShowThinking();
\r
5756 AnalyzeModeEvent();
\r
5760 case IDM_AnalyzeFile:
\r
5761 if (!first.analysisSupport) {
\r
5762 char buf[MSG_SIZ];
\r
5763 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5764 DisplayError(buf, 0);
\r
5766 if (!appData.showThinking) ToggleShowThinking();
\r
5767 AnalyzeFileEvent();
\r
5768 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5769 AnalysisPeriodicEvent(1);
\r
5773 case IDM_IcsClient:
\r
5777 case IDM_EditGame:
\r
5781 case IDM_EditPosition:
\r
5782 EditPositionEvent();
\r
5785 case IDM_Training:
\r
5789 case IDM_ShowGameList:
\r
5790 ShowGameListProc();
\r
5793 case IDM_EditTags:
\r
5797 case IDM_EditComment:
\r
5798 if (commentDialogUp && editComment) {
\r
5801 EditCommentEvent();
\r
5821 case IDM_CallFlag:
\r
5841 case IDM_StopObserving:
\r
5842 StopObservingEvent();
\r
5845 case IDM_StopExamining:
\r
5846 StopExaminingEvent();
\r
5849 case IDM_TypeInMove:
\r
5850 PopUpMoveDialog('\000');
\r
5853 case IDM_TypeInName:
\r
5854 PopUpNameDialog('\000');
\r
5857 case IDM_Backward:
\r
5859 SetFocus(hwndMain);
\r
5864 SetFocus(hwndMain);
\r
5869 SetFocus(hwndMain);
\r
5874 SetFocus(hwndMain);
\r
5881 case IDM_TruncateGame:
\r
5882 TruncateGameEvent();
\r
5889 case IDM_RetractMove:
\r
5890 RetractMoveEvent();
\r
5893 case IDM_FlipView:
\r
5894 flipView = !flipView;
\r
5895 DrawPosition(FALSE, NULL);
\r
5898 case IDM_FlipClock:
\r
5899 flipClock = !flipClock;
\r
5900 DisplayBothClocks();
\r
5903 case IDM_GeneralOptions:
\r
5904 GeneralOptionsPopup(hwnd);
\r
5905 DrawPosition(TRUE, NULL);
\r
5908 case IDM_BoardOptions:
\r
5909 BoardOptionsPopup(hwnd);
\r
5912 case IDM_EnginePlayOptions:
\r
5913 EnginePlayOptionsPopup(hwnd);
\r
5916 case IDM_OptionsUCI:
\r
5917 UciOptionsPopup(hwnd);
\r
5920 case IDM_IcsOptions:
\r
5921 IcsOptionsPopup(hwnd);
\r
5925 FontsOptionsPopup(hwnd);
\r
5929 SoundOptionsPopup(hwnd);
\r
5932 case IDM_CommPort:
\r
5933 CommPortOptionsPopup(hwnd);
\r
5936 case IDM_LoadOptions:
\r
5937 LoadOptionsPopup(hwnd);
\r
5940 case IDM_SaveOptions:
\r
5941 SaveOptionsPopup(hwnd);
\r
5944 case IDM_TimeControl:
\r
5945 TimeControlOptionsPopup(hwnd);
\r
5948 case IDM_SaveSettings:
\r
5949 SaveSettings(settingsFileName);
\r
5952 case IDM_SaveSettingsOnExit:
\r
5953 saveSettingsOnExit = !saveSettingsOnExit;
\r
5954 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5955 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5956 MF_CHECKED : MF_UNCHECKED));
\r
5967 case IDM_AboutGame:
\r
5972 appData.debugMode = !appData.debugMode;
\r
5973 if (appData.debugMode) {
\r
5974 char dir[MSG_SIZ];
\r
5975 GetCurrentDirectory(MSG_SIZ, dir);
\r
5976 SetCurrentDirectory(installDir);
\r
5977 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5978 SetCurrentDirectory(dir);
\r
5979 setbuf(debugFP, NULL);
\r
5986 case IDM_HELPCONTENTS:
\r
5987 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5988 MessageBox (GetFocus(),
\r
5989 "Unable to activate help",
\r
5990 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5994 case IDM_HELPSEARCH:
\r
5995 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5996 MessageBox (GetFocus(),
\r
5997 "Unable to activate help",
\r
5998 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6002 case IDM_HELPHELP:
\r
6003 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6004 MessageBox (GetFocus(),
\r
6005 "Unable to activate help",
\r
6006 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6011 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6013 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6014 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6015 FreeProcInstance(lpProc);
\r
6018 case IDM_DirectCommand1:
\r
6019 AskQuestionEvent("Direct Command",
\r
6020 "Send to chess program:", "", "1");
\r
6022 case IDM_DirectCommand2:
\r
6023 AskQuestionEvent("Direct Command",
\r
6024 "Send to second chess program:", "", "2");
\r
6027 case EP_WhitePawn:
\r
6028 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6029 fromX = fromY = -1;
\r
6032 case EP_WhiteKnight:
\r
6033 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6034 fromX = fromY = -1;
\r
6037 case EP_WhiteBishop:
\r
6038 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6039 fromX = fromY = -1;
\r
6042 case EP_WhiteRook:
\r
6043 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6044 fromX = fromY = -1;
\r
6047 case EP_WhiteQueen:
\r
6048 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6049 fromX = fromY = -1;
\r
6052 case EP_WhiteFerz:
\r
6053 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6054 fromX = fromY = -1;
\r
6057 case EP_WhiteWazir:
\r
6058 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6059 fromX = fromY = -1;
\r
6062 case EP_WhiteAlfil:
\r
6063 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6064 fromX = fromY = -1;
\r
6067 case EP_WhiteCannon:
\r
6068 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6069 fromX = fromY = -1;
\r
6072 case EP_WhiteCardinal:
\r
6073 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6074 fromX = fromY = -1;
\r
6077 case EP_WhiteMarshall:
\r
6078 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6079 fromX = fromY = -1;
\r
6082 case EP_WhiteKing:
\r
6083 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6084 fromX = fromY = -1;
\r
6087 case EP_BlackPawn:
\r
6088 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6089 fromX = fromY = -1;
\r
6092 case EP_BlackKnight:
\r
6093 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6094 fromX = fromY = -1;
\r
6097 case EP_BlackBishop:
\r
6098 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6099 fromX = fromY = -1;
\r
6102 case EP_BlackRook:
\r
6103 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6104 fromX = fromY = -1;
\r
6107 case EP_BlackQueen:
\r
6108 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6109 fromX = fromY = -1;
\r
6112 case EP_BlackFerz:
\r
6113 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6114 fromX = fromY = -1;
\r
6117 case EP_BlackWazir:
\r
6118 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6119 fromX = fromY = -1;
\r
6122 case EP_BlackAlfil:
\r
6123 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6124 fromX = fromY = -1;
\r
6127 case EP_BlackCannon:
\r
6128 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6129 fromX = fromY = -1;
\r
6132 case EP_BlackCardinal:
\r
6133 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6134 fromX = fromY = -1;
\r
6137 case EP_BlackMarshall:
\r
6138 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6139 fromX = fromY = -1;
\r
6142 case EP_BlackKing:
\r
6143 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6144 fromX = fromY = -1;
\r
6147 case EP_EmptySquare:
\r
6148 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6149 fromX = fromY = -1;
\r
6152 case EP_ClearBoard:
\r
6153 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6154 fromX = fromY = -1;
\r
6158 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6159 fromX = fromY = -1;
\r
6163 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6164 fromX = fromY = -1;
\r
6168 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6169 fromX = fromY = -1;
\r
6173 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6174 fromX = fromY = -1;
\r
6178 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6179 fromX = fromY = -1;
\r
6183 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6184 fromX = fromY = -1;
\r
6188 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6189 fromX = fromY = -1;
\r
6193 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6194 fromX = fromY = -1;
\r
6198 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6199 fromX = fromY = -1;
\r
6203 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6209 case CLOCK_TIMER_ID:
\r
6210 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6211 clockTimerEvent = 0;
\r
6212 DecrementClocks(); /* call into back end */
\r
6214 case LOAD_GAME_TIMER_ID:
\r
6215 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6216 loadGameTimerEvent = 0;
\r
6217 AutoPlayGameLoop(); /* call into back end */
\r
6219 case ANALYSIS_TIMER_ID:
\r
6220 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6221 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6222 AnalysisPeriodicEvent(0);
\r
6224 KillTimer(hwnd, analysisTimerEvent);
\r
6225 analysisTimerEvent = 0;
\r
6228 case DELAYED_TIMER_ID:
\r
6229 KillTimer(hwnd, delayedTimerEvent);
\r
6230 delayedTimerEvent = 0;
\r
6231 delayedTimerCallback();
\r
6236 case WM_USER_Input:
\r
6237 InputEvent(hwnd, message, wParam, lParam);
\r
6240 /* [AS] Also move "attached" child windows */
\r
6241 case WM_WINDOWPOSCHANGING:
\r
6242 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6243 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6245 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6246 /* Window is moving */
\r
6249 GetWindowRect( hwnd, &rcMain );
\r
6251 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6252 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6253 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6258 /* [AS] Snapping */
\r
6259 case WM_ENTERSIZEMOVE:
\r
6260 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6261 if (hwnd == hwndMain) {
\r
6262 doingSizing = TRUE;
\r
6265 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6269 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6270 if (hwnd == hwndMain) {
\r
6271 lastSizing = wParam;
\r
6276 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6277 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6279 case WM_EXITSIZEMOVE:
\r
6280 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6281 if (hwnd == hwndMain) {
\r
6283 doingSizing = FALSE;
\r
6284 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6285 GetClientRect(hwnd, &client);
\r
6286 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6288 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6290 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6293 case WM_DESTROY: /* message: window being destroyed */
\r
6294 PostQuitMessage(0);
\r
6298 if (hwnd == hwndMain) {
\r
6303 default: /* Passes it on if unprocessed */
\r
6304 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6309 /*---------------------------------------------------------------------------*\
\r
6311 * Misc utility routines
\r
6313 \*---------------------------------------------------------------------------*/
\r
6316 * Decent random number generator, at least not as bad as Windows
\r
6317 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6319 unsigned int randstate;
\r
6324 randstate = randstate * 1664525 + 1013904223;
\r
6325 return (int) randstate & 0x7fffffff;
\r
6329 mysrandom(unsigned int seed)
\r
6336 * returns TRUE if user selects a different color, FALSE otherwise
\r
6340 ChangeColor(HWND hwnd, COLORREF *which)
\r
6342 static BOOL firstTime = TRUE;
\r
6343 static DWORD customColors[16];
\r
6345 COLORREF newcolor;
\r
6350 /* Make initial colors in use available as custom colors */
\r
6351 /* Should we put the compiled-in defaults here instead? */
\r
6353 customColors[i++] = lightSquareColor & 0xffffff;
\r
6354 customColors[i++] = darkSquareColor & 0xffffff;
\r
6355 customColors[i++] = whitePieceColor & 0xffffff;
\r
6356 customColors[i++] = blackPieceColor & 0xffffff;
\r
6357 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6358 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6360 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6361 customColors[i++] = textAttribs[ccl].color;
\r
6363 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6364 firstTime = FALSE;
\r
6367 cc.lStructSize = sizeof(cc);
\r
6368 cc.hwndOwner = hwnd;
\r
6369 cc.hInstance = NULL;
\r
6370 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6371 cc.lpCustColors = (LPDWORD) customColors;
\r
6372 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6374 if (!ChooseColor(&cc)) return FALSE;
\r
6376 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6377 if (newcolor == *which) return FALSE;
\r
6378 *which = newcolor;
\r
6382 InitDrawingColors();
\r
6383 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6388 MyLoadSound(MySound *ms)
\r
6394 if (ms->data) free(ms->data);
\r
6397 switch (ms->name[0]) {
\r
6403 /* System sound from Control Panel. Don't preload here. */
\r
6407 if (ms->name[1] == NULLCHAR) {
\r
6408 /* "!" alone = silence */
\r
6411 /* Builtin wave resource. Error if not found. */
\r
6412 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6413 if (h == NULL) break;
\r
6414 ms->data = (void *)LoadResource(hInst, h);
\r
6415 if (h == NULL) break;
\r
6420 /* .wav file. Error if not found. */
\r
6421 f = fopen(ms->name, "rb");
\r
6422 if (f == NULL) break;
\r
6423 if (fstat(fileno(f), &st) < 0) break;
\r
6424 ms->data = malloc(st.st_size);
\r
6425 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6431 char buf[MSG_SIZ];
\r
6432 sprintf(buf, "Error loading sound %s", ms->name);
\r
6433 DisplayError(buf, GetLastError());
\r
6439 MyPlaySound(MySound *ms)
\r
6441 BOOLEAN ok = FALSE;
\r
6442 switch (ms->name[0]) {
\r
6448 /* System sound from Control Panel (deprecated feature).
\r
6449 "$" alone or an unset sound name gets default beep (still in use). */
\r
6450 if (ms->name[1]) {
\r
6451 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6453 if (!ok) ok = MessageBeep(MB_OK);
\r
6456 /* Builtin wave resource, or "!" alone for silence */
\r
6457 if (ms->name[1]) {
\r
6458 if (ms->data == NULL) return FALSE;
\r
6459 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6465 /* .wav file. Error if not found. */
\r
6466 if (ms->data == NULL) return FALSE;
\r
6467 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6470 /* Don't print an error: this can happen innocently if the sound driver
\r
6471 is busy; for instance, if another instance of WinBoard is playing
\r
6472 a sound at about the same time. */
\r
6475 char buf[MSG_SIZ];
\r
6476 sprintf(buf, "Error playing sound %s", ms->name);
\r
6477 DisplayError(buf, GetLastError());
\r
6485 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6488 OPENFILENAME *ofn;
\r
6489 static UINT *number; /* gross that this is static */
\r
6491 switch (message) {
\r
6492 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6493 /* Center the dialog over the application window */
\r
6494 ofn = (OPENFILENAME *) lParam;
\r
6495 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6496 number = (UINT *) ofn->lCustData;
\r
6497 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6501 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6502 return FALSE; /* Allow for further processing */
\r
6505 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6506 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6508 return FALSE; /* Allow for further processing */
\r
6514 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6516 static UINT *number;
\r
6517 OPENFILENAME *ofname;
\r
6520 case WM_INITDIALOG:
\r
6521 ofname = (OPENFILENAME *)lParam;
\r
6522 number = (UINT *)(ofname->lCustData);
\r
6525 ofnot = (OFNOTIFY *)lParam;
\r
6526 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6527 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6536 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6537 char *nameFilt, char *dlgTitle, UINT *number,
\r
6538 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6540 OPENFILENAME openFileName;
\r
6541 char buf1[MSG_SIZ];
\r
6544 if (fileName == NULL) fileName = buf1;
\r
6545 if (defName == NULL) {
\r
6546 strcpy(fileName, "*.");
\r
6547 strcat(fileName, defExt);
\r
6549 strcpy(fileName, defName);
\r
6551 if (fileTitle) strcpy(fileTitle, "");
\r
6552 if (number) *number = 0;
\r
6554 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6555 openFileName.hwndOwner = hwnd;
\r
6556 openFileName.hInstance = (HANDLE) hInst;
\r
6557 openFileName.lpstrFilter = nameFilt;
\r
6558 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6559 openFileName.nMaxCustFilter = 0L;
\r
6560 openFileName.nFilterIndex = 1L;
\r
6561 openFileName.lpstrFile = fileName;
\r
6562 openFileName.nMaxFile = MSG_SIZ;
\r
6563 openFileName.lpstrFileTitle = fileTitle;
\r
6564 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6565 openFileName.lpstrInitialDir = NULL;
\r
6566 openFileName.lpstrTitle = dlgTitle;
\r
6567 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6568 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6569 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6570 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6571 openFileName.nFileOffset = 0;
\r
6572 openFileName.nFileExtension = 0;
\r
6573 openFileName.lpstrDefExt = defExt;
\r
6574 openFileName.lCustData = (LONG) number;
\r
6575 openFileName.lpfnHook = oldDialog ?
\r
6576 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6577 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6579 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6580 GetOpenFileName(&openFileName)) {
\r
6581 /* open the file */
\r
6582 f = fopen(openFileName.lpstrFile, write);
\r
6584 MessageBox(hwnd, "File open failed", NULL,
\r
6585 MB_OK|MB_ICONEXCLAMATION);
\r
6589 int err = CommDlgExtendedError();
\r
6590 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6599 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6601 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6604 * Get the first pop-up menu in the menu template. This is the
\r
6605 * menu that TrackPopupMenu displays.
\r
6607 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6609 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6612 * TrackPopup uses screen coordinates, so convert the
\r
6613 * coordinates of the mouse click to screen coordinates.
\r
6615 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6617 /* Draw and track the floating pop-up menu. */
\r
6618 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6619 pt.x, pt.y, 0, hwnd, NULL);
\r
6621 /* Destroy the menu.*/
\r
6622 DestroyMenu(hmenu);
\r
6627 int sizeX, sizeY, newSizeX, newSizeY;
\r
6629 } ResizeEditPlusButtonsClosure;
\r
6632 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6634 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6638 if (hChild == cl->hText) return TRUE;
\r
6639 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6640 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6641 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6642 ScreenToClient(cl->hDlg, &pt);
\r
6643 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6644 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6648 /* Resize a dialog that has a (rich) edit field filling most of
\r
6649 the top, with a row of buttons below */
\r
6651 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6654 int newTextHeight, newTextWidth;
\r
6655 ResizeEditPlusButtonsClosure cl;
\r
6657 /*if (IsIconic(hDlg)) return;*/
\r
6658 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6660 cl.hdwp = BeginDeferWindowPos(8);
\r
6662 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6663 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6664 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6665 if (newTextHeight < 0) {
\r
6666 newSizeY += -newTextHeight;
\r
6667 newTextHeight = 0;
\r
6669 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6670 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6676 cl.newSizeX = newSizeX;
\r
6677 cl.newSizeY = newSizeY;
\r
6678 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6680 EndDeferWindowPos(cl.hdwp);
\r
6683 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6685 RECT rChild, rParent;
\r
6686 int wChild, hChild, wParent, hParent;
\r
6687 int wScreen, hScreen, xNew, yNew;
\r
6690 /* Get the Height and Width of the child window */
\r
6691 GetWindowRect (hwndChild, &rChild);
\r
6692 wChild = rChild.right - rChild.left;
\r
6693 hChild = rChild.bottom - rChild.top;
\r
6695 /* Get the Height and Width of the parent window */
\r
6696 GetWindowRect (hwndParent, &rParent);
\r
6697 wParent = rParent.right - rParent.left;
\r
6698 hParent = rParent.bottom - rParent.top;
\r
6700 /* Get the display limits */
\r
6701 hdc = GetDC (hwndChild);
\r
6702 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6703 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6704 ReleaseDC(hwndChild, hdc);
\r
6706 /* Calculate new X position, then adjust for screen */
\r
6707 xNew = rParent.left + ((wParent - wChild) /2);
\r
6710 } else if ((xNew+wChild) > wScreen) {
\r
6711 xNew = wScreen - wChild;
\r
6714 /* Calculate new Y position, then adjust for screen */
\r
6716 yNew = rParent.top + ((hParent - hChild) /2);
\r
6719 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6724 } else if ((yNew+hChild) > hScreen) {
\r
6725 yNew = hScreen - hChild;
\r
6728 /* Set it, and return */
\r
6729 return SetWindowPos (hwndChild, NULL,
\r
6730 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6733 /* Center one window over another */
\r
6734 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6736 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6739 /*---------------------------------------------------------------------------*\
\r
6741 * Startup Dialog functions
\r
6743 \*---------------------------------------------------------------------------*/
\r
6745 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6747 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6749 while (*cd != NULL) {
\r
6750 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6756 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6758 char buf1[ARG_MAX];
\r
6761 if (str[0] == '@') {
\r
6762 FILE* f = fopen(str + 1, "r");
\r
6764 DisplayFatalError(str + 1, errno, 2);
\r
6767 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6769 buf1[len] = NULLCHAR;
\r
6773 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6776 char buf[MSG_SIZ];
\r
6777 char *end = strchr(str, '\n');
\r
6778 if (end == NULL) return;
\r
6779 memcpy(buf, str, end - str);
\r
6780 buf[end - str] = NULLCHAR;
\r
6781 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6787 SetStartupDialogEnables(HWND hDlg)
\r
6789 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6790 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6791 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6792 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6793 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6794 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6795 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6796 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6797 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6798 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6799 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6800 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6801 IsDlgButtonChecked(hDlg, OPT_View));
\r
6805 QuoteForFilename(char *filename)
\r
6807 int dquote, space;
\r
6808 dquote = strchr(filename, '"') != NULL;
\r
6809 space = strchr(filename, ' ') != NULL;
\r
6810 if (dquote || space) {
\r
6822 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6824 char buf[MSG_SIZ];
\r
6827 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6828 q = QuoteForFilename(nthcp);
\r
6829 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6830 if (*nthdir != NULLCHAR) {
\r
6831 q = QuoteForFilename(nthdir);
\r
6832 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6834 if (*nthcp == NULLCHAR) {
\r
6835 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6836 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6837 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6838 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6843 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6845 char buf[MSG_SIZ];
\r
6849 switch (message) {
\r
6850 case WM_INITDIALOG:
\r
6851 /* Center the dialog */
\r
6852 CenterWindow (hDlg, GetDesktopWindow());
\r
6853 /* Initialize the dialog items */
\r
6854 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6855 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6856 firstChessProgramNames);
\r
6857 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6858 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6859 secondChessProgramNames);
\r
6860 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6861 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6862 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6863 if (*appData.icsHelper != NULLCHAR) {
\r
6864 char *q = QuoteForFilename(appData.icsHelper);
\r
6865 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6867 if (*appData.icsHost == NULLCHAR) {
\r
6868 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6869 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6870 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6871 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6872 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6875 if (appData.icsActive) {
\r
6876 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6878 else if (appData.noChessProgram) {
\r
6879 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6882 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6885 SetStartupDialogEnables(hDlg);
\r
6889 switch (LOWORD(wParam)) {
\r
6891 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6892 strcpy(buf, "/fcp=");
\r
6893 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6895 ParseArgs(StringGet, &p);
\r
6896 strcpy(buf, "/scp=");
\r
6897 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6899 ParseArgs(StringGet, &p);
\r
6900 appData.noChessProgram = FALSE;
\r
6901 appData.icsActive = FALSE;
\r
6902 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6903 strcpy(buf, "/ics /icshost=");
\r
6904 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6906 ParseArgs(StringGet, &p);
\r
6907 if (appData.zippyPlay) {
\r
6908 strcpy(buf, "/fcp=");
\r
6909 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6911 ParseArgs(StringGet, &p);
\r
6913 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6914 appData.noChessProgram = TRUE;
\r
6915 appData.icsActive = FALSE;
\r
6917 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6918 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6921 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6922 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6924 ParseArgs(StringGet, &p);
\r
6926 EndDialog(hDlg, TRUE);
\r
6933 case IDM_HELPCONTENTS:
\r
6934 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6935 MessageBox (GetFocus(),
\r
6936 "Unable to activate help",
\r
6937 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6942 SetStartupDialogEnables(hDlg);
\r
6950 /*---------------------------------------------------------------------------*\
\r
6952 * About box dialog functions
\r
6954 \*---------------------------------------------------------------------------*/
\r
6956 /* Process messages for "About" dialog box */
\r
6958 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6960 switch (message) {
\r
6961 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6962 /* Center the dialog over the application window */
\r
6963 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6964 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6967 case WM_COMMAND: /* message: received a command */
\r
6968 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6969 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6970 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6978 /*---------------------------------------------------------------------------*\
\r
6980 * Comment Dialog functions
\r
6982 \*---------------------------------------------------------------------------*/
\r
6985 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6987 static HANDLE hwndText = NULL;
\r
6988 int len, newSizeX, newSizeY, flags;
\r
6989 static int sizeX, sizeY;
\r
6994 switch (message) {
\r
6995 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6996 /* Initialize the dialog items */
\r
6997 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6998 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6999 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7000 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7001 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7002 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7003 SetWindowText(hDlg, commentTitle);
\r
7004 if (editComment) {
\r
7005 SetFocus(hwndText);
\r
7007 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7009 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7010 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7011 MAKELPARAM(FALSE, 0));
\r
7012 /* Size and position the dialog */
\r
7013 if (!commentDialog) {
\r
7014 commentDialog = hDlg;
\r
7015 flags = SWP_NOZORDER;
\r
7016 GetClientRect(hDlg, &rect);
\r
7017 sizeX = rect.right;
\r
7018 sizeY = rect.bottom;
\r
7019 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7020 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7021 WINDOWPLACEMENT wp;
\r
7022 EnsureOnScreen(&commentX, &commentY);
\r
7023 wp.length = sizeof(WINDOWPLACEMENT);
\r
7025 wp.showCmd = SW_SHOW;
\r
7026 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7027 wp.rcNormalPosition.left = commentX;
\r
7028 wp.rcNormalPosition.right = commentX + commentW;
\r
7029 wp.rcNormalPosition.top = commentY;
\r
7030 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7031 SetWindowPlacement(hDlg, &wp);
\r
7033 GetClientRect(hDlg, &rect);
\r
7034 newSizeX = rect.right;
\r
7035 newSizeY = rect.bottom;
\r
7036 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7037 newSizeX, newSizeY);
\r
7044 case WM_COMMAND: /* message: received a command */
\r
7045 switch (LOWORD(wParam)) {
\r
7047 if (editComment) {
\r
7049 /* Read changed options from the dialog box */
\r
7050 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7051 len = GetWindowTextLength(hwndText);
\r
7052 str = (char *) malloc(len + 1);
\r
7053 GetWindowText(hwndText, str, len + 1);
\r
7062 ReplaceComment(commentIndex, str);
\r
7069 case OPT_CancelComment:
\r
7073 case OPT_ClearComment:
\r
7074 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7077 case OPT_EditComment:
\r
7078 EditCommentEvent();
\r
7087 newSizeX = LOWORD(lParam);
\r
7088 newSizeY = HIWORD(lParam);
\r
7089 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7094 case WM_GETMINMAXINFO:
\r
7095 /* Prevent resizing window too small */
\r
7096 mmi = (MINMAXINFO *) lParam;
\r
7097 mmi->ptMinTrackSize.x = 100;
\r
7098 mmi->ptMinTrackSize.y = 100;
\r
7105 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7110 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7112 if (str == NULL) str = "";
\r
7113 p = (char *) malloc(2 * strlen(str) + 2);
\r
7116 if (*str == '\n') *q++ = '\r';
\r
7120 if (commentText != NULL) free(commentText);
\r
7122 commentIndex = index;
\r
7123 commentTitle = title;
\r
7125 editComment = edit;
\r
7127 if (commentDialog) {
\r
7128 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7129 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7131 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7132 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7133 hwndMain, (DLGPROC)lpProc);
\r
7134 FreeProcInstance(lpProc);
\r
7136 commentDialogUp = TRUE;
\r
7140 /*---------------------------------------------------------------------------*\
\r
7142 * Type-in move dialog functions
\r
7144 \*---------------------------------------------------------------------------*/
\r
7147 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7149 char move[MSG_SIZ];
\r
7151 ChessMove moveType;
\r
7152 int fromX, fromY, toX, toY;
\r
7155 switch (message) {
\r
7156 case WM_INITDIALOG:
\r
7157 move[0] = (char) lParam;
\r
7158 move[1] = NULLCHAR;
\r
7159 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7160 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7161 SetWindowText(hInput, move);
\r
7163 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7167 switch (LOWORD(wParam)) {
\r
7169 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7170 gameMode != Training) {
\r
7171 DisplayMoveError("Displayed move is not current");
\r
7173 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7174 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7175 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7176 if (gameMode != Training)
\r
7177 forwardMostMove = currentMove;
\r
7178 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7180 DisplayMoveError("Could not parse move");
\r
7183 EndDialog(hDlg, TRUE);
\r
7186 EndDialog(hDlg, FALSE);
\r
7197 PopUpMoveDialog(char firstchar)
\r
7201 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7202 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7203 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7204 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7205 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7206 gameMode == Training) {
\r
7207 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7208 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7209 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7210 FreeProcInstance(lpProc);
\r
7214 /*---------------------------------------------------------------------------*\
\r
7216 * Type-in name dialog functions
\r
7218 \*---------------------------------------------------------------------------*/
\r
7221 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7223 char move[MSG_SIZ];
\r
7226 switch (message) {
\r
7227 case WM_INITDIALOG:
\r
7228 move[0] = (char) lParam;
\r
7229 move[1] = NULLCHAR;
\r
7230 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7231 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7232 SetWindowText(hInput, move);
\r
7234 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7238 switch (LOWORD(wParam)) {
\r
7240 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7241 appData.userName = strdup(move);
\r
7243 EndDialog(hDlg, TRUE);
\r
7246 EndDialog(hDlg, FALSE);
\r
7257 PopUpNameDialog(char firstchar)
\r
7261 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7262 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7263 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7264 FreeProcInstance(lpProc);
\r
7267 /*---------------------------------------------------------------------------*\
\r
7271 \*---------------------------------------------------------------------------*/
\r
7273 /* Nonmodal error box */
\r
7274 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7275 WPARAM wParam, LPARAM lParam);
\r
7278 ErrorPopUp(char *title, char *content)
\r
7282 BOOLEAN modal = hwndMain == NULL;
\r
7300 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7301 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7304 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7306 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7307 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7308 hwndMain, (DLGPROC)lpProc);
\r
7309 FreeProcInstance(lpProc);
\r
7316 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7317 if (errorDialog == NULL) return;
\r
7318 DestroyWindow(errorDialog);
\r
7319 errorDialog = NULL;
\r
7323 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7328 switch (message) {
\r
7329 case WM_INITDIALOG:
\r
7330 GetWindowRect(hDlg, &rChild);
\r
7333 SetWindowPos(hDlg, NULL, rChild.left,
\r
7334 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7335 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7339 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7340 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7341 and it doesn't work when you resize the dialog.
\r
7342 For now, just give it a default position.
\r
7344 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7346 errorDialog = hDlg;
\r
7347 SetWindowText(hDlg, errorTitle);
\r
7348 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7349 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7353 switch (LOWORD(wParam)) {
\r
7356 if (errorDialog == hDlg) errorDialog = NULL;
\r
7357 DestroyWindow(hDlg);
\r
7369 HWND gothicDialog = NULL;
\r
7372 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7376 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7378 switch (message) {
\r
7379 case WM_INITDIALOG:
\r
7380 GetWindowRect(hDlg, &rChild);
\r
7382 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7386 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7387 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7388 and it doesn't work when you resize the dialog.
\r
7389 For now, just give it a default position.
\r
7391 gothicDialog = hDlg;
\r
7392 SetWindowText(hDlg, errorTitle);
\r
7393 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7394 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7398 switch (LOWORD(wParam)) {
\r
7401 if (errorDialog == hDlg) errorDialog = NULL;
\r
7402 DestroyWindow(hDlg);
\r
7414 GothicPopUp(char *title, VariantClass variant)
\r
7417 static char *lastTitle;
\r
7419 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7420 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7422 if(lastTitle != title && gothicDialog != NULL) {
\r
7423 DestroyWindow(gothicDialog);
\r
7424 gothicDialog = NULL;
\r
7426 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7427 title = lastTitle;
\r
7428 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7429 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7430 hwndMain, (DLGPROC)lpProc);
\r
7431 FreeProcInstance(lpProc);
\r
7436 /*---------------------------------------------------------------------------*\
\r
7438 * Ics Interaction console functions
\r
7440 \*---------------------------------------------------------------------------*/
\r
7442 #define HISTORY_SIZE 64
\r
7443 static char *history[HISTORY_SIZE];
\r
7444 int histIn = 0, histP = 0;
\r
7447 SaveInHistory(char *cmd)
\r
7449 if (history[histIn] != NULL) {
\r
7450 free(history[histIn]);
\r
7451 history[histIn] = NULL;
\r
7453 if (*cmd == NULLCHAR) return;
\r
7454 history[histIn] = StrSave(cmd);
\r
7455 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7456 if (history[histIn] != NULL) {
\r
7457 free(history[histIn]);
\r
7458 history[histIn] = NULL;
\r
7464 PrevInHistory(char *cmd)
\r
7467 if (histP == histIn) {
\r
7468 if (history[histIn] != NULL) free(history[histIn]);
\r
7469 history[histIn] = StrSave(cmd);
\r
7471 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7472 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7474 return history[histP];
\r
7480 if (histP == histIn) return NULL;
\r
7481 histP = (histP + 1) % HISTORY_SIZE;
\r
7482 return history[histP];
\r
7489 BOOLEAN immediate;
\r
7490 } IcsTextMenuEntry;
\r
7491 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7492 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7495 ParseIcsTextMenu(char *icsTextMenuString)
\r
7498 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7499 char *p = icsTextMenuString;
\r
7500 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7503 if (e->command != NULL) {
\r
7505 e->command = NULL;
\r
7509 e = icsTextMenuEntry;
\r
7510 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7511 if (*p == ';' || *p == '\n') {
\r
7512 e->item = strdup("-");
\r
7513 e->command = NULL;
\r
7515 } else if (*p == '-') {
\r
7516 e->item = strdup("-");
\r
7517 e->command = NULL;
\r
7521 char *q, *r, *s, *t;
\r
7523 q = strchr(p, ',');
\r
7524 if (q == NULL) break;
\r
7526 r = strchr(q + 1, ',');
\r
7527 if (r == NULL) break;
\r
7529 s = strchr(r + 1, ',');
\r
7530 if (s == NULL) break;
\r
7533 t = strchr(s + 1, c);
\r
7536 t = strchr(s + 1, c);
\r
7538 if (t != NULL) *t = NULLCHAR;
\r
7539 e->item = strdup(p);
\r
7540 e->command = strdup(q + 1);
\r
7541 e->getname = *(r + 1) != '0';
\r
7542 e->immediate = *(s + 1) != '0';
\r
7546 if (t == NULL) break;
\r
7555 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7559 hmenu = LoadMenu(hInst, "TextMenu");
\r
7560 h = GetSubMenu(hmenu, 0);
\r
7562 if (strcmp(e->item, "-") == 0) {
\r
7563 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7565 if (e->item[0] == '|') {
\r
7566 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7567 IDM_CommandX + i, &e->item[1]);
\r
7569 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7578 WNDPROC consoleTextWindowProc;
\r
7581 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7583 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7584 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7588 SetWindowText(hInput, command);
\r
7590 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7592 sel.cpMin = 999999;
\r
7593 sel.cpMax = 999999;
\r
7594 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7599 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7600 if (sel.cpMin == sel.cpMax) {
\r
7601 /* Expand to surrounding word */
\r
7604 tr.chrg.cpMax = sel.cpMin;
\r
7605 tr.chrg.cpMin = --sel.cpMin;
\r
7606 if (sel.cpMin < 0) break;
\r
7607 tr.lpstrText = name;
\r
7608 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7609 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7613 tr.chrg.cpMin = sel.cpMax;
\r
7614 tr.chrg.cpMax = ++sel.cpMax;
\r
7615 tr.lpstrText = name;
\r
7616 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7617 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7620 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7621 MessageBeep(MB_ICONEXCLAMATION);
\r
7625 tr.lpstrText = name;
\r
7626 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7628 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7629 MessageBeep(MB_ICONEXCLAMATION);
\r
7632 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7635 sprintf(buf, "%s %s", command, name);
\r
7636 SetWindowText(hInput, buf);
\r
7637 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7639 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7640 SetWindowText(hInput, buf);
\r
7641 sel.cpMin = 999999;
\r
7642 sel.cpMax = 999999;
\r
7643 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7649 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7654 switch (message) {
\r
7656 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7659 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7662 sel.cpMin = 999999;
\r
7663 sel.cpMax = 999999;
\r
7664 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7665 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7670 if (wParam == '\t') {
\r
7671 if (GetKeyState(VK_SHIFT) < 0) {
\r
7673 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7674 if (buttonDesc[0].hwnd) {
\r
7675 SetFocus(buttonDesc[0].hwnd);
\r
7677 SetFocus(hwndMain);
\r
7681 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7684 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7686 SendMessage(hInput, message, wParam, lParam);
\r
7690 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7692 return SendMessage(hInput, message, wParam, lParam);
\r
7693 case WM_MBUTTONDOWN:
\r
7694 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7695 case WM_RBUTTONDOWN:
\r
7696 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7697 /* Move selection here if it was empty */
\r
7699 pt.x = LOWORD(lParam);
\r
7700 pt.y = HIWORD(lParam);
\r
7701 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7702 if (sel.cpMin == sel.cpMax) {
\r
7703 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7704 sel.cpMax = sel.cpMin;
\r
7705 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7707 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7710 case WM_RBUTTONUP:
\r
7711 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7712 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7713 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7716 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7717 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7718 if (sel.cpMin == sel.cpMax) {
\r
7719 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7720 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7722 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7723 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7725 pt.x = LOWORD(lParam);
\r
7726 pt.y = HIWORD(lParam);
\r
7727 MenuPopup(hwnd, pt, hmenu, -1);
\r
7731 switch (LOWORD(wParam)) {
\r
7732 case IDM_QuickPaste:
\r
7734 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7735 if (sel.cpMin == sel.cpMax) {
\r
7736 MessageBeep(MB_ICONEXCLAMATION);
\r
7739 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7740 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7741 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7746 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7749 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7752 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7756 int i = LOWORD(wParam) - IDM_CommandX;
\r
7757 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7758 icsTextMenuEntry[i].command != NULL) {
\r
7759 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7760 icsTextMenuEntry[i].getname,
\r
7761 icsTextMenuEntry[i].immediate);
\r
7769 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7772 WNDPROC consoleInputWindowProc;
\r
7775 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7777 char buf[MSG_SIZ];
\r
7779 static BOOL sendNextChar = FALSE;
\r
7780 static BOOL quoteNextChar = FALSE;
\r
7781 InputSource *is = consoleInputSource;
\r
7785 switch (message) {
\r
7787 if (!appData.localLineEditing || sendNextChar) {
\r
7788 is->buf[0] = (CHAR) wParam;
\r
7790 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7791 sendNextChar = FALSE;
\r
7794 if (quoteNextChar) {
\r
7795 buf[0] = (char) wParam;
\r
7796 buf[1] = NULLCHAR;
\r
7797 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7798 quoteNextChar = FALSE;
\r
7802 case '\r': /* Enter key */
\r
7803 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7804 if (consoleEcho) SaveInHistory(is->buf);
\r
7805 is->buf[is->count++] = '\n';
\r
7806 is->buf[is->count] = NULLCHAR;
\r
7807 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7808 if (consoleEcho) {
\r
7809 ConsoleOutput(is->buf, is->count, TRUE);
\r
7810 } else if (appData.localLineEditing) {
\r
7811 ConsoleOutput("\n", 1, TRUE);
\r
7814 case '\033': /* Escape key */
\r
7815 SetWindowText(hwnd, "");
\r
7816 cf.cbSize = sizeof(CHARFORMAT);
\r
7817 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7818 if (consoleEcho) {
\r
7819 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7821 cf.crTextColor = COLOR_ECHOOFF;
\r
7823 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7824 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7826 case '\t': /* Tab key */
\r
7827 if (GetKeyState(VK_SHIFT) < 0) {
\r
7829 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7832 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7833 if (buttonDesc[0].hwnd) {
\r
7834 SetFocus(buttonDesc[0].hwnd);
\r
7836 SetFocus(hwndMain);
\r
7840 case '\023': /* Ctrl+S */
\r
7841 sendNextChar = TRUE;
\r
7843 case '\021': /* Ctrl+Q */
\r
7844 quoteNextChar = TRUE;
\r
7853 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7854 p = PrevInHistory(buf);
\r
7856 SetWindowText(hwnd, p);
\r
7857 sel.cpMin = 999999;
\r
7858 sel.cpMax = 999999;
\r
7859 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7864 p = NextInHistory();
\r
7866 SetWindowText(hwnd, p);
\r
7867 sel.cpMin = 999999;
\r
7868 sel.cpMax = 999999;
\r
7869 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7875 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7879 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7883 case WM_MBUTTONDOWN:
\r
7884 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7885 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7887 case WM_RBUTTONUP:
\r
7888 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7889 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7890 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7894 hmenu = LoadMenu(hInst, "InputMenu");
\r
7895 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7896 if (sel.cpMin == sel.cpMax) {
\r
7897 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7898 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7900 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7901 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7903 pt.x = LOWORD(lParam);
\r
7904 pt.y = HIWORD(lParam);
\r
7905 MenuPopup(hwnd, pt, hmenu, -1);
\r
7909 switch (LOWORD(wParam)) {
\r
7911 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7913 case IDM_SelectAll:
\r
7915 sel.cpMax = -1; /*999999?*/
\r
7916 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7919 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7922 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7925 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7930 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7933 #define CO_MAX 100000
\r
7934 #define CO_TRIM 1000
\r
7937 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7939 static SnapData sd;
\r
7940 static HWND hText, hInput /*, hFocus*/;
\r
7941 // InputSource *is = consoleInputSource;
\r
7943 static int sizeX, sizeY;
\r
7944 int newSizeX, newSizeY;
\r
7947 switch (message) {
\r
7948 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7949 hwndConsole = hDlg;
\r
7950 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7951 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7953 consoleTextWindowProc = (WNDPROC)
\r
7954 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7955 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7956 consoleInputWindowProc = (WNDPROC)
\r
7957 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7958 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7959 Colorize(ColorNormal, TRUE);
\r
7960 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7961 ChangedConsoleFont();
\r
7962 GetClientRect(hDlg, &rect);
\r
7963 sizeX = rect.right;
\r
7964 sizeY = rect.bottom;
\r
7965 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7966 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7967 WINDOWPLACEMENT wp;
\r
7968 EnsureOnScreen(&consoleX, &consoleY);
\r
7969 wp.length = sizeof(WINDOWPLACEMENT);
\r
7971 wp.showCmd = SW_SHOW;
\r
7972 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7973 wp.rcNormalPosition.left = consoleX;
\r
7974 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7975 wp.rcNormalPosition.top = consoleY;
\r
7976 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7977 SetWindowPlacement(hDlg, &wp);
\r
7980 // [HGM] Chessknight's change 2004-07-13
\r
7981 else { /* Determine Defaults */
\r
7982 WINDOWPLACEMENT wp;
\r
7983 consoleX = winWidth + 1;
\r
7984 consoleY = boardY;
\r
7985 consoleW = screenWidth - winWidth;
\r
7986 consoleH = winHeight;
\r
7987 EnsureOnScreen(&consoleX, &consoleY);
\r
7988 wp.length = sizeof(WINDOWPLACEMENT);
\r
7990 wp.showCmd = SW_SHOW;
\r
7991 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7992 wp.rcNormalPosition.left = consoleX;
\r
7993 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7994 wp.rcNormalPosition.top = consoleY;
\r
7995 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7996 SetWindowPlacement(hDlg, &wp);
\r
8011 if (IsIconic(hDlg)) break;
\r
8012 newSizeX = LOWORD(lParam);
\r
8013 newSizeY = HIWORD(lParam);
\r
8014 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8015 RECT rectText, rectInput;
\r
8017 int newTextHeight, newTextWidth;
\r
8018 GetWindowRect(hText, &rectText);
\r
8019 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8020 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8021 if (newTextHeight < 0) {
\r
8022 newSizeY += -newTextHeight;
\r
8023 newTextHeight = 0;
\r
8025 SetWindowPos(hText, NULL, 0, 0,
\r
8026 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8027 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8028 pt.x = rectInput.left;
\r
8029 pt.y = rectInput.top + newSizeY - sizeY;
\r
8030 ScreenToClient(hDlg, &pt);
\r
8031 SetWindowPos(hInput, NULL,
\r
8032 pt.x, pt.y, /* needs client coords */
\r
8033 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8034 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8040 case WM_GETMINMAXINFO:
\r
8041 /* Prevent resizing window too small */
\r
8042 mmi = (MINMAXINFO *) lParam;
\r
8043 mmi->ptMinTrackSize.x = 100;
\r
8044 mmi->ptMinTrackSize.y = 100;
\r
8047 /* [AS] Snapping */
\r
8048 case WM_ENTERSIZEMOVE:
\r
8049 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8052 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8055 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8057 case WM_EXITSIZEMOVE:
\r
8058 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8061 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8069 if (hwndConsole) return;
\r
8070 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8071 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8076 ConsoleOutput(char* data, int length, int forceVisible)
\r
8081 char buf[CO_MAX+1];
\r
8084 static int delayLF = 0;
\r
8085 CHARRANGE savesel, sel;
\r
8087 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8095 while (length--) {
\r
8103 } else if (*p == '\007') {
\r
8104 MyPlaySound(&sounds[(int)SoundBell]);
\r
8111 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8112 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8113 /* Save current selection */
\r
8114 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8115 exlen = GetWindowTextLength(hText);
\r
8116 /* Find out whether current end of text is visible */
\r
8117 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8118 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8119 /* Trim existing text if it's too long */
\r
8120 if (exlen + (q - buf) > CO_MAX) {
\r
8121 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8124 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8125 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8127 savesel.cpMin -= trim;
\r
8128 savesel.cpMax -= trim;
\r
8129 if (exlen < 0) exlen = 0;
\r
8130 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8131 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8133 /* Append the new text */
\r
8134 sel.cpMin = exlen;
\r
8135 sel.cpMax = exlen;
\r
8136 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8137 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8138 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8139 if (forceVisible || exlen == 0 ||
\r
8140 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8141 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8142 /* Scroll to make new end of text visible if old end of text
\r
8143 was visible or new text is an echo of user typein */
\r
8144 sel.cpMin = 9999999;
\r
8145 sel.cpMax = 9999999;
\r
8146 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8147 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8148 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8149 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8151 if (savesel.cpMax == exlen || forceVisible) {
\r
8152 /* Move insert point to new end of text if it was at the old
\r
8153 end of text or if the new text is an echo of user typein */
\r
8154 sel.cpMin = 9999999;
\r
8155 sel.cpMax = 9999999;
\r
8156 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8158 /* Restore previous selection */
\r
8159 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8161 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8168 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8172 COLORREF oldFg, oldBg;
\r
8176 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8178 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8179 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8180 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8183 rect.right = x + squareSize;
\r
8185 rect.bottom = y + squareSize;
\r
8188 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8189 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8190 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8191 &rect, str, strlen(str), NULL);
\r
8193 (void) SetTextColor(hdc, oldFg);
\r
8194 (void) SetBkColor(hdc, oldBg);
\r
8195 (void) SelectObject(hdc, oldFont);
\r
8199 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8200 RECT *rect, char *color, char *flagFell)
\r
8204 COLORREF oldFg, oldBg;
\r
8207 if (appData.clockMode) {
\r
8209 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8211 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
8218 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8219 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8221 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8222 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8224 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8226 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8227 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8228 rect, str, strlen(str), NULL);
\r
8230 (void) SetTextColor(hdc, oldFg);
\r
8231 (void) SetBkColor(hdc, oldBg);
\r
8232 (void) SelectObject(hdc, oldFont);
\r
8237 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8243 if( count <= 0 ) {
\r
8244 if (appData.debugMode) {
\r
8245 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8248 return ERROR_INVALID_USER_BUFFER;
\r
8251 ResetEvent(ovl->hEvent);
\r
8252 ovl->Offset = ovl->OffsetHigh = 0;
\r
8253 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8257 err = GetLastError();
\r
8258 if (err == ERROR_IO_PENDING) {
\r
8259 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8263 err = GetLastError();
\r
8270 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8275 ResetEvent(ovl->hEvent);
\r
8276 ovl->Offset = ovl->OffsetHigh = 0;
\r
8277 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8281 err = GetLastError();
\r
8282 if (err == ERROR_IO_PENDING) {
\r
8283 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8287 err = GetLastError();
\r
8293 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8294 void CheckForInputBufferFull( InputSource * is )
\r
8296 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8297 /* Look for end of line */
\r
8298 char * p = is->buf;
\r
8300 while( p < is->next && *p != '\n' ) {
\r
8304 if( p >= is->next ) {
\r
8305 if (appData.debugMode) {
\r
8306 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8309 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8310 is->count = (DWORD) -1;
\r
8311 is->next = is->buf;
\r
8317 InputThread(LPVOID arg)
\r
8322 is = (InputSource *) arg;
\r
8323 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8324 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8325 while (is->hThread != NULL) {
\r
8326 is->error = DoReadFile(is->hFile, is->next,
\r
8327 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8328 &is->count, &ovl);
\r
8329 if (is->error == NO_ERROR) {
\r
8330 is->next += is->count;
\r
8332 if (is->error == ERROR_BROKEN_PIPE) {
\r
8333 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8336 is->count = (DWORD) -1;
\r
8337 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8342 CheckForInputBufferFull( is );
\r
8344 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8346 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8348 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8351 CloseHandle(ovl.hEvent);
\r
8352 CloseHandle(is->hFile);
\r
8354 if (appData.debugMode) {
\r
8355 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8362 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8364 NonOvlInputThread(LPVOID arg)
\r
8371 is = (InputSource *) arg;
\r
8372 while (is->hThread != NULL) {
\r
8373 is->error = ReadFile(is->hFile, is->next,
\r
8374 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8375 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8376 if (is->error == NO_ERROR) {
\r
8377 /* Change CRLF to LF */
\r
8378 if (is->next > is->buf) {
\r
8380 i = is->count + 1;
\r
8388 if (prev == '\r' && *p == '\n') {
\r
8400 if (is->error == ERROR_BROKEN_PIPE) {
\r
8401 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8404 is->count = (DWORD) -1;
\r
8408 CheckForInputBufferFull( is );
\r
8410 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8412 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8414 if (is->count < 0) break; /* Quit on error */
\r
8416 CloseHandle(is->hFile);
\r
8421 SocketInputThread(LPVOID arg)
\r
8425 is = (InputSource *) arg;
\r
8426 while (is->hThread != NULL) {
\r
8427 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8428 if ((int)is->count == SOCKET_ERROR) {
\r
8429 is->count = (DWORD) -1;
\r
8430 is->error = WSAGetLastError();
\r
8432 is->error = NO_ERROR;
\r
8433 is->next += is->count;
\r
8434 if (is->count == 0 && is->second == is) {
\r
8435 /* End of file on stderr; quit with no message */
\r
8439 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8441 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8443 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8449 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8453 is = (InputSource *) lParam;
\r
8454 if (is->lineByLine) {
\r
8455 /* Feed in lines one by one */
\r
8456 char *p = is->buf;
\r
8458 while (q < is->next) {
\r
8459 if (*q++ == '\n') {
\r
8460 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8465 /* Move any partial line to the start of the buffer */
\r
8467 while (p < is->next) {
\r
8472 if (is->error != NO_ERROR || is->count == 0) {
\r
8473 /* Notify backend of the error. Note: If there was a partial
\r
8474 line at the end, it is not flushed through. */
\r
8475 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8478 /* Feed in the whole chunk of input at once */
\r
8479 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8480 is->next = is->buf;
\r
8484 /*---------------------------------------------------------------------------*\
\r
8486 * Menu enables. Used when setting various modes.
\r
8488 \*---------------------------------------------------------------------------*/
\r
8496 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8498 while (enab->item > 0) {
\r
8499 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8504 Enables gnuEnables[] = {
\r
8505 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8506 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8507 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8508 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8509 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8510 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8511 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8512 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8513 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8514 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8518 Enables icsEnables[] = {
\r
8519 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8520 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8521 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8522 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8523 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8524 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8525 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8526 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8527 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8528 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8529 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8530 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8535 Enables zippyEnables[] = {
\r
8536 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8537 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8538 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8543 Enables ncpEnables[] = {
\r
8544 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8545 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8546 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8547 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8548 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8549 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8550 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8551 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8552 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8553 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8554 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8555 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8556 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8557 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8558 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8562 Enables trainingOnEnables[] = {
\r
8563 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8564 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8565 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8566 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8567 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8568 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8569 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8570 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8574 Enables trainingOffEnables[] = {
\r
8575 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8576 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8577 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8578 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8579 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8580 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8581 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8582 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8586 /* These modify either ncpEnables or gnuEnables */
\r
8587 Enables cmailEnables[] = {
\r
8588 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8589 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8590 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8591 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8592 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8593 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8594 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8598 Enables machineThinkingEnables[] = {
\r
8599 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8600 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8601 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8602 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8603 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8604 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8605 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8606 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8607 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8608 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8609 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8610 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8611 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8612 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8613 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8617 Enables userThinkingEnables[] = {
\r
8618 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8619 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8620 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8621 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8622 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8623 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8624 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8625 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8626 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8627 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8628 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8629 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8630 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8631 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8632 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8636 /*---------------------------------------------------------------------------*\
\r
8638 * Front-end interface functions exported by XBoard.
\r
8639 * Functions appear in same order as prototypes in frontend.h.
\r
8641 \*---------------------------------------------------------------------------*/
\r
8645 static UINT prevChecked = 0;
\r
8646 static int prevPausing = 0;
\r
8649 if (pausing != prevPausing) {
\r
8650 prevPausing = pausing;
\r
8651 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8652 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8653 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8656 switch (gameMode) {
\r
8657 case BeginningOfGame:
\r
8658 if (appData.icsActive)
\r
8659 nowChecked = IDM_IcsClient;
\r
8660 else if (appData.noChessProgram)
\r
8661 nowChecked = IDM_EditGame;
\r
8663 nowChecked = IDM_MachineBlack;
\r
8665 case MachinePlaysBlack:
\r
8666 nowChecked = IDM_MachineBlack;
\r
8668 case MachinePlaysWhite:
\r
8669 nowChecked = IDM_MachineWhite;
\r
8671 case TwoMachinesPlay:
\r
8672 nowChecked = IDM_TwoMachines;
\r
8675 nowChecked = IDM_AnalysisMode;
\r
8678 nowChecked = IDM_AnalyzeFile;
\r
8681 nowChecked = IDM_EditGame;
\r
8683 case PlayFromGameFile:
\r
8684 nowChecked = IDM_LoadGame;
\r
8686 case EditPosition:
\r
8687 nowChecked = IDM_EditPosition;
\r
8690 nowChecked = IDM_Training;
\r
8692 case IcsPlayingWhite:
\r
8693 case IcsPlayingBlack:
\r
8694 case IcsObserving:
\r
8696 nowChecked = IDM_IcsClient;
\r
8703 if (prevChecked != 0)
\r
8704 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8705 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8706 if (nowChecked != 0)
\r
8707 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8708 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8710 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8711 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8712 MF_BYCOMMAND|MF_ENABLED);
\r
8714 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8715 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8718 prevChecked = nowChecked;
\r
8720 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8721 if (appData.icsActive) {
\r
8722 if (appData.icsEngineAnalyze) {
\r
8723 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8724 MF_BYCOMMAND|MF_CHECKED);
\r
8726 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8727 MF_BYCOMMAND|MF_UNCHECKED);
\r
8735 HMENU hmenu = GetMenu(hwndMain);
\r
8736 SetMenuEnables(hmenu, icsEnables);
\r
8737 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8738 MF_BYPOSITION|MF_ENABLED);
\r
8740 if (appData.zippyPlay) {
\r
8741 SetMenuEnables(hmenu, zippyEnables);
\r
8742 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8743 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8744 MF_BYCOMMAND|MF_ENABLED);
\r
8752 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8758 HMENU hmenu = GetMenu(hwndMain);
\r
8759 SetMenuEnables(hmenu, ncpEnables);
\r
8760 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8761 MF_BYPOSITION|MF_GRAYED);
\r
8762 DrawMenuBar(hwndMain);
\r
8768 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8772 SetTrainingModeOn()
\r
8775 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8776 for (i = 0; i < N_BUTTONS; i++) {
\r
8777 if (buttonDesc[i].hwnd != NULL)
\r
8778 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8783 VOID SetTrainingModeOff()
\r
8786 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8787 for (i = 0; i < N_BUTTONS; i++) {
\r
8788 if (buttonDesc[i].hwnd != NULL)
\r
8789 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8795 SetUserThinkingEnables()
\r
8797 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8801 SetMachineThinkingEnables()
\r
8803 HMENU hMenu = GetMenu(hwndMain);
\r
8804 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8806 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8808 if (gameMode == MachinePlaysBlack) {
\r
8809 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8810 } else if (gameMode == MachinePlaysWhite) {
\r
8811 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8812 } else if (gameMode == TwoMachinesPlay) {
\r
8813 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8819 DisplayTitle(char *str)
\r
8821 char title[MSG_SIZ], *host;
\r
8822 if (str[0] != NULLCHAR) {
\r
8823 strcpy(title, str);
\r
8824 } else if (appData.icsActive) {
\r
8825 if (appData.icsCommPort[0] != NULLCHAR)
\r
8828 host = appData.icsHost;
\r
8829 sprintf(title, "%s: %s", szTitle, host);
\r
8830 } else if (appData.noChessProgram) {
\r
8831 strcpy(title, szTitle);
\r
8833 strcpy(title, szTitle);
\r
8834 strcat(title, ": ");
\r
8835 strcat(title, first.tidy);
\r
8837 SetWindowText(hwndMain, title);
\r
8842 DisplayMessage(char *str1, char *str2)
\r
8846 int remain = MESSAGE_TEXT_MAX - 1;
\r
8849 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8850 messageText[0] = NULLCHAR;
\r
8852 len = strlen(str1);
\r
8853 if (len > remain) len = remain;
\r
8854 strncpy(messageText, str1, len);
\r
8855 messageText[len] = NULLCHAR;
\r
8858 if (*str2 && remain >= 2) {
\r
8860 strcat(messageText, " ");
\r
8863 len = strlen(str2);
\r
8864 if (len > remain) len = remain;
\r
8865 strncat(messageText, str2, len);
\r
8867 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8869 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8870 hdc = GetDC(hwndMain);
\r
8871 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8872 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8873 &messageRect, messageText, strlen(messageText), NULL);
\r
8874 (void) SelectObject(hdc, oldFont);
\r
8875 (void) ReleaseDC(hwndMain, hdc);
\r
8879 DisplayError(char *str, int error)
\r
8881 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8887 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8888 NULL, error, LANG_NEUTRAL,
\r
8889 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8891 sprintf(buf, "%s:\n%s", str, buf2);
\r
8893 ErrorMap *em = errmap;
\r
8894 while (em->err != 0 && em->err != error) em++;
\r
8895 if (em->err != 0) {
\r
8896 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8898 sprintf(buf, "%s:\nError code %d", str, error);
\r
8903 ErrorPopUp("Error", buf);
\r
8908 DisplayMoveError(char *str)
\r
8910 fromX = fromY = -1;
\r
8911 ClearHighlights();
\r
8912 DrawPosition(FALSE, NULL);
\r
8913 if (appData.popupMoveErrors) {
\r
8914 ErrorPopUp("Error", str);
\r
8916 DisplayMessage(str, "");
\r
8917 moveErrorMessageUp = TRUE;
\r
8922 DisplayFatalError(char *str, int error, int exitStatus)
\r
8924 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8926 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8929 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8930 NULL, error, LANG_NEUTRAL,
\r
8931 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8933 sprintf(buf, "%s:\n%s", str, buf2);
\r
8935 ErrorMap *em = errmap;
\r
8936 while (em->err != 0 && em->err != error) em++;
\r
8937 if (em->err != 0) {
\r
8938 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8940 sprintf(buf, "%s:\nError code %d", str, error);
\r
8945 if (appData.debugMode) {
\r
8946 fprintf(debugFP, "%s: %s\n", label, str);
\r
8948 if (appData.popupExitMessage) {
\r
8949 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8950 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8952 ExitEvent(exitStatus);
\r
8957 DisplayInformation(char *str)
\r
8959 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8964 DisplayNote(char *str)
\r
8966 ErrorPopUp("Note", str);
\r
8971 char *title, *question, *replyPrefix;
\r
8976 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8978 static QuestionParams *qp;
\r
8979 char reply[MSG_SIZ];
\r
8982 switch (message) {
\r
8983 case WM_INITDIALOG:
\r
8984 qp = (QuestionParams *) lParam;
\r
8985 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8986 SetWindowText(hDlg, qp->title);
\r
8987 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8988 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8992 switch (LOWORD(wParam)) {
\r
8994 strcpy(reply, qp->replyPrefix);
\r
8995 if (*reply) strcat(reply, " ");
\r
8996 len = strlen(reply);
\r
8997 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8998 strcat(reply, "\n");
\r
8999 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9000 EndDialog(hDlg, TRUE);
\r
9001 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9004 EndDialog(hDlg, FALSE);
\r
9015 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9017 QuestionParams qp;
\r
9021 qp.question = question;
\r
9022 qp.replyPrefix = replyPrefix;
\r
9024 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9025 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9026 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9027 FreeProcInstance(lpProc);
\r
9030 /* [AS] Pick FRC position */
\r
9031 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9033 static int * lpIndexFRC;
\r
9039 case WM_INITDIALOG:
\r
9040 lpIndexFRC = (int *) lParam;
\r
9042 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9044 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9045 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9046 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9047 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9052 switch( LOWORD(wParam) ) {
\r
9054 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9055 EndDialog( hDlg, 0 );
\r
9056 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9059 EndDialog( hDlg, 1 );
\r
9061 case IDC_NFG_Edit:
\r
9062 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9063 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9065 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9068 case IDC_NFG_Random:
\r
9069 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9070 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9083 int index = appData.defaultFrcPosition;
\r
9084 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9086 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9088 if( result == 0 ) {
\r
9089 appData.defaultFrcPosition = index;
\r
9095 /* [AS] Game list options */
\r
9101 static GLT_Item GLT_ItemInfo[] = {
\r
9102 { GLT_EVENT, "Event" },
\r
9103 { GLT_SITE, "Site" },
\r
9104 { GLT_DATE, "Date" },
\r
9105 { GLT_ROUND, "Round" },
\r
9106 { GLT_PLAYERS, "Players" },
\r
9107 { GLT_RESULT, "Result" },
\r
9108 { GLT_WHITE_ELO, "White Rating" },
\r
9109 { GLT_BLACK_ELO, "Black Rating" },
\r
9110 { GLT_TIME_CONTROL,"Time Control" },
\r
9111 { GLT_VARIANT, "Variant" },
\r
9112 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9116 const char * GLT_FindItem( char id )
\r
9118 const char * result = 0;
\r
9120 GLT_Item * list = GLT_ItemInfo;
\r
9122 while( list->id != 0 ) {
\r
9123 if( list->id == id ) {
\r
9124 result = list->name;
\r
9134 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9136 const char * name = GLT_FindItem( id );
\r
9139 if( index >= 0 ) {
\r
9140 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9143 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9148 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9152 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9155 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9159 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9161 pc = GLT_ALL_TAGS;
\r
9164 if( strchr( tags, *pc ) == 0 ) {
\r
9165 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9170 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9173 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9175 char result = '\0';
\r
9178 GLT_Item * list = GLT_ItemInfo;
\r
9180 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9181 while( list->id != 0 ) {
\r
9182 if( strcmp( list->name, name ) == 0 ) {
\r
9183 result = list->id;
\r
9194 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9196 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9197 int idx2 = idx1 + delta;
\r
9198 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9200 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9203 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9204 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9205 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9206 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9210 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9212 static char glt[64];
\r
9213 static char * lpUserGLT;
\r
9217 case WM_INITDIALOG:
\r
9218 lpUserGLT = (char *) lParam;
\r
9220 strcpy( glt, lpUserGLT );
\r
9222 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9224 /* Initialize list */
\r
9225 GLT_TagsToList( hDlg, glt );
\r
9227 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9232 switch( LOWORD(wParam) ) {
\r
9235 char * pc = lpUserGLT;
\r
9237 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9241 id = GLT_ListItemToTag( hDlg, idx );
\r
9245 } while( id != '\0' );
\r
9247 EndDialog( hDlg, 0 );
\r
9250 EndDialog( hDlg, 1 );
\r
9253 case IDC_GLT_Default:
\r
9254 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9255 GLT_TagsToList( hDlg, glt );
\r
9258 case IDC_GLT_Restore:
\r
9259 strcpy( glt, lpUserGLT );
\r
9260 GLT_TagsToList( hDlg, glt );
\r
9264 GLT_MoveSelection( hDlg, -1 );
\r
9267 case IDC_GLT_Down:
\r
9268 GLT_MoveSelection( hDlg, +1 );
\r
9278 int GameListOptions()
\r
9282 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9284 strcpy( glt, appData.gameListTags );
\r
9286 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9288 if( result == 0 ) {
\r
9289 /* [AS] Memory leak here! */
\r
9290 appData.gameListTags = strdup( glt );
\r
9298 DisplayIcsInteractionTitle(char *str)
\r
9300 char consoleTitle[MSG_SIZ];
\r
9302 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9303 SetWindowText(hwndConsole, consoleTitle);
\r
9307 DrawPosition(int fullRedraw, Board board)
\r
9309 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9316 fromX = fromY = -1;
\r
9317 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9318 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9319 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9320 dragInfo.lastpos = dragInfo.pos;
\r
9321 dragInfo.start.x = dragInfo.start.y = -1;
\r
9322 dragInfo.from = dragInfo.start;
\r
9324 DrawPosition(TRUE, NULL);
\r
9330 CommentPopUp(char *title, char *str)
\r
9332 HWND hwnd = GetActiveWindow();
\r
9333 EitherCommentPopUp(0, title, str, FALSE);
\r
9334 SetActiveWindow(hwnd);
\r
9338 CommentPopDown(void)
\r
9340 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9341 if (commentDialog) {
\r
9342 ShowWindow(commentDialog, SW_HIDE);
\r
9344 commentDialogUp = FALSE;
\r
9348 EditCommentPopUp(int index, char *title, char *str)
\r
9350 EitherCommentPopUp(index, title, str, TRUE);
\r
9357 MyPlaySound(&sounds[(int)SoundMove]);
\r
9360 VOID PlayIcsWinSound()
\r
9362 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9365 VOID PlayIcsLossSound()
\r
9367 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9370 VOID PlayIcsDrawSound()
\r
9372 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9375 VOID PlayIcsUnfinishedSound()
\r
9377 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9383 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9391 consoleEcho = TRUE;
\r
9392 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9393 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9394 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9403 consoleEcho = FALSE;
\r
9404 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9405 /* This works OK: set text and background both to the same color */
\r
9407 cf.crTextColor = COLOR_ECHOOFF;
\r
9408 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9409 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9412 /* No Raw()...? */
\r
9414 void Colorize(ColorClass cc, int continuation)
\r
9416 currentColorClass = cc;
\r
9417 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9418 consoleCF.crTextColor = textAttribs[cc].color;
\r
9419 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9420 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9426 static char buf[MSG_SIZ];
\r
9427 DWORD bufsiz = MSG_SIZ;
\r
9429 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9430 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9432 if (!GetUserName(buf, &bufsiz)) {
\r
9433 /*DisplayError("Error getting user name", GetLastError());*/
\r
9434 strcpy(buf, "User");
\r
9442 static char buf[MSG_SIZ];
\r
9443 DWORD bufsiz = MSG_SIZ;
\r
9445 if (!GetComputerName(buf, &bufsiz)) {
\r
9446 /*DisplayError("Error getting host name", GetLastError());*/
\r
9447 strcpy(buf, "Unknown");
\r
9454 ClockTimerRunning()
\r
9456 return clockTimerEvent != 0;
\r
9462 if (clockTimerEvent == 0) return FALSE;
\r
9463 KillTimer(hwndMain, clockTimerEvent);
\r
9464 clockTimerEvent = 0;
\r
9469 StartClockTimer(long millisec)
\r
9471 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9472 (UINT) millisec, NULL);
\r
9476 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9479 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9481 if(appData.noGUI) return;
\r
9482 hdc = GetDC(hwndMain);
\r
9483 if (!IsIconic(hwndMain)) {
\r
9484 DisplayAClock(hdc, timeRemaining, highlight,
\r
9485 (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);
\r
9487 if (highlight && iconCurrent == iconBlack) {
\r
9488 iconCurrent = iconWhite;
\r
9489 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9490 if (IsIconic(hwndMain)) {
\r
9491 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9494 (void) ReleaseDC(hwndMain, hdc);
\r
9496 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9500 DisplayBlackClock(long timeRemaining, int highlight)
\r
9503 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9505 if(appData.noGUI) return;
\r
9506 hdc = GetDC(hwndMain);
\r
9507 if (!IsIconic(hwndMain)) {
\r
9508 DisplayAClock(hdc, timeRemaining, highlight,
\r
9509 (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);
\r
9511 if (highlight && iconCurrent == iconWhite) {
\r
9512 iconCurrent = iconBlack;
\r
9513 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9514 if (IsIconic(hwndMain)) {
\r
9515 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9518 (void) ReleaseDC(hwndMain, hdc);
\r
9520 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9525 LoadGameTimerRunning()
\r
9527 return loadGameTimerEvent != 0;
\r
9531 StopLoadGameTimer()
\r
9533 if (loadGameTimerEvent == 0) return FALSE;
\r
9534 KillTimer(hwndMain, loadGameTimerEvent);
\r
9535 loadGameTimerEvent = 0;
\r
9540 StartLoadGameTimer(long millisec)
\r
9542 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9543 (UINT) millisec, NULL);
\r
9551 char fileTitle[MSG_SIZ];
\r
9553 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9554 f = OpenFileDialog(hwndMain, "a", defName,
\r
9555 appData.oldSaveStyle ? "gam" : "pgn",
\r
9557 "Save Game to File", NULL, fileTitle, NULL);
\r
9559 SaveGame(f, 0, "");
\r
9566 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9568 if (delayedTimerEvent != 0) {
\r
9569 if (appData.debugMode) {
\r
9570 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9572 KillTimer(hwndMain, delayedTimerEvent);
\r
9573 delayedTimerEvent = 0;
\r
9574 delayedTimerCallback();
\r
9576 delayedTimerCallback = cb;
\r
9577 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9578 (UINT) millisec, NULL);
\r
9581 DelayedEventCallback
\r
9584 if (delayedTimerEvent) {
\r
9585 return delayedTimerCallback;
\r
9592 CancelDelayedEvent()
\r
9594 if (delayedTimerEvent) {
\r
9595 KillTimer(hwndMain, delayedTimerEvent);
\r
9596 delayedTimerEvent = 0;
\r
9600 DWORD GetWin32Priority(int nice)
\r
9601 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9603 REALTIME_PRIORITY_CLASS 0x00000100
\r
9604 HIGH_PRIORITY_CLASS 0x00000080
\r
9605 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9606 NORMAL_PRIORITY_CLASS 0x00000020
\r
9607 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9608 IDLE_PRIORITY_CLASS 0x00000040
\r
9610 if (nice < -15) return 0x00000080;
\r
9611 if (nice < 0) return 0x00008000;
\r
9612 if (nice == 0) return 0x00000020;
\r
9613 if (nice < 15) return 0x00004000;
\r
9614 return 0x00000040;
\r
9617 /* Start a child process running the given program.
\r
9618 The process's standard output can be read from "from", and its
\r
9619 standard input can be written to "to".
\r
9620 Exit with fatal error if anything goes wrong.
\r
9621 Returns an opaque pointer that can be used to destroy the process
\r
9625 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9627 #define BUFSIZE 4096
\r
9629 HANDLE hChildStdinRd, hChildStdinWr,
\r
9630 hChildStdoutRd, hChildStdoutWr;
\r
9631 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9632 SECURITY_ATTRIBUTES saAttr;
\r
9634 PROCESS_INFORMATION piProcInfo;
\r
9635 STARTUPINFO siStartInfo;
\r
9637 char buf[MSG_SIZ];
\r
9640 if (appData.debugMode) {
\r
9641 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9646 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9647 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9648 saAttr.bInheritHandle = TRUE;
\r
9649 saAttr.lpSecurityDescriptor = NULL;
\r
9652 * The steps for redirecting child's STDOUT:
\r
9653 * 1. Create anonymous pipe to be STDOUT for child.
\r
9654 * 2. Create a noninheritable duplicate of read handle,
\r
9655 * and close the inheritable read handle.
\r
9658 /* Create a pipe for the child's STDOUT. */
\r
9659 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9660 return GetLastError();
\r
9663 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9664 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9665 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9666 FALSE, /* not inherited */
\r
9667 DUPLICATE_SAME_ACCESS);
\r
9669 return GetLastError();
\r
9671 CloseHandle(hChildStdoutRd);
\r
9674 * The steps for redirecting child's STDIN:
\r
9675 * 1. Create anonymous pipe to be STDIN for child.
\r
9676 * 2. Create a noninheritable duplicate of write handle,
\r
9677 * and close the inheritable write handle.
\r
9680 /* Create a pipe for the child's STDIN. */
\r
9681 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9682 return GetLastError();
\r
9685 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9686 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9687 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9688 FALSE, /* not inherited */
\r
9689 DUPLICATE_SAME_ACCESS);
\r
9691 return GetLastError();
\r
9693 CloseHandle(hChildStdinWr);
\r
9695 /* Arrange to (1) look in dir for the child .exe file, and
\r
9696 * (2) have dir be the child's working directory. Interpret
\r
9697 * dir relative to the directory WinBoard loaded from. */
\r
9698 GetCurrentDirectory(MSG_SIZ, buf);
\r
9699 SetCurrentDirectory(installDir);
\r
9700 SetCurrentDirectory(dir);
\r
9702 /* Now create the child process. */
\r
9704 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9705 siStartInfo.lpReserved = NULL;
\r
9706 siStartInfo.lpDesktop = NULL;
\r
9707 siStartInfo.lpTitle = NULL;
\r
9708 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9709 siStartInfo.cbReserved2 = 0;
\r
9710 siStartInfo.lpReserved2 = NULL;
\r
9711 siStartInfo.hStdInput = hChildStdinRd;
\r
9712 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9713 siStartInfo.hStdError = hChildStdoutWr;
\r
9715 fSuccess = CreateProcess(NULL,
\r
9716 cmdLine, /* command line */
\r
9717 NULL, /* process security attributes */
\r
9718 NULL, /* primary thread security attrs */
\r
9719 TRUE, /* handles are inherited */
\r
9720 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9721 NULL, /* use parent's environment */
\r
9723 &siStartInfo, /* STARTUPINFO pointer */
\r
9724 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9726 err = GetLastError();
\r
9727 SetCurrentDirectory(buf); /* return to prev directory */
\r
9732 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9733 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9734 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9737 /* Close the handles we don't need in the parent */
\r
9738 CloseHandle(piProcInfo.hThread);
\r
9739 CloseHandle(hChildStdinRd);
\r
9740 CloseHandle(hChildStdoutWr);
\r
9742 /* Prepare return value */
\r
9743 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9744 cp->kind = CPReal;
\r
9745 cp->hProcess = piProcInfo.hProcess;
\r
9746 cp->pid = piProcInfo.dwProcessId;
\r
9747 cp->hFrom = hChildStdoutRdDup;
\r
9748 cp->hTo = hChildStdinWrDup;
\r
9750 *pr = (void *) cp;
\r
9752 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9753 2000 where engines sometimes don't see the initial command(s)
\r
9754 from WinBoard and hang. I don't understand how that can happen,
\r
9755 but the Sleep is harmless, so I've put it in. Others have also
\r
9756 reported what may be the same problem, so hopefully this will fix
\r
9757 it for them too. */
\r
9765 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9767 ChildProc *cp; int result;
\r
9769 cp = (ChildProc *) pr;
\r
9770 if (cp == NULL) return;
\r
9772 switch (cp->kind) {
\r
9774 /* TerminateProcess is considered harmful, so... */
\r
9775 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9776 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9777 /* The following doesn't work because the chess program
\r
9778 doesn't "have the same console" as WinBoard. Maybe
\r
9779 we could arrange for this even though neither WinBoard
\r
9780 nor the chess program uses a console for stdio? */
\r
9781 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9783 /* [AS] Special termination modes for misbehaving programs... */
\r
9784 if( signal == 9 ) {
\r
9785 result = TerminateProcess( cp->hProcess, 0 );
\r
9787 if ( appData.debugMode) {
\r
9788 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9791 else if( signal == 10 ) {
\r
9792 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9794 if( dw != WAIT_OBJECT_0 ) {
\r
9795 result = TerminateProcess( cp->hProcess, 0 );
\r
9797 if ( appData.debugMode) {
\r
9798 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9804 CloseHandle(cp->hProcess);
\r
9808 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9812 closesocket(cp->sock);
\r
9817 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9818 closesocket(cp->sock);
\r
9819 closesocket(cp->sock2);
\r
9827 InterruptChildProcess(ProcRef pr)
\r
9831 cp = (ChildProc *) pr;
\r
9832 if (cp == NULL) return;
\r
9833 switch (cp->kind) {
\r
9835 /* The following doesn't work because the chess program
\r
9836 doesn't "have the same console" as WinBoard. Maybe
\r
9837 we could arrange for this even though neither WinBoard
\r
9838 nor the chess program uses a console for stdio */
\r
9839 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9844 /* Can't interrupt */
\r
9848 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9855 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9857 char cmdLine[MSG_SIZ];
\r
9859 if (port[0] == NULLCHAR) {
\r
9860 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9862 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9864 return StartChildProcess(cmdLine, "", pr);
\r
9868 /* Code to open TCP sockets */
\r
9871 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9876 struct sockaddr_in sa, mysa;
\r
9877 struct hostent FAR *hp;
\r
9878 unsigned short uport;
\r
9879 WORD wVersionRequested;
\r
9882 /* Initialize socket DLL */
\r
9883 wVersionRequested = MAKEWORD(1, 1);
\r
9884 err = WSAStartup(wVersionRequested, &wsaData);
\r
9885 if (err != 0) return err;
\r
9888 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9889 err = WSAGetLastError();
\r
9894 /* Bind local address using (mostly) don't-care values.
\r
9896 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9897 mysa.sin_family = AF_INET;
\r
9898 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9899 uport = (unsigned short) 0;
\r
9900 mysa.sin_port = htons(uport);
\r
9901 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9902 == SOCKET_ERROR) {
\r
9903 err = WSAGetLastError();
\r
9908 /* Resolve remote host name */
\r
9909 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9910 if (!(hp = gethostbyname(host))) {
\r
9911 unsigned int b0, b1, b2, b3;
\r
9913 err = WSAGetLastError();
\r
9915 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9916 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9917 hp->h_addrtype = AF_INET;
\r
9919 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9920 hp->h_addr_list[0] = (char *) malloc(4);
\r
9921 hp->h_addr_list[0][0] = (char) b0;
\r
9922 hp->h_addr_list[0][1] = (char) b1;
\r
9923 hp->h_addr_list[0][2] = (char) b2;
\r
9924 hp->h_addr_list[0][3] = (char) b3;
\r
9930 sa.sin_family = hp->h_addrtype;
\r
9931 uport = (unsigned short) atoi(port);
\r
9932 sa.sin_port = htons(uport);
\r
9933 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9935 /* Make connection */
\r
9936 if (connect(s, (struct sockaddr *) &sa,
\r
9937 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9938 err = WSAGetLastError();
\r
9943 /* Prepare return value */
\r
9944 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9945 cp->kind = CPSock;
\r
9947 *pr = (ProcRef *) cp;
\r
9953 OpenCommPort(char *name, ProcRef *pr)
\r
9958 char fullname[MSG_SIZ];
\r
9960 if (*name != '\\')
\r
9961 sprintf(fullname, "\\\\.\\%s", name);
\r
9963 strcpy(fullname, name);
\r
9965 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9966 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9967 if (h == (HANDLE) -1) {
\r
9968 return GetLastError();
\r
9972 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9974 /* Accumulate characters until a 100ms pause, then parse */
\r
9975 ct.ReadIntervalTimeout = 100;
\r
9976 ct.ReadTotalTimeoutMultiplier = 0;
\r
9977 ct.ReadTotalTimeoutConstant = 0;
\r
9978 ct.WriteTotalTimeoutMultiplier = 0;
\r
9979 ct.WriteTotalTimeoutConstant = 0;
\r
9980 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9982 /* Prepare return value */
\r
9983 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9984 cp->kind = CPComm;
\r
9987 *pr = (ProcRef *) cp;
\r
9993 OpenLoopback(ProcRef *pr)
\r
9995 DisplayFatalError("Not implemented", 0, 1);
\r
10001 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10005 SOCKET s, s2, s3;
\r
10006 struct sockaddr_in sa, mysa;
\r
10007 struct hostent FAR *hp;
\r
10008 unsigned short uport;
\r
10009 WORD wVersionRequested;
\r
10012 char stderrPortStr[MSG_SIZ];
\r
10014 /* Initialize socket DLL */
\r
10015 wVersionRequested = MAKEWORD(1, 1);
\r
10016 err = WSAStartup(wVersionRequested, &wsaData);
\r
10017 if (err != 0) return err;
\r
10019 /* Resolve remote host name */
\r
10020 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10021 if (!(hp = gethostbyname(host))) {
\r
10022 unsigned int b0, b1, b2, b3;
\r
10024 err = WSAGetLastError();
\r
10026 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10027 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10028 hp->h_addrtype = AF_INET;
\r
10029 hp->h_length = 4;
\r
10030 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10031 hp->h_addr_list[0] = (char *) malloc(4);
\r
10032 hp->h_addr_list[0][0] = (char) b0;
\r
10033 hp->h_addr_list[0][1] = (char) b1;
\r
10034 hp->h_addr_list[0][2] = (char) b2;
\r
10035 hp->h_addr_list[0][3] = (char) b3;
\r
10041 sa.sin_family = hp->h_addrtype;
\r
10042 uport = (unsigned short) 514;
\r
10043 sa.sin_port = htons(uport);
\r
10044 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10046 /* Bind local socket to unused "privileged" port address
\r
10048 s = INVALID_SOCKET;
\r
10049 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10050 mysa.sin_family = AF_INET;
\r
10051 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10052 for (fromPort = 1023;; fromPort--) {
\r
10053 if (fromPort < 0) {
\r
10055 return WSAEADDRINUSE;
\r
10057 if (s == INVALID_SOCKET) {
\r
10058 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10059 err = WSAGetLastError();
\r
10064 uport = (unsigned short) fromPort;
\r
10065 mysa.sin_port = htons(uport);
\r
10066 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10067 == SOCKET_ERROR) {
\r
10068 err = WSAGetLastError();
\r
10069 if (err == WSAEADDRINUSE) continue;
\r
10073 if (connect(s, (struct sockaddr *) &sa,
\r
10074 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10075 err = WSAGetLastError();
\r
10076 if (err == WSAEADDRINUSE) {
\r
10087 /* Bind stderr local socket to unused "privileged" port address
\r
10089 s2 = INVALID_SOCKET;
\r
10090 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10091 mysa.sin_family = AF_INET;
\r
10092 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10093 for (fromPort = 1023;; fromPort--) {
\r
10094 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10095 if (fromPort < 0) {
\r
10096 (void) closesocket(s);
\r
10098 return WSAEADDRINUSE;
\r
10100 if (s2 == INVALID_SOCKET) {
\r
10101 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10102 err = WSAGetLastError();
\r
10108 uport = (unsigned short) fromPort;
\r
10109 mysa.sin_port = htons(uport);
\r
10110 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10111 == SOCKET_ERROR) {
\r
10112 err = WSAGetLastError();
\r
10113 if (err == WSAEADDRINUSE) continue;
\r
10114 (void) closesocket(s);
\r
10118 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10119 err = WSAGetLastError();
\r
10120 if (err == WSAEADDRINUSE) {
\r
10122 s2 = INVALID_SOCKET;
\r
10125 (void) closesocket(s);
\r
10126 (void) closesocket(s2);
\r
10132 prevStderrPort = fromPort; // remember port used
\r
10133 sprintf(stderrPortStr, "%d", fromPort);
\r
10135 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10136 err = WSAGetLastError();
\r
10137 (void) closesocket(s);
\r
10138 (void) closesocket(s2);
\r
10143 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10144 err = WSAGetLastError();
\r
10145 (void) closesocket(s);
\r
10146 (void) closesocket(s2);
\r
10150 if (*user == NULLCHAR) user = UserName();
\r
10151 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10152 err = WSAGetLastError();
\r
10153 (void) closesocket(s);
\r
10154 (void) closesocket(s2);
\r
10158 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10159 err = WSAGetLastError();
\r
10160 (void) closesocket(s);
\r
10161 (void) closesocket(s2);
\r
10166 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10167 err = WSAGetLastError();
\r
10168 (void) closesocket(s);
\r
10169 (void) closesocket(s2);
\r
10173 (void) closesocket(s2); /* Stop listening */
\r
10175 /* Prepare return value */
\r
10176 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10177 cp->kind = CPRcmd;
\r
10180 *pr = (ProcRef *) cp;
\r
10187 AddInputSource(ProcRef pr, int lineByLine,
\r
10188 InputCallback func, VOIDSTAR closure)
\r
10190 InputSource *is, *is2 = NULL;
\r
10191 ChildProc *cp = (ChildProc *) pr;
\r
10193 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10194 is->lineByLine = lineByLine;
\r
10196 is->closure = closure;
\r
10197 is->second = NULL;
\r
10198 is->next = is->buf;
\r
10199 if (pr == NoProc) {
\r
10200 is->kind = CPReal;
\r
10201 consoleInputSource = is;
\r
10203 is->kind = cp->kind;
\r
10205 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10206 we create all threads suspended so that the is->hThread variable can be
\r
10207 safely assigned, then let the threads start with ResumeThread.
\r
10209 switch (cp->kind) {
\r
10211 is->hFile = cp->hFrom;
\r
10212 cp->hFrom = NULL; /* now owned by InputThread */
\r
10214 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10215 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10219 is->hFile = cp->hFrom;
\r
10220 cp->hFrom = NULL; /* now owned by InputThread */
\r
10222 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10223 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10227 is->sock = cp->sock;
\r
10229 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10230 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10234 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10236 is->sock = cp->sock;
\r
10237 is->second = is2;
\r
10238 is2->sock = cp->sock2;
\r
10239 is2->second = is2;
\r
10241 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10242 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10244 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10245 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10249 if( is->hThread != NULL ) {
\r
10250 ResumeThread( is->hThread );
\r
10253 if( is2 != NULL && is2->hThread != NULL ) {
\r
10254 ResumeThread( is2->hThread );
\r
10258 return (InputSourceRef) is;
\r
10262 RemoveInputSource(InputSourceRef isr)
\r
10266 is = (InputSource *) isr;
\r
10267 is->hThread = NULL; /* tell thread to stop */
\r
10268 CloseHandle(is->hThread);
\r
10269 if (is->second != NULL) {
\r
10270 is->second->hThread = NULL;
\r
10271 CloseHandle(is->second->hThread);
\r
10277 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10280 int outCount = SOCKET_ERROR;
\r
10281 ChildProc *cp = (ChildProc *) pr;
\r
10282 static OVERLAPPED ovl;
\r
10284 if (pr == NoProc) {
\r
10285 ConsoleOutput(message, count, FALSE);
\r
10289 if (ovl.hEvent == NULL) {
\r
10290 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10292 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10294 switch (cp->kind) {
\r
10297 outCount = send(cp->sock, message, count, 0);
\r
10298 if (outCount == SOCKET_ERROR) {
\r
10299 *outError = WSAGetLastError();
\r
10301 *outError = NO_ERROR;
\r
10306 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10307 &dOutCount, NULL)) {
\r
10308 *outError = NO_ERROR;
\r
10309 outCount = (int) dOutCount;
\r
10311 *outError = GetLastError();
\r
10316 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10317 &dOutCount, &ovl);
\r
10318 if (*outError == NO_ERROR) {
\r
10319 outCount = (int) dOutCount;
\r
10327 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10330 /* Ignore delay, not implemented for WinBoard */
\r
10331 return OutputToProcess(pr, message, count, outError);
\r
10336 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10337 char *buf, int count, int error)
\r
10339 DisplayFatalError("Not implemented", 0, 1);
\r
10342 /* see wgamelist.c for Game List functions */
\r
10343 /* see wedittags.c for Edit Tags functions */
\r
10350 char buf[MSG_SIZ];
\r
10353 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10354 f = fopen(buf, "r");
\r
10356 ProcessICSInitScript(f);
\r
10364 StartAnalysisClock()
\r
10366 if (analysisTimerEvent) return;
\r
10367 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10368 (UINT) 2000, NULL);
\r
10372 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10374 static HANDLE hwndText;
\r
10376 static int sizeX, sizeY;
\r
10377 int newSizeX, newSizeY, flags;
\r
10380 switch (message) {
\r
10381 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10382 /* Initialize the dialog items */
\r
10383 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10384 SetWindowText(hDlg, analysisTitle);
\r
10385 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10386 /* Size and position the dialog */
\r
10387 if (!analysisDialog) {
\r
10388 analysisDialog = hDlg;
\r
10389 flags = SWP_NOZORDER;
\r
10390 GetClientRect(hDlg, &rect);
\r
10391 sizeX = rect.right;
\r
10392 sizeY = rect.bottom;
\r
10393 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10394 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10395 WINDOWPLACEMENT wp;
\r
10396 EnsureOnScreen(&analysisX, &analysisY);
\r
10397 wp.length = sizeof(WINDOWPLACEMENT);
\r
10399 wp.showCmd = SW_SHOW;
\r
10400 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10401 wp.rcNormalPosition.left = analysisX;
\r
10402 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10403 wp.rcNormalPosition.top = analysisY;
\r
10404 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10405 SetWindowPlacement(hDlg, &wp);
\r
10407 GetClientRect(hDlg, &rect);
\r
10408 newSizeX = rect.right;
\r
10409 newSizeY = rect.bottom;
\r
10410 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10411 newSizeX, newSizeY);
\r
10412 sizeX = newSizeX;
\r
10413 sizeY = newSizeY;
\r
10418 case WM_COMMAND: /* message: received a command */
\r
10419 switch (LOWORD(wParam)) {
\r
10421 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10422 ExitAnalyzeMode();
\r
10434 newSizeX = LOWORD(lParam);
\r
10435 newSizeY = HIWORD(lParam);
\r
10436 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10437 sizeX = newSizeX;
\r
10438 sizeY = newSizeY;
\r
10441 case WM_GETMINMAXINFO:
\r
10442 /* Prevent resizing window too small */
\r
10443 mmi = (MINMAXINFO *) lParam;
\r
10444 mmi->ptMinTrackSize.x = 100;
\r
10445 mmi->ptMinTrackSize.y = 100;
\r
10452 AnalysisPopUp(char* title, char* str)
\r
10458 EngineOutputPopUp();
\r
10461 if (str == NULL) str = "";
\r
10462 p = (char *) malloc(2 * strlen(str) + 2);
\r
10465 if (*str == '\n') *q++ = '\r';
\r
10469 if (analysisText != NULL) free(analysisText);
\r
10470 analysisText = p;
\r
10472 if (analysisDialog) {
\r
10473 SetWindowText(analysisDialog, title);
\r
10474 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10475 ShowWindow(analysisDialog, SW_SHOW);
\r
10477 analysisTitle = title;
\r
10478 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10479 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10480 hwndMain, (DLGPROC)lpProc);
\r
10481 FreeProcInstance(lpProc);
\r
10483 analysisDialogUp = TRUE;
\r
10487 AnalysisPopDown()
\r
10489 if (analysisDialog) {
\r
10490 ShowWindow(analysisDialog, SW_HIDE);
\r
10492 analysisDialogUp = FALSE;
\r
10497 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10499 highlightInfo.sq[0].x = fromX;
\r
10500 highlightInfo.sq[0].y = fromY;
\r
10501 highlightInfo.sq[1].x = toX;
\r
10502 highlightInfo.sq[1].y = toY;
\r
10506 ClearHighlights()
\r
10508 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10509 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10513 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10515 premoveHighlightInfo.sq[0].x = fromX;
\r
10516 premoveHighlightInfo.sq[0].y = fromY;
\r
10517 premoveHighlightInfo.sq[1].x = toX;
\r
10518 premoveHighlightInfo.sq[1].y = toY;
\r
10522 ClearPremoveHighlights()
\r
10524 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10525 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10529 ShutDownFrontEnd()
\r
10531 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10532 DeleteClipboardTempFiles();
\r
10538 if (IsIconic(hwndMain))
\r
10539 ShowWindow(hwndMain, SW_RESTORE);
\r
10541 SetActiveWindow(hwndMain);
\r
10545 * Prototypes for animation support routines
\r
10547 static void ScreenSquare(int column, int row, POINT * pt);
\r
10548 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10549 POINT frames[], int * nFrames);
\r
10552 #define kFactor 4
\r
10555 AnimateMove(board, fromX, fromY, toX, toY)
\r
10562 ChessSquare piece;
\r
10563 POINT start, finish, mid;
\r
10564 POINT frames[kFactor * 2 + 1];
\r
10567 if (!appData.animate) return;
\r
10568 if (doingSizing) return;
\r
10569 if (fromY < 0 || fromX < 0) return;
\r
10570 piece = board[fromY][fromX];
\r
10571 if (piece >= EmptySquare) return;
\r
10573 ScreenSquare(fromX, fromY, &start);
\r
10574 ScreenSquare(toX, toY, &finish);
\r
10576 /* All pieces except knights move in straight line */
\r
10577 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10578 mid.x = start.x + (finish.x - start.x) / 2;
\r
10579 mid.y = start.y + (finish.y - start.y) / 2;
\r
10581 /* Knight: make diagonal movement then straight */
\r
10582 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10583 mid.x = start.x + (finish.x - start.x) / 2;
\r
10584 mid.y = finish.y;
\r
10586 mid.x = finish.x;
\r
10587 mid.y = start.y + (finish.y - start.y) / 2;
\r
10591 /* Don't use as many frames for very short moves */
\r
10592 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10593 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10595 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10597 animInfo.from.x = fromX;
\r
10598 animInfo.from.y = fromY;
\r
10599 animInfo.to.x = toX;
\r
10600 animInfo.to.y = toY;
\r
10601 animInfo.lastpos = start;
\r
10602 animInfo.piece = piece;
\r
10603 for (n = 0; n < nFrames; n++) {
\r
10604 animInfo.pos = frames[n];
\r
10605 DrawPosition(FALSE, NULL);
\r
10606 animInfo.lastpos = animInfo.pos;
\r
10607 Sleep(appData.animSpeed);
\r
10609 animInfo.pos = finish;
\r
10610 DrawPosition(FALSE, NULL);
\r
10611 animInfo.piece = EmptySquare;
\r
10614 /* Convert board position to corner of screen rect and color */
\r
10617 ScreenSquare(column, row, pt)
\r
10618 int column; int row; POINT * pt;
\r
10621 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10622 pt->y = lineGap + row * (squareSize + lineGap);
\r
10624 pt->x = lineGap + column * (squareSize + lineGap);
\r
10625 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10629 /* Generate a series of frame coords from start->mid->finish.
\r
10630 The movement rate doubles until the half way point is
\r
10631 reached, then halves back down to the final destination,
\r
10632 which gives a nice slow in/out effect. The algorithmn
\r
10633 may seem to generate too many intermediates for short
\r
10634 moves, but remember that the purpose is to attract the
\r
10635 viewers attention to the piece about to be moved and
\r
10636 then to where it ends up. Too few frames would be less
\r
10640 Tween(start, mid, finish, factor, frames, nFrames)
\r
10641 POINT * start; POINT * mid;
\r
10642 POINT * finish; int factor;
\r
10643 POINT frames[]; int * nFrames;
\r
10645 int n, fraction = 1, count = 0;
\r
10647 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10648 for (n = 0; n < factor; n++)
\r
10650 for (n = 0; n < factor; n++) {
\r
10651 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10652 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10654 fraction = fraction / 2;
\r
10658 frames[count] = *mid;
\r
10661 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10663 for (n = 0; n < factor; n++) {
\r
10664 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10665 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10667 fraction = fraction * 2;
\r
10669 *nFrames = count;
\r
10673 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10678 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10679 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10681 OutputDebugString( buf );
\r
10684 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10686 EvalGraphSet( first, last, current, pvInfoList );
\r
10689 void SetProgramStats( FrontEndProgramStats * stats )
\r
10694 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10695 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10697 OutputDebugString( buf );
\r
10700 EngineOutputUpdate( stats );
\r