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
106 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
109 ChessSquare piece;
\r
110 POINT pos; /* window coordinates of current pos */
\r
111 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
112 POINT from; /* board coordinates of the piece's orig pos */
\r
113 POINT to; /* board coordinates of the piece's new pos */
\r
116 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
119 POINT start; /* window coordinates of start pos */
\r
120 POINT pos; /* window coordinates of current pos */
\r
121 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
122 POINT from; /* board coordinates of the piece's orig pos */
\r
125 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
128 POINT sq[2]; /* board coordinates of from, to squares */
\r
131 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
132 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
134 typedef struct { // [HGM] atomic
\r
135 int fromX, fromY, toX, toY, radius;
\r
138 static ExplodeInfo explodeInfo;
\r
140 /* Window class names */
\r
141 char szAppName[] = "WinBoard";
\r
142 char szConsoleName[] = "WBConsole";
\r
144 /* Title bar text */
\r
145 char szTitle[] = "WinBoard";
\r
146 char szConsoleTitle[] = "ICS Interaction";
\r
149 char *settingsFileName;
\r
150 BOOLEAN saveSettingsOnExit;
\r
151 char installDir[MSG_SIZ];
\r
153 BoardSize boardSize;
\r
154 BOOLEAN chessProgram;
\r
155 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
156 static int squareSize, lineGap, minorSize;
\r
157 static int winWidth, winHeight;
\r
158 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
159 static int logoHeight = 0;
\r
160 static char messageText[MESSAGE_TEXT_MAX];
\r
161 static int clockTimerEvent = 0;
\r
162 static int loadGameTimerEvent = 0;
\r
163 static int analysisTimerEvent = 0;
\r
164 static DelayedEventCallback delayedTimerCallback;
\r
165 static int delayedTimerEvent = 0;
\r
166 static int buttonCount = 2;
\r
167 char *icsTextMenuString;
\r
169 char *firstChessProgramNames;
\r
170 char *secondChessProgramNames;
\r
172 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
174 #define PALETTESIZE 256
\r
176 HINSTANCE hInst; /* current instance */
\r
177 HWND hwndMain = NULL; /* root window*/
\r
178 HWND hwndConsole = NULL;
\r
179 BOOLEAN alwaysOnTop = FALSE;
\r
181 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
182 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
184 ColorClass currentColorClass;
\r
186 HWND hCommPort = NULL; /* currently open comm port */
\r
187 static HWND hwndPause; /* pause button */
\r
188 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
189 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
190 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
191 explodeBrush, /* [HGM] atomic */
\r
192 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
193 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
194 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
195 static HPEN gridPen = NULL;
\r
196 static HPEN highlightPen = NULL;
\r
197 static HPEN premovePen = NULL;
\r
198 static NPLOGPALETTE pLogPal;
\r
199 static BOOL paletteChanged = FALSE;
\r
200 static HICON iconWhite, iconBlack, iconCurrent;
\r
201 static int doingSizing = FALSE;
\r
202 static int lastSizing = 0;
\r
203 static int prevStderrPort;
\r
204 static HBITMAP userLogo;
\r
206 /* [AS] Support for background textures */
\r
207 #define BACK_TEXTURE_MODE_DISABLED 0
\r
208 #define BACK_TEXTURE_MODE_PLAIN 1
\r
209 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
211 static HBITMAP liteBackTexture = NULL;
\r
212 static HBITMAP darkBackTexture = NULL;
\r
213 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
214 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
215 static int backTextureSquareSize = 0;
\r
216 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
218 #if __GNUC__ && !defined(_winmajor)
\r
219 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
221 #define oldDialog (_winmajor < 4)
\r
224 char *defaultTextAttribs[] =
\r
226 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
227 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
237 int cliWidth, cliHeight;
\r
240 SizeInfo sizeInfo[] =
\r
242 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
243 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
244 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
245 { "petite", 33, 1, 1, 1, 0, 0 },
\r
246 { "slim", 37, 2, 1, 0, 0, 0 },
\r
247 { "small", 40, 2, 1, 0, 0, 0 },
\r
248 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
249 { "middling", 49, 2, 0, 0, 0, 0 },
\r
250 { "average", 54, 2, 0, 0, 0, 0 },
\r
251 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
252 { "medium", 64, 3, 0, 0, 0, 0 },
\r
253 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
254 { "large", 80, 3, 0, 0, 0, 0 },
\r
255 { "big", 87, 3, 0, 0, 0, 0 },
\r
256 { "huge", 95, 3, 0, 0, 0, 0 },
\r
257 { "giant", 108, 3, 0, 0, 0, 0 },
\r
258 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
259 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
260 { NULL, 0, 0, 0, 0, 0, 0 }
\r
263 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
264 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
266 { 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
267 { 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
268 { 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
269 { 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
270 { 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
271 { 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
272 { 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
273 { 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
274 { 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
275 { 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
276 { 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
277 { 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
278 { 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
279 { 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
280 { 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
281 { 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
282 { 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
283 { 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
286 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
295 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
296 #define N_BUTTONS 5
\r
298 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
300 {"<<", IDM_ToStart, NULL, NULL},
\r
301 {"<", IDM_Backward, NULL, NULL},
\r
302 {"P", IDM_Pause, NULL, NULL},
\r
303 {">", IDM_Forward, NULL, NULL},
\r
304 {">>", IDM_ToEnd, NULL, NULL},
\r
307 int tinyLayout = 0, smallLayout = 0;
\r
308 #define MENU_BAR_ITEMS 6
\r
309 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
310 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
311 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
315 MySound sounds[(int)NSoundClasses];
\r
316 MyTextAttribs textAttribs[(int)NColorClasses];
\r
318 MyColorizeAttribs colorizeAttribs[] = {
\r
319 { (COLORREF)0, 0, "Shout Text" },
\r
320 { (COLORREF)0, 0, "SShout/CShout" },
\r
321 { (COLORREF)0, 0, "Channel 1 Text" },
\r
322 { (COLORREF)0, 0, "Channel Text" },
\r
323 { (COLORREF)0, 0, "Kibitz Text" },
\r
324 { (COLORREF)0, 0, "Tell Text" },
\r
325 { (COLORREF)0, 0, "Challenge Text" },
\r
326 { (COLORREF)0, 0, "Request Text" },
\r
327 { (COLORREF)0, 0, "Seek Text" },
\r
328 { (COLORREF)0, 0, "Normal Text" },
\r
329 { (COLORREF)0, 0, "None" }
\r
334 static char *commentTitle;
\r
335 static char *commentText;
\r
336 static int commentIndex;
\r
337 static Boolean editComment = FALSE;
\r
338 HWND commentDialog = NULL;
\r
339 BOOLEAN commentDialogUp = FALSE;
\r
340 static int commentX, commentY, commentH, commentW;
\r
342 static char *analysisTitle;
\r
343 static char *analysisText;
\r
344 HWND analysisDialog = NULL;
\r
345 BOOLEAN analysisDialogUp = FALSE;
\r
346 static int analysisX, analysisY, analysisH, analysisW;
\r
348 char errorTitle[MSG_SIZ];
\r
349 char errorMessage[2*MSG_SIZ];
\r
350 HWND errorDialog = NULL;
\r
351 BOOLEAN moveErrorMessageUp = FALSE;
\r
352 BOOLEAN consoleEcho = TRUE;
\r
353 CHARFORMAT consoleCF;
\r
354 COLORREF consoleBackgroundColor;
\r
356 char *programVersion;
\r
362 typedef int CPKind;
\r
371 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
374 #define INPUT_SOURCE_BUF_SIZE 4096
\r
376 typedef struct _InputSource {
\r
383 char buf[INPUT_SOURCE_BUF_SIZE];
\r
387 InputCallback func;
\r
388 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
392 InputSource *consoleInputSource;
\r
397 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
398 VOID ConsoleCreate();
\r
400 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
401 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
402 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
403 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
405 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
406 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
407 void ParseIcsTextMenu(char *icsTextMenuString);
\r
408 VOID PopUpMoveDialog(char firstchar);
\r
409 VOID PopUpNameDialog(char firstchar);
\r
410 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
414 int GameListOptions();
\r
416 HWND moveHistoryDialog = NULL;
\r
417 BOOLEAN moveHistoryDialogUp = FALSE;
\r
419 WindowPlacement wpMoveHistory;
\r
421 HWND evalGraphDialog = NULL;
\r
422 BOOLEAN evalGraphDialogUp = FALSE;
\r
424 WindowPlacement wpEvalGraph;
\r
426 HWND engineOutputDialog = NULL;
\r
427 BOOLEAN engineOutputDialogUp = FALSE;
\r
429 WindowPlacement wpEngineOutput;
\r
431 VOID MoveHistoryPopUp();
\r
432 VOID MoveHistoryPopDown();
\r
433 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
434 BOOL MoveHistoryIsUp();
\r
436 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
437 VOID EvalGraphPopUp();
\r
438 VOID EvalGraphPopDown();
\r
439 BOOL EvalGraphIsUp();
\r
441 VOID EngineOutputPopUp();
\r
442 VOID EngineOutputPopDown();
\r
443 BOOL EngineOutputIsUp();
\r
444 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
446 VOID GothicPopUp(char *title, VariantClass variant);
\r
448 * Setting "frozen" should disable all user input other than deleting
\r
449 * the window. We do this while engines are initializing themselves.
\r
451 static int frozen = 0;
\r
452 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
458 if (frozen) return;
\r
460 hmenu = GetMenu(hwndMain);
\r
461 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
462 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
464 DrawMenuBar(hwndMain);
\r
467 /* Undo a FreezeUI */
\r
473 if (!frozen) return;
\r
475 hmenu = GetMenu(hwndMain);
\r
476 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
477 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
479 DrawMenuBar(hwndMain);
\r
482 /*---------------------------------------------------------------------------*\
\r
486 \*---------------------------------------------------------------------------*/
\r
489 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
490 LPSTR lpCmdLine, int nCmdShow)
\r
493 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
494 // INITCOMMONCONTROLSEX ex;
\r
498 LoadLibrary("RICHED32.DLL");
\r
499 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
501 if (!InitApplication(hInstance)) {
\r
504 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
508 // InitCommonControlsEx(&ex);
\r
509 InitCommonControls();
\r
511 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
512 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
513 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
515 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
517 while (GetMessage(&msg, /* message structure */
\r
518 NULL, /* handle of window receiving the message */
\r
519 0, /* lowest message to examine */
\r
520 0)) /* highest message to examine */
\r
522 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
523 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
524 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
525 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
526 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
527 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
528 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
529 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
530 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
531 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
532 TranslateMessage(&msg); /* Translates virtual key codes */
\r
533 DispatchMessage(&msg); /* Dispatches message to window */
\r
538 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
541 /*---------------------------------------------------------------------------*\
\r
543 * Initialization functions
\r
545 \*---------------------------------------------------------------------------*/
\r
549 { // update user logo if necessary
\r
550 static char oldUserName[MSG_SIZ], *curName;
\r
552 if(appData.autoLogo) {
\r
553 curName = UserName();
\r
554 if(strcmp(curName, oldUserName)) {
\r
555 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
556 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
557 strcpy(oldUserName, curName);
\r
563 InitApplication(HINSTANCE hInstance)
\r
567 /* Fill in window class structure with parameters that describe the */
\r
570 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
571 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
572 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
573 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
574 wc.hInstance = hInstance; /* Owner of this class */
\r
575 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
576 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
577 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
578 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
579 wc.lpszClassName = szAppName; /* Name to register as */
\r
581 /* Register the window class and return success/failure code. */
\r
582 if (!RegisterClass(&wc)) return FALSE;
\r
584 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
585 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
587 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
588 wc.hInstance = hInstance;
\r
589 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
590 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
591 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
592 wc.lpszMenuName = NULL;
\r
593 wc.lpszClassName = szConsoleName;
\r
595 if (!RegisterClass(&wc)) return FALSE;
\r
600 /* Set by InitInstance, used by EnsureOnScreen */
\r
601 int screenHeight, screenWidth;
\r
604 EnsureOnScreen(int *x, int *y)
\r
606 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
607 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
608 if (*x > screenWidth - 32) *x = 0;
\r
609 if (*y > screenHeight - 32) *y = 0;
\r
610 if (*x < 0) *x = 0;
\r
611 if (*y < 0) *y = 0;
\r
612 // if (*x < 10) *x = 10;
\r
613 // if (*y < gap) *y = gap;
\r
617 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
619 HWND hwnd; /* Main window handle. */
\r
621 WINDOWPLACEMENT wp;
\r
624 hInst = hInstance; /* Store instance handle in our global variable */
\r
626 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
627 *filepart = NULLCHAR;
\r
629 GetCurrentDirectory(MSG_SIZ, installDir);
\r
631 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
632 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
633 if (appData.debugMode) {
\r
634 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
635 setbuf(debugFP, NULL);
\r
640 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
641 // InitEngineUCI( installDir, &second );
\r
643 /* Create a main window for this application instance. */
\r
644 hwnd = CreateWindow(szAppName, szTitle,
\r
645 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
646 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
647 NULL, NULL, hInstance, NULL);
\r
650 /* If window could not be created, return "failure" */
\r
655 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
656 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
657 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
659 if (first.programLogo == NULL && appData.debugMode) {
\r
660 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
662 } else if(appData.autoLogo) {
\r
663 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
665 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
666 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
670 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
671 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
673 if (second.programLogo == NULL && appData.debugMode) {
\r
674 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
676 } else if(appData.autoLogo) {
\r
678 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
679 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
680 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
682 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
683 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
684 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
690 iconWhite = LoadIcon(hInstance, "icon_white");
\r
691 iconBlack = LoadIcon(hInstance, "icon_black");
\r
692 iconCurrent = iconWhite;
\r
693 InitDrawingColors();
\r
694 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
695 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
696 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
697 /* Compute window size for each board size, and use the largest
\r
698 size that fits on this screen as the default. */
\r
699 InitDrawingSizes((BoardSize)ibs, 0);
\r
700 if (boardSize == (BoardSize)-1 &&
\r
701 winHeight <= screenHeight
\r
702 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
703 && winWidth <= screenWidth) {
\r
704 boardSize = (BoardSize)ibs;
\r
708 InitDrawingSizes(boardSize, 0);
\r
710 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
712 /* [AS] Load textures if specified */
\r
713 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
715 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
716 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
717 liteBackTextureMode = appData.liteBackTextureMode;
\r
719 if (liteBackTexture == NULL && appData.debugMode) {
\r
720 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
724 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
725 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
726 darkBackTextureMode = appData.darkBackTextureMode;
\r
728 if (darkBackTexture == NULL && appData.debugMode) {
\r
729 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
733 mysrandom( (unsigned) time(NULL) );
\r
735 /* [AS] Restore layout */
\r
736 if( wpMoveHistory.visible ) {
\r
737 MoveHistoryPopUp();
\r
740 if( wpEvalGraph.visible ) {
\r
744 if( wpEngineOutput.visible ) {
\r
745 EngineOutputPopUp();
\r
750 /* Make the window visible; update its client area; and return "success" */
\r
751 EnsureOnScreen(&boardX, &boardY);
\r
752 wp.length = sizeof(WINDOWPLACEMENT);
\r
754 wp.showCmd = nCmdShow;
\r
755 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
756 wp.rcNormalPosition.left = boardX;
\r
757 wp.rcNormalPosition.right = boardX + winWidth;
\r
758 wp.rcNormalPosition.top = boardY;
\r
759 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
760 SetWindowPlacement(hwndMain, &wp);
\r
762 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
763 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
766 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
767 if( gameInfo.variant != VariantFischeRandom ) {
\r
768 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
773 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
774 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
776 ShowWindow(hwndConsole, nCmdShow);
\r
778 UpdateWindow(hwnd);
\r
786 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
787 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
788 ArgSettingsFilename
\r
796 String *pString; // ArgString
\r
797 int *pInt; // ArgInt
\r
798 float *pFloat; // ArgFloat
\r
799 Boolean *pBoolean; // ArgBoolean
\r
800 COLORREF *pColor; // ArgColor
\r
801 ColorClass cc; // ArgAttribs
\r
802 String *pFilename; // ArgFilename
\r
803 BoardSize *pBoardSize; // ArgBoardSize
\r
804 int whichFont; // ArgFont
\r
805 DCB *pDCB; // ArgCommSettings
\r
806 String *pFilename; // ArgSettingsFilename
\r
814 ArgDescriptor argDescriptors[] = {
\r
815 /* positional arguments */
\r
816 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
817 { "", ArgNone, NULL },
\r
818 /* keyword arguments */
\r
819 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
820 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
821 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
822 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
823 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
824 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
825 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
826 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
827 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
828 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
829 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
830 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
831 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
832 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
833 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
834 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
835 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
836 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
838 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
840 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
842 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
843 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
845 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
846 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
847 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
848 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
849 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
850 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
851 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
852 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
853 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
854 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
855 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
856 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
857 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
858 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
859 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
860 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
861 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
862 /*!!bitmapDirectory?*/
\r
863 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
864 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
865 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
866 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
867 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
868 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
869 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
870 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
871 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
872 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
873 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
874 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
875 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
876 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
877 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
878 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
879 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
880 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
881 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
882 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
883 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
884 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
885 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
886 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
887 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
888 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
889 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
890 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
891 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
892 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
893 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
894 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
895 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
896 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
897 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
898 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
899 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
900 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
901 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
902 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
903 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
904 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
905 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
906 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
907 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
908 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
909 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
910 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
911 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
912 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
913 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
914 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
915 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
916 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
917 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
918 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
919 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
920 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
921 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
922 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
923 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
924 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
925 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
926 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
927 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
928 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
929 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
930 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
931 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
932 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
933 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
934 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
935 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
936 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
937 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
938 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
939 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
940 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
941 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
942 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
943 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
944 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
945 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
946 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
947 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
948 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
949 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
950 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
951 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
952 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
953 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
954 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
955 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
956 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
957 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
958 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
959 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
960 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
961 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
962 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
963 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
964 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
965 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
966 TRUE }, /* must come after all fonts */
\r
967 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
968 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
969 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
970 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
971 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
972 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
973 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
974 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
975 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
976 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
977 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
978 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
979 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
980 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
981 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
982 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
983 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
984 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
985 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
986 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
987 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
988 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
989 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
990 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
991 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
992 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
993 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
994 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
995 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
996 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
997 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
999 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1000 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1002 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1003 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1004 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1005 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1006 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1007 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1008 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1009 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1010 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1011 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1012 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1013 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1014 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1015 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1016 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1017 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1018 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1019 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1020 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1021 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1022 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1023 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1024 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1025 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1026 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1027 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1028 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1029 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1030 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1031 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1032 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1033 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1034 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1035 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1036 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1037 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1038 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1039 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1040 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1041 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1042 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1043 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1044 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1045 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1046 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1047 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1048 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1049 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1050 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1051 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1052 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1053 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1054 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1055 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1056 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1057 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1058 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1059 { "highlightLastMove", ArgBoolean,
\r
1060 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1061 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1062 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1063 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1064 { "highlightDragging", ArgBoolean,
\r
1065 (LPVOID) &appData.highlightDragging, TRUE },
\r
1066 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1067 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1068 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1069 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1070 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1071 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1072 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1073 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1074 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1075 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1076 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1077 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1078 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1079 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1080 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1081 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1082 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1083 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1084 { "soundShout", ArgFilename,
\r
1085 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1086 { "soundSShout", ArgFilename,
\r
1087 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1088 { "soundChannel1", ArgFilename,
\r
1089 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1090 { "soundChannel", ArgFilename,
\r
1091 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1092 { "soundKibitz", ArgFilename,
\r
1093 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1094 { "soundTell", ArgFilename,
\r
1095 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1096 { "soundChallenge", ArgFilename,
\r
1097 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1098 { "soundRequest", ArgFilename,
\r
1099 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1100 { "soundSeek", ArgFilename,
\r
1101 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1102 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1103 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1104 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1105 { "soundIcsLoss", ArgFilename,
\r
1106 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1107 { "soundIcsDraw", ArgFilename,
\r
1108 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1109 { "soundIcsUnfinished", ArgFilename,
\r
1110 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1111 { "soundIcsAlarm", ArgFilename,
\r
1112 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1113 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1114 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1115 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1116 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1117 { "reuseChessPrograms", ArgBoolean,
\r
1118 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1119 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1120 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1121 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1122 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1123 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1124 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1125 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1126 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1127 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1128 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1129 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1130 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1131 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1132 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1133 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1134 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1135 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1136 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1137 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1138 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1139 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1140 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1141 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1142 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1143 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1144 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1145 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1146 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1147 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1148 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1149 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1150 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1151 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1152 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1153 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1154 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1155 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1157 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1159 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1160 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1161 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1162 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1163 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1164 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1165 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1166 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1167 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1168 /* [AS] New features */
\r
1169 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1170 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1171 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1172 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1173 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1174 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1175 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1176 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1177 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1178 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1179 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1180 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1181 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1182 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1183 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1184 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1185 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1186 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1187 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1188 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1189 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1190 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1191 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1192 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1193 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1194 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1195 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1196 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1197 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1198 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1199 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1200 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1201 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1202 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1203 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1204 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1205 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1206 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1207 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1208 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1209 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1210 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1211 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1212 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1213 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1214 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1215 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1216 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1217 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1218 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1220 /* [AS] Layout stuff */
\r
1221 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1222 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1223 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1224 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1225 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1227 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1228 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1229 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1230 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1231 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1233 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1234 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1235 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1236 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1237 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1239 /* [HGM] board-size, adjudication and misc. options */
\r
1240 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1241 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1242 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1243 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1244 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1245 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1246 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1247 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1248 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1249 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1250 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1251 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1252 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1253 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1254 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1255 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1256 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1257 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1258 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1259 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1260 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1261 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1262 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1263 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1264 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1265 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1266 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1267 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1268 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1269 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1270 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1273 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1274 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1275 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1276 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1277 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1278 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1279 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1280 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1281 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1282 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1283 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1284 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1285 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1287 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1288 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1289 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1290 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1291 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1292 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1293 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1295 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1296 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1297 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1298 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1299 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1300 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1301 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1302 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1303 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1304 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1305 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1306 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1307 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1308 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1309 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1310 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1311 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1312 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1313 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1315 /* [HGM] options for broadcasting and time odds */
\r
1316 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1317 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1318 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1319 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1320 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1321 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1322 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1323 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1324 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1325 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1326 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1327 { NULL, ArgNone, NULL, FALSE }
\r
1331 /* Kludge for indirection files on command line */
\r
1332 char* lastIndirectionFilename;
\r
1333 ArgDescriptor argDescriptorIndirection =
\r
1334 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1338 ExitArgError(char *msg, char *badArg)
\r
1340 char buf[MSG_SIZ];
\r
1342 sprintf(buf, "%s %s", msg, badArg);
\r
1343 DisplayFatalError(buf, 0, 2);
\r
1347 /* Command line font name parser. NULL name means do nothing.
\r
1348 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1349 For backward compatibility, syntax without the colon is also
\r
1350 accepted, but font names with digits in them won't work in that case.
\r
1353 ParseFontName(char *name, MyFontParams *mfp)
\r
1356 if (name == NULL) return;
\r
1358 q = strchr(p, ':');
\r
1360 if (q - p >= sizeof(mfp->faceName))
\r
1361 ExitArgError("Font name too long:", name);
\r
1362 memcpy(mfp->faceName, p, q - p);
\r
1363 mfp->faceName[q - p] = NULLCHAR;
\r
1366 q = mfp->faceName;
\r
1367 while (*p && !isdigit(*p)) {
\r
1369 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1370 ExitArgError("Font name too long:", name);
\r
1372 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1375 if (!*p) ExitArgError("Font point size missing:", name);
\r
1376 mfp->pointSize = (float) atof(p);
\r
1377 mfp->bold = (strchr(p, 'b') != NULL);
\r
1378 mfp->italic = (strchr(p, 'i') != NULL);
\r
1379 mfp->underline = (strchr(p, 'u') != NULL);
\r
1380 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1383 /* Color name parser.
\r
1384 X version accepts X color names, but this one
\r
1385 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1387 ParseColorName(char *name)
\r
1389 int red, green, blue, count;
\r
1390 char buf[MSG_SIZ];
\r
1392 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1394 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1395 &red, &green, &blue);
\r
1398 sprintf(buf, "Can't parse color name %s", name);
\r
1399 DisplayError(buf, 0);
\r
1400 return RGB(0, 0, 0);
\r
1402 return PALETTERGB(red, green, blue);
\r
1406 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1408 char *e = argValue;
\r
1412 if (*e == 'b') eff |= CFE_BOLD;
\r
1413 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1414 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1415 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1416 else if (*e == '#' || isdigit(*e)) break;
\r
1420 *color = ParseColorName(e);
\r
1425 ParseBoardSize(char *name)
\r
1427 BoardSize bs = SizeTiny;
\r
1428 while (sizeInfo[bs].name != NULL) {
\r
1429 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1432 ExitArgError("Unrecognized board size value", name);
\r
1433 return bs; /* not reached */
\r
1438 StringGet(void *getClosure)
\r
1440 char **p = (char **) getClosure;
\r
1445 FileGet(void *getClosure)
\r
1448 FILE* f = (FILE*) getClosure;
\r
1451 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1458 /* Parse settings file named "name". If file found, return the
\r
1459 full name in fullname and return TRUE; else return FALSE */
\r
1461 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1465 int ok; char buf[MSG_SIZ];
\r
1467 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1468 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1469 sprintf(buf, "%s.ini", name);
\r
1470 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1473 f = fopen(fullname, "r");
\r
1475 ParseArgs(FileGet, f);
\r
1484 ParseArgs(GetFunc get, void *cl)
\r
1486 char argName[ARG_MAX];
\r
1487 char argValue[ARG_MAX];
\r
1488 ArgDescriptor *ad;
\r
1497 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1498 if (ch == NULLCHAR) break;
\r
1500 /* Comment to end of line */
\r
1502 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1504 } else if (ch == '/' || ch == '-') {
\r
1507 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1508 ch != '\n' && ch != '\t') {
\r
1514 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1515 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1517 if (ad->argName == NULL)
\r
1518 ExitArgError("Unrecognized argument", argName);
\r
1520 } else if (ch == '@') {
\r
1521 /* Indirection file */
\r
1522 ad = &argDescriptorIndirection;
\r
1525 /* Positional argument */
\r
1526 ad = &argDescriptors[posarg++];
\r
1527 strcpy(argName, ad->argName);
\r
1530 if (ad->argType == ArgTrue) {
\r
1531 *(Boolean *) ad->argLoc = TRUE;
\r
1534 if (ad->argType == ArgFalse) {
\r
1535 *(Boolean *) ad->argLoc = FALSE;
\r
1539 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1540 if (ch == NULLCHAR || ch == '\n') {
\r
1541 ExitArgError("No value provided for argument", argName);
\r
1545 // Quoting with { }. No characters have to (or can) be escaped.
\r
1546 // Thus the string cannot contain a '}' character.
\r
1566 } else if (ch == '\'' || ch == '"') {
\r
1567 // Quoting with ' ' or " ", with \ as escape character.
\r
1568 // Inconvenient for long strings that may contain Windows filenames.
\r
1585 if (ch == start) {
\r
1594 if (ad->argType == ArgFilename
\r
1595 || ad->argType == ArgSettingsFilename) {
\r
1601 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1625 for (i = 0; i < 3; i++) {
\r
1626 if (ch >= '0' && ch <= '7') {
\r
1627 octval = octval*8 + (ch - '0');
\r
1634 *q++ = (char) octval;
\r
1645 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1652 switch (ad->argType) {
\r
1654 *(int *) ad->argLoc = atoi(argValue);
\r
1658 *(float *) ad->argLoc = (float) atof(argValue);
\r
1663 *(char **) ad->argLoc = strdup(argValue);
\r
1666 case ArgSettingsFilename:
\r
1668 char fullname[MSG_SIZ];
\r
1669 if (ParseSettingsFile(argValue, fullname)) {
\r
1670 if (ad->argLoc != NULL) {
\r
1671 *(char **) ad->argLoc = strdup(fullname);
\r
1674 if (ad->argLoc != NULL) {
\r
1676 ExitArgError("Failed to open indirection file", argValue);
\r
1683 switch (argValue[0]) {
\r
1686 *(Boolean *) ad->argLoc = TRUE;
\r
1690 *(Boolean *) ad->argLoc = FALSE;
\r
1693 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1699 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1702 case ArgAttribs: {
\r
1703 ColorClass cc = (ColorClass)ad->argLoc;
\r
1704 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1708 case ArgBoardSize:
\r
1709 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1713 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1716 case ArgCommSettings:
\r
1717 ParseCommSettings(argValue, &dcb);
\r
1721 ExitArgError("Unrecognized argument", argValue);
\r
1730 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1732 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1733 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1736 lf->lfEscapement = 0;
\r
1737 lf->lfOrientation = 0;
\r
1738 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1739 lf->lfItalic = mfp->italic;
\r
1740 lf->lfUnderline = mfp->underline;
\r
1741 lf->lfStrikeOut = mfp->strikeout;
\r
1742 lf->lfCharSet = DEFAULT_CHARSET;
\r
1743 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1744 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1745 lf->lfQuality = DEFAULT_QUALITY;
\r
1746 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1747 strcpy(lf->lfFaceName, mfp->faceName);
\r
1751 CreateFontInMF(MyFont *mf)
\r
1753 LFfromMFP(&mf->lf, &mf->mfp);
\r
1754 if (mf->hf) DeleteObject(mf->hf);
\r
1755 mf->hf = CreateFontIndirect(&mf->lf);
\r
1759 SetDefaultTextAttribs()
\r
1762 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1763 ParseAttribs(&textAttribs[cc].color,
\r
1764 &textAttribs[cc].effects,
\r
1765 defaultTextAttribs[cc]);
\r
1770 SetDefaultSounds()
\r
1774 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1775 textAttribs[cc].sound.name = strdup("");
\r
1776 textAttribs[cc].sound.data = NULL;
\r
1778 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1779 sounds[sc].name = strdup("");
\r
1780 sounds[sc].data = NULL;
\r
1782 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1790 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1791 MyLoadSound(&textAttribs[cc].sound);
\r
1793 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1794 MyLoadSound(&sounds[sc]);
\r
1799 InitAppData(LPSTR lpCmdLine)
\r
1802 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1805 programName = szAppName;
\r
1807 /* Initialize to defaults */
\r
1808 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1809 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1810 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1811 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1812 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1813 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1814 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1815 SetDefaultTextAttribs();
\r
1816 SetDefaultSounds();
\r
1817 appData.movesPerSession = MOVES_PER_SESSION;
\r
1818 appData.initString = INIT_STRING;
\r
1819 appData.secondInitString = INIT_STRING;
\r
1820 appData.firstComputerString = COMPUTER_STRING;
\r
1821 appData.secondComputerString = COMPUTER_STRING;
\r
1822 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1823 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1824 appData.firstPlaysBlack = FALSE;
\r
1825 appData.noChessProgram = FALSE;
\r
1826 chessProgram = FALSE;
\r
1827 appData.firstHost = FIRST_HOST;
\r
1828 appData.secondHost = SECOND_HOST;
\r
1829 appData.firstDirectory = FIRST_DIRECTORY;
\r
1830 appData.secondDirectory = SECOND_DIRECTORY;
\r
1831 appData.bitmapDirectory = "";
\r
1832 appData.remoteShell = REMOTE_SHELL;
\r
1833 appData.remoteUser = "";
\r
1834 appData.timeDelay = TIME_DELAY;
\r
1835 appData.timeControl = TIME_CONTROL;
\r
1836 appData.timeIncrement = TIME_INCREMENT;
\r
1837 appData.icsActive = FALSE;
\r
1838 appData.icsHost = "";
\r
1839 appData.icsPort = ICS_PORT;
\r
1840 appData.icsCommPort = ICS_COMM_PORT;
\r
1841 appData.icsLogon = ICS_LOGON;
\r
1842 appData.icsHelper = "";
\r
1843 appData.useTelnet = FALSE;
\r
1844 appData.telnetProgram = TELNET_PROGRAM;
\r
1845 appData.gateway = "";
\r
1846 appData.loadGameFile = "";
\r
1847 appData.loadGameIndex = 0;
\r
1848 appData.saveGameFile = "";
\r
1849 appData.autoSaveGames = FALSE;
\r
1850 appData.loadPositionFile = "";
\r
1851 appData.loadPositionIndex = 1;
\r
1852 appData.savePositionFile = "";
\r
1853 appData.matchMode = FALSE;
\r
1854 appData.matchGames = 0;
\r
1855 appData.monoMode = FALSE;
\r
1856 appData.debugMode = FALSE;
\r
1857 appData.clockMode = TRUE;
\r
1858 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1859 appData.Iconic = FALSE; /*unused*/
\r
1860 appData.searchTime = "";
\r
1861 appData.searchDepth = 0;
\r
1862 appData.showCoords = FALSE;
\r
1863 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1864 appData.autoCallFlag = FALSE;
\r
1865 appData.flipView = FALSE;
\r
1866 appData.autoFlipView = TRUE;
\r
1867 appData.cmailGameName = "";
\r
1868 appData.alwaysPromoteToQueen = FALSE;
\r
1869 appData.oldSaveStyle = FALSE;
\r
1870 appData.quietPlay = FALSE;
\r
1871 appData.showThinking = FALSE;
\r
1872 appData.ponderNextMove = TRUE;
\r
1873 appData.periodicUpdates = TRUE;
\r
1874 appData.popupExitMessage = TRUE;
\r
1875 appData.popupMoveErrors = FALSE;
\r
1876 appData.autoObserve = FALSE;
\r
1877 appData.autoComment = FALSE;
\r
1878 appData.animate = TRUE;
\r
1879 appData.animSpeed = 10;
\r
1880 appData.animateDragging = TRUE;
\r
1881 appData.highlightLastMove = TRUE;
\r
1882 appData.getMoveList = TRUE;
\r
1883 appData.testLegality = TRUE;
\r
1884 appData.premove = TRUE;
\r
1885 appData.premoveWhite = FALSE;
\r
1886 appData.premoveWhiteText = "";
\r
1887 appData.premoveBlack = FALSE;
\r
1888 appData.premoveBlackText = "";
\r
1889 appData.icsAlarm = TRUE;
\r
1890 appData.icsAlarmTime = 5000;
\r
1891 appData.autoRaiseBoard = TRUE;
\r
1892 appData.localLineEditing = TRUE;
\r
1893 appData.colorize = TRUE;
\r
1894 appData.reuseFirst = TRUE;
\r
1895 appData.reuseSecond = TRUE;
\r
1896 appData.blindfold = FALSE;
\r
1897 appData.icsEngineAnalyze = FALSE;
\r
1898 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1899 dcb.DCBlength = sizeof(DCB);
\r
1900 dcb.BaudRate = 9600;
\r
1901 dcb.fBinary = TRUE;
\r
1902 dcb.fParity = FALSE;
\r
1903 dcb.fOutxCtsFlow = FALSE;
\r
1904 dcb.fOutxDsrFlow = FALSE;
\r
1905 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1906 dcb.fDsrSensitivity = FALSE;
\r
1907 dcb.fTXContinueOnXoff = TRUE;
\r
1908 dcb.fOutX = FALSE;
\r
1910 dcb.fNull = FALSE;
\r
1911 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1912 dcb.fAbortOnError = FALSE;
\r
1914 dcb.Parity = SPACEPARITY;
\r
1915 dcb.StopBits = ONESTOPBIT;
\r
1916 settingsFileName = SETTINGS_FILE;
\r
1917 saveSettingsOnExit = TRUE;
\r
1918 boardX = CW_USEDEFAULT;
\r
1919 boardY = CW_USEDEFAULT;
\r
1920 consoleX = CW_USEDEFAULT;
\r
1921 consoleY = CW_USEDEFAULT;
\r
1922 consoleW = CW_USEDEFAULT;
\r
1923 consoleH = CW_USEDEFAULT;
\r
1924 analysisX = CW_USEDEFAULT;
\r
1925 analysisY = CW_USEDEFAULT;
\r
1926 analysisW = CW_USEDEFAULT;
\r
1927 analysisH = CW_USEDEFAULT;
\r
1928 commentX = CW_USEDEFAULT;
\r
1929 commentY = CW_USEDEFAULT;
\r
1930 commentW = CW_USEDEFAULT;
\r
1931 commentH = CW_USEDEFAULT;
\r
1932 editTagsX = CW_USEDEFAULT;
\r
1933 editTagsY = CW_USEDEFAULT;
\r
1934 editTagsW = CW_USEDEFAULT;
\r
1935 editTagsH = CW_USEDEFAULT;
\r
1936 gameListX = CW_USEDEFAULT;
\r
1937 gameListY = CW_USEDEFAULT;
\r
1938 gameListW = CW_USEDEFAULT;
\r
1939 gameListH = CW_USEDEFAULT;
\r
1940 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1941 icsNames = ICS_NAMES;
\r
1942 firstChessProgramNames = FCP_NAMES;
\r
1943 secondChessProgramNames = SCP_NAMES;
\r
1944 appData.initialMode = "";
\r
1945 appData.variant = "normal";
\r
1946 appData.firstProtocolVersion = PROTOVER;
\r
1947 appData.secondProtocolVersion = PROTOVER;
\r
1948 appData.showButtonBar = TRUE;
\r
1950 /* [AS] New properties (see comments in header file) */
\r
1951 appData.firstScoreIsAbsolute = FALSE;
\r
1952 appData.secondScoreIsAbsolute = FALSE;
\r
1953 appData.saveExtendedInfoInPGN = FALSE;
\r
1954 appData.hideThinkingFromHuman = FALSE;
\r
1955 appData.liteBackTextureFile = "";
\r
1956 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1957 appData.darkBackTextureFile = "";
\r
1958 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1959 appData.renderPiecesWithFont = "";
\r
1960 appData.fontToPieceTable = "";
\r
1961 appData.fontBackColorWhite = 0;
\r
1962 appData.fontForeColorWhite = 0;
\r
1963 appData.fontBackColorBlack = 0;
\r
1964 appData.fontForeColorBlack = 0;
\r
1965 appData.fontPieceSize = 80;
\r
1966 appData.overrideLineGap = 1;
\r
1967 appData.adjudicateLossThreshold = 0;
\r
1968 appData.delayBeforeQuit = 0;
\r
1969 appData.delayAfterQuit = 0;
\r
1970 appData.nameOfDebugFile = "winboard.debug";
\r
1971 appData.pgnEventHeader = "Computer Chess Game";
\r
1972 appData.defaultFrcPosition = -1;
\r
1973 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1974 appData.saveOutOfBookInfo = TRUE;
\r
1975 appData.showEvalInMoveHistory = TRUE;
\r
1976 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1977 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1978 appData.highlightMoveWithArrow = FALSE;
\r
1979 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1980 appData.useStickyWindows = TRUE;
\r
1981 appData.adjudicateDrawMoves = 0;
\r
1982 appData.autoDisplayComment = TRUE;
\r
1983 appData.autoDisplayTags = TRUE;
\r
1984 appData.firstIsUCI = FALSE;
\r
1985 appData.secondIsUCI = FALSE;
\r
1986 appData.firstHasOwnBookUCI = TRUE;
\r
1987 appData.secondHasOwnBookUCI = TRUE;
\r
1988 appData.polyglotDir = "";
\r
1989 appData.usePolyglotBook = FALSE;
\r
1990 appData.polyglotBook = "";
\r
1991 appData.defaultHashSize = 64;
\r
1992 appData.defaultCacheSizeEGTB = 4;
\r
1993 appData.defaultPathEGTB = "c:\\egtb";
\r
1994 appData.firstOptions = "";
\r
1995 appData.secondOptions = "";
\r
1997 InitWindowPlacement( &wpMoveHistory );
\r
1998 InitWindowPlacement( &wpEvalGraph );
\r
1999 InitWindowPlacement( &wpEngineOutput );
\r
2001 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2002 appData.NrFiles = -1;
\r
2003 appData.NrRanks = -1;
\r
2004 appData.holdingsSize = -1;
\r
2005 appData.testClaims = FALSE;
\r
2006 appData.checkMates = FALSE;
\r
2007 appData.materialDraws= FALSE;
\r
2008 appData.trivialDraws = FALSE;
\r
2009 appData.ruleMoves = 51;
\r
2010 appData.drawRepeats = 6;
\r
2011 appData.matchPause = 10000;
\r
2012 appData.alphaRank = FALSE;
\r
2013 appData.allWhite = FALSE;
\r
2014 appData.upsideDown = FALSE;
\r
2015 appData.serverPause = 15;
\r
2016 appData.serverMovesName = NULL;
\r
2017 appData.suppressLoadMoves = FALSE;
\r
2018 appData.firstTimeOdds = 1;
\r
2019 appData.secondTimeOdds = 1;
\r
2020 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2021 appData.secondAccumulateTC = 1;
\r
2022 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2023 appData.secondNPS = -1;
\r
2024 appData.engineComments = 1;
\r
2025 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2026 appData.egtFormats = "";
\r
2029 appData.zippyTalk = ZIPPY_TALK;
\r
2030 appData.zippyPlay = ZIPPY_PLAY;
\r
2031 appData.zippyLines = ZIPPY_LINES;
\r
2032 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2033 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2034 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2035 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2036 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2037 appData.zippyUseI = ZIPPY_USE_I;
\r
2038 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2039 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2040 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2041 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2042 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2043 appData.zippyAbort = ZIPPY_ABORT;
\r
2044 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2045 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2046 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2049 /* Point font array elements to structures and
\r
2050 parse default font names */
\r
2051 for (i=0; i<NUM_FONTS; i++) {
\r
2052 for (j=0; j<NUM_SIZES; j++) {
\r
2053 font[j][i] = &fontRec[j][i];
\r
2054 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2058 /* Parse default settings file if any */
\r
2059 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2060 settingsFileName = strdup(buf);
\r
2063 /* Parse command line */
\r
2064 ParseArgs(StringGet, &lpCmdLine);
\r
2066 /* [HGM] make sure board size is acceptable */
\r
2067 if(appData.NrFiles > BOARD_SIZE ||
\r
2068 appData.NrRanks > BOARD_SIZE )
\r
2069 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2071 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2072 * with options from the command line, we now make an even higher priority
\r
2073 * overrule by WB options attached to the engine command line. This so that
\r
2074 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2077 if(appData.firstChessProgram != NULL) {
\r
2078 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2079 static char *f = "first";
\r
2080 char buf[MSG_SIZ], *q = buf;
\r
2081 if(p != NULL) { // engine command line contains WinBoard options
\r
2082 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2083 ParseArgs(StringGet, &q);
\r
2084 p[-1] = 0; // cut them offengine command line
\r
2087 // now do same for second chess program
\r
2088 if(appData.secondChessProgram != NULL) {
\r
2089 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2090 static char *s = "second";
\r
2091 char buf[MSG_SIZ], *q = buf;
\r
2092 if(p != NULL) { // engine command line contains WinBoard options
\r
2093 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2094 ParseArgs(StringGet, &q);
\r
2095 p[-1] = 0; // cut them offengine command line
\r
2100 /* Propagate options that affect others */
\r
2101 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2102 if (appData.icsActive || appData.noChessProgram) {
\r
2103 chessProgram = FALSE; /* not local chess program mode */
\r
2106 /* Open startup dialog if needed */
\r
2107 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2108 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2109 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2110 *appData.secondChessProgram == NULLCHAR))) {
\r
2113 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2114 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2115 FreeProcInstance(lpProc);
\r
2118 /* Make sure save files land in the right (?) directory */
\r
2119 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2120 appData.saveGameFile = strdup(buf);
\r
2122 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2123 appData.savePositionFile = strdup(buf);
\r
2126 /* Finish initialization for fonts and sounds */
\r
2127 for (i=0; i<NUM_FONTS; i++) {
\r
2128 for (j=0; j<NUM_SIZES; j++) {
\r
2129 CreateFontInMF(font[j][i]);
\r
2132 /* xboard, and older WinBoards, controlled the move sound with the
\r
2133 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2134 always turn the option on (so that the backend will call us),
\r
2135 then let the user turn the sound off by setting it to silence if
\r
2136 desired. To accommodate old winboard.ini files saved by old
\r
2137 versions of WinBoard, we also turn off the sound if the option
\r
2138 was initially set to false. */
\r
2139 if (!appData.ringBellAfterMoves) {
\r
2140 sounds[(int)SoundMove].name = strdup("");
\r
2141 appData.ringBellAfterMoves = TRUE;
\r
2143 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2144 SetCurrentDirectory(installDir);
\r
2146 SetCurrentDirectory(currDir);
\r
2148 p = icsTextMenuString;
\r
2149 if (p[0] == '@') {
\r
2150 FILE* f = fopen(p + 1, "r");
\r
2152 DisplayFatalError(p + 1, errno, 2);
\r
2155 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2157 buf[i] = NULLCHAR;
\r
2160 ParseIcsTextMenu(strdup(p));
\r
2167 HMENU hmenu = GetMenu(hwndMain);
\r
2169 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2170 MF_BYCOMMAND|((appData.icsActive &&
\r
2171 *appData.icsCommPort != NULLCHAR) ?
\r
2172 MF_ENABLED : MF_GRAYED));
\r
2173 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2174 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2175 MF_CHECKED : MF_UNCHECKED));
\r
2180 SaveSettings(char* name)
\r
2183 ArgDescriptor *ad;
\r
2184 WINDOWPLACEMENT wp;
\r
2185 char dir[MSG_SIZ];
\r
2187 if (!hwndMain) return;
\r
2189 GetCurrentDirectory(MSG_SIZ, dir);
\r
2190 SetCurrentDirectory(installDir);
\r
2191 f = fopen(name, "w");
\r
2192 SetCurrentDirectory(dir);
\r
2194 DisplayError(name, errno);
\r
2197 fprintf(f, ";\n");
\r
2198 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2199 fprintf(f, ";\n");
\r
2200 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2201 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2202 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2203 fprintf(f, ";\n");
\r
2205 wp.length = sizeof(WINDOWPLACEMENT);
\r
2206 GetWindowPlacement(hwndMain, &wp);
\r
2207 boardX = wp.rcNormalPosition.left;
\r
2208 boardY = wp.rcNormalPosition.top;
\r
2210 if (hwndConsole) {
\r
2211 GetWindowPlacement(hwndConsole, &wp);
\r
2212 consoleX = wp.rcNormalPosition.left;
\r
2213 consoleY = wp.rcNormalPosition.top;
\r
2214 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2215 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2218 if (analysisDialog) {
\r
2219 GetWindowPlacement(analysisDialog, &wp);
\r
2220 analysisX = wp.rcNormalPosition.left;
\r
2221 analysisY = wp.rcNormalPosition.top;
\r
2222 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2223 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2226 if (commentDialog) {
\r
2227 GetWindowPlacement(commentDialog, &wp);
\r
2228 commentX = wp.rcNormalPosition.left;
\r
2229 commentY = wp.rcNormalPosition.top;
\r
2230 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2231 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2234 if (editTagsDialog) {
\r
2235 GetWindowPlacement(editTagsDialog, &wp);
\r
2236 editTagsX = wp.rcNormalPosition.left;
\r
2237 editTagsY = wp.rcNormalPosition.top;
\r
2238 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2239 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2242 if (gameListDialog) {
\r
2243 GetWindowPlacement(gameListDialog, &wp);
\r
2244 gameListX = wp.rcNormalPosition.left;
\r
2245 gameListY = wp.rcNormalPosition.top;
\r
2246 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2247 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2250 /* [AS] Move history */
\r
2251 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2253 if( moveHistoryDialog ) {
\r
2254 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2255 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2256 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2257 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2258 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2261 /* [AS] Eval graph */
\r
2262 wpEvalGraph.visible = EvalGraphIsUp();
\r
2264 if( evalGraphDialog ) {
\r
2265 GetWindowPlacement(evalGraphDialog, &wp);
\r
2266 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2267 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2268 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2269 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2272 /* [AS] Engine output */
\r
2273 wpEngineOutput.visible = EngineOutputIsUp();
\r
2275 if( engineOutputDialog ) {
\r
2276 GetWindowPlacement(engineOutputDialog, &wp);
\r
2277 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2278 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2279 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2280 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2283 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2284 if (!ad->save) continue;
\r
2285 switch (ad->argType) {
\r
2288 char *p = *(char **)ad->argLoc;
\r
2289 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2290 /* Quote multiline values or \-containing values
\r
2291 with { } if possible */
\r
2292 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2294 /* Else quote with " " */
\r
2295 fprintf(f, "/%s=\"", ad->argName);
\r
2297 if (*p == '\n') fprintf(f, "\n");
\r
2298 else if (*p == '\r') fprintf(f, "\\r");
\r
2299 else if (*p == '\t') fprintf(f, "\\t");
\r
2300 else if (*p == '\b') fprintf(f, "\\b");
\r
2301 else if (*p == '\f') fprintf(f, "\\f");
\r
2302 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2303 else if (*p == '\"') fprintf(f, "\\\"");
\r
2304 else if (*p == '\\') fprintf(f, "\\\\");
\r
2308 fprintf(f, "\"\n");
\r
2313 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2316 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2319 fprintf(f, "/%s=%s\n", ad->argName,
\r
2320 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2323 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2326 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2330 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2331 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2332 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2337 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2338 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2339 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2340 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2341 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2342 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2343 (ta->effects) ? " " : "",
\r
2344 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2348 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2349 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2351 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2354 case ArgBoardSize:
\r
2355 fprintf(f, "/%s=%s\n", ad->argName,
\r
2356 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2361 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2362 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2363 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2364 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2365 ad->argName, mfp->faceName, mfp->pointSize,
\r
2366 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2367 mfp->bold ? "b" : "",
\r
2368 mfp->italic ? "i" : "",
\r
2369 mfp->underline ? "u" : "",
\r
2370 mfp->strikeout ? "s" : "");
\r
2374 case ArgCommSettings:
\r
2375 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2377 case ArgSettingsFilename: ;
\r
2385 /*---------------------------------------------------------------------------*\
\r
2387 * GDI board drawing routines
\r
2389 \*---------------------------------------------------------------------------*/
\r
2391 /* [AS] Draw square using background texture */
\r
2392 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2397 return; /* Should never happen! */
\r
2400 SetGraphicsMode( dst, GM_ADVANCED );
\r
2407 /* X reflection */
\r
2412 x.eDx = (FLOAT) dw + dx - 1;
\r
2415 SetWorldTransform( dst, &x );
\r
2418 /* Y reflection */
\r
2424 x.eDy = (FLOAT) dh + dy - 1;
\r
2426 SetWorldTransform( dst, &x );
\r
2434 x.eDx = (FLOAT) dx;
\r
2435 x.eDy = (FLOAT) dy;
\r
2438 SetWorldTransform( dst, &x );
\r
2442 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2450 SetWorldTransform( dst, &x );
\r
2452 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2455 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2457 PM_WP = (int) WhitePawn,
\r
2458 PM_WN = (int) WhiteKnight,
\r
2459 PM_WB = (int) WhiteBishop,
\r
2460 PM_WR = (int) WhiteRook,
\r
2461 PM_WQ = (int) WhiteQueen,
\r
2462 PM_WF = (int) WhiteFerz,
\r
2463 PM_WW = (int) WhiteWazir,
\r
2464 PM_WE = (int) WhiteAlfil,
\r
2465 PM_WM = (int) WhiteMan,
\r
2466 PM_WO = (int) WhiteCannon,
\r
2467 PM_WU = (int) WhiteUnicorn,
\r
2468 PM_WH = (int) WhiteNightrider,
\r
2469 PM_WA = (int) WhiteAngel,
\r
2470 PM_WC = (int) WhiteMarshall,
\r
2471 PM_WAB = (int) WhiteCardinal,
\r
2472 PM_WD = (int) WhiteDragon,
\r
2473 PM_WL = (int) WhiteLance,
\r
2474 PM_WS = (int) WhiteCobra,
\r
2475 PM_WV = (int) WhiteFalcon,
\r
2476 PM_WSG = (int) WhiteSilver,
\r
2477 PM_WG = (int) WhiteGrasshopper,
\r
2478 PM_WK = (int) WhiteKing,
\r
2479 PM_BP = (int) BlackPawn,
\r
2480 PM_BN = (int) BlackKnight,
\r
2481 PM_BB = (int) BlackBishop,
\r
2482 PM_BR = (int) BlackRook,
\r
2483 PM_BQ = (int) BlackQueen,
\r
2484 PM_BF = (int) BlackFerz,
\r
2485 PM_BW = (int) BlackWazir,
\r
2486 PM_BE = (int) BlackAlfil,
\r
2487 PM_BM = (int) BlackMan,
\r
2488 PM_BO = (int) BlackCannon,
\r
2489 PM_BU = (int) BlackUnicorn,
\r
2490 PM_BH = (int) BlackNightrider,
\r
2491 PM_BA = (int) BlackAngel,
\r
2492 PM_BC = (int) BlackMarshall,
\r
2493 PM_BG = (int) BlackGrasshopper,
\r
2494 PM_BAB = (int) BlackCardinal,
\r
2495 PM_BD = (int) BlackDragon,
\r
2496 PM_BL = (int) BlackLance,
\r
2497 PM_BS = (int) BlackCobra,
\r
2498 PM_BV = (int) BlackFalcon,
\r
2499 PM_BSG = (int) BlackSilver,
\r
2500 PM_BK = (int) BlackKing
\r
2503 static HFONT hPieceFont = NULL;
\r
2504 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2505 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2506 static int fontBitmapSquareSize = 0;
\r
2507 static char pieceToFontChar[(int) EmptySquare] =
\r
2508 { 'p', 'n', 'b', 'r', 'q',
\r
2509 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2510 'k', 'o', 'm', 'v', 't', 'w',
\r
2511 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2514 extern BOOL SetCharTable( char *table, const char * map );
\r
2515 /* [HGM] moved to backend.c */
\r
2517 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2520 BYTE r1 = GetRValue( color );
\r
2521 BYTE g1 = GetGValue( color );
\r
2522 BYTE b1 = GetBValue( color );
\r
2528 /* Create a uniform background first */
\r
2529 hbrush = CreateSolidBrush( color );
\r
2530 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2531 FillRect( hdc, &rc, hbrush );
\r
2532 DeleteObject( hbrush );
\r
2535 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2536 int steps = squareSize / 2;
\r
2539 for( i=0; i<steps; i++ ) {
\r
2540 BYTE r = r1 - (r1-r2) * i / steps;
\r
2541 BYTE g = g1 - (g1-g2) * i / steps;
\r
2542 BYTE b = b1 - (b1-b2) * i / steps;
\r
2544 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2545 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2546 FillRect( hdc, &rc, hbrush );
\r
2547 DeleteObject(hbrush);
\r
2550 else if( mode == 2 ) {
\r
2551 /* Diagonal gradient, good more or less for every piece */
\r
2552 POINT triangle[3];
\r
2553 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2554 HBRUSH hbrush_old;
\r
2555 int steps = squareSize;
\r
2558 triangle[0].x = squareSize - steps;
\r
2559 triangle[0].y = squareSize;
\r
2560 triangle[1].x = squareSize;
\r
2561 triangle[1].y = squareSize;
\r
2562 triangle[2].x = squareSize;
\r
2563 triangle[2].y = squareSize - steps;
\r
2565 for( i=0; i<steps; i++ ) {
\r
2566 BYTE r = r1 - (r1-r2) * i / steps;
\r
2567 BYTE g = g1 - (g1-g2) * i / steps;
\r
2568 BYTE b = b1 - (b1-b2) * i / steps;
\r
2570 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2571 hbrush_old = SelectObject( hdc, hbrush );
\r
2572 Polygon( hdc, triangle, 3 );
\r
2573 SelectObject( hdc, hbrush_old );
\r
2574 DeleteObject(hbrush);
\r
2579 SelectObject( hdc, hpen );
\r
2584 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2585 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2586 piece: follow the steps as explained below.
\r
2588 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2592 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2596 int backColor = whitePieceColor;
\r
2597 int foreColor = blackPieceColor;
\r
2599 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2600 backColor = appData.fontBackColorWhite;
\r
2601 foreColor = appData.fontForeColorWhite;
\r
2603 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2604 backColor = appData.fontBackColorBlack;
\r
2605 foreColor = appData.fontForeColorBlack;
\r
2609 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2611 hbm_old = SelectObject( hdc, hbm );
\r
2615 rc.right = squareSize;
\r
2616 rc.bottom = squareSize;
\r
2618 /* Step 1: background is now black */
\r
2619 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2621 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2623 pt.x = (squareSize - sz.cx) / 2;
\r
2624 pt.y = (squareSize - sz.cy) / 2;
\r
2626 SetBkMode( hdc, TRANSPARENT );
\r
2627 SetTextColor( hdc, chroma );
\r
2628 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2629 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2631 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2632 /* Step 3: the area outside the piece is filled with white */
\r
2633 // FloodFill( hdc, 0, 0, chroma );
\r
2634 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2635 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2636 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2637 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2638 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2640 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2641 but if the start point is not inside the piece we're lost!
\r
2642 There should be a better way to do this... if we could create a region or path
\r
2643 from the fill operation we would be fine for example.
\r
2645 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2646 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2648 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2649 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2650 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2652 SelectObject( dc2, bm2 );
\r
2653 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2654 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2655 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2656 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2657 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2660 DeleteObject( bm2 );
\r
2663 SetTextColor( hdc, 0 );
\r
2665 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2666 draw the piece again in black for safety.
\r
2668 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2670 SelectObject( hdc, hbm_old );
\r
2672 if( hPieceMask[index] != NULL ) {
\r
2673 DeleteObject( hPieceMask[index] );
\r
2676 hPieceMask[index] = hbm;
\r
2679 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2681 SelectObject( hdc, hbm );
\r
2684 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2685 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2686 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2688 SelectObject( dc1, hPieceMask[index] );
\r
2689 SelectObject( dc2, bm2 );
\r
2690 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2691 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2694 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2695 the piece background and deletes (makes transparent) the rest.
\r
2696 Thanks to that mask, we are free to paint the background with the greates
\r
2697 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2698 We use this, to make gradients and give the pieces a "roundish" look.
\r
2700 SetPieceBackground( hdc, backColor, 2 );
\r
2701 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2705 DeleteObject( bm2 );
\r
2708 SetTextColor( hdc, foreColor );
\r
2709 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2711 SelectObject( hdc, hbm_old );
\r
2713 if( hPieceFace[index] != NULL ) {
\r
2714 DeleteObject( hPieceFace[index] );
\r
2717 hPieceFace[index] = hbm;
\r
2720 static int TranslatePieceToFontPiece( int piece )
\r
2750 case BlackMarshall:
\r
2754 case BlackNightrider:
\r
2760 case BlackUnicorn:
\r
2764 case BlackGrasshopper:
\r
2776 case BlackCardinal:
\r
2783 case WhiteMarshall:
\r
2787 case WhiteNightrider:
\r
2793 case WhiteUnicorn:
\r
2797 case WhiteGrasshopper:
\r
2809 case WhiteCardinal:
\r
2818 void CreatePiecesFromFont()
\r
2821 HDC hdc_window = NULL;
\r
2827 if( fontBitmapSquareSize < 0 ) {
\r
2828 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2832 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2833 fontBitmapSquareSize = -1;
\r
2837 if( fontBitmapSquareSize != squareSize ) {
\r
2838 hdc_window = GetDC( hwndMain );
\r
2839 hdc = CreateCompatibleDC( hdc_window );
\r
2841 if( hPieceFont != NULL ) {
\r
2842 DeleteObject( hPieceFont );
\r
2845 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2846 hPieceMask[i] = NULL;
\r
2847 hPieceFace[i] = NULL;
\r
2853 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2854 fontHeight = appData.fontPieceSize;
\r
2857 fontHeight = (fontHeight * squareSize) / 100;
\r
2859 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2861 lf.lfEscapement = 0;
\r
2862 lf.lfOrientation = 0;
\r
2863 lf.lfWeight = FW_NORMAL;
\r
2865 lf.lfUnderline = 0;
\r
2866 lf.lfStrikeOut = 0;
\r
2867 lf.lfCharSet = DEFAULT_CHARSET;
\r
2868 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2869 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2870 lf.lfQuality = PROOF_QUALITY;
\r
2871 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2872 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2873 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2875 hPieceFont = CreateFontIndirect( &lf );
\r
2877 if( hPieceFont == NULL ) {
\r
2878 fontBitmapSquareSize = -2;
\r
2881 /* Setup font-to-piece character table */
\r
2882 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2883 /* No (or wrong) global settings, try to detect the font */
\r
2884 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2886 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2888 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2889 /* DiagramTT* family */
\r
2890 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2892 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2893 /* Fairy symbols */
\r
2894 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2896 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2897 /* Good Companion (Some characters get warped as literal :-( */
\r
2898 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2899 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2900 SetCharTable(pieceToFontChar, s);
\r
2903 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2904 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2908 /* Create bitmaps */
\r
2909 hfont_old = SelectObject( hdc, hPieceFont );
\r
2911 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2912 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2913 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2914 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2915 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2916 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2917 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2918 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2919 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2920 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2921 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2922 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2924 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2925 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2926 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2927 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2928 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2929 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2930 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2931 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2932 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2933 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2934 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
2935 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
2936 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
2937 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
2938 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
2939 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
2940 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2941 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2942 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2943 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2944 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2945 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2946 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2947 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2948 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2949 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2950 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
2951 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
2952 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
2953 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
2954 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
2955 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
2957 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2958 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2959 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2961 SelectObject( hdc, hfont_old );
\r
2963 fontBitmapSquareSize = squareSize;
\r
2967 if( hdc != NULL ) {
\r
2971 if( hdc_window != NULL ) {
\r
2972 ReleaseDC( hwndMain, hdc_window );
\r
2977 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2981 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2982 if (gameInfo.event &&
\r
2983 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2984 strcmp(name, "k80s") == 0) {
\r
2985 strcpy(name, "tim");
\r
2987 return LoadBitmap(hinst, name);
\r
2991 /* Insert a color into the program's logical palette
\r
2992 structure. This code assumes the given color is
\r
2993 the result of the RGB or PALETTERGB macro, and it
\r
2994 knows how those macros work (which is documented).
\r
2997 InsertInPalette(COLORREF color)
\r
2999 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3001 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3002 DisplayFatalError("Too many colors", 0, 1);
\r
3003 pLogPal->palNumEntries--;
\r
3007 pe->peFlags = (char) 0;
\r
3008 pe->peRed = (char) (0xFF & color);
\r
3009 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3010 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3016 InitDrawingColors()
\r
3018 if (pLogPal == NULL) {
\r
3019 /* Allocate enough memory for a logical palette with
\r
3020 * PALETTESIZE entries and set the size and version fields
\r
3021 * of the logical palette structure.
\r
3023 pLogPal = (NPLOGPALETTE)
\r
3024 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3025 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3026 pLogPal->palVersion = 0x300;
\r
3028 pLogPal->palNumEntries = 0;
\r
3030 InsertInPalette(lightSquareColor);
\r
3031 InsertInPalette(darkSquareColor);
\r
3032 InsertInPalette(whitePieceColor);
\r
3033 InsertInPalette(blackPieceColor);
\r
3034 InsertInPalette(highlightSquareColor);
\r
3035 InsertInPalette(premoveHighlightColor);
\r
3037 /* create a logical color palette according the information
\r
3038 * in the LOGPALETTE structure.
\r
3040 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3042 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3043 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3044 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3045 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3046 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3047 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3048 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3049 /* [AS] Force rendering of the font-based pieces */
\r
3050 if( fontBitmapSquareSize > 0 ) {
\r
3051 fontBitmapSquareSize = 0;
\r
3057 BoardWidth(int boardSize, int n)
\r
3058 { /* [HGM] argument n added to allow different width and height */
\r
3059 int lineGap = sizeInfo[boardSize].lineGap;
\r
3061 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3062 lineGap = appData.overrideLineGap;
\r
3065 return (n + 1) * lineGap +
\r
3066 n * sizeInfo[boardSize].squareSize;
\r
3069 /* Respond to board resize by dragging edge */
\r
3071 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3073 BoardSize newSize = NUM_SIZES - 1;
\r
3074 static int recurse = 0;
\r
3075 if (IsIconic(hwndMain)) return;
\r
3076 if (recurse > 0) return;
\r
3078 while (newSize > 0) {
\r
3079 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3080 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3081 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3084 boardSize = newSize;
\r
3085 InitDrawingSizes(boardSize, flags);
\r
3092 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3094 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3095 ChessSquare piece;
\r
3096 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3098 SIZE clockSize, messageSize;
\r
3100 char buf[MSG_SIZ];
\r
3102 HMENU hmenu = GetMenu(hwndMain);
\r
3103 RECT crect, wrect;
\r
3105 LOGBRUSH logbrush;
\r
3107 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3108 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3110 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3111 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3113 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3114 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3115 squareSize = sizeInfo[boardSize].squareSize;
\r
3116 lineGap = sizeInfo[boardSize].lineGap;
\r
3117 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3119 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3120 lineGap = appData.overrideLineGap;
\r
3123 if (tinyLayout != oldTinyLayout) {
\r
3124 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3126 style &= ~WS_SYSMENU;
\r
3127 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3128 "&Minimize\tCtrl+F4");
\r
3130 style |= WS_SYSMENU;
\r
3131 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3133 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3135 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3136 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3137 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3139 DrawMenuBar(hwndMain);
\r
3142 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3143 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3145 /* Get text area sizes */
\r
3146 hdc = GetDC(hwndMain);
\r
3147 if (appData.clockMode) {
\r
3148 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3150 sprintf(buf, "White");
\r
3152 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3153 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3154 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3155 str = "We only care about the height here";
\r
3156 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3157 SelectObject(hdc, oldFont);
\r
3158 ReleaseDC(hwndMain, hdc);
\r
3160 /* Compute where everything goes */
\r
3161 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3162 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3163 logoHeight = 2*clockSize.cy;
\r
3164 leftLogoRect.left = OUTER_MARGIN;
\r
3165 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3166 leftLogoRect.top = OUTER_MARGIN;
\r
3167 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3169 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3170 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3171 rightLogoRect.top = OUTER_MARGIN;
\r
3172 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3175 whiteRect.left = leftLogoRect.right;
\r
3176 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3177 whiteRect.top = OUTER_MARGIN;
\r
3178 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3180 blackRect.right = rightLogoRect.left;
\r
3181 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3182 blackRect.top = whiteRect.top;
\r
3183 blackRect.bottom = whiteRect.bottom;
\r
3185 whiteRect.left = OUTER_MARGIN;
\r
3186 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3187 whiteRect.top = OUTER_MARGIN;
\r
3188 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3190 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3191 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3192 blackRect.top = whiteRect.top;
\r
3193 blackRect.bottom = whiteRect.bottom;
\r
3196 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3197 if (appData.showButtonBar) {
\r
3198 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3199 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3201 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3203 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3204 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3206 boardRect.left = OUTER_MARGIN;
\r
3207 boardRect.right = boardRect.left + boardWidth;
\r
3208 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3209 boardRect.bottom = boardRect.top + boardHeight;
\r
3211 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3212 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3213 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3214 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3215 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3216 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3217 GetWindowRect(hwndMain, &wrect);
\r
3218 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3219 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3220 /* compensate if menu bar wrapped */
\r
3221 GetClientRect(hwndMain, &crect);
\r
3222 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3223 winHeight += offby;
\r
3225 case WMSZ_TOPLEFT:
\r
3226 SetWindowPos(hwndMain, NULL,
\r
3227 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3228 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3231 case WMSZ_TOPRIGHT:
\r
3233 SetWindowPos(hwndMain, NULL,
\r
3234 wrect.left, wrect.bottom - winHeight,
\r
3235 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3238 case WMSZ_BOTTOMLEFT:
\r
3240 SetWindowPos(hwndMain, NULL,
\r
3241 wrect.right - winWidth, wrect.top,
\r
3242 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3245 case WMSZ_BOTTOMRIGHT:
\r
3249 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3250 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3255 for (i = 0; i < N_BUTTONS; i++) {
\r
3256 if (buttonDesc[i].hwnd != NULL) {
\r
3257 DestroyWindow(buttonDesc[i].hwnd);
\r
3258 buttonDesc[i].hwnd = NULL;
\r
3260 if (appData.showButtonBar) {
\r
3261 buttonDesc[i].hwnd =
\r
3262 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3263 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3264 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3265 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3266 (HMENU) buttonDesc[i].id,
\r
3267 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3269 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3270 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3271 MAKELPARAM(FALSE, 0));
\r
3273 if (buttonDesc[i].id == IDM_Pause)
\r
3274 hwndPause = buttonDesc[i].hwnd;
\r
3275 buttonDesc[i].wndproc = (WNDPROC)
\r
3276 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3279 if (gridPen != NULL) DeleteObject(gridPen);
\r
3280 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3281 if (premovePen != NULL) DeleteObject(premovePen);
\r
3282 if (lineGap != 0) {
\r
3283 logbrush.lbStyle = BS_SOLID;
\r
3284 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3286 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3287 lineGap, &logbrush, 0, NULL);
\r
3288 logbrush.lbColor = highlightSquareColor;
\r
3290 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3291 lineGap, &logbrush, 0, NULL);
\r
3293 logbrush.lbColor = premoveHighlightColor;
\r
3295 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3296 lineGap, &logbrush, 0, NULL);
\r
3298 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3299 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3300 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3301 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3302 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3303 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3304 BOARD_WIDTH * (squareSize + lineGap);
\r
3305 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3307 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3308 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3309 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3310 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3311 lineGap / 2 + (i * (squareSize + lineGap));
\r
3312 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3313 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3314 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3318 /* [HGM] Licensing requirement */
\r
3320 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3323 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3325 GothicPopUp( "", VariantNormal);
\r
3328 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3329 oldBoardSize = boardSize;
\r
3330 oldTinyLayout = tinyLayout;
\r
3332 /* Load piece bitmaps for this board size */
\r
3333 for (i=0; i<=2; i++) {
\r
3334 for (piece = WhitePawn;
\r
3335 (int) piece < (int) BlackPawn;
\r
3336 piece = (ChessSquare) ((int) piece + 1)) {
\r
3337 if (pieceBitmap[i][piece] != NULL)
\r
3338 DeleteObject(pieceBitmap[i][piece]);
\r
3342 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3343 // Orthodox Chess pieces
\r
3344 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3345 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3346 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3347 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3348 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3349 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3350 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3351 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3352 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3353 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3354 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3355 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3356 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3357 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3358 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3359 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3360 // in Shogi, Hijack the unused Queen for Lance
\r
3361 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3362 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3363 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3365 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3366 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3367 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3370 if(squareSize <= 72 && squareSize >= 33) {
\r
3371 /* A & C are available in most sizes now */
\r
3372 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3373 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3374 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3375 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3376 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3377 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3378 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3379 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3380 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3381 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3382 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3383 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3384 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3385 } else { // Smirf-like
\r
3386 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3387 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3388 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3390 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3391 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3392 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3393 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3394 } else { // WinBoard standard
\r
3395 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3396 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3397 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3402 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3403 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3404 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3405 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3406 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3407 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3408 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3409 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3410 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3411 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3412 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3413 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3414 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3415 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3416 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3417 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3418 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3419 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3420 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3421 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3422 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3423 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3424 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3425 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3426 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3427 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3428 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3429 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3430 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3431 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3432 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3434 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3435 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3436 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3437 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3438 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3439 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3440 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3441 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3442 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3443 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3444 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3445 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3446 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3448 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3449 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3450 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3451 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3452 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3453 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3454 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3455 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3456 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3457 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3458 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3459 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3462 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3463 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3464 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3465 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3466 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3467 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3468 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3469 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3470 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3471 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3472 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3473 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3474 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3475 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3476 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3480 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3481 /* special Shogi support in this size */
\r
3482 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3483 for (piece = WhitePawn;
\r
3484 (int) piece < (int) BlackPawn;
\r
3485 piece = (ChessSquare) ((int) piece + 1)) {
\r
3486 if (pieceBitmap[i][piece] != NULL)
\r
3487 DeleteObject(pieceBitmap[i][piece]);
\r
3490 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3491 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3492 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3493 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3494 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3495 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3496 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3497 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3498 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3499 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3500 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3501 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3502 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3503 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3504 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3505 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3506 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3507 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3508 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3509 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3510 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3511 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3512 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3513 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3514 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3515 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3516 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3517 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3518 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3519 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3520 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3521 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3522 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3523 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3524 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3525 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3526 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3527 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3528 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3529 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3530 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3531 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3537 PieceBitmap(ChessSquare p, int kind)
\r
3539 if ((int) p >= (int) BlackPawn)
\r
3540 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3542 return pieceBitmap[kind][(int) p];
\r
3545 /***************************************************************/
\r
3547 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3548 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3550 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3551 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3555 SquareToPos(int row, int column, int * x, int * y)
\r
3558 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3559 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3561 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3562 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3567 DrawCoordsOnDC(HDC hdc)
\r
3569 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
3570 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
3571 char str[2] = { NULLCHAR, NULLCHAR };
\r
3572 int oldMode, oldAlign, x, y, start, i;
\r
3576 if (!appData.showCoords)
\r
3579 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3581 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3582 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3583 oldAlign = GetTextAlign(hdc);
\r
3584 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3586 y = boardRect.top + lineGap;
\r
3587 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3589 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3590 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3591 str[0] = files[start + i];
\r
3592 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3593 y += squareSize + lineGap;
\r
3596 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3598 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3599 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3600 str[0] = ranks[start + i];
\r
3601 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3602 x += squareSize + lineGap;
\r
3605 SelectObject(hdc, oldBrush);
\r
3606 SetBkMode(hdc, oldMode);
\r
3607 SetTextAlign(hdc, oldAlign);
\r
3608 SelectObject(hdc, oldFont);
\r
3612 DrawGridOnDC(HDC hdc)
\r
3616 if (lineGap != 0) {
\r
3617 oldPen = SelectObject(hdc, gridPen);
\r
3618 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3619 SelectObject(hdc, oldPen);
\r
3623 #define HIGHLIGHT_PEN 0
\r
3624 #define PREMOVE_PEN 1
\r
3627 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3630 HPEN oldPen, hPen;
\r
3631 if (lineGap == 0) return;
\r
3633 x1 = boardRect.left +
\r
3634 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3635 y1 = boardRect.top +
\r
3636 lineGap/2 + y * (squareSize + lineGap);
\r
3638 x1 = boardRect.left +
\r
3639 lineGap/2 + x * (squareSize + lineGap);
\r
3640 y1 = boardRect.top +
\r
3641 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3643 hPen = pen ? premovePen : highlightPen;
\r
3644 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3645 MoveToEx(hdc, x1, y1, NULL);
\r
3646 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3647 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3648 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3649 LineTo(hdc, x1, y1);
\r
3650 SelectObject(hdc, oldPen);
\r
3654 DrawHighlightsOnDC(HDC hdc)
\r
3657 for (i=0; i<2; i++) {
\r
3658 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3659 DrawHighlightOnDC(hdc, TRUE,
\r
3660 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3663 for (i=0; i<2; i++) {
\r
3664 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3665 premoveHighlightInfo.sq[i].y >= 0) {
\r
3666 DrawHighlightOnDC(hdc, TRUE,
\r
3667 premoveHighlightInfo.sq[i].x,
\r
3668 premoveHighlightInfo.sq[i].y,
\r
3674 /* Note: sqcolor is used only in monoMode */
\r
3675 /* Note that this code is largely duplicated in woptions.c,
\r
3676 function DrawSampleSquare, so that needs to be updated too */
\r
3678 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3680 HBITMAP oldBitmap;
\r
3684 if (appData.blindfold) return;
\r
3686 /* [AS] Use font-based pieces if needed */
\r
3687 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3688 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3689 CreatePiecesFromFont();
\r
3691 if( fontBitmapSquareSize == squareSize ) {
\r
3692 int index = TranslatePieceToFontPiece(piece);
\r
3694 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3698 squareSize, squareSize,
\r
3703 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3707 squareSize, squareSize,
\r
3716 if (appData.monoMode) {
\r
3717 SelectObject(tmphdc, PieceBitmap(piece,
\r
3718 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3719 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3720 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3722 tmpSize = squareSize;
\r
3724 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3725 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3726 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3727 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3728 x += (squareSize - minorSize)>>1;
\r
3729 y += squareSize - minorSize - 2;
\r
3730 tmpSize = minorSize;
\r
3732 if (color || appData.allWhite ) {
\r
3733 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3735 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3736 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3737 if(appData.upsideDown && color==flipView)
\r
3738 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3740 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3742 /* Use black piece color for outline of white pieces */
\r
3743 /* Not sure this looks really good (though xboard does it).
\r
3744 Maybe better to have another selectable color, default black */
\r
3745 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3746 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3747 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3749 /* Use black for outline of white pieces */
\r
3750 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3751 if(appData.upsideDown && color==flipView)
\r
3752 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3754 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3758 /* Use white piece color for details of black pieces */
\r
3759 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3760 WHITE_PIECE ones aren't always the right shape. */
\r
3761 /* Not sure this looks really good (though xboard does it).
\r
3762 Maybe better to have another selectable color, default medium gray? */
\r
3763 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3764 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3765 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3766 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3767 SelectObject(hdc, blackPieceBrush);
\r
3768 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3770 /* Use square color for details of black pieces */
\r
3771 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3772 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3773 if(appData.upsideDown && !flipView)
\r
3774 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3776 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3779 SelectObject(hdc, oldBrush);
\r
3780 SelectObject(tmphdc, oldBitmap);
\r
3784 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3785 int GetBackTextureMode( int algo )
\r
3787 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3791 case BACK_TEXTURE_MODE_PLAIN:
\r
3792 result = 1; /* Always use identity map */
\r
3794 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3795 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3803 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3804 to handle redraws cleanly (as random numbers would always be different).
\r
3806 VOID RebuildTextureSquareInfo()
\r
3816 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3818 if( liteBackTexture != NULL ) {
\r
3819 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3820 lite_w = bi.bmWidth;
\r
3821 lite_h = bi.bmHeight;
\r
3825 if( darkBackTexture != NULL ) {
\r
3826 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3827 dark_w = bi.bmWidth;
\r
3828 dark_h = bi.bmHeight;
\r
3832 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3833 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3834 if( (col + row) & 1 ) {
\r
3836 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3837 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3838 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3839 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3844 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3845 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3846 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3847 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3854 /* [AS] Arrow highlighting support */
\r
3856 static int A_WIDTH = 5; /* Width of arrow body */
\r
3858 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3859 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3861 static double Sqr( double x )
\r
3866 static int Round( double x )
\r
3868 return (int) (x + 0.5);
\r
3871 /* Draw an arrow between two points using current settings */
\r
3872 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3875 double dx, dy, j, k, x, y;
\r
3877 if( d_x == s_x ) {
\r
3878 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3880 arrow[0].x = s_x + A_WIDTH;
\r
3883 arrow[1].x = s_x + A_WIDTH;
\r
3884 arrow[1].y = d_y - h;
\r
3886 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3887 arrow[2].y = d_y - h;
\r
3892 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3893 arrow[4].y = d_y - h;
\r
3895 arrow[5].x = s_x - A_WIDTH;
\r
3896 arrow[5].y = d_y - h;
\r
3898 arrow[6].x = s_x - A_WIDTH;
\r
3901 else if( d_y == s_y ) {
\r
3902 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3905 arrow[0].y = s_y + A_WIDTH;
\r
3907 arrow[1].x = d_x - w;
\r
3908 arrow[1].y = s_y + A_WIDTH;
\r
3910 arrow[2].x = d_x - w;
\r
3911 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3916 arrow[4].x = d_x - w;
\r
3917 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3919 arrow[5].x = d_x - w;
\r
3920 arrow[5].y = s_y - A_WIDTH;
\r
3923 arrow[6].y = s_y - A_WIDTH;
\r
3926 /* [AS] Needed a lot of paper for this! :-) */
\r
3927 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3928 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3930 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3932 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3937 arrow[0].x = Round(x - j);
\r
3938 arrow[0].y = Round(y + j*dx);
\r
3940 arrow[1].x = Round(x + j);
\r
3941 arrow[1].y = Round(y - j*dx);
\r
3944 x = (double) d_x - k;
\r
3945 y = (double) d_y - k*dy;
\r
3948 x = (double) d_x + k;
\r
3949 y = (double) d_y + k*dy;
\r
3952 arrow[2].x = Round(x + j);
\r
3953 arrow[2].y = Round(y - j*dx);
\r
3955 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3956 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3961 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3962 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3964 arrow[6].x = Round(x - j);
\r
3965 arrow[6].y = Round(y + j*dx);
\r
3968 Polygon( hdc, arrow, 7 );
\r
3971 /* [AS] Draw an arrow between two squares */
\r
3972 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3974 int s_x, s_y, d_x, d_y;
\r
3981 if( s_col == d_col && s_row == d_row ) {
\r
3985 /* Get source and destination points */
\r
3986 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3987 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3990 d_y += squareSize / 4;
\r
3992 else if( d_y < s_y ) {
\r
3993 d_y += 3 * squareSize / 4;
\r
3996 d_y += squareSize / 2;
\r
4000 d_x += squareSize / 4;
\r
4002 else if( d_x < s_x ) {
\r
4003 d_x += 3 * squareSize / 4;
\r
4006 d_x += squareSize / 2;
\r
4009 s_x += squareSize / 2;
\r
4010 s_y += squareSize / 2;
\r
4012 /* Adjust width */
\r
4013 A_WIDTH = squareSize / 14;
\r
4016 stLB.lbStyle = BS_SOLID;
\r
4017 stLB.lbColor = appData.highlightArrowColor;
\r
4020 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4021 holdpen = SelectObject( hdc, hpen );
\r
4022 hbrush = CreateBrushIndirect( &stLB );
\r
4023 holdbrush = SelectObject( hdc, hbrush );
\r
4025 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4027 SelectObject( hdc, holdpen );
\r
4028 SelectObject( hdc, holdbrush );
\r
4029 DeleteObject( hpen );
\r
4030 DeleteObject( hbrush );
\r
4033 BOOL HasHighlightInfo()
\r
4035 BOOL result = FALSE;
\r
4037 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4038 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4046 BOOL IsDrawArrowEnabled()
\r
4048 BOOL result = FALSE;
\r
4050 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4057 VOID DrawArrowHighlight( HDC hdc )
\r
4059 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4060 DrawArrowBetweenSquares( hdc,
\r
4061 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4062 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4066 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4068 HRGN result = NULL;
\r
4070 if( HasHighlightInfo() ) {
\r
4071 int x1, y1, x2, y2;
\r
4072 int sx, sy, dx, dy;
\r
4074 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4075 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4077 sx = MIN( x1, x2 );
\r
4078 sy = MIN( y1, y2 );
\r
4079 dx = MAX( x1, x2 ) + squareSize;
\r
4080 dy = MAX( y1, y2 ) + squareSize;
\r
4082 result = CreateRectRgn( sx, sy, dx, dy );
\r
4089 Warning: this function modifies the behavior of several other functions.
\r
4091 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4092 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4093 repaint is scattered all over the place, which is not good for features such as
\r
4094 "arrow highlighting" that require a full repaint of the board.
\r
4096 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4097 user interaction, when speed is not so important) but especially to avoid errors
\r
4098 in the displayed graphics.
\r
4100 In such patched places, I always try refer to this function so there is a single
\r
4101 place to maintain knowledge.
\r
4103 To restore the original behavior, just return FALSE unconditionally.
\r
4105 BOOL IsFullRepaintPreferrable()
\r
4107 BOOL result = FALSE;
\r
4109 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4110 /* Arrow may appear on the board */
\r
4118 This function is called by DrawPosition to know whether a full repaint must
\r
4121 Only DrawPosition may directly call this function, which makes use of
\r
4122 some state information. Other function should call DrawPosition specifying
\r
4123 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4125 BOOL DrawPositionNeedsFullRepaint()
\r
4127 BOOL result = FALSE;
\r
4130 Probably a slightly better policy would be to trigger a full repaint
\r
4131 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4132 but animation is fast enough that it's difficult to notice.
\r
4134 if( animInfo.piece == EmptySquare ) {
\r
4135 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4144 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4146 int row, column, x, y, square_color, piece_color;
\r
4147 ChessSquare piece;
\r
4149 HDC texture_hdc = NULL;
\r
4151 /* [AS] Initialize background textures if needed */
\r
4152 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4153 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4154 if( backTextureSquareSize != squareSize
\r
4155 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4156 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4157 backTextureSquareSize = squareSize;
\r
4158 RebuildTextureSquareInfo();
\r
4161 texture_hdc = CreateCompatibleDC( hdc );
\r
4164 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4165 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4167 SquareToPos(row, column, &x, &y);
\r
4169 piece = board[row][column];
\r
4171 square_color = ((column + row) % 2) == 1;
\r
4172 if( gameInfo.variant == VariantXiangqi ) {
\r
4173 square_color = !InPalace(row, column);
\r
4174 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4175 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4177 piece_color = (int) piece < (int) BlackPawn;
\r
4180 /* [HGM] holdings file: light square or black */
\r
4181 if(column == BOARD_LEFT-2) {
\r
4182 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4185 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4189 if(column == BOARD_RGHT + 1 ) {
\r
4190 if( row < gameInfo.holdingsSize )
\r
4193 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4197 if(column == BOARD_LEFT-1 ) /* left align */
\r
4198 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4199 else if( column == BOARD_RGHT) /* right align */
\r
4200 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4202 if (appData.monoMode) {
\r
4203 if (piece == EmptySquare) {
\r
4204 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4205 square_color ? WHITENESS : BLACKNESS);
\r
4207 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4210 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4211 /* [AS] Draw the square using a texture bitmap */
\r
4212 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4213 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4214 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4217 squareSize, squareSize,
\r
4220 backTextureSquareInfo[r][c].mode,
\r
4221 backTextureSquareInfo[r][c].x,
\r
4222 backTextureSquareInfo[r][c].y );
\r
4224 SelectObject( texture_hdc, hbm );
\r
4226 if (piece != EmptySquare) {
\r
4227 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4231 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4233 oldBrush = SelectObject(hdc, brush );
\r
4234 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4235 SelectObject(hdc, oldBrush);
\r
4236 if (piece != EmptySquare)
\r
4237 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4242 if( texture_hdc != NULL ) {
\r
4243 DeleteDC( texture_hdc );
\r
4247 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4248 void fputDW(FILE *f, int x)
\r
4250 fputc(x & 255, f);
\r
4251 fputc(x>>8 & 255, f);
\r
4252 fputc(x>>16 & 255, f);
\r
4253 fputc(x>>24 & 255, f);
\r
4256 #define MAX_CLIPS 200 /* more than enough */
\r
4259 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4261 // HBITMAP bufferBitmap;
\r
4266 int w = 100, h = 50;
\r
4268 if(logo == NULL) return;
\r
4269 // GetClientRect(hwndMain, &Rect);
\r
4270 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4271 // Rect.bottom-Rect.top+1);
\r
4272 tmphdc = CreateCompatibleDC(hdc);
\r
4273 hbm = SelectObject(tmphdc, logo);
\r
4274 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4278 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4279 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4280 SelectObject(tmphdc, hbm);
\r
4285 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4287 static Board lastReq, lastDrawn;
\r
4288 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4289 static int lastDrawnFlipView = 0;
\r
4290 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4291 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4294 HBITMAP bufferBitmap;
\r
4295 HBITMAP oldBitmap;
\r
4297 HRGN clips[MAX_CLIPS];
\r
4298 ChessSquare dragged_piece = EmptySquare;
\r
4300 /* I'm undecided on this - this function figures out whether a full
\r
4301 * repaint is necessary on its own, so there's no real reason to have the
\r
4302 * caller tell it that. I think this can safely be set to FALSE - but
\r
4303 * if we trust the callers not to request full repaints unnessesarily, then
\r
4304 * we could skip some clipping work. In other words, only request a full
\r
4305 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4306 * gamestart and similar) --Hawk
\r
4308 Boolean fullrepaint = repaint;
\r
4310 if( DrawPositionNeedsFullRepaint() ) {
\r
4311 fullrepaint = TRUE;
\r
4315 if( fullrepaint ) {
\r
4316 static int repaint_count = 0;
\r
4320 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4321 OutputDebugString( buf );
\r
4325 if (board == NULL) {
\r
4326 if (!lastReqValid) {
\r
4331 CopyBoard(lastReq, board);
\r
4335 if (doingSizing) {
\r
4339 if (IsIconic(hwndMain)) {
\r
4343 if (hdc == NULL) {
\r
4344 hdc = GetDC(hwndMain);
\r
4345 if (!appData.monoMode) {
\r
4346 SelectPalette(hdc, hPal, FALSE);
\r
4347 RealizePalette(hdc);
\r
4351 releaseDC = FALSE;
\r
4355 fprintf(debugFP, "*******************************\n"
\r
4357 "dragInfo.from (%d,%d)\n"
\r
4358 "dragInfo.start (%d,%d)\n"
\r
4359 "dragInfo.pos (%d,%d)\n"
\r
4360 "dragInfo.lastpos (%d,%d)\n",
\r
4361 repaint ? "TRUE" : "FALSE",
\r
4362 dragInfo.from.x, dragInfo.from.y,
\r
4363 dragInfo.start.x, dragInfo.start.y,
\r
4364 dragInfo.pos.x, dragInfo.pos.y,
\r
4365 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4366 fprintf(debugFP, "prev: ");
\r
4367 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4368 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4369 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4372 fprintf(debugFP, "\n");
\r
4373 fprintf(debugFP, "board: ");
\r
4374 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4375 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4376 fprintf(debugFP, "%d ", board[row][column]);
\r
4379 fprintf(debugFP, "\n");
\r
4383 /* Create some work-DCs */
\r
4384 hdcmem = CreateCompatibleDC(hdc);
\r
4385 tmphdc = CreateCompatibleDC(hdc);
\r
4387 /* If dragging is in progress, we temporarely remove the piece */
\r
4388 /* [HGM] or temporarily decrease count if stacked */
\r
4389 /* !! Moved to before board compare !! */
\r
4390 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4391 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4392 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4393 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4394 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4396 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4397 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4398 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4400 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4403 /* Figure out which squares need updating by comparing the
\r
4404 * newest board with the last drawn board and checking if
\r
4405 * flipping has changed.
\r
4407 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4408 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4409 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4410 if (lastDrawn[row][column] != board[row][column]) {
\r
4411 SquareToPos(row, column, &x, &y);
\r
4412 clips[num_clips++] =
\r
4413 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4417 for (i=0; i<2; i++) {
\r
4418 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4419 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4420 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4421 lastDrawnHighlight.sq[i].y >= 0) {
\r
4422 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4423 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4424 clips[num_clips++] =
\r
4425 CreateRectRgn(x - lineGap, y - lineGap,
\r
4426 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4428 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4429 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4430 clips[num_clips++] =
\r
4431 CreateRectRgn(x - lineGap, y - lineGap,
\r
4432 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4436 for (i=0; i<2; i++) {
\r
4437 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4438 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4439 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4440 lastDrawnPremove.sq[i].y >= 0) {
\r
4441 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4442 lastDrawnPremove.sq[i].x, &x, &y);
\r
4443 clips[num_clips++] =
\r
4444 CreateRectRgn(x - lineGap, y - lineGap,
\r
4445 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4447 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4448 premoveHighlightInfo.sq[i].y >= 0) {
\r
4449 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4450 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4451 clips[num_clips++] =
\r
4452 CreateRectRgn(x - lineGap, y - lineGap,
\r
4453 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4458 fullrepaint = TRUE;
\r
4461 /* Create a buffer bitmap - this is the actual bitmap
\r
4462 * being written to. When all the work is done, we can
\r
4463 * copy it to the real DC (the screen). This avoids
\r
4464 * the problems with flickering.
\r
4466 GetClientRect(hwndMain, &Rect);
\r
4467 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4468 Rect.bottom-Rect.top+1);
\r
4469 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4470 if (!appData.monoMode) {
\r
4471 SelectPalette(hdcmem, hPal, FALSE);
\r
4474 /* Create clips for dragging */
\r
4475 if (!fullrepaint) {
\r
4476 if (dragInfo.from.x >= 0) {
\r
4477 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4478 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4480 if (dragInfo.start.x >= 0) {
\r
4481 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4482 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4484 if (dragInfo.pos.x >= 0) {
\r
4485 x = dragInfo.pos.x - squareSize / 2;
\r
4486 y = dragInfo.pos.y - squareSize / 2;
\r
4487 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4489 if (dragInfo.lastpos.x >= 0) {
\r
4490 x = dragInfo.lastpos.x - squareSize / 2;
\r
4491 y = dragInfo.lastpos.y - squareSize / 2;
\r
4492 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4496 /* Are we animating a move?
\r
4498 * - remove the piece from the board (temporarely)
\r
4499 * - calculate the clipping region
\r
4501 if (!fullrepaint) {
\r
4502 if (animInfo.piece != EmptySquare) {
\r
4503 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4504 x = boardRect.left + animInfo.lastpos.x;
\r
4505 y = boardRect.top + animInfo.lastpos.y;
\r
4506 x2 = boardRect.left + animInfo.pos.x;
\r
4507 y2 = boardRect.top + animInfo.pos.y;
\r
4508 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4509 /* Slight kludge. The real problem is that after AnimateMove is
\r
4510 done, the position on the screen does not match lastDrawn.
\r
4511 This currently causes trouble only on e.p. captures in
\r
4512 atomic, where the piece moves to an empty square and then
\r
4513 explodes. The old and new positions both had an empty square
\r
4514 at the destination, but animation has drawn a piece there and
\r
4515 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4516 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4520 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4521 if (num_clips == 0)
\r
4522 fullrepaint = TRUE;
\r
4524 /* Set clipping on the memory DC */
\r
4525 if (!fullrepaint) {
\r
4526 SelectClipRgn(hdcmem, clips[0]);
\r
4527 for (x = 1; x < num_clips; x++) {
\r
4528 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4529 abort(); // this should never ever happen!
\r
4533 /* Do all the drawing to the memory DC */
\r
4534 if(explodeInfo.radius) { // [HGM] atomic
\r
4536 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4537 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4538 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4539 x += squareSize/2;
\r
4540 y += squareSize/2;
\r
4541 if(!fullrepaint) {
\r
4542 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4543 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4545 DrawGridOnDC(hdcmem);
\r
4546 DrawHighlightsOnDC(hdcmem);
\r
4547 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4548 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4549 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4550 SelectObject(hdcmem, oldBrush);
\r
4552 DrawGridOnDC(hdcmem);
\r
4553 DrawHighlightsOnDC(hdcmem);
\r
4554 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4557 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4558 if(appData.autoLogo) {
\r
4560 switch(gameMode) { // pick logos based on game mode
\r
4561 case IcsObserving:
\r
4562 whiteLogo = second.programLogo; // ICS logo
\r
4563 blackLogo = second.programLogo;
\r
4566 case IcsPlayingWhite:
\r
4567 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4568 blackLogo = second.programLogo; // ICS logo
\r
4570 case IcsPlayingBlack:
\r
4571 whiteLogo = second.programLogo; // ICS logo
\r
4572 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4574 case TwoMachinesPlay:
\r
4575 if(first.twoMachinesColor[0] == 'b') {
\r
4576 whiteLogo = second.programLogo;
\r
4577 blackLogo = first.programLogo;
\r
4580 case MachinePlaysWhite:
\r
4581 blackLogo = userLogo;
\r
4583 case MachinePlaysBlack:
\r
4584 whiteLogo = userLogo;
\r
4585 blackLogo = first.programLogo;
\r
4588 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4589 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4592 if( appData.highlightMoveWithArrow ) {
\r
4593 DrawArrowHighlight(hdcmem);
\r
4596 DrawCoordsOnDC(hdcmem);
\r
4598 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4599 /* to make sure lastDrawn contains what is actually drawn */
\r
4601 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4602 if (dragged_piece != EmptySquare) {
\r
4603 /* [HGM] or restack */
\r
4604 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4605 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4607 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4608 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4609 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4610 x = dragInfo.pos.x - squareSize / 2;
\r
4611 y = dragInfo.pos.y - squareSize / 2;
\r
4612 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4613 ((int) dragged_piece < (int) BlackPawn),
\r
4614 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4617 /* Put the animated piece back into place and draw it */
\r
4618 if (animInfo.piece != EmptySquare) {
\r
4619 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4620 x = boardRect.left + animInfo.pos.x;
\r
4621 y = boardRect.top + animInfo.pos.y;
\r
4622 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4623 ((int) animInfo.piece < (int) BlackPawn),
\r
4624 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4627 /* Release the bufferBitmap by selecting in the old bitmap
\r
4628 * and delete the memory DC
\r
4630 SelectObject(hdcmem, oldBitmap);
\r
4633 /* Set clipping on the target DC */
\r
4634 if (!fullrepaint) {
\r
4635 SelectClipRgn(hdc, clips[0]);
\r
4636 for (x = 1; x < num_clips; x++) {
\r
4637 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4638 abort(); // this should never ever happen!
\r
4642 /* Copy the new bitmap onto the screen in one go.
\r
4643 * This way we avoid any flickering
\r
4645 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4646 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4647 boardRect.right - boardRect.left,
\r
4648 boardRect.bottom - boardRect.top,
\r
4649 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4650 if(saveDiagFlag) {
\r
4651 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4652 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4654 GetObject(bufferBitmap, sizeof(b), &b);
\r
4655 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4656 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4657 bih.biWidth = b.bmWidth;
\r
4658 bih.biHeight = b.bmHeight;
\r
4660 bih.biBitCount = b.bmBitsPixel;
\r
4661 bih.biCompression = 0;
\r
4662 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4663 bih.biXPelsPerMeter = 0;
\r
4664 bih.biYPelsPerMeter = 0;
\r
4665 bih.biClrUsed = 0;
\r
4666 bih.biClrImportant = 0;
\r
4667 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4668 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4669 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4670 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4673 wb = b.bmWidthBytes;
\r
4675 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4676 int k = ((int*) pData)[i];
\r
4677 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4678 if(j >= 16) break;
\r
4680 if(j >= nrColors) nrColors = j+1;
\r
4682 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4684 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4685 for(w=0; w<(wb>>2); w+=2) {
\r
4686 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4687 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4688 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4689 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4690 pData[p++] = m | j<<4;
\r
4692 while(p&3) pData[p++] = 0;
\r
4695 wb = ((wb+31)>>5)<<2;
\r
4697 // write BITMAPFILEHEADER
\r
4698 fprintf(diagFile, "BM");
\r
4699 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4700 fputDW(diagFile, 0);
\r
4701 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4702 // write BITMAPINFOHEADER
\r
4703 fputDW(diagFile, 40);
\r
4704 fputDW(diagFile, b.bmWidth);
\r
4705 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4706 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4707 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4708 fputDW(diagFile, 0);
\r
4709 fputDW(diagFile, 0);
\r
4710 fputDW(diagFile, 0);
\r
4711 fputDW(diagFile, 0);
\r
4712 fputDW(diagFile, 0);
\r
4713 fputDW(diagFile, 0);
\r
4714 // write color table
\r
4716 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4717 // write bitmap data
\r
4718 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4719 fputc(pData[i], diagFile);
\r
4724 SelectObject(tmphdc, oldBitmap);
\r
4726 /* Massive cleanup */
\r
4727 for (x = 0; x < num_clips; x++)
\r
4728 DeleteObject(clips[x]);
\r
4731 DeleteObject(bufferBitmap);
\r
4734 ReleaseDC(hwndMain, hdc);
\r
4736 if (lastDrawnFlipView != flipView) {
\r
4738 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4740 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4743 /* CopyBoard(lastDrawn, board);*/
\r
4744 lastDrawnHighlight = highlightInfo;
\r
4745 lastDrawnPremove = premoveHighlightInfo;
\r
4746 lastDrawnFlipView = flipView;
\r
4747 lastDrawnValid = 1;
\r
4750 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4755 saveDiagFlag = 1; diagFile = f;
\r
4756 HDCDrawPosition(NULL, TRUE, NULL);
\r
4760 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4767 /*---------------------------------------------------------------------------*\
\r
4768 | CLIENT PAINT PROCEDURE
\r
4769 | This is the main event-handler for the WM_PAINT message.
\r
4771 \*---------------------------------------------------------------------------*/
\r
4773 PaintProc(HWND hwnd)
\r
4779 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4780 if (IsIconic(hwnd)) {
\r
4781 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4783 if (!appData.monoMode) {
\r
4784 SelectPalette(hdc, hPal, FALSE);
\r
4785 RealizePalette(hdc);
\r
4787 HDCDrawPosition(hdc, 1, NULL);
\r
4789 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4790 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4791 ETO_CLIPPED|ETO_OPAQUE,
\r
4792 &messageRect, messageText, strlen(messageText), NULL);
\r
4793 SelectObject(hdc, oldFont);
\r
4794 DisplayBothClocks();
\r
4796 EndPaint(hwnd,&ps);
\r
4804 * If the user selects on a border boundary, return -1; if off the board,
\r
4805 * return -2. Otherwise map the event coordinate to the square.
\r
4806 * The offset boardRect.left or boardRect.top must already have been
\r
4807 * subtracted from x.
\r
4810 EventToSquare(int x)
\r
4817 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4819 x /= (squareSize + lineGap);
\r
4820 if (x >= BOARD_SIZE)
\r
4831 DropEnable dropEnables[] = {
\r
4832 { 'P', DP_Pawn, "Pawn" },
\r
4833 { 'N', DP_Knight, "Knight" },
\r
4834 { 'B', DP_Bishop, "Bishop" },
\r
4835 { 'R', DP_Rook, "Rook" },
\r
4836 { 'Q', DP_Queen, "Queen" },
\r
4840 SetupDropMenu(HMENU hmenu)
\r
4842 int i, count, enable;
\r
4844 extern char white_holding[], black_holding[];
\r
4845 char item[MSG_SIZ];
\r
4847 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4848 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4849 dropEnables[i].piece);
\r
4851 while (p && *p++ == dropEnables[i].piece) count++;
\r
4852 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4853 enable = count > 0 || !appData.testLegality
\r
4854 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4855 && !appData.icsActive);
\r
4856 ModifyMenu(hmenu, dropEnables[i].command,
\r
4857 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4858 dropEnables[i].command, item);
\r
4862 static int fromX = -1, fromY = -1, toX, toY;
\r
4864 /* Event handler for mouse messages */
\r
4866 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4870 static int recursive = 0;
\r
4872 // BOOLEAN needsRedraw = FALSE;
\r
4873 BOOLEAN saveAnimate;
\r
4874 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4875 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4876 ChessMove moveType;
\r
4879 if (message == WM_MBUTTONUP) {
\r
4880 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4881 to the middle button: we simulate pressing the left button too!
\r
4883 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4884 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4890 pt.x = LOWORD(lParam);
\r
4891 pt.y = HIWORD(lParam);
\r
4892 x = EventToSquare(pt.x - boardRect.left);
\r
4893 y = EventToSquare(pt.y - boardRect.top);
\r
4894 if (!flipView && y >= 0) {
\r
4895 y = BOARD_HEIGHT - 1 - y;
\r
4897 if (flipView && x >= 0) {
\r
4898 x = BOARD_WIDTH - 1 - x;
\r
4901 switch (message) {
\r
4902 case WM_LBUTTONDOWN:
\r
4903 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4904 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4905 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4906 if(gameInfo.holdingsWidth &&
\r
4907 (WhiteOnMove(currentMove)
\r
4908 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4909 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4910 // click in right holdings, for determining promotion piece
\r
4911 ChessSquare p = boards[currentMove][y][x];
\r
4912 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4913 if(p != EmptySquare) {
\r
4914 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4915 fromX = fromY = -1;
\r
4919 DrawPosition(FALSE, boards[currentMove]);
\r
4923 sameAgain = FALSE;
\r
4925 /* Downclick vertically off board; check if on clock */
\r
4926 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4927 if (gameMode == EditPosition) {
\r
4928 SetWhiteToPlayEvent();
\r
4929 } else if (gameMode == IcsPlayingBlack ||
\r
4930 gameMode == MachinePlaysWhite) {
\r
4932 } else if (gameMode == EditGame) {
\r
4933 AdjustClock(flipClock, -1);
\r
4935 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4936 if (gameMode == EditPosition) {
\r
4937 SetBlackToPlayEvent();
\r
4938 } else if (gameMode == IcsPlayingWhite ||
\r
4939 gameMode == MachinePlaysBlack) {
\r
4941 } else if (gameMode == EditGame) {
\r
4942 AdjustClock(!flipClock, -1);
\r
4945 if (!appData.highlightLastMove) {
\r
4946 ClearHighlights();
\r
4947 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4949 fromX = fromY = -1;
\r
4950 dragInfo.start.x = dragInfo.start.y = -1;
\r
4951 dragInfo.from = dragInfo.start;
\r
4953 } else if (x < 0 || y < 0
\r
4954 /* [HGM] block clicks between board and holdings */
\r
4955 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4956 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4957 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4958 /* EditPosition, empty square, or different color piece;
\r
4959 click-click move is possible */
\r
4962 } else if (fromX == x && fromY == y) {
\r
4963 /* Downclick on same square again */
\r
4964 ClearHighlights();
\r
4965 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4966 sameAgain = TRUE;
\r
4967 } else if (fromX != -1 &&
\r
4968 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4970 /* Downclick on different square. */
\r
4971 /* [HGM] if on holdings file, should count as new first click ! */
\r
4972 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4975 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4976 to make sure move is legal before showing promotion popup */
\r
4977 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4978 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4979 fromX = fromY = -1;
\r
4980 ClearHighlights();
\r
4981 DrawPosition(FALSE, boards[currentMove]);
\r
4984 if(moveType != ImpossibleMove) {
\r
4985 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4986 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4987 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4988 appData.alwaysPromoteToQueen)) {
\r
4989 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4990 if (!appData.highlightLastMove) {
\r
4991 ClearHighlights();
\r
4992 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4995 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4996 SetHighlights(fromX, fromY, toX, toY);
\r
4997 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4998 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4999 If promotion to Q is legal, all are legal! */
\r
5000 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5001 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5002 // kludge to temporarily execute move on display, wthout promotng yet
\r
5003 promotionChoice = TRUE;
\r
5004 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5005 boards[currentMove][toY][toX] = p;
\r
5006 DrawPosition(FALSE, boards[currentMove]);
\r
5007 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5008 boards[currentMove][toY][toX] = q;
\r
5010 PromotionPopup(hwnd);
\r
5011 } else { /* not a promotion */
\r
5012 if (appData.animate || appData.highlightLastMove) {
\r
5013 SetHighlights(fromX, fromY, toX, toY);
\r
5015 ClearHighlights();
\r
5017 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5018 fromX = fromY = -1;
\r
5019 if (appData.animate && !appData.highlightLastMove) {
\r
5020 ClearHighlights();
\r
5021 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5027 /* [HGM] it seemed that braces were missing here */
\r
5028 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5029 fromX = fromY = -1;
\r
5033 ClearHighlights();
\r
5034 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5036 /* First downclick, or restart on a square with same color piece */
\r
5037 if (!frozen && OKToStartUserMove(x, y)) {
\r
5040 dragInfo.lastpos = pt;
\r
5041 dragInfo.from.x = fromX;
\r
5042 dragInfo.from.y = fromY;
\r
5043 dragInfo.start = dragInfo.from;
\r
5044 SetCapture(hwndMain);
\r
5046 fromX = fromY = -1;
\r
5047 dragInfo.start.x = dragInfo.start.y = -1;
\r
5048 dragInfo.from = dragInfo.start;
\r
5049 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5053 case WM_LBUTTONUP:
\r
5055 if (fromX == -1) break;
\r
5056 if (x == fromX && y == fromY) {
\r
5057 dragInfo.from.x = dragInfo.from.y = -1;
\r
5058 /* Upclick on same square */
\r
5060 /* Clicked same square twice: abort click-click move */
\r
5061 fromX = fromY = -1;
\r
5063 ClearPremoveHighlights();
\r
5065 /* First square clicked: start click-click move */
\r
5066 SetHighlights(fromX, fromY, -1, -1);
\r
5068 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5069 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5070 /* Errant click; ignore */
\r
5073 /* Finish drag move. */
\r
5074 if (appData.debugMode) {
\r
5075 fprintf(debugFP, "release\n");
\r
5077 dragInfo.from.x = dragInfo.from.y = -1;
\r
5080 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5081 appData.animate = appData.animate && !appData.animateDragging;
\r
5082 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5083 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5084 fromX = fromY = -1;
\r
5085 ClearHighlights();
\r
5086 DrawPosition(FALSE, boards[currentMove]);
\r
5089 if(moveType != ImpossibleMove) {
\r
5090 /* [HGM] use move type to determine if move is promotion.
\r
5091 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5092 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5093 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5094 appData.alwaysPromoteToQueen))
\r
5095 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5097 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5098 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5099 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5100 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5101 // kludge to temporarily execute move on display, wthout promotng yet
\r
5102 promotionChoice = TRUE;
\r
5103 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5104 boards[currentMove][toY][toX] = p;
\r
5105 DrawPosition(FALSE, boards[currentMove]);
\r
5106 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5107 boards[currentMove][toY][toX] = q;
\r
5110 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5112 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5113 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5114 moveType == WhiteCapturesEnPassant ||
\r
5115 moveType == BlackCapturesEnPassant ) )
\r
5116 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5117 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5120 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5121 appData.animate = saveAnimate;
\r
5122 fromX = fromY = -1;
\r
5123 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5124 ClearHighlights();
\r
5126 if (appData.animate || appData.animateDragging ||
\r
5127 appData.highlightDragging || gotPremove) {
\r
5128 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5131 dragInfo.start.x = dragInfo.start.y = -1;
\r
5132 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5135 case WM_MOUSEMOVE:
\r
5136 if ((appData.animateDragging || appData.highlightDragging)
\r
5137 && (wParam & MK_LBUTTON)
\r
5138 && dragInfo.from.x >= 0)
\r
5140 BOOL full_repaint = FALSE;
\r
5142 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5143 if (appData.animateDragging) {
\r
5144 dragInfo.pos = pt;
\r
5146 if (appData.highlightDragging) {
\r
5147 SetHighlights(fromX, fromY, x, y);
\r
5148 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5149 full_repaint = TRUE;
\r
5153 DrawPosition( full_repaint, NULL);
\r
5155 dragInfo.lastpos = dragInfo.pos;
\r
5159 case WM_MOUSEWHEEL: // [DM]
\r
5160 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5161 /* Mouse Wheel is being rolled forward
\r
5162 * Play moves forward
\r
5164 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5165 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5166 /* Mouse Wheel is being rolled backward
\r
5167 * Play moves backward
\r
5169 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5170 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5174 case WM_MBUTTONDOWN:
\r
5175 case WM_RBUTTONDOWN:
\r
5178 fromX = fromY = -1;
\r
5179 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5180 dragInfo.start.x = dragInfo.start.y = -1;
\r
5181 dragInfo.from = dragInfo.start;
\r
5182 dragInfo.lastpos = dragInfo.pos;
\r
5183 if (appData.highlightDragging) {
\r
5184 ClearHighlights();
\r
5187 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5188 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5189 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5190 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5191 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5194 DrawPosition(TRUE, NULL);
\r
5196 switch (gameMode) {
\r
5197 case EditPosition:
\r
5198 case IcsExamining:
\r
5199 if (x < 0 || y < 0) break;
\r
5202 if (message == WM_MBUTTONDOWN) {
\r
5203 buttonCount = 3; /* even if system didn't think so */
\r
5204 if (wParam & MK_SHIFT)
\r
5205 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5207 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5208 } else { /* message == WM_RBUTTONDOWN */
\r
5210 if (buttonCount == 3) {
\r
5211 if (wParam & MK_SHIFT)
\r
5212 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5214 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5216 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5219 /* Just have one menu, on the right button. Windows users don't
\r
5220 think to try the middle one, and sometimes other software steals
\r
5221 it, or it doesn't really exist. */
\r
5222 if(gameInfo.variant != VariantShogi)
\r
5223 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5225 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5229 case IcsPlayingWhite:
\r
5230 case IcsPlayingBlack:
\r
5232 case MachinePlaysWhite:
\r
5233 case MachinePlaysBlack:
\r
5234 if (appData.testLegality &&
\r
5235 gameInfo.variant != VariantBughouse &&
\r
5236 gameInfo.variant != VariantCrazyhouse) break;
\r
5237 if (x < 0 || y < 0) break;
\r
5240 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5241 SetupDropMenu(hmenu);
\r
5242 MenuPopup(hwnd, pt, hmenu, -1);
\r
5253 /* Preprocess messages for buttons in main window */
\r
5255 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5257 int id = GetWindowLong(hwnd, GWL_ID);
\r
5260 for (i=0; i<N_BUTTONS; i++) {
\r
5261 if (buttonDesc[i].id == id) break;
\r
5263 if (i == N_BUTTONS) return 0;
\r
5264 switch (message) {
\r
5269 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5270 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5277 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5280 if (appData.icsActive) {
\r
5281 if (GetKeyState(VK_SHIFT) < 0) {
\r
5283 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5284 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5288 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5289 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5296 if (appData.icsActive) {
\r
5297 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5298 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5300 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5302 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5303 PopUpMoveDialog((char)wParam);
\r
5309 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5312 /* Process messages for Promotion dialog box */
\r
5314 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5318 switch (message) {
\r
5319 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5320 /* Center the dialog over the application window */
\r
5321 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5322 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5323 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5324 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5325 SW_SHOW : SW_HIDE);
\r
5326 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5327 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5328 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5329 PieceToChar(WhiteAngel) != '~') ||
\r
5330 (PieceToChar(BlackAngel) >= 'A' &&
\r
5331 PieceToChar(BlackAngel) != '~') ) ?
\r
5332 SW_SHOW : SW_HIDE);
\r
5333 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5334 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5335 PieceToChar(WhiteMarshall) != '~') ||
\r
5336 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5337 PieceToChar(BlackMarshall) != '~') ) ?
\r
5338 SW_SHOW : SW_HIDE);
\r
5339 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5340 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5341 gameInfo.variant != VariantShogi ?
\r
5342 SW_SHOW : SW_HIDE);
\r
5343 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5344 gameInfo.variant != VariantShogi ?
\r
5345 SW_SHOW : SW_HIDE);
\r
5346 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5347 gameInfo.variant == VariantShogi ?
\r
5348 SW_SHOW : SW_HIDE);
\r
5349 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5350 gameInfo.variant == VariantShogi ?
\r
5351 SW_SHOW : SW_HIDE);
\r
5352 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5353 gameInfo.variant == VariantSuper ?
\r
5354 SW_SHOW : SW_HIDE);
\r
5357 case WM_COMMAND: /* message: received a command */
\r
5358 switch (LOWORD(wParam)) {
\r
5360 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5361 ClearHighlights();
\r
5362 DrawPosition(FALSE, NULL);
\r
5365 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5368 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5371 promoChar = PieceToChar(BlackRook);
\r
5374 promoChar = PieceToChar(BlackBishop);
\r
5376 case PB_Chancellor:
\r
5377 promoChar = PieceToChar(BlackMarshall);
\r
5379 case PB_Archbishop:
\r
5380 promoChar = PieceToChar(BlackAngel);
\r
5383 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5388 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5389 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5390 only show the popup when we are already sure the move is valid or
\r
5391 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5392 will figure out it is a promotion from the promoChar. */
\r
5393 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5394 if (!appData.highlightLastMove) {
\r
5395 ClearHighlights();
\r
5396 DrawPosition(FALSE, NULL);
\r
5403 /* Pop up promotion dialog */
\r
5405 PromotionPopup(HWND hwnd)
\r
5409 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5410 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5411 hwnd, (DLGPROC)lpProc);
\r
5412 FreeProcInstance(lpProc);
\r
5415 /* Toggle ShowThinking */
\r
5417 ToggleShowThinking()
\r
5419 appData.showThinking = !appData.showThinking;
\r
5420 ShowThinkingEvent();
\r
5424 LoadGameDialog(HWND hwnd, char* title)
\r
5428 char fileTitle[MSG_SIZ];
\r
5429 f = OpenFileDialog(hwnd, "rb", "",
\r
5430 appData.oldSaveStyle ? "gam" : "pgn",
\r
5432 title, &number, fileTitle, NULL);
\r
5434 cmailMsgLoaded = FALSE;
\r
5435 if (number == 0) {
\r
5436 int error = GameListBuild(f);
\r
5438 DisplayError("Cannot build game list", error);
\r
5439 } else if (!ListEmpty(&gameList) &&
\r
5440 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5441 GameListPopUp(f, fileTitle);
\r
5444 GameListDestroy();
\r
5447 LoadGame(f, number, fileTitle, FALSE);
\r
5452 ChangedConsoleFont()
\r
5455 CHARRANGE tmpsel, sel;
\r
5456 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5457 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5458 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5461 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5462 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5463 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5464 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5465 * size. This was undocumented in the version of MSVC++ that I had
\r
5466 * when I wrote the code, but is apparently documented now.
\r
5468 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5469 cfmt.bCharSet = f->lf.lfCharSet;
\r
5470 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5471 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5472 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5473 /* Why are the following seemingly needed too? */
\r
5474 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5475 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5476 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5478 tmpsel.cpMax = -1; /*999999?*/
\r
5479 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5480 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5481 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5482 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5484 paraf.cbSize = sizeof(paraf);
\r
5485 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5486 paraf.dxStartIndent = 0;
\r
5487 paraf.dxOffset = WRAP_INDENT;
\r
5488 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5489 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5492 /*---------------------------------------------------------------------------*\
\r
5494 * Window Proc for main window
\r
5496 \*---------------------------------------------------------------------------*/
\r
5498 /* Process messages for main window, etc. */
\r
5500 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5503 int wmId, wmEvent;
\r
5507 char fileTitle[MSG_SIZ];
\r
5508 char buf[MSG_SIZ];
\r
5509 static SnapData sd;
\r
5511 switch (message) {
\r
5513 case WM_PAINT: /* message: repaint portion of window */
\r
5517 case WM_ERASEBKGND:
\r
5518 if (IsIconic(hwnd)) {
\r
5519 /* Cheat; change the message */
\r
5520 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5522 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5526 case WM_LBUTTONDOWN:
\r
5527 case WM_MBUTTONDOWN:
\r
5528 case WM_RBUTTONDOWN:
\r
5529 case WM_LBUTTONUP:
\r
5530 case WM_MBUTTONUP:
\r
5531 case WM_RBUTTONUP:
\r
5532 case WM_MOUSEMOVE:
\r
5533 case WM_MOUSEWHEEL:
\r
5534 MouseEvent(hwnd, message, wParam, lParam);
\r
5539 if (appData.icsActive) {
\r
5540 if (wParam == '\t') {
\r
5541 if (GetKeyState(VK_SHIFT) < 0) {
\r
5543 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5544 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5548 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5549 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5553 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5554 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5556 SendMessage(h, message, wParam, lParam);
\r
5558 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5559 PopUpMoveDialog((char)wParam);
\r
5563 case WM_PALETTECHANGED:
\r
5564 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5566 HDC hdc = GetDC(hwndMain);
\r
5567 SelectPalette(hdc, hPal, TRUE);
\r
5568 nnew = RealizePalette(hdc);
\r
5570 paletteChanged = TRUE;
\r
5572 UpdateColors(hdc);
\r
5574 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5577 ReleaseDC(hwnd, hdc);
\r
5581 case WM_QUERYNEWPALETTE:
\r
5582 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5584 HDC hdc = GetDC(hwndMain);
\r
5585 paletteChanged = FALSE;
\r
5586 SelectPalette(hdc, hPal, FALSE);
\r
5587 nnew = RealizePalette(hdc);
\r
5589 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5591 ReleaseDC(hwnd, hdc);
\r
5596 case WM_COMMAND: /* message: command from application menu */
\r
5597 wmId = LOWORD(wParam);
\r
5598 wmEvent = HIWORD(wParam);
\r
5603 AnalysisPopDown();
\r
5606 case IDM_NewGameFRC:
\r
5607 if( NewGameFRC() == 0 ) {
\r
5609 AnalysisPopDown();
\r
5613 case IDM_NewVariant:
\r
5614 NewVariantPopup(hwnd);
\r
5617 case IDM_LoadGame:
\r
5618 LoadGameDialog(hwnd, "Load Game from File");
\r
5621 case IDM_LoadNextGame:
\r
5625 case IDM_LoadPrevGame:
\r
5629 case IDM_ReloadGame:
\r
5633 case IDM_LoadPosition:
\r
5634 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5635 Reset(FALSE, TRUE);
\r
5638 f = OpenFileDialog(hwnd, "rb", "",
\r
5639 appData.oldSaveStyle ? "pos" : "fen",
\r
5641 "Load Position from File", &number, fileTitle, NULL);
\r
5643 LoadPosition(f, number, fileTitle);
\r
5647 case IDM_LoadNextPosition:
\r
5648 ReloadPosition(1);
\r
5651 case IDM_LoadPrevPosition:
\r
5652 ReloadPosition(-1);
\r
5655 case IDM_ReloadPosition:
\r
5656 ReloadPosition(0);
\r
5659 case IDM_SaveGame:
\r
5660 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5661 f = OpenFileDialog(hwnd, "a", defName,
\r
5662 appData.oldSaveStyle ? "gam" : "pgn",
\r
5664 "Save Game to File", NULL, fileTitle, NULL);
\r
5666 SaveGame(f, 0, "");
\r
5670 case IDM_SavePosition:
\r
5671 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5672 f = OpenFileDialog(hwnd, "a", defName,
\r
5673 appData.oldSaveStyle ? "pos" : "fen",
\r
5675 "Save Position to File", NULL, fileTitle, NULL);
\r
5677 SavePosition(f, 0, "");
\r
5681 case IDM_SaveDiagram:
\r
5682 defName = "diagram";
\r
5683 f = OpenFileDialog(hwnd, "wb", defName,
\r
5686 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5692 case IDM_CopyGame:
\r
5693 CopyGameToClipboard();
\r
5696 case IDM_PasteGame:
\r
5697 PasteGameFromClipboard();
\r
5700 case IDM_CopyGameListToClipboard:
\r
5701 CopyGameListToClipboard();
\r
5704 /* [AS] Autodetect FEN or PGN data */
\r
5705 case IDM_PasteAny:
\r
5706 PasteGameOrFENFromClipboard();
\r
5709 /* [AS] Move history */
\r
5710 case IDM_ShowMoveHistory:
\r
5711 if( MoveHistoryIsUp() ) {
\r
5712 MoveHistoryPopDown();
\r
5715 MoveHistoryPopUp();
\r
5719 /* [AS] Eval graph */
\r
5720 case IDM_ShowEvalGraph:
\r
5721 if( EvalGraphIsUp() ) {
\r
5722 EvalGraphPopDown();
\r
5729 /* [AS] Engine output */
\r
5730 case IDM_ShowEngineOutput:
\r
5731 if( EngineOutputIsUp() ) {
\r
5732 EngineOutputPopDown();
\r
5735 EngineOutputPopUp();
\r
5739 /* [AS] User adjudication */
\r
5740 case IDM_UserAdjudication_White:
\r
5741 UserAdjudicationEvent( +1 );
\r
5744 case IDM_UserAdjudication_Black:
\r
5745 UserAdjudicationEvent( -1 );
\r
5748 case IDM_UserAdjudication_Draw:
\r
5749 UserAdjudicationEvent( 0 );
\r
5752 /* [AS] Game list options dialog */
\r
5753 case IDM_GameListOptions:
\r
5754 GameListOptions();
\r
5757 case IDM_CopyPosition:
\r
5758 CopyFENToClipboard();
\r
5761 case IDM_PastePosition:
\r
5762 PasteFENFromClipboard();
\r
5765 case IDM_MailMove:
\r
5769 case IDM_ReloadCMailMsg:
\r
5770 Reset(TRUE, TRUE);
\r
5771 ReloadCmailMsgEvent(FALSE);
\r
5774 case IDM_Minimize:
\r
5775 ShowWindow(hwnd, SW_MINIMIZE);
\r
5782 case IDM_MachineWhite:
\r
5783 MachineWhiteEvent();
\r
5785 * refresh the tags dialog only if it's visible
\r
5787 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5789 tags = PGNTags(&gameInfo);
\r
5790 TagsPopUp(tags, CmailMsg());
\r
5795 case IDM_MachineBlack:
\r
5796 MachineBlackEvent();
\r
5798 * refresh the tags dialog only if it's visible
\r
5800 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5802 tags = PGNTags(&gameInfo);
\r
5803 TagsPopUp(tags, CmailMsg());
\r
5808 case IDM_TwoMachines:
\r
5809 TwoMachinesEvent();
\r
5811 * refresh the tags dialog only if it's visible
\r
5813 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5815 tags = PGNTags(&gameInfo);
\r
5816 TagsPopUp(tags, CmailMsg());
\r
5821 case IDM_AnalysisMode:
\r
5822 if (!first.analysisSupport) {
\r
5823 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5824 DisplayError(buf, 0);
\r
5826 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5827 if (appData.icsActive) {
\r
5828 if (gameMode != IcsObserving) {
\r
5829 sprintf(buf, "You are not observing a game");
\r
5830 DisplayError(buf, 0);
\r
5831 /* secure check */
\r
5832 if (appData.icsEngineAnalyze) {
\r
5833 if (appData.debugMode)
\r
5834 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5835 ExitAnalyzeMode();
\r
5841 /* if enable, user want disable icsEngineAnalyze */
\r
5842 if (appData.icsEngineAnalyze) {
\r
5843 ExitAnalyzeMode();
\r
5847 appData.icsEngineAnalyze = TRUE;
\r
5848 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5851 if (!appData.showThinking) ToggleShowThinking();
\r
5852 AnalyzeModeEvent();
\r
5856 case IDM_AnalyzeFile:
\r
5857 if (!first.analysisSupport) {
\r
5858 char buf[MSG_SIZ];
\r
5859 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5860 DisplayError(buf, 0);
\r
5862 if (!appData.showThinking) ToggleShowThinking();
\r
5863 AnalyzeFileEvent();
\r
5864 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5865 AnalysisPeriodicEvent(1);
\r
5869 case IDM_IcsClient:
\r
5873 case IDM_EditGame:
\r
5877 case IDM_EditPosition:
\r
5878 EditPositionEvent();
\r
5881 case IDM_Training:
\r
5885 case IDM_ShowGameList:
\r
5886 ShowGameListProc();
\r
5889 case IDM_EditTags:
\r
5893 case IDM_EditComment:
\r
5894 if (commentDialogUp && editComment) {
\r
5897 EditCommentEvent();
\r
5917 case IDM_CallFlag:
\r
5937 case IDM_StopObserving:
\r
5938 StopObservingEvent();
\r
5941 case IDM_StopExamining:
\r
5942 StopExaminingEvent();
\r
5945 case IDM_TypeInMove:
\r
5946 PopUpMoveDialog('\000');
\r
5949 case IDM_TypeInName:
\r
5950 PopUpNameDialog('\000');
\r
5953 case IDM_Backward:
\r
5955 SetFocus(hwndMain);
\r
5960 SetFocus(hwndMain);
\r
5965 SetFocus(hwndMain);
\r
5970 SetFocus(hwndMain);
\r
5977 case IDM_TruncateGame:
\r
5978 TruncateGameEvent();
\r
5985 case IDM_RetractMove:
\r
5986 RetractMoveEvent();
\r
5989 case IDM_FlipView:
\r
5990 flipView = !flipView;
\r
5991 DrawPosition(FALSE, NULL);
\r
5994 case IDM_FlipClock:
\r
5995 flipClock = !flipClock;
\r
5996 DisplayBothClocks();
\r
5997 DrawPosition(FALSE, NULL);
\r
6000 case IDM_GeneralOptions:
\r
6001 GeneralOptionsPopup(hwnd);
\r
6002 DrawPosition(TRUE, NULL);
\r
6005 case IDM_BoardOptions:
\r
6006 BoardOptionsPopup(hwnd);
\r
6009 case IDM_EnginePlayOptions:
\r
6010 EnginePlayOptionsPopup(hwnd);
\r
6013 case IDM_OptionsUCI:
\r
6014 UciOptionsPopup(hwnd);
\r
6017 case IDM_IcsOptions:
\r
6018 IcsOptionsPopup(hwnd);
\r
6022 FontsOptionsPopup(hwnd);
\r
6026 SoundOptionsPopup(hwnd);
\r
6029 case IDM_CommPort:
\r
6030 CommPortOptionsPopup(hwnd);
\r
6033 case IDM_LoadOptions:
\r
6034 LoadOptionsPopup(hwnd);
\r
6037 case IDM_SaveOptions:
\r
6038 SaveOptionsPopup(hwnd);
\r
6041 case IDM_TimeControl:
\r
6042 TimeControlOptionsPopup(hwnd);
\r
6045 case IDM_SaveSettings:
\r
6046 SaveSettings(settingsFileName);
\r
6049 case IDM_SaveSettingsOnExit:
\r
6050 saveSettingsOnExit = !saveSettingsOnExit;
\r
6051 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6052 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6053 MF_CHECKED : MF_UNCHECKED));
\r
6064 case IDM_AboutGame:
\r
6069 appData.debugMode = !appData.debugMode;
\r
6070 if (appData.debugMode) {
\r
6071 char dir[MSG_SIZ];
\r
6072 GetCurrentDirectory(MSG_SIZ, dir);
\r
6073 SetCurrentDirectory(installDir);
\r
6074 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6075 SetCurrentDirectory(dir);
\r
6076 setbuf(debugFP, NULL);
\r
6083 case IDM_HELPCONTENTS:
\r
6084 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6085 MessageBox (GetFocus(),
\r
6086 "Unable to activate help",
\r
6087 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6091 case IDM_HELPSEARCH:
\r
6092 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
6093 MessageBox (GetFocus(),
\r
6094 "Unable to activate help",
\r
6095 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6099 case IDM_HELPHELP:
\r
6100 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6101 MessageBox (GetFocus(),
\r
6102 "Unable to activate help",
\r
6103 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6108 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6110 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6111 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6112 FreeProcInstance(lpProc);
\r
6115 case IDM_DirectCommand1:
\r
6116 AskQuestionEvent("Direct Command",
\r
6117 "Send to chess program:", "", "1");
\r
6119 case IDM_DirectCommand2:
\r
6120 AskQuestionEvent("Direct Command",
\r
6121 "Send to second chess program:", "", "2");
\r
6124 case EP_WhitePawn:
\r
6125 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6126 fromX = fromY = -1;
\r
6129 case EP_WhiteKnight:
\r
6130 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6131 fromX = fromY = -1;
\r
6134 case EP_WhiteBishop:
\r
6135 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6136 fromX = fromY = -1;
\r
6139 case EP_WhiteRook:
\r
6140 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6141 fromX = fromY = -1;
\r
6144 case EP_WhiteQueen:
\r
6145 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6146 fromX = fromY = -1;
\r
6149 case EP_WhiteFerz:
\r
6150 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6151 fromX = fromY = -1;
\r
6154 case EP_WhiteWazir:
\r
6155 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6156 fromX = fromY = -1;
\r
6159 case EP_WhiteAlfil:
\r
6160 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6161 fromX = fromY = -1;
\r
6164 case EP_WhiteCannon:
\r
6165 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6166 fromX = fromY = -1;
\r
6169 case EP_WhiteCardinal:
\r
6170 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6171 fromX = fromY = -1;
\r
6174 case EP_WhiteMarshall:
\r
6175 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6176 fromX = fromY = -1;
\r
6179 case EP_WhiteKing:
\r
6180 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6181 fromX = fromY = -1;
\r
6184 case EP_BlackPawn:
\r
6185 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6186 fromX = fromY = -1;
\r
6189 case EP_BlackKnight:
\r
6190 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6191 fromX = fromY = -1;
\r
6194 case EP_BlackBishop:
\r
6195 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6196 fromX = fromY = -1;
\r
6199 case EP_BlackRook:
\r
6200 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6201 fromX = fromY = -1;
\r
6204 case EP_BlackQueen:
\r
6205 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6206 fromX = fromY = -1;
\r
6209 case EP_BlackFerz:
\r
6210 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6211 fromX = fromY = -1;
\r
6214 case EP_BlackWazir:
\r
6215 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6216 fromX = fromY = -1;
\r
6219 case EP_BlackAlfil:
\r
6220 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6221 fromX = fromY = -1;
\r
6224 case EP_BlackCannon:
\r
6225 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6226 fromX = fromY = -1;
\r
6229 case EP_BlackCardinal:
\r
6230 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6231 fromX = fromY = -1;
\r
6234 case EP_BlackMarshall:
\r
6235 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6236 fromX = fromY = -1;
\r
6239 case EP_BlackKing:
\r
6240 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6241 fromX = fromY = -1;
\r
6244 case EP_EmptySquare:
\r
6245 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6246 fromX = fromY = -1;
\r
6249 case EP_ClearBoard:
\r
6250 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6251 fromX = fromY = -1;
\r
6255 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6256 fromX = fromY = -1;
\r
6260 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6261 fromX = fromY = -1;
\r
6265 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6266 fromX = fromY = -1;
\r
6270 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6271 fromX = fromY = -1;
\r
6275 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6276 fromX = fromY = -1;
\r
6280 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6281 fromX = fromY = -1;
\r
6285 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6286 fromX = fromY = -1;
\r
6290 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6291 fromX = fromY = -1;
\r
6295 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6296 fromX = fromY = -1;
\r
6300 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6306 case CLOCK_TIMER_ID:
\r
6307 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6308 clockTimerEvent = 0;
\r
6309 DecrementClocks(); /* call into back end */
\r
6311 case LOAD_GAME_TIMER_ID:
\r
6312 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6313 loadGameTimerEvent = 0;
\r
6314 AutoPlayGameLoop(); /* call into back end */
\r
6316 case ANALYSIS_TIMER_ID:
\r
6317 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6318 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6319 AnalysisPeriodicEvent(0);
\r
6321 KillTimer(hwnd, analysisTimerEvent);
\r
6322 analysisTimerEvent = 0;
\r
6325 case DELAYED_TIMER_ID:
\r
6326 KillTimer(hwnd, delayedTimerEvent);
\r
6327 delayedTimerEvent = 0;
\r
6328 delayedTimerCallback();
\r
6333 case WM_USER_Input:
\r
6334 InputEvent(hwnd, message, wParam, lParam);
\r
6337 /* [AS] Also move "attached" child windows */
\r
6338 case WM_WINDOWPOSCHANGING:
\r
6340 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6341 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6343 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6344 /* Window is moving */
\r
6347 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6348 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6349 rcMain.right = boardX + winWidth;
\r
6350 rcMain.top = boardY;
\r
6351 rcMain.bottom = boardY + winHeight;
\r
6353 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6354 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6355 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6362 /* [AS] Snapping */
\r
6363 case WM_ENTERSIZEMOVE:
\r
6364 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6365 if (hwnd == hwndMain) {
\r
6366 doingSizing = TRUE;
\r
6369 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6373 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6374 if (hwnd == hwndMain) {
\r
6375 lastSizing = wParam;
\r
6380 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6381 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6383 case WM_EXITSIZEMOVE:
\r
6384 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6385 if (hwnd == hwndMain) {
\r
6387 doingSizing = FALSE;
\r
6388 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6389 GetClientRect(hwnd, &client);
\r
6390 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6392 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6394 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6397 case WM_DESTROY: /* message: window being destroyed */
\r
6398 PostQuitMessage(0);
\r
6402 if (hwnd == hwndMain) {
\r
6407 default: /* Passes it on if unprocessed */
\r
6408 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6413 /*---------------------------------------------------------------------------*\
\r
6415 * Misc utility routines
\r
6417 \*---------------------------------------------------------------------------*/
\r
6420 * Decent random number generator, at least not as bad as Windows
\r
6421 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6423 unsigned int randstate;
\r
6428 randstate = randstate * 1664525 + 1013904223;
\r
6429 return (int) randstate & 0x7fffffff;
\r
6433 mysrandom(unsigned int seed)
\r
6440 * returns TRUE if user selects a different color, FALSE otherwise
\r
6444 ChangeColor(HWND hwnd, COLORREF *which)
\r
6446 static BOOL firstTime = TRUE;
\r
6447 static DWORD customColors[16];
\r
6449 COLORREF newcolor;
\r
6454 /* Make initial colors in use available as custom colors */
\r
6455 /* Should we put the compiled-in defaults here instead? */
\r
6457 customColors[i++] = lightSquareColor & 0xffffff;
\r
6458 customColors[i++] = darkSquareColor & 0xffffff;
\r
6459 customColors[i++] = whitePieceColor & 0xffffff;
\r
6460 customColors[i++] = blackPieceColor & 0xffffff;
\r
6461 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6462 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6464 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6465 customColors[i++] = textAttribs[ccl].color;
\r
6467 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6468 firstTime = FALSE;
\r
6471 cc.lStructSize = sizeof(cc);
\r
6472 cc.hwndOwner = hwnd;
\r
6473 cc.hInstance = NULL;
\r
6474 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6475 cc.lpCustColors = (LPDWORD) customColors;
\r
6476 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6478 if (!ChooseColor(&cc)) return FALSE;
\r
6480 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6481 if (newcolor == *which) return FALSE;
\r
6482 *which = newcolor;
\r
6486 InitDrawingColors();
\r
6487 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6492 MyLoadSound(MySound *ms)
\r
6498 if (ms->data) free(ms->data);
\r
6501 switch (ms->name[0]) {
\r
6507 /* System sound from Control Panel. Don't preload here. */
\r
6511 if (ms->name[1] == NULLCHAR) {
\r
6512 /* "!" alone = silence */
\r
6515 /* Builtin wave resource. Error if not found. */
\r
6516 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6517 if (h == NULL) break;
\r
6518 ms->data = (void *)LoadResource(hInst, h);
\r
6519 if (h == NULL) break;
\r
6524 /* .wav file. Error if not found. */
\r
6525 f = fopen(ms->name, "rb");
\r
6526 if (f == NULL) break;
\r
6527 if (fstat(fileno(f), &st) < 0) break;
\r
6528 ms->data = malloc(st.st_size);
\r
6529 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6535 char buf[MSG_SIZ];
\r
6536 sprintf(buf, "Error loading sound %s", ms->name);
\r
6537 DisplayError(buf, GetLastError());
\r
6543 MyPlaySound(MySound *ms)
\r
6545 BOOLEAN ok = FALSE;
\r
6546 switch (ms->name[0]) {
\r
6552 /* System sound from Control Panel (deprecated feature).
\r
6553 "$" alone or an unset sound name gets default beep (still in use). */
\r
6554 if (ms->name[1]) {
\r
6555 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6557 if (!ok) ok = MessageBeep(MB_OK);
\r
6560 /* Builtin wave resource, or "!" alone for silence */
\r
6561 if (ms->name[1]) {
\r
6562 if (ms->data == NULL) return FALSE;
\r
6563 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6569 /* .wav file. Error if not found. */
\r
6570 if (ms->data == NULL) return FALSE;
\r
6571 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6574 /* Don't print an error: this can happen innocently if the sound driver
\r
6575 is busy; for instance, if another instance of WinBoard is playing
\r
6576 a sound at about the same time. */
\r
6579 char buf[MSG_SIZ];
\r
6580 sprintf(buf, "Error playing sound %s", ms->name);
\r
6581 DisplayError(buf, GetLastError());
\r
6589 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6592 OPENFILENAME *ofn;
\r
6593 static UINT *number; /* gross that this is static */
\r
6595 switch (message) {
\r
6596 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6597 /* Center the dialog over the application window */
\r
6598 ofn = (OPENFILENAME *) lParam;
\r
6599 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6600 number = (UINT *) ofn->lCustData;
\r
6601 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6605 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6606 return FALSE; /* Allow for further processing */
\r
6609 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6610 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6612 return FALSE; /* Allow for further processing */
\r
6618 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6620 static UINT *number;
\r
6621 OPENFILENAME *ofname;
\r
6624 case WM_INITDIALOG:
\r
6625 ofname = (OPENFILENAME *)lParam;
\r
6626 number = (UINT *)(ofname->lCustData);
\r
6629 ofnot = (OFNOTIFY *)lParam;
\r
6630 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6631 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6640 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6641 char *nameFilt, char *dlgTitle, UINT *number,
\r
6642 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6644 OPENFILENAME openFileName;
\r
6645 char buf1[MSG_SIZ];
\r
6648 if (fileName == NULL) fileName = buf1;
\r
6649 if (defName == NULL) {
\r
6650 strcpy(fileName, "*.");
\r
6651 strcat(fileName, defExt);
\r
6653 strcpy(fileName, defName);
\r
6655 if (fileTitle) strcpy(fileTitle, "");
\r
6656 if (number) *number = 0;
\r
6658 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6659 openFileName.hwndOwner = hwnd;
\r
6660 openFileName.hInstance = (HANDLE) hInst;
\r
6661 openFileName.lpstrFilter = nameFilt;
\r
6662 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6663 openFileName.nMaxCustFilter = 0L;
\r
6664 openFileName.nFilterIndex = 1L;
\r
6665 openFileName.lpstrFile = fileName;
\r
6666 openFileName.nMaxFile = MSG_SIZ;
\r
6667 openFileName.lpstrFileTitle = fileTitle;
\r
6668 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6669 openFileName.lpstrInitialDir = NULL;
\r
6670 openFileName.lpstrTitle = dlgTitle;
\r
6671 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6672 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6673 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6674 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6675 openFileName.nFileOffset = 0;
\r
6676 openFileName.nFileExtension = 0;
\r
6677 openFileName.lpstrDefExt = defExt;
\r
6678 openFileName.lCustData = (LONG) number;
\r
6679 openFileName.lpfnHook = oldDialog ?
\r
6680 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6681 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6683 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6684 GetOpenFileName(&openFileName)) {
\r
6685 /* open the file */
\r
6686 f = fopen(openFileName.lpstrFile, write);
\r
6688 MessageBox(hwnd, "File open failed", NULL,
\r
6689 MB_OK|MB_ICONEXCLAMATION);
\r
6693 int err = CommDlgExtendedError();
\r
6694 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6703 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6705 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6708 * Get the first pop-up menu in the menu template. This is the
\r
6709 * menu that TrackPopupMenu displays.
\r
6711 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6713 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6716 * TrackPopup uses screen coordinates, so convert the
\r
6717 * coordinates of the mouse click to screen coordinates.
\r
6719 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6721 /* Draw and track the floating pop-up menu. */
\r
6722 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6723 pt.x, pt.y, 0, hwnd, NULL);
\r
6725 /* Destroy the menu.*/
\r
6726 DestroyMenu(hmenu);
\r
6731 int sizeX, sizeY, newSizeX, newSizeY;
\r
6733 } ResizeEditPlusButtonsClosure;
\r
6736 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6738 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6742 if (hChild == cl->hText) return TRUE;
\r
6743 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6744 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6745 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6746 ScreenToClient(cl->hDlg, &pt);
\r
6747 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6748 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6752 /* Resize a dialog that has a (rich) edit field filling most of
\r
6753 the top, with a row of buttons below */
\r
6755 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6758 int newTextHeight, newTextWidth;
\r
6759 ResizeEditPlusButtonsClosure cl;
\r
6761 /*if (IsIconic(hDlg)) return;*/
\r
6762 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6764 cl.hdwp = BeginDeferWindowPos(8);
\r
6766 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6767 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6768 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6769 if (newTextHeight < 0) {
\r
6770 newSizeY += -newTextHeight;
\r
6771 newTextHeight = 0;
\r
6773 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6774 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6780 cl.newSizeX = newSizeX;
\r
6781 cl.newSizeY = newSizeY;
\r
6782 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6784 EndDeferWindowPos(cl.hdwp);
\r
6787 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6789 RECT rChild, rParent;
\r
6790 int wChild, hChild, wParent, hParent;
\r
6791 int wScreen, hScreen, xNew, yNew;
\r
6794 /* Get the Height and Width of the child window */
\r
6795 GetWindowRect (hwndChild, &rChild);
\r
6796 wChild = rChild.right - rChild.left;
\r
6797 hChild = rChild.bottom - rChild.top;
\r
6799 /* Get the Height and Width of the parent window */
\r
6800 GetWindowRect (hwndParent, &rParent);
\r
6801 wParent = rParent.right - rParent.left;
\r
6802 hParent = rParent.bottom - rParent.top;
\r
6804 /* Get the display limits */
\r
6805 hdc = GetDC (hwndChild);
\r
6806 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6807 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6808 ReleaseDC(hwndChild, hdc);
\r
6810 /* Calculate new X position, then adjust for screen */
\r
6811 xNew = rParent.left + ((wParent - wChild) /2);
\r
6814 } else if ((xNew+wChild) > wScreen) {
\r
6815 xNew = wScreen - wChild;
\r
6818 /* Calculate new Y position, then adjust for screen */
\r
6820 yNew = rParent.top + ((hParent - hChild) /2);
\r
6823 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6828 } else if ((yNew+hChild) > hScreen) {
\r
6829 yNew = hScreen - hChild;
\r
6832 /* Set it, and return */
\r
6833 return SetWindowPos (hwndChild, NULL,
\r
6834 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6837 /* Center one window over another */
\r
6838 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6840 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6843 /*---------------------------------------------------------------------------*\
\r
6845 * Startup Dialog functions
\r
6847 \*---------------------------------------------------------------------------*/
\r
6849 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6851 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6853 while (*cd != NULL) {
\r
6854 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6860 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6862 char buf1[ARG_MAX];
\r
6865 if (str[0] == '@') {
\r
6866 FILE* f = fopen(str + 1, "r");
\r
6868 DisplayFatalError(str + 1, errno, 2);
\r
6871 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6873 buf1[len] = NULLCHAR;
\r
6877 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6880 char buf[MSG_SIZ];
\r
6881 char *end = strchr(str, '\n');
\r
6882 if (end == NULL) return;
\r
6883 memcpy(buf, str, end - str);
\r
6884 buf[end - str] = NULLCHAR;
\r
6885 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6891 SetStartupDialogEnables(HWND hDlg)
\r
6893 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6894 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6895 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6896 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6897 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6898 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6899 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6900 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6901 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6902 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6903 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6904 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6905 IsDlgButtonChecked(hDlg, OPT_View));
\r
6909 QuoteForFilename(char *filename)
\r
6911 int dquote, space;
\r
6912 dquote = strchr(filename, '"') != NULL;
\r
6913 space = strchr(filename, ' ') != NULL;
\r
6914 if (dquote || space) {
\r
6926 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6928 char buf[MSG_SIZ];
\r
6931 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6932 q = QuoteForFilename(nthcp);
\r
6933 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6934 if (*nthdir != NULLCHAR) {
\r
6935 q = QuoteForFilename(nthdir);
\r
6936 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6938 if (*nthcp == NULLCHAR) {
\r
6939 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6940 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6941 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6942 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6947 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6949 char buf[MSG_SIZ];
\r
6953 switch (message) {
\r
6954 case WM_INITDIALOG:
\r
6955 /* Center the dialog */
\r
6956 CenterWindow (hDlg, GetDesktopWindow());
\r
6957 /* Initialize the dialog items */
\r
6958 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6959 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6960 firstChessProgramNames);
\r
6961 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6962 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6963 secondChessProgramNames);
\r
6964 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6965 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6966 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6967 if (*appData.icsHelper != NULLCHAR) {
\r
6968 char *q = QuoteForFilename(appData.icsHelper);
\r
6969 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6971 if (*appData.icsHost == NULLCHAR) {
\r
6972 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6973 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6974 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6975 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6976 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6979 if (appData.icsActive) {
\r
6980 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6982 else if (appData.noChessProgram) {
\r
6983 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6986 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6989 SetStartupDialogEnables(hDlg);
\r
6993 switch (LOWORD(wParam)) {
\r
6995 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6996 strcpy(buf, "/fcp=");
\r
6997 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6999 ParseArgs(StringGet, &p);
\r
7000 strcpy(buf, "/scp=");
\r
7001 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7003 ParseArgs(StringGet, &p);
\r
7004 appData.noChessProgram = FALSE;
\r
7005 appData.icsActive = FALSE;
\r
7006 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7007 strcpy(buf, "/ics /icshost=");
\r
7008 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7010 ParseArgs(StringGet, &p);
\r
7011 if (appData.zippyPlay) {
\r
7012 strcpy(buf, "/fcp=");
\r
7013 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7015 ParseArgs(StringGet, &p);
\r
7017 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7018 appData.noChessProgram = TRUE;
\r
7019 appData.icsActive = FALSE;
\r
7021 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7022 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7025 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7026 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7028 ParseArgs(StringGet, &p);
\r
7030 EndDialog(hDlg, TRUE);
\r
7037 case IDM_HELPCONTENTS:
\r
7038 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7039 MessageBox (GetFocus(),
\r
7040 "Unable to activate help",
\r
7041 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7046 SetStartupDialogEnables(hDlg);
\r
7054 /*---------------------------------------------------------------------------*\
\r
7056 * About box dialog functions
\r
7058 \*---------------------------------------------------------------------------*/
\r
7060 /* Process messages for "About" dialog box */
\r
7062 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7064 switch (message) {
\r
7065 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7066 /* Center the dialog over the application window */
\r
7067 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7068 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7071 case WM_COMMAND: /* message: received a command */
\r
7072 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7073 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7074 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7082 /*---------------------------------------------------------------------------*\
\r
7084 * Comment Dialog functions
\r
7086 \*---------------------------------------------------------------------------*/
\r
7089 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7091 static HANDLE hwndText = NULL;
\r
7092 int len, newSizeX, newSizeY, flags;
\r
7093 static int sizeX, sizeY;
\r
7098 switch (message) {
\r
7099 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7100 /* Initialize the dialog items */
\r
7101 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7102 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7103 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7104 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7105 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7106 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7107 SetWindowText(hDlg, commentTitle);
\r
7108 if (editComment) {
\r
7109 SetFocus(hwndText);
\r
7111 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7113 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7114 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7115 MAKELPARAM(FALSE, 0));
\r
7116 /* Size and position the dialog */
\r
7117 if (!commentDialog) {
\r
7118 commentDialog = hDlg;
\r
7119 flags = SWP_NOZORDER;
\r
7120 GetClientRect(hDlg, &rect);
\r
7121 sizeX = rect.right;
\r
7122 sizeY = rect.bottom;
\r
7123 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7124 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7125 WINDOWPLACEMENT wp;
\r
7126 EnsureOnScreen(&commentX, &commentY);
\r
7127 wp.length = sizeof(WINDOWPLACEMENT);
\r
7129 wp.showCmd = SW_SHOW;
\r
7130 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7131 wp.rcNormalPosition.left = commentX;
\r
7132 wp.rcNormalPosition.right = commentX + commentW;
\r
7133 wp.rcNormalPosition.top = commentY;
\r
7134 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7135 SetWindowPlacement(hDlg, &wp);
\r
7137 GetClientRect(hDlg, &rect);
\r
7138 newSizeX = rect.right;
\r
7139 newSizeY = rect.bottom;
\r
7140 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7141 newSizeX, newSizeY);
\r
7148 case WM_COMMAND: /* message: received a command */
\r
7149 switch (LOWORD(wParam)) {
\r
7151 if (editComment) {
\r
7153 /* Read changed options from the dialog box */
\r
7154 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7155 len = GetWindowTextLength(hwndText);
\r
7156 str = (char *) malloc(len + 1);
\r
7157 GetWindowText(hwndText, str, len + 1);
\r
7166 ReplaceComment(commentIndex, str);
\r
7173 case OPT_CancelComment:
\r
7177 case OPT_ClearComment:
\r
7178 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7181 case OPT_EditComment:
\r
7182 EditCommentEvent();
\r
7191 newSizeX = LOWORD(lParam);
\r
7192 newSizeY = HIWORD(lParam);
\r
7193 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7198 case WM_GETMINMAXINFO:
\r
7199 /* Prevent resizing window too small */
\r
7200 mmi = (MINMAXINFO *) lParam;
\r
7201 mmi->ptMinTrackSize.x = 100;
\r
7202 mmi->ptMinTrackSize.y = 100;
\r
7209 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7214 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7216 if (str == NULL) str = "";
\r
7217 p = (char *) malloc(2 * strlen(str) + 2);
\r
7220 if (*str == '\n') *q++ = '\r';
\r
7224 if (commentText != NULL) free(commentText);
\r
7226 commentIndex = index;
\r
7227 commentTitle = title;
\r
7229 editComment = edit;
\r
7231 if (commentDialog) {
\r
7232 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7233 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7235 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7236 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7237 hwndMain, (DLGPROC)lpProc);
\r
7238 FreeProcInstance(lpProc);
\r
7240 commentDialogUp = TRUE;
\r
7244 /*---------------------------------------------------------------------------*\
\r
7246 * Type-in move dialog functions
\r
7248 \*---------------------------------------------------------------------------*/
\r
7251 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7253 char move[MSG_SIZ];
\r
7255 ChessMove moveType;
\r
7256 int fromX, fromY, toX, toY;
\r
7259 switch (message) {
\r
7260 case WM_INITDIALOG:
\r
7261 move[0] = (char) lParam;
\r
7262 move[1] = NULLCHAR;
\r
7263 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7264 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7265 SetWindowText(hInput, move);
\r
7267 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7271 switch (LOWORD(wParam)) {
\r
7273 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7274 gameMode != Training) {
\r
7275 DisplayMoveError("Displayed move is not current");
\r
7277 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7278 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7279 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7280 if (gameMode != Training)
\r
7281 forwardMostMove = currentMove;
\r
7282 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7284 DisplayMoveError("Could not parse move");
\r
7287 EndDialog(hDlg, TRUE);
\r
7290 EndDialog(hDlg, FALSE);
\r
7301 PopUpMoveDialog(char firstchar)
\r
7305 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7306 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7307 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7308 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7309 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7310 gameMode == Training) {
\r
7311 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7312 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7313 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7314 FreeProcInstance(lpProc);
\r
7318 /*---------------------------------------------------------------------------*\
\r
7320 * Type-in name dialog functions
\r
7322 \*---------------------------------------------------------------------------*/
\r
7325 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7327 char move[MSG_SIZ];
\r
7330 switch (message) {
\r
7331 case WM_INITDIALOG:
\r
7332 move[0] = (char) lParam;
\r
7333 move[1] = NULLCHAR;
\r
7334 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7335 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7336 SetWindowText(hInput, move);
\r
7338 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7342 switch (LOWORD(wParam)) {
\r
7344 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7345 appData.userName = strdup(move);
\r
7348 EndDialog(hDlg, TRUE);
\r
7351 EndDialog(hDlg, FALSE);
\r
7362 PopUpNameDialog(char firstchar)
\r
7366 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7367 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7368 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7369 FreeProcInstance(lpProc);
\r
7372 /*---------------------------------------------------------------------------*\
\r
7376 \*---------------------------------------------------------------------------*/
\r
7378 /* Nonmodal error box */
\r
7379 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7380 WPARAM wParam, LPARAM lParam);
\r
7383 ErrorPopUp(char *title, char *content)
\r
7387 BOOLEAN modal = hwndMain == NULL;
\r
7405 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7406 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7409 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7411 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7412 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7413 hwndMain, (DLGPROC)lpProc);
\r
7414 FreeProcInstance(lpProc);
\r
7421 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7422 if (errorDialog == NULL) return;
\r
7423 DestroyWindow(errorDialog);
\r
7424 errorDialog = NULL;
\r
7428 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7433 switch (message) {
\r
7434 case WM_INITDIALOG:
\r
7435 GetWindowRect(hDlg, &rChild);
\r
7438 SetWindowPos(hDlg, NULL, rChild.left,
\r
7439 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7440 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7444 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7445 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7446 and it doesn't work when you resize the dialog.
\r
7447 For now, just give it a default position.
\r
7449 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7451 errorDialog = hDlg;
\r
7452 SetWindowText(hDlg, errorTitle);
\r
7453 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7454 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7458 switch (LOWORD(wParam)) {
\r
7461 if (errorDialog == hDlg) errorDialog = NULL;
\r
7462 DestroyWindow(hDlg);
\r
7474 HWND gothicDialog = NULL;
\r
7477 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7481 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7483 switch (message) {
\r
7484 case WM_INITDIALOG:
\r
7485 GetWindowRect(hDlg, &rChild);
\r
7487 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7491 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7492 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7493 and it doesn't work when you resize the dialog.
\r
7494 For now, just give it a default position.
\r
7496 gothicDialog = hDlg;
\r
7497 SetWindowText(hDlg, errorTitle);
\r
7498 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7499 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7503 switch (LOWORD(wParam)) {
\r
7506 if (errorDialog == hDlg) errorDialog = NULL;
\r
7507 DestroyWindow(hDlg);
\r
7519 GothicPopUp(char *title, VariantClass variant)
\r
7522 static char *lastTitle;
\r
7524 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7525 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7527 if(lastTitle != title && gothicDialog != NULL) {
\r
7528 DestroyWindow(gothicDialog);
\r
7529 gothicDialog = NULL;
\r
7531 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7532 title = lastTitle;
\r
7533 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7534 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7535 hwndMain, (DLGPROC)lpProc);
\r
7536 FreeProcInstance(lpProc);
\r
7541 /*---------------------------------------------------------------------------*\
\r
7543 * Ics Interaction console functions
\r
7545 \*---------------------------------------------------------------------------*/
\r
7547 #define HISTORY_SIZE 64
\r
7548 static char *history[HISTORY_SIZE];
\r
7549 int histIn = 0, histP = 0;
\r
7552 SaveInHistory(char *cmd)
\r
7554 if (history[histIn] != NULL) {
\r
7555 free(history[histIn]);
\r
7556 history[histIn] = NULL;
\r
7558 if (*cmd == NULLCHAR) return;
\r
7559 history[histIn] = StrSave(cmd);
\r
7560 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7561 if (history[histIn] != NULL) {
\r
7562 free(history[histIn]);
\r
7563 history[histIn] = NULL;
\r
7569 PrevInHistory(char *cmd)
\r
7572 if (histP == histIn) {
\r
7573 if (history[histIn] != NULL) free(history[histIn]);
\r
7574 history[histIn] = StrSave(cmd);
\r
7576 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7577 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7579 return history[histP];
\r
7585 if (histP == histIn) return NULL;
\r
7586 histP = (histP + 1) % HISTORY_SIZE;
\r
7587 return history[histP];
\r
7594 BOOLEAN immediate;
\r
7595 } IcsTextMenuEntry;
\r
7596 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7597 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7600 ParseIcsTextMenu(char *icsTextMenuString)
\r
7603 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7604 char *p = icsTextMenuString;
\r
7605 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7608 if (e->command != NULL) {
\r
7610 e->command = NULL;
\r
7614 e = icsTextMenuEntry;
\r
7615 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7616 if (*p == ';' || *p == '\n') {
\r
7617 e->item = strdup("-");
\r
7618 e->command = NULL;
\r
7620 } else if (*p == '-') {
\r
7621 e->item = strdup("-");
\r
7622 e->command = NULL;
\r
7626 char *q, *r, *s, *t;
\r
7628 q = strchr(p, ',');
\r
7629 if (q == NULL) break;
\r
7631 r = strchr(q + 1, ',');
\r
7632 if (r == NULL) break;
\r
7634 s = strchr(r + 1, ',');
\r
7635 if (s == NULL) break;
\r
7638 t = strchr(s + 1, c);
\r
7641 t = strchr(s + 1, c);
\r
7643 if (t != NULL) *t = NULLCHAR;
\r
7644 e->item = strdup(p);
\r
7645 e->command = strdup(q + 1);
\r
7646 e->getname = *(r + 1) != '0';
\r
7647 e->immediate = *(s + 1) != '0';
\r
7651 if (t == NULL) break;
\r
7660 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7664 hmenu = LoadMenu(hInst, "TextMenu");
\r
7665 h = GetSubMenu(hmenu, 0);
\r
7667 if (strcmp(e->item, "-") == 0) {
\r
7668 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7670 if (e->item[0] == '|') {
\r
7671 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7672 IDM_CommandX + i, &e->item[1]);
\r
7674 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7683 WNDPROC consoleTextWindowProc;
\r
7686 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7688 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7689 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7693 SetWindowText(hInput, command);
\r
7695 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7697 sel.cpMin = 999999;
\r
7698 sel.cpMax = 999999;
\r
7699 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7704 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7705 if (sel.cpMin == sel.cpMax) {
\r
7706 /* Expand to surrounding word */
\r
7709 tr.chrg.cpMax = sel.cpMin;
\r
7710 tr.chrg.cpMin = --sel.cpMin;
\r
7711 if (sel.cpMin < 0) break;
\r
7712 tr.lpstrText = name;
\r
7713 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7714 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7718 tr.chrg.cpMin = sel.cpMax;
\r
7719 tr.chrg.cpMax = ++sel.cpMax;
\r
7720 tr.lpstrText = name;
\r
7721 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7722 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7725 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7726 MessageBeep(MB_ICONEXCLAMATION);
\r
7730 tr.lpstrText = name;
\r
7731 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7733 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7734 MessageBeep(MB_ICONEXCLAMATION);
\r
7737 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7740 sprintf(buf, "%s %s", command, name);
\r
7741 SetWindowText(hInput, buf);
\r
7742 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7744 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7745 SetWindowText(hInput, buf);
\r
7746 sel.cpMin = 999999;
\r
7747 sel.cpMax = 999999;
\r
7748 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7754 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7759 switch (message) {
\r
7761 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7764 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7767 sel.cpMin = 999999;
\r
7768 sel.cpMax = 999999;
\r
7769 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7770 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7775 if (wParam == '\t') {
\r
7776 if (GetKeyState(VK_SHIFT) < 0) {
\r
7778 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7779 if (buttonDesc[0].hwnd) {
\r
7780 SetFocus(buttonDesc[0].hwnd);
\r
7782 SetFocus(hwndMain);
\r
7786 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7789 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7791 SendMessage(hInput, message, wParam, lParam);
\r
7795 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7797 return SendMessage(hInput, message, wParam, lParam);
\r
7798 case WM_MBUTTONDOWN:
\r
7799 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7800 case WM_RBUTTONDOWN:
\r
7801 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7802 /* Move selection here if it was empty */
\r
7804 pt.x = LOWORD(lParam);
\r
7805 pt.y = HIWORD(lParam);
\r
7806 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7807 if (sel.cpMin == sel.cpMax) {
\r
7808 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7809 sel.cpMax = sel.cpMin;
\r
7810 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7812 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7815 case WM_RBUTTONUP:
\r
7816 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7817 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7818 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7821 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7822 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7823 if (sel.cpMin == sel.cpMax) {
\r
7824 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7825 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7827 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7828 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7830 pt.x = LOWORD(lParam);
\r
7831 pt.y = HIWORD(lParam);
\r
7832 MenuPopup(hwnd, pt, hmenu, -1);
\r
7836 switch (LOWORD(wParam)) {
\r
7837 case IDM_QuickPaste:
\r
7839 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7840 if (sel.cpMin == sel.cpMax) {
\r
7841 MessageBeep(MB_ICONEXCLAMATION);
\r
7844 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7845 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7846 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7851 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7854 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7857 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7861 int i = LOWORD(wParam) - IDM_CommandX;
\r
7862 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7863 icsTextMenuEntry[i].command != NULL) {
\r
7864 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7865 icsTextMenuEntry[i].getname,
\r
7866 icsTextMenuEntry[i].immediate);
\r
7874 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7877 WNDPROC consoleInputWindowProc;
\r
7880 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7882 char buf[MSG_SIZ];
\r
7884 static BOOL sendNextChar = FALSE;
\r
7885 static BOOL quoteNextChar = FALSE;
\r
7886 InputSource *is = consoleInputSource;
\r
7890 switch (message) {
\r
7892 if (!appData.localLineEditing || sendNextChar) {
\r
7893 is->buf[0] = (CHAR) wParam;
\r
7895 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7896 sendNextChar = FALSE;
\r
7899 if (quoteNextChar) {
\r
7900 buf[0] = (char) wParam;
\r
7901 buf[1] = NULLCHAR;
\r
7902 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7903 quoteNextChar = FALSE;
\r
7907 case '\r': /* Enter key */
\r
7908 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7909 if (consoleEcho) SaveInHistory(is->buf);
\r
7910 is->buf[is->count++] = '\n';
\r
7911 is->buf[is->count] = NULLCHAR;
\r
7912 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7913 if (consoleEcho) {
\r
7914 ConsoleOutput(is->buf, is->count, TRUE);
\r
7915 } else if (appData.localLineEditing) {
\r
7916 ConsoleOutput("\n", 1, TRUE);
\r
7919 case '\033': /* Escape key */
\r
7920 SetWindowText(hwnd, "");
\r
7921 cf.cbSize = sizeof(CHARFORMAT);
\r
7922 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7923 if (consoleEcho) {
\r
7924 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7926 cf.crTextColor = COLOR_ECHOOFF;
\r
7928 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7929 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7931 case '\t': /* Tab key */
\r
7932 if (GetKeyState(VK_SHIFT) < 0) {
\r
7934 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7937 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7938 if (buttonDesc[0].hwnd) {
\r
7939 SetFocus(buttonDesc[0].hwnd);
\r
7941 SetFocus(hwndMain);
\r
7945 case '\023': /* Ctrl+S */
\r
7946 sendNextChar = TRUE;
\r
7948 case '\021': /* Ctrl+Q */
\r
7949 quoteNextChar = TRUE;
\r
7958 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7959 p = PrevInHistory(buf);
\r
7961 SetWindowText(hwnd, p);
\r
7962 sel.cpMin = 999999;
\r
7963 sel.cpMax = 999999;
\r
7964 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7969 p = NextInHistory();
\r
7971 SetWindowText(hwnd, p);
\r
7972 sel.cpMin = 999999;
\r
7973 sel.cpMax = 999999;
\r
7974 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7980 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7984 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7988 case WM_MBUTTONDOWN:
\r
7989 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7990 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7992 case WM_RBUTTONUP:
\r
7993 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7994 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7995 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7999 hmenu = LoadMenu(hInst, "InputMenu");
\r
8000 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8001 if (sel.cpMin == sel.cpMax) {
\r
8002 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8003 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8005 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8006 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8008 pt.x = LOWORD(lParam);
\r
8009 pt.y = HIWORD(lParam);
\r
8010 MenuPopup(hwnd, pt, hmenu, -1);
\r
8014 switch (LOWORD(wParam)) {
\r
8016 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8018 case IDM_SelectAll:
\r
8020 sel.cpMax = -1; /*999999?*/
\r
8021 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8024 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8027 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8030 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8035 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8038 #define CO_MAX 100000
\r
8039 #define CO_TRIM 1000
\r
8042 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8044 static SnapData sd;
\r
8045 static HWND hText, hInput /*, hFocus*/;
\r
8046 // InputSource *is = consoleInputSource;
\r
8048 static int sizeX, sizeY;
\r
8049 int newSizeX, newSizeY;
\r
8052 switch (message) {
\r
8053 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8054 hwndConsole = hDlg;
\r
8055 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8056 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8058 consoleTextWindowProc = (WNDPROC)
\r
8059 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8060 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8061 consoleInputWindowProc = (WNDPROC)
\r
8062 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8063 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8064 Colorize(ColorNormal, TRUE);
\r
8065 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8066 ChangedConsoleFont();
\r
8067 GetClientRect(hDlg, &rect);
\r
8068 sizeX = rect.right;
\r
8069 sizeY = rect.bottom;
\r
8070 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
8071 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
8072 WINDOWPLACEMENT wp;
\r
8073 EnsureOnScreen(&consoleX, &consoleY);
\r
8074 wp.length = sizeof(WINDOWPLACEMENT);
\r
8076 wp.showCmd = SW_SHOW;
\r
8077 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8078 wp.rcNormalPosition.left = consoleX;
\r
8079 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8080 wp.rcNormalPosition.top = consoleY;
\r
8081 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8082 SetWindowPlacement(hDlg, &wp);
\r
8085 // [HGM] Chessknight's change 2004-07-13
\r
8086 else { /* Determine Defaults */
\r
8087 WINDOWPLACEMENT wp;
\r
8088 consoleX = winWidth + 1;
\r
8089 consoleY = boardY;
\r
8090 consoleW = screenWidth - winWidth;
\r
8091 consoleH = winHeight;
\r
8092 EnsureOnScreen(&consoleX, &consoleY);
\r
8093 wp.length = sizeof(WINDOWPLACEMENT);
\r
8095 wp.showCmd = SW_SHOW;
\r
8096 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8097 wp.rcNormalPosition.left = consoleX;
\r
8098 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8099 wp.rcNormalPosition.top = consoleY;
\r
8100 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8101 SetWindowPlacement(hDlg, &wp);
\r
8116 if (IsIconic(hDlg)) break;
\r
8117 newSizeX = LOWORD(lParam);
\r
8118 newSizeY = HIWORD(lParam);
\r
8119 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8120 RECT rectText, rectInput;
\r
8122 int newTextHeight, newTextWidth;
\r
8123 GetWindowRect(hText, &rectText);
\r
8124 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8125 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8126 if (newTextHeight < 0) {
\r
8127 newSizeY += -newTextHeight;
\r
8128 newTextHeight = 0;
\r
8130 SetWindowPos(hText, NULL, 0, 0,
\r
8131 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8132 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8133 pt.x = rectInput.left;
\r
8134 pt.y = rectInput.top + newSizeY - sizeY;
\r
8135 ScreenToClient(hDlg, &pt);
\r
8136 SetWindowPos(hInput, NULL,
\r
8137 pt.x, pt.y, /* needs client coords */
\r
8138 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8139 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8145 case WM_GETMINMAXINFO:
\r
8146 /* Prevent resizing window too small */
\r
8147 mmi = (MINMAXINFO *) lParam;
\r
8148 mmi->ptMinTrackSize.x = 100;
\r
8149 mmi->ptMinTrackSize.y = 100;
\r
8152 /* [AS] Snapping */
\r
8153 case WM_ENTERSIZEMOVE:
\r
8154 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8157 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8160 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8162 case WM_EXITSIZEMOVE:
\r
8163 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8166 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8174 if (hwndConsole) return;
\r
8175 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8176 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8181 ConsoleOutput(char* data, int length, int forceVisible)
\r
8186 char buf[CO_MAX+1];
\r
8189 static int delayLF = 0;
\r
8190 CHARRANGE savesel, sel;
\r
8192 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8200 while (length--) {
\r
8208 } else if (*p == '\007') {
\r
8209 MyPlaySound(&sounds[(int)SoundBell]);
\r
8216 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8217 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8218 /* Save current selection */
\r
8219 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8220 exlen = GetWindowTextLength(hText);
\r
8221 /* Find out whether current end of text is visible */
\r
8222 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8223 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8224 /* Trim existing text if it's too long */
\r
8225 if (exlen + (q - buf) > CO_MAX) {
\r
8226 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8229 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8230 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8232 savesel.cpMin -= trim;
\r
8233 savesel.cpMax -= trim;
\r
8234 if (exlen < 0) exlen = 0;
\r
8235 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8236 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8238 /* Append the new text */
\r
8239 sel.cpMin = exlen;
\r
8240 sel.cpMax = exlen;
\r
8241 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8242 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8243 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8244 if (forceVisible || exlen == 0 ||
\r
8245 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8246 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8247 /* Scroll to make new end of text visible if old end of text
\r
8248 was visible or new text is an echo of user typein */
\r
8249 sel.cpMin = 9999999;
\r
8250 sel.cpMax = 9999999;
\r
8251 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8252 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8253 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8254 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8256 if (savesel.cpMax == exlen || forceVisible) {
\r
8257 /* Move insert point to new end of text if it was at the old
\r
8258 end of text or if the new text is an echo of user typein */
\r
8259 sel.cpMin = 9999999;
\r
8260 sel.cpMax = 9999999;
\r
8261 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8263 /* Restore previous selection */
\r
8264 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8266 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8273 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8277 COLORREF oldFg, oldBg;
\r
8281 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8283 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8284 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8285 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8288 rect.right = x + squareSize;
\r
8290 rect.bottom = y + squareSize;
\r
8293 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8294 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8295 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8296 &rect, str, strlen(str), NULL);
\r
8298 (void) SetTextColor(hdc, oldFg);
\r
8299 (void) SetBkColor(hdc, oldBg);
\r
8300 (void) SelectObject(hdc, oldFont);
\r
8304 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8305 RECT *rect, char *color, char *flagFell)
\r
8309 COLORREF oldFg, oldBg;
\r
8312 if (appData.clockMode) {
\r
8314 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8316 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8323 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8324 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8326 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8327 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8329 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8331 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8332 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8333 rect, str, strlen(str), NULL);
\r
8334 if(logoHeight > 0 && appData.clockMode) {
\r
8336 sprintf(buf, "%s %s", TimeString(timeRemaining), flagFell);
\r
8337 r.top = rect->top + logoHeight/2;
\r
8338 r.left = rect->left;
\r
8339 r.right = rect->right;
\r
8340 r.bottom = rect->bottom;
\r
8341 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8342 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8343 &r, str, strlen(str), NULL);
\r
8345 (void) SetTextColor(hdc, oldFg);
\r
8346 (void) SetBkColor(hdc, oldBg);
\r
8347 (void) SelectObject(hdc, oldFont);
\r
8352 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8358 if( count <= 0 ) {
\r
8359 if (appData.debugMode) {
\r
8360 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8363 return ERROR_INVALID_USER_BUFFER;
\r
8366 ResetEvent(ovl->hEvent);
\r
8367 ovl->Offset = ovl->OffsetHigh = 0;
\r
8368 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8372 err = GetLastError();
\r
8373 if (err == ERROR_IO_PENDING) {
\r
8374 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8378 err = GetLastError();
\r
8385 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8390 ResetEvent(ovl->hEvent);
\r
8391 ovl->Offset = ovl->OffsetHigh = 0;
\r
8392 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8396 err = GetLastError();
\r
8397 if (err == ERROR_IO_PENDING) {
\r
8398 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8402 err = GetLastError();
\r
8408 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8409 void CheckForInputBufferFull( InputSource * is )
\r
8411 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8412 /* Look for end of line */
\r
8413 char * p = is->buf;
\r
8415 while( p < is->next && *p != '\n' ) {
\r
8419 if( p >= is->next ) {
\r
8420 if (appData.debugMode) {
\r
8421 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8424 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8425 is->count = (DWORD) -1;
\r
8426 is->next = is->buf;
\r
8432 InputThread(LPVOID arg)
\r
8437 is = (InputSource *) arg;
\r
8438 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8439 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8440 while (is->hThread != NULL) {
\r
8441 is->error = DoReadFile(is->hFile, is->next,
\r
8442 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8443 &is->count, &ovl);
\r
8444 if (is->error == NO_ERROR) {
\r
8445 is->next += is->count;
\r
8447 if (is->error == ERROR_BROKEN_PIPE) {
\r
8448 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8451 is->count = (DWORD) -1;
\r
8452 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8457 CheckForInputBufferFull( is );
\r
8459 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8461 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8463 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8466 CloseHandle(ovl.hEvent);
\r
8467 CloseHandle(is->hFile);
\r
8469 if (appData.debugMode) {
\r
8470 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8477 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8479 NonOvlInputThread(LPVOID arg)
\r
8486 is = (InputSource *) arg;
\r
8487 while (is->hThread != NULL) {
\r
8488 is->error = ReadFile(is->hFile, is->next,
\r
8489 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8490 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8491 if (is->error == NO_ERROR) {
\r
8492 /* Change CRLF to LF */
\r
8493 if (is->next > is->buf) {
\r
8495 i = is->count + 1;
\r
8503 if (prev == '\r' && *p == '\n') {
\r
8515 if (is->error == ERROR_BROKEN_PIPE) {
\r
8516 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8519 is->count = (DWORD) -1;
\r
8523 CheckForInputBufferFull( is );
\r
8525 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8527 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8529 if (is->count < 0) break; /* Quit on error */
\r
8531 CloseHandle(is->hFile);
\r
8536 SocketInputThread(LPVOID arg)
\r
8540 is = (InputSource *) arg;
\r
8541 while (is->hThread != NULL) {
\r
8542 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8543 if ((int)is->count == SOCKET_ERROR) {
\r
8544 is->count = (DWORD) -1;
\r
8545 is->error = WSAGetLastError();
\r
8547 is->error = NO_ERROR;
\r
8548 is->next += is->count;
\r
8549 if (is->count == 0 && is->second == is) {
\r
8550 /* End of file on stderr; quit with no message */
\r
8554 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8556 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8558 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8564 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8568 is = (InputSource *) lParam;
\r
8569 if (is->lineByLine) {
\r
8570 /* Feed in lines one by one */
\r
8571 char *p = is->buf;
\r
8573 while (q < is->next) {
\r
8574 if (*q++ == '\n') {
\r
8575 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8580 /* Move any partial line to the start of the buffer */
\r
8582 while (p < is->next) {
\r
8587 if (is->error != NO_ERROR || is->count == 0) {
\r
8588 /* Notify backend of the error. Note: If there was a partial
\r
8589 line at the end, it is not flushed through. */
\r
8590 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8593 /* Feed in the whole chunk of input at once */
\r
8594 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8595 is->next = is->buf;
\r
8599 /*---------------------------------------------------------------------------*\
\r
8601 * Menu enables. Used when setting various modes.
\r
8603 \*---------------------------------------------------------------------------*/
\r
8611 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8613 while (enab->item > 0) {
\r
8614 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8619 Enables gnuEnables[] = {
\r
8620 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8621 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8622 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8623 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8624 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8625 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8626 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8627 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8628 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8629 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8633 Enables icsEnables[] = {
\r
8634 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8635 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8636 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8637 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8638 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8639 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8640 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8641 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8642 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8643 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8644 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8645 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8650 Enables zippyEnables[] = {
\r
8651 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8652 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8653 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8658 Enables ncpEnables[] = {
\r
8659 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8660 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8661 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8662 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8663 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8664 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8665 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8666 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8667 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8668 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8669 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8670 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8671 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8672 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8673 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8677 Enables trainingOnEnables[] = {
\r
8678 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8679 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8680 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8681 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8682 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8683 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8684 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8685 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8689 Enables trainingOffEnables[] = {
\r
8690 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8691 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8692 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8693 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8694 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8695 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8696 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8697 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8701 /* These modify either ncpEnables or gnuEnables */
\r
8702 Enables cmailEnables[] = {
\r
8703 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8704 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8705 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8706 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8707 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8708 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8709 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8713 Enables machineThinkingEnables[] = {
\r
8714 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8715 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8716 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8717 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8718 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8719 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8720 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8721 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8722 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8723 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8724 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8725 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8726 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8727 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8728 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8732 Enables userThinkingEnables[] = {
\r
8733 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8734 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8735 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8736 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8737 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8738 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8739 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8740 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8741 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8742 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8743 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8744 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8745 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8746 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8747 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8751 /*---------------------------------------------------------------------------*\
\r
8753 * Front-end interface functions exported by XBoard.
\r
8754 * Functions appear in same order as prototypes in frontend.h.
\r
8756 \*---------------------------------------------------------------------------*/
\r
8760 static UINT prevChecked = 0;
\r
8761 static int prevPausing = 0;
\r
8764 if (pausing != prevPausing) {
\r
8765 prevPausing = pausing;
\r
8766 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8767 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8768 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8771 switch (gameMode) {
\r
8772 case BeginningOfGame:
\r
8773 if (appData.icsActive)
\r
8774 nowChecked = IDM_IcsClient;
\r
8775 else if (appData.noChessProgram)
\r
8776 nowChecked = IDM_EditGame;
\r
8778 nowChecked = IDM_MachineBlack;
\r
8780 case MachinePlaysBlack:
\r
8781 nowChecked = IDM_MachineBlack;
\r
8783 case MachinePlaysWhite:
\r
8784 nowChecked = IDM_MachineWhite;
\r
8786 case TwoMachinesPlay:
\r
8787 nowChecked = IDM_TwoMachines;
\r
8790 nowChecked = IDM_AnalysisMode;
\r
8793 nowChecked = IDM_AnalyzeFile;
\r
8796 nowChecked = IDM_EditGame;
\r
8798 case PlayFromGameFile:
\r
8799 nowChecked = IDM_LoadGame;
\r
8801 case EditPosition:
\r
8802 nowChecked = IDM_EditPosition;
\r
8805 nowChecked = IDM_Training;
\r
8807 case IcsPlayingWhite:
\r
8808 case IcsPlayingBlack:
\r
8809 case IcsObserving:
\r
8811 nowChecked = IDM_IcsClient;
\r
8818 if (prevChecked != 0)
\r
8819 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8820 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8821 if (nowChecked != 0)
\r
8822 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8823 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8825 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8826 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8827 MF_BYCOMMAND|MF_ENABLED);
\r
8829 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8830 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8833 prevChecked = nowChecked;
\r
8835 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8836 if (appData.icsActive) {
\r
8837 if (appData.icsEngineAnalyze) {
\r
8838 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8839 MF_BYCOMMAND|MF_CHECKED);
\r
8841 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8842 MF_BYCOMMAND|MF_UNCHECKED);
\r
8850 HMENU hmenu = GetMenu(hwndMain);
\r
8851 SetMenuEnables(hmenu, icsEnables);
\r
8852 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8853 MF_BYPOSITION|MF_ENABLED);
\r
8855 if (appData.zippyPlay) {
\r
8856 SetMenuEnables(hmenu, zippyEnables);
\r
8857 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8858 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8859 MF_BYCOMMAND|MF_ENABLED);
\r
8867 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8873 HMENU hmenu = GetMenu(hwndMain);
\r
8874 SetMenuEnables(hmenu, ncpEnables);
\r
8875 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8876 MF_BYPOSITION|MF_GRAYED);
\r
8877 DrawMenuBar(hwndMain);
\r
8883 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8887 SetTrainingModeOn()
\r
8890 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8891 for (i = 0; i < N_BUTTONS; i++) {
\r
8892 if (buttonDesc[i].hwnd != NULL)
\r
8893 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8898 VOID SetTrainingModeOff()
\r
8901 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8902 for (i = 0; i < N_BUTTONS; i++) {
\r
8903 if (buttonDesc[i].hwnd != NULL)
\r
8904 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8910 SetUserThinkingEnables()
\r
8912 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8916 SetMachineThinkingEnables()
\r
8918 HMENU hMenu = GetMenu(hwndMain);
\r
8919 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8921 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8923 if (gameMode == MachinePlaysBlack) {
\r
8924 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8925 } else if (gameMode == MachinePlaysWhite) {
\r
8926 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8927 } else if (gameMode == TwoMachinesPlay) {
\r
8928 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8934 DisplayTitle(char *str)
\r
8936 char title[MSG_SIZ], *host;
\r
8937 if (str[0] != NULLCHAR) {
\r
8938 strcpy(title, str);
\r
8939 } else if (appData.icsActive) {
\r
8940 if (appData.icsCommPort[0] != NULLCHAR)
\r
8943 host = appData.icsHost;
\r
8944 sprintf(title, "%s: %s", szTitle, host);
\r
8945 } else if (appData.noChessProgram) {
\r
8946 strcpy(title, szTitle);
\r
8948 strcpy(title, szTitle);
\r
8949 strcat(title, ": ");
\r
8950 strcat(title, first.tidy);
\r
8952 SetWindowText(hwndMain, title);
\r
8957 DisplayMessage(char *str1, char *str2)
\r
8961 int remain = MESSAGE_TEXT_MAX - 1;
\r
8964 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8965 messageText[0] = NULLCHAR;
\r
8967 len = strlen(str1);
\r
8968 if (len > remain) len = remain;
\r
8969 strncpy(messageText, str1, len);
\r
8970 messageText[len] = NULLCHAR;
\r
8973 if (*str2 && remain >= 2) {
\r
8975 strcat(messageText, " ");
\r
8978 len = strlen(str2);
\r
8979 if (len > remain) len = remain;
\r
8980 strncat(messageText, str2, len);
\r
8982 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8984 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8985 hdc = GetDC(hwndMain);
\r
8986 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8987 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8988 &messageRect, messageText, strlen(messageText), NULL);
\r
8989 (void) SelectObject(hdc, oldFont);
\r
8990 (void) ReleaseDC(hwndMain, hdc);
\r
8994 DisplayError(char *str, int error)
\r
8996 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9002 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9003 NULL, error, LANG_NEUTRAL,
\r
9004 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9006 sprintf(buf, "%s:\n%s", str, buf2);
\r
9008 ErrorMap *em = errmap;
\r
9009 while (em->err != 0 && em->err != error) em++;
\r
9010 if (em->err != 0) {
\r
9011 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9013 sprintf(buf, "%s:\nError code %d", str, error);
\r
9018 ErrorPopUp("Error", buf);
\r
9023 DisplayMoveError(char *str)
\r
9025 fromX = fromY = -1;
\r
9026 ClearHighlights();
\r
9027 DrawPosition(FALSE, NULL);
\r
9028 if (appData.popupMoveErrors) {
\r
9029 ErrorPopUp("Error", str);
\r
9031 DisplayMessage(str, "");
\r
9032 moveErrorMessageUp = TRUE;
\r
9037 DisplayFatalError(char *str, int error, int exitStatus)
\r
9039 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9041 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9044 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9045 NULL, error, LANG_NEUTRAL,
\r
9046 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9048 sprintf(buf, "%s:\n%s", str, buf2);
\r
9050 ErrorMap *em = errmap;
\r
9051 while (em->err != 0 && em->err != error) em++;
\r
9052 if (em->err != 0) {
\r
9053 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9055 sprintf(buf, "%s:\nError code %d", str, error);
\r
9060 if (appData.debugMode) {
\r
9061 fprintf(debugFP, "%s: %s\n", label, str);
\r
9063 if (appData.popupExitMessage) {
\r
9064 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9065 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9067 ExitEvent(exitStatus);
\r
9072 DisplayInformation(char *str)
\r
9074 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9079 DisplayNote(char *str)
\r
9081 ErrorPopUp("Note", str);
\r
9086 char *title, *question, *replyPrefix;
\r
9091 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9093 static QuestionParams *qp;
\r
9094 char reply[MSG_SIZ];
\r
9097 switch (message) {
\r
9098 case WM_INITDIALOG:
\r
9099 qp = (QuestionParams *) lParam;
\r
9100 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9101 SetWindowText(hDlg, qp->title);
\r
9102 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9103 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9107 switch (LOWORD(wParam)) {
\r
9109 strcpy(reply, qp->replyPrefix);
\r
9110 if (*reply) strcat(reply, " ");
\r
9111 len = strlen(reply);
\r
9112 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9113 strcat(reply, "\n");
\r
9114 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9115 EndDialog(hDlg, TRUE);
\r
9116 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9119 EndDialog(hDlg, FALSE);
\r
9130 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9132 QuestionParams qp;
\r
9136 qp.question = question;
\r
9137 qp.replyPrefix = replyPrefix;
\r
9139 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9140 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9141 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9142 FreeProcInstance(lpProc);
\r
9145 /* [AS] Pick FRC position */
\r
9146 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9148 static int * lpIndexFRC;
\r
9154 case WM_INITDIALOG:
\r
9155 lpIndexFRC = (int *) lParam;
\r
9157 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9159 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9160 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9161 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9162 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9167 switch( LOWORD(wParam) ) {
\r
9169 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9170 EndDialog( hDlg, 0 );
\r
9171 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9174 EndDialog( hDlg, 1 );
\r
9176 case IDC_NFG_Edit:
\r
9177 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9178 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9180 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9183 case IDC_NFG_Random:
\r
9184 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9185 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9198 int index = appData.defaultFrcPosition;
\r
9199 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9201 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9203 if( result == 0 ) {
\r
9204 appData.defaultFrcPosition = index;
\r
9210 /* [AS] Game list options */
\r
9216 static GLT_Item GLT_ItemInfo[] = {
\r
9217 { GLT_EVENT, "Event" },
\r
9218 { GLT_SITE, "Site" },
\r
9219 { GLT_DATE, "Date" },
\r
9220 { GLT_ROUND, "Round" },
\r
9221 { GLT_PLAYERS, "Players" },
\r
9222 { GLT_RESULT, "Result" },
\r
9223 { GLT_WHITE_ELO, "White Rating" },
\r
9224 { GLT_BLACK_ELO, "Black Rating" },
\r
9225 { GLT_TIME_CONTROL,"Time Control" },
\r
9226 { GLT_VARIANT, "Variant" },
\r
9227 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9231 const char * GLT_FindItem( char id )
\r
9233 const char * result = 0;
\r
9235 GLT_Item * list = GLT_ItemInfo;
\r
9237 while( list->id != 0 ) {
\r
9238 if( list->id == id ) {
\r
9239 result = list->name;
\r
9249 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9251 const char * name = GLT_FindItem( id );
\r
9254 if( index >= 0 ) {
\r
9255 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9258 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9263 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9267 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9270 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9274 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9276 pc = GLT_ALL_TAGS;
\r
9279 if( strchr( tags, *pc ) == 0 ) {
\r
9280 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9285 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9288 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9290 char result = '\0';
\r
9293 GLT_Item * list = GLT_ItemInfo;
\r
9295 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9296 while( list->id != 0 ) {
\r
9297 if( strcmp( list->name, name ) == 0 ) {
\r
9298 result = list->id;
\r
9309 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9311 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9312 int idx2 = idx1 + delta;
\r
9313 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9315 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9318 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9319 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9320 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9321 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9325 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9327 static char glt[64];
\r
9328 static char * lpUserGLT;
\r
9332 case WM_INITDIALOG:
\r
9333 lpUserGLT = (char *) lParam;
\r
9335 strcpy( glt, lpUserGLT );
\r
9337 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9339 /* Initialize list */
\r
9340 GLT_TagsToList( hDlg, glt );
\r
9342 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9347 switch( LOWORD(wParam) ) {
\r
9350 char * pc = lpUserGLT;
\r
9352 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9356 id = GLT_ListItemToTag( hDlg, idx );
\r
9360 } while( id != '\0' );
\r
9362 EndDialog( hDlg, 0 );
\r
9365 EndDialog( hDlg, 1 );
\r
9368 case IDC_GLT_Default:
\r
9369 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9370 GLT_TagsToList( hDlg, glt );
\r
9373 case IDC_GLT_Restore:
\r
9374 strcpy( glt, lpUserGLT );
\r
9375 GLT_TagsToList( hDlg, glt );
\r
9379 GLT_MoveSelection( hDlg, -1 );
\r
9382 case IDC_GLT_Down:
\r
9383 GLT_MoveSelection( hDlg, +1 );
\r
9393 int GameListOptions()
\r
9397 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9399 strcpy( glt, appData.gameListTags );
\r
9401 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9403 if( result == 0 ) {
\r
9404 /* [AS] Memory leak here! */
\r
9405 appData.gameListTags = strdup( glt );
\r
9413 DisplayIcsInteractionTitle(char *str)
\r
9415 char consoleTitle[MSG_SIZ];
\r
9417 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9418 SetWindowText(hwndConsole, consoleTitle);
\r
9422 DrawPosition(int fullRedraw, Board board)
\r
9424 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9431 fromX = fromY = -1;
\r
9432 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9433 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9434 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9435 dragInfo.lastpos = dragInfo.pos;
\r
9436 dragInfo.start.x = dragInfo.start.y = -1;
\r
9437 dragInfo.from = dragInfo.start;
\r
9439 DrawPosition(TRUE, NULL);
\r
9445 CommentPopUp(char *title, char *str)
\r
9447 HWND hwnd = GetActiveWindow();
\r
9448 EitherCommentPopUp(0, title, str, FALSE);
\r
9449 SetActiveWindow(hwnd);
\r
9453 CommentPopDown(void)
\r
9455 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9456 if (commentDialog) {
\r
9457 ShowWindow(commentDialog, SW_HIDE);
\r
9459 commentDialogUp = FALSE;
\r
9463 EditCommentPopUp(int index, char *title, char *str)
\r
9465 EitherCommentPopUp(index, title, str, TRUE);
\r
9472 MyPlaySound(&sounds[(int)SoundMove]);
\r
9475 VOID PlayIcsWinSound()
\r
9477 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9480 VOID PlayIcsLossSound()
\r
9482 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9485 VOID PlayIcsDrawSound()
\r
9487 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9490 VOID PlayIcsUnfinishedSound()
\r
9492 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9498 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9506 consoleEcho = TRUE;
\r
9507 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9508 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9509 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9518 consoleEcho = FALSE;
\r
9519 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9520 /* This works OK: set text and background both to the same color */
\r
9522 cf.crTextColor = COLOR_ECHOOFF;
\r
9523 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9524 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9527 /* No Raw()...? */
\r
9529 void Colorize(ColorClass cc, int continuation)
\r
9531 currentColorClass = cc;
\r
9532 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9533 consoleCF.crTextColor = textAttribs[cc].color;
\r
9534 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9535 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9541 static char buf[MSG_SIZ];
\r
9542 DWORD bufsiz = MSG_SIZ;
\r
9544 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9545 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9547 if (!GetUserName(buf, &bufsiz)) {
\r
9548 /*DisplayError("Error getting user name", GetLastError());*/
\r
9549 strcpy(buf, "User");
\r
9557 static char buf[MSG_SIZ];
\r
9558 DWORD bufsiz = MSG_SIZ;
\r
9560 if (!GetComputerName(buf, &bufsiz)) {
\r
9561 /*DisplayError("Error getting host name", GetLastError());*/
\r
9562 strcpy(buf, "Unknown");
\r
9569 ClockTimerRunning()
\r
9571 return clockTimerEvent != 0;
\r
9577 if (clockTimerEvent == 0) return FALSE;
\r
9578 KillTimer(hwndMain, clockTimerEvent);
\r
9579 clockTimerEvent = 0;
\r
9584 StartClockTimer(long millisec)
\r
9586 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9587 (UINT) millisec, NULL);
\r
9591 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9594 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9596 if(appData.noGUI) return;
\r
9597 hdc = GetDC(hwndMain);
\r
9598 if (!IsIconic(hwndMain)) {
\r
9599 DisplayAClock(hdc, timeRemaining, highlight,
\r
9600 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9602 if (highlight && iconCurrent == iconBlack) {
\r
9603 iconCurrent = iconWhite;
\r
9604 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9605 if (IsIconic(hwndMain)) {
\r
9606 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9609 (void) ReleaseDC(hwndMain, hdc);
\r
9611 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9615 DisplayBlackClock(long timeRemaining, int highlight)
\r
9618 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9620 if(appData.noGUI) return;
\r
9621 hdc = GetDC(hwndMain);
\r
9622 if (!IsIconic(hwndMain)) {
\r
9623 DisplayAClock(hdc, timeRemaining, highlight,
\r
9624 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9626 if (highlight && iconCurrent == iconWhite) {
\r
9627 iconCurrent = iconBlack;
\r
9628 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9629 if (IsIconic(hwndMain)) {
\r
9630 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9633 (void) ReleaseDC(hwndMain, hdc);
\r
9635 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9640 LoadGameTimerRunning()
\r
9642 return loadGameTimerEvent != 0;
\r
9646 StopLoadGameTimer()
\r
9648 if (loadGameTimerEvent == 0) return FALSE;
\r
9649 KillTimer(hwndMain, loadGameTimerEvent);
\r
9650 loadGameTimerEvent = 0;
\r
9655 StartLoadGameTimer(long millisec)
\r
9657 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9658 (UINT) millisec, NULL);
\r
9666 char fileTitle[MSG_SIZ];
\r
9668 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9669 f = OpenFileDialog(hwndMain, "a", defName,
\r
9670 appData.oldSaveStyle ? "gam" : "pgn",
\r
9672 "Save Game to File", NULL, fileTitle, NULL);
\r
9674 SaveGame(f, 0, "");
\r
9681 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9683 if (delayedTimerEvent != 0) {
\r
9684 if (appData.debugMode) {
\r
9685 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9687 KillTimer(hwndMain, delayedTimerEvent);
\r
9688 delayedTimerEvent = 0;
\r
9689 delayedTimerCallback();
\r
9691 delayedTimerCallback = cb;
\r
9692 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9693 (UINT) millisec, NULL);
\r
9696 DelayedEventCallback
\r
9699 if (delayedTimerEvent) {
\r
9700 return delayedTimerCallback;
\r
9707 CancelDelayedEvent()
\r
9709 if (delayedTimerEvent) {
\r
9710 KillTimer(hwndMain, delayedTimerEvent);
\r
9711 delayedTimerEvent = 0;
\r
9715 DWORD GetWin32Priority(int nice)
\r
9716 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9718 REALTIME_PRIORITY_CLASS 0x00000100
\r
9719 HIGH_PRIORITY_CLASS 0x00000080
\r
9720 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9721 NORMAL_PRIORITY_CLASS 0x00000020
\r
9722 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9723 IDLE_PRIORITY_CLASS 0x00000040
\r
9725 if (nice < -15) return 0x00000080;
\r
9726 if (nice < 0) return 0x00008000;
\r
9727 if (nice == 0) return 0x00000020;
\r
9728 if (nice < 15) return 0x00004000;
\r
9729 return 0x00000040;
\r
9732 /* Start a child process running the given program.
\r
9733 The process's standard output can be read from "from", and its
\r
9734 standard input can be written to "to".
\r
9735 Exit with fatal error if anything goes wrong.
\r
9736 Returns an opaque pointer that can be used to destroy the process
\r
9740 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9742 #define BUFSIZE 4096
\r
9744 HANDLE hChildStdinRd, hChildStdinWr,
\r
9745 hChildStdoutRd, hChildStdoutWr;
\r
9746 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9747 SECURITY_ATTRIBUTES saAttr;
\r
9749 PROCESS_INFORMATION piProcInfo;
\r
9750 STARTUPINFO siStartInfo;
\r
9752 char buf[MSG_SIZ];
\r
9755 if (appData.debugMode) {
\r
9756 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9761 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9762 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9763 saAttr.bInheritHandle = TRUE;
\r
9764 saAttr.lpSecurityDescriptor = NULL;
\r
9767 * The steps for redirecting child's STDOUT:
\r
9768 * 1. Create anonymous pipe to be STDOUT for child.
\r
9769 * 2. Create a noninheritable duplicate of read handle,
\r
9770 * and close the inheritable read handle.
\r
9773 /* Create a pipe for the child's STDOUT. */
\r
9774 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9775 return GetLastError();
\r
9778 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9779 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9780 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9781 FALSE, /* not inherited */
\r
9782 DUPLICATE_SAME_ACCESS);
\r
9784 return GetLastError();
\r
9786 CloseHandle(hChildStdoutRd);
\r
9789 * The steps for redirecting child's STDIN:
\r
9790 * 1. Create anonymous pipe to be STDIN for child.
\r
9791 * 2. Create a noninheritable duplicate of write handle,
\r
9792 * and close the inheritable write handle.
\r
9795 /* Create a pipe for the child's STDIN. */
\r
9796 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9797 return GetLastError();
\r
9800 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9801 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9802 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9803 FALSE, /* not inherited */
\r
9804 DUPLICATE_SAME_ACCESS);
\r
9806 return GetLastError();
\r
9808 CloseHandle(hChildStdinWr);
\r
9810 /* Arrange to (1) look in dir for the child .exe file, and
\r
9811 * (2) have dir be the child's working directory. Interpret
\r
9812 * dir relative to the directory WinBoard loaded from. */
\r
9813 GetCurrentDirectory(MSG_SIZ, buf);
\r
9814 SetCurrentDirectory(installDir);
\r
9815 SetCurrentDirectory(dir);
\r
9817 /* Now create the child process. */
\r
9819 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9820 siStartInfo.lpReserved = NULL;
\r
9821 siStartInfo.lpDesktop = NULL;
\r
9822 siStartInfo.lpTitle = NULL;
\r
9823 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9824 siStartInfo.cbReserved2 = 0;
\r
9825 siStartInfo.lpReserved2 = NULL;
\r
9826 siStartInfo.hStdInput = hChildStdinRd;
\r
9827 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9828 siStartInfo.hStdError = hChildStdoutWr;
\r
9830 fSuccess = CreateProcess(NULL,
\r
9831 cmdLine, /* command line */
\r
9832 NULL, /* process security attributes */
\r
9833 NULL, /* primary thread security attrs */
\r
9834 TRUE, /* handles are inherited */
\r
9835 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9836 NULL, /* use parent's environment */
\r
9838 &siStartInfo, /* STARTUPINFO pointer */
\r
9839 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9841 err = GetLastError();
\r
9842 SetCurrentDirectory(buf); /* return to prev directory */
\r
9847 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9848 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9849 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9852 /* Close the handles we don't need in the parent */
\r
9853 CloseHandle(piProcInfo.hThread);
\r
9854 CloseHandle(hChildStdinRd);
\r
9855 CloseHandle(hChildStdoutWr);
\r
9857 /* Prepare return value */
\r
9858 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9859 cp->kind = CPReal;
\r
9860 cp->hProcess = piProcInfo.hProcess;
\r
9861 cp->pid = piProcInfo.dwProcessId;
\r
9862 cp->hFrom = hChildStdoutRdDup;
\r
9863 cp->hTo = hChildStdinWrDup;
\r
9865 *pr = (void *) cp;
\r
9867 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9868 2000 where engines sometimes don't see the initial command(s)
\r
9869 from WinBoard and hang. I don't understand how that can happen,
\r
9870 but the Sleep is harmless, so I've put it in. Others have also
\r
9871 reported what may be the same problem, so hopefully this will fix
\r
9872 it for them too. */
\r
9880 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9882 ChildProc *cp; int result;
\r
9884 cp = (ChildProc *) pr;
\r
9885 if (cp == NULL) return;
\r
9887 switch (cp->kind) {
\r
9889 /* TerminateProcess is considered harmful, so... */
\r
9890 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9891 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9892 /* The following doesn't work because the chess program
\r
9893 doesn't "have the same console" as WinBoard. Maybe
\r
9894 we could arrange for this even though neither WinBoard
\r
9895 nor the chess program uses a console for stdio? */
\r
9896 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9898 /* [AS] Special termination modes for misbehaving programs... */
\r
9899 if( signal == 9 ) {
\r
9900 result = TerminateProcess( cp->hProcess, 0 );
\r
9902 if ( appData.debugMode) {
\r
9903 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9906 else if( signal == 10 ) {
\r
9907 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9909 if( dw != WAIT_OBJECT_0 ) {
\r
9910 result = TerminateProcess( cp->hProcess, 0 );
\r
9912 if ( appData.debugMode) {
\r
9913 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9919 CloseHandle(cp->hProcess);
\r
9923 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9927 closesocket(cp->sock);
\r
9932 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9933 closesocket(cp->sock);
\r
9934 closesocket(cp->sock2);
\r
9942 InterruptChildProcess(ProcRef pr)
\r
9946 cp = (ChildProc *) pr;
\r
9947 if (cp == NULL) return;
\r
9948 switch (cp->kind) {
\r
9950 /* The following doesn't work because the chess program
\r
9951 doesn't "have the same console" as WinBoard. Maybe
\r
9952 we could arrange for this even though neither WinBoard
\r
9953 nor the chess program uses a console for stdio */
\r
9954 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9959 /* Can't interrupt */
\r
9963 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9970 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9972 char cmdLine[MSG_SIZ];
\r
9974 if (port[0] == NULLCHAR) {
\r
9975 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9977 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9979 return StartChildProcess(cmdLine, "", pr);
\r
9983 /* Code to open TCP sockets */
\r
9986 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9991 struct sockaddr_in sa, mysa;
\r
9992 struct hostent FAR *hp;
\r
9993 unsigned short uport;
\r
9994 WORD wVersionRequested;
\r
9997 /* Initialize socket DLL */
\r
9998 wVersionRequested = MAKEWORD(1, 1);
\r
9999 err = WSAStartup(wVersionRequested, &wsaData);
\r
10000 if (err != 0) return err;
\r
10002 /* Make socket */
\r
10003 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10004 err = WSAGetLastError();
\r
10009 /* Bind local address using (mostly) don't-care values.
\r
10011 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10012 mysa.sin_family = AF_INET;
\r
10013 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10014 uport = (unsigned short) 0;
\r
10015 mysa.sin_port = htons(uport);
\r
10016 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10017 == SOCKET_ERROR) {
\r
10018 err = WSAGetLastError();
\r
10023 /* Resolve remote host name */
\r
10024 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10025 if (!(hp = gethostbyname(host))) {
\r
10026 unsigned int b0, b1, b2, b3;
\r
10028 err = WSAGetLastError();
\r
10030 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10031 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10032 hp->h_addrtype = AF_INET;
\r
10033 hp->h_length = 4;
\r
10034 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10035 hp->h_addr_list[0] = (char *) malloc(4);
\r
10036 hp->h_addr_list[0][0] = (char) b0;
\r
10037 hp->h_addr_list[0][1] = (char) b1;
\r
10038 hp->h_addr_list[0][2] = (char) b2;
\r
10039 hp->h_addr_list[0][3] = (char) b3;
\r
10045 sa.sin_family = hp->h_addrtype;
\r
10046 uport = (unsigned short) atoi(port);
\r
10047 sa.sin_port = htons(uport);
\r
10048 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10050 /* Make connection */
\r
10051 if (connect(s, (struct sockaddr *) &sa,
\r
10052 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10053 err = WSAGetLastError();
\r
10058 /* Prepare return value */
\r
10059 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10060 cp->kind = CPSock;
\r
10062 *pr = (ProcRef *) cp;
\r
10068 OpenCommPort(char *name, ProcRef *pr)
\r
10073 char fullname[MSG_SIZ];
\r
10075 if (*name != '\\')
\r
10076 sprintf(fullname, "\\\\.\\%s", name);
\r
10078 strcpy(fullname, name);
\r
10080 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10081 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10082 if (h == (HANDLE) -1) {
\r
10083 return GetLastError();
\r
10087 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10089 /* Accumulate characters until a 100ms pause, then parse */
\r
10090 ct.ReadIntervalTimeout = 100;
\r
10091 ct.ReadTotalTimeoutMultiplier = 0;
\r
10092 ct.ReadTotalTimeoutConstant = 0;
\r
10093 ct.WriteTotalTimeoutMultiplier = 0;
\r
10094 ct.WriteTotalTimeoutConstant = 0;
\r
10095 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10097 /* Prepare return value */
\r
10098 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10099 cp->kind = CPComm;
\r
10102 *pr = (ProcRef *) cp;
\r
10108 OpenLoopback(ProcRef *pr)
\r
10110 DisplayFatalError("Not implemented", 0, 1);
\r
10116 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10120 SOCKET s, s2, s3;
\r
10121 struct sockaddr_in sa, mysa;
\r
10122 struct hostent FAR *hp;
\r
10123 unsigned short uport;
\r
10124 WORD wVersionRequested;
\r
10127 char stderrPortStr[MSG_SIZ];
\r
10129 /* Initialize socket DLL */
\r
10130 wVersionRequested = MAKEWORD(1, 1);
\r
10131 err = WSAStartup(wVersionRequested, &wsaData);
\r
10132 if (err != 0) return err;
\r
10134 /* Resolve remote host name */
\r
10135 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10136 if (!(hp = gethostbyname(host))) {
\r
10137 unsigned int b0, b1, b2, b3;
\r
10139 err = WSAGetLastError();
\r
10141 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10142 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10143 hp->h_addrtype = AF_INET;
\r
10144 hp->h_length = 4;
\r
10145 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10146 hp->h_addr_list[0] = (char *) malloc(4);
\r
10147 hp->h_addr_list[0][0] = (char) b0;
\r
10148 hp->h_addr_list[0][1] = (char) b1;
\r
10149 hp->h_addr_list[0][2] = (char) b2;
\r
10150 hp->h_addr_list[0][3] = (char) b3;
\r
10156 sa.sin_family = hp->h_addrtype;
\r
10157 uport = (unsigned short) 514;
\r
10158 sa.sin_port = htons(uport);
\r
10159 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10161 /* Bind local socket to unused "privileged" port address
\r
10163 s = INVALID_SOCKET;
\r
10164 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10165 mysa.sin_family = AF_INET;
\r
10166 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10167 for (fromPort = 1023;; fromPort--) {
\r
10168 if (fromPort < 0) {
\r
10170 return WSAEADDRINUSE;
\r
10172 if (s == INVALID_SOCKET) {
\r
10173 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10174 err = WSAGetLastError();
\r
10179 uport = (unsigned short) fromPort;
\r
10180 mysa.sin_port = htons(uport);
\r
10181 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10182 == SOCKET_ERROR) {
\r
10183 err = WSAGetLastError();
\r
10184 if (err == WSAEADDRINUSE) continue;
\r
10188 if (connect(s, (struct sockaddr *) &sa,
\r
10189 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10190 err = WSAGetLastError();
\r
10191 if (err == WSAEADDRINUSE) {
\r
10202 /* Bind stderr local socket to unused "privileged" port address
\r
10204 s2 = INVALID_SOCKET;
\r
10205 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10206 mysa.sin_family = AF_INET;
\r
10207 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10208 for (fromPort = 1023;; fromPort--) {
\r
10209 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10210 if (fromPort < 0) {
\r
10211 (void) closesocket(s);
\r
10213 return WSAEADDRINUSE;
\r
10215 if (s2 == INVALID_SOCKET) {
\r
10216 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10217 err = WSAGetLastError();
\r
10223 uport = (unsigned short) fromPort;
\r
10224 mysa.sin_port = htons(uport);
\r
10225 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10226 == SOCKET_ERROR) {
\r
10227 err = WSAGetLastError();
\r
10228 if (err == WSAEADDRINUSE) continue;
\r
10229 (void) closesocket(s);
\r
10233 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10234 err = WSAGetLastError();
\r
10235 if (err == WSAEADDRINUSE) {
\r
10237 s2 = INVALID_SOCKET;
\r
10240 (void) closesocket(s);
\r
10241 (void) closesocket(s2);
\r
10247 prevStderrPort = fromPort; // remember port used
\r
10248 sprintf(stderrPortStr, "%d", fromPort);
\r
10250 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10251 err = WSAGetLastError();
\r
10252 (void) closesocket(s);
\r
10253 (void) closesocket(s2);
\r
10258 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10259 err = WSAGetLastError();
\r
10260 (void) closesocket(s);
\r
10261 (void) closesocket(s2);
\r
10265 if (*user == NULLCHAR) user = UserName();
\r
10266 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10267 err = WSAGetLastError();
\r
10268 (void) closesocket(s);
\r
10269 (void) closesocket(s2);
\r
10273 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10274 err = WSAGetLastError();
\r
10275 (void) closesocket(s);
\r
10276 (void) closesocket(s2);
\r
10281 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10282 err = WSAGetLastError();
\r
10283 (void) closesocket(s);
\r
10284 (void) closesocket(s2);
\r
10288 (void) closesocket(s2); /* Stop listening */
\r
10290 /* Prepare return value */
\r
10291 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10292 cp->kind = CPRcmd;
\r
10295 *pr = (ProcRef *) cp;
\r
10302 AddInputSource(ProcRef pr, int lineByLine,
\r
10303 InputCallback func, VOIDSTAR closure)
\r
10305 InputSource *is, *is2 = NULL;
\r
10306 ChildProc *cp = (ChildProc *) pr;
\r
10308 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10309 is->lineByLine = lineByLine;
\r
10311 is->closure = closure;
\r
10312 is->second = NULL;
\r
10313 is->next = is->buf;
\r
10314 if (pr == NoProc) {
\r
10315 is->kind = CPReal;
\r
10316 consoleInputSource = is;
\r
10318 is->kind = cp->kind;
\r
10320 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10321 we create all threads suspended so that the is->hThread variable can be
\r
10322 safely assigned, then let the threads start with ResumeThread.
\r
10324 switch (cp->kind) {
\r
10326 is->hFile = cp->hFrom;
\r
10327 cp->hFrom = NULL; /* now owned by InputThread */
\r
10329 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10330 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10334 is->hFile = cp->hFrom;
\r
10335 cp->hFrom = NULL; /* now owned by InputThread */
\r
10337 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10338 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10342 is->sock = cp->sock;
\r
10344 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10345 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10349 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10351 is->sock = cp->sock;
\r
10352 is->second = is2;
\r
10353 is2->sock = cp->sock2;
\r
10354 is2->second = is2;
\r
10356 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10357 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10359 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10360 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10364 if( is->hThread != NULL ) {
\r
10365 ResumeThread( is->hThread );
\r
10368 if( is2 != NULL && is2->hThread != NULL ) {
\r
10369 ResumeThread( is2->hThread );
\r
10373 return (InputSourceRef) is;
\r
10377 RemoveInputSource(InputSourceRef isr)
\r
10381 is = (InputSource *) isr;
\r
10382 is->hThread = NULL; /* tell thread to stop */
\r
10383 CloseHandle(is->hThread);
\r
10384 if (is->second != NULL) {
\r
10385 is->second->hThread = NULL;
\r
10386 CloseHandle(is->second->hThread);
\r
10392 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10395 int outCount = SOCKET_ERROR;
\r
10396 ChildProc *cp = (ChildProc *) pr;
\r
10397 static OVERLAPPED ovl;
\r
10399 if (pr == NoProc) {
\r
10400 ConsoleOutput(message, count, FALSE);
\r
10404 if (ovl.hEvent == NULL) {
\r
10405 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10407 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10409 switch (cp->kind) {
\r
10412 outCount = send(cp->sock, message, count, 0);
\r
10413 if (outCount == SOCKET_ERROR) {
\r
10414 *outError = WSAGetLastError();
\r
10416 *outError = NO_ERROR;
\r
10421 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10422 &dOutCount, NULL)) {
\r
10423 *outError = NO_ERROR;
\r
10424 outCount = (int) dOutCount;
\r
10426 *outError = GetLastError();
\r
10431 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10432 &dOutCount, &ovl);
\r
10433 if (*outError == NO_ERROR) {
\r
10434 outCount = (int) dOutCount;
\r
10442 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10445 /* Ignore delay, not implemented for WinBoard */
\r
10446 return OutputToProcess(pr, message, count, outError);
\r
10451 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10452 char *buf, int count, int error)
\r
10454 DisplayFatalError("Not implemented", 0, 1);
\r
10457 /* see wgamelist.c for Game List functions */
\r
10458 /* see wedittags.c for Edit Tags functions */
\r
10465 char buf[MSG_SIZ];
\r
10468 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10469 f = fopen(buf, "r");
\r
10471 ProcessICSInitScript(f);
\r
10479 StartAnalysisClock()
\r
10481 if (analysisTimerEvent) return;
\r
10482 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10483 (UINT) 2000, NULL);
\r
10487 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10489 static HANDLE hwndText;
\r
10491 static int sizeX, sizeY;
\r
10492 int newSizeX, newSizeY, flags;
\r
10495 switch (message) {
\r
10496 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10497 /* Initialize the dialog items */
\r
10498 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10499 SetWindowText(hDlg, analysisTitle);
\r
10500 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10501 /* Size and position the dialog */
\r
10502 if (!analysisDialog) {
\r
10503 analysisDialog = hDlg;
\r
10504 flags = SWP_NOZORDER;
\r
10505 GetClientRect(hDlg, &rect);
\r
10506 sizeX = rect.right;
\r
10507 sizeY = rect.bottom;
\r
10508 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10509 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10510 WINDOWPLACEMENT wp;
\r
10511 EnsureOnScreen(&analysisX, &analysisY);
\r
10512 wp.length = sizeof(WINDOWPLACEMENT);
\r
10514 wp.showCmd = SW_SHOW;
\r
10515 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10516 wp.rcNormalPosition.left = analysisX;
\r
10517 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10518 wp.rcNormalPosition.top = analysisY;
\r
10519 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10520 SetWindowPlacement(hDlg, &wp);
\r
10522 GetClientRect(hDlg, &rect);
\r
10523 newSizeX = rect.right;
\r
10524 newSizeY = rect.bottom;
\r
10525 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10526 newSizeX, newSizeY);
\r
10527 sizeX = newSizeX;
\r
10528 sizeY = newSizeY;
\r
10533 case WM_COMMAND: /* message: received a command */
\r
10534 switch (LOWORD(wParam)) {
\r
10536 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10537 ExitAnalyzeMode();
\r
10549 newSizeX = LOWORD(lParam);
\r
10550 newSizeY = HIWORD(lParam);
\r
10551 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10552 sizeX = newSizeX;
\r
10553 sizeY = newSizeY;
\r
10556 case WM_GETMINMAXINFO:
\r
10557 /* Prevent resizing window too small */
\r
10558 mmi = (MINMAXINFO *) lParam;
\r
10559 mmi->ptMinTrackSize.x = 100;
\r
10560 mmi->ptMinTrackSize.y = 100;
\r
10567 AnalysisPopUp(char* title, char* str)
\r
10573 EngineOutputPopUp();
\r
10576 if (str == NULL) str = "";
\r
10577 p = (char *) malloc(2 * strlen(str) + 2);
\r
10580 if (*str == '\n') *q++ = '\r';
\r
10584 if (analysisText != NULL) free(analysisText);
\r
10585 analysisText = p;
\r
10587 if (analysisDialog) {
\r
10588 SetWindowText(analysisDialog, title);
\r
10589 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10590 ShowWindow(analysisDialog, SW_SHOW);
\r
10592 analysisTitle = title;
\r
10593 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10594 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10595 hwndMain, (DLGPROC)lpProc);
\r
10596 FreeProcInstance(lpProc);
\r
10598 analysisDialogUp = TRUE;
\r
10602 AnalysisPopDown()
\r
10604 if (analysisDialog) {
\r
10605 ShowWindow(analysisDialog, SW_HIDE);
\r
10607 analysisDialogUp = FALSE;
\r
10612 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10614 highlightInfo.sq[0].x = fromX;
\r
10615 highlightInfo.sq[0].y = fromY;
\r
10616 highlightInfo.sq[1].x = toX;
\r
10617 highlightInfo.sq[1].y = toY;
\r
10621 ClearHighlights()
\r
10623 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10624 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10628 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10630 premoveHighlightInfo.sq[0].x = fromX;
\r
10631 premoveHighlightInfo.sq[0].y = fromY;
\r
10632 premoveHighlightInfo.sq[1].x = toX;
\r
10633 premoveHighlightInfo.sq[1].y = toY;
\r
10637 ClearPremoveHighlights()
\r
10639 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10640 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10644 ShutDownFrontEnd()
\r
10646 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10647 DeleteClipboardTempFiles();
\r
10653 if (IsIconic(hwndMain))
\r
10654 ShowWindow(hwndMain, SW_RESTORE);
\r
10656 SetActiveWindow(hwndMain);
\r
10660 * Prototypes for animation support routines
\r
10662 static void ScreenSquare(int column, int row, POINT * pt);
\r
10663 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10664 POINT frames[], int * nFrames);
\r
10668 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10669 { // [HGM] atomic: animate blast wave
\r
10671 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10672 explodeInfo.fromX = fromX;
\r
10673 explodeInfo.fromY = fromY;
\r
10674 explodeInfo.toX = toX;
\r
10675 explodeInfo.toY = toY;
\r
10676 for(i=1; i<nFrames; i++) {
\r
10677 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10678 DrawPosition(FALSE, NULL);
\r
10679 Sleep(appData.animSpeed);
\r
10681 explodeInfo.radius = 0;
\r
10682 DrawPosition(TRUE, NULL);
\r
10685 #define kFactor 4
\r
10688 AnimateMove(board, fromX, fromY, toX, toY)
\r
10695 ChessSquare piece;
\r
10696 POINT start, finish, mid;
\r
10697 POINT frames[kFactor * 2 + 1];
\r
10700 if (!appData.animate) return;
\r
10701 if (doingSizing) return;
\r
10702 if (fromY < 0 || fromX < 0) return;
\r
10703 piece = board[fromY][fromX];
\r
10704 if (piece >= EmptySquare) return;
\r
10706 ScreenSquare(fromX, fromY, &start);
\r
10707 ScreenSquare(toX, toY, &finish);
\r
10709 /* All pieces except knights move in straight line */
\r
10710 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10711 mid.x = start.x + (finish.x - start.x) / 2;
\r
10712 mid.y = start.y + (finish.y - start.y) / 2;
\r
10714 /* Knight: make diagonal movement then straight */
\r
10715 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10716 mid.x = start.x + (finish.x - start.x) / 2;
\r
10717 mid.y = finish.y;
\r
10719 mid.x = finish.x;
\r
10720 mid.y = start.y + (finish.y - start.y) / 2;
\r
10724 /* Don't use as many frames for very short moves */
\r
10725 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10726 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10728 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10730 animInfo.from.x = fromX;
\r
10731 animInfo.from.y = fromY;
\r
10732 animInfo.to.x = toX;
\r
10733 animInfo.to.y = toY;
\r
10734 animInfo.lastpos = start;
\r
10735 animInfo.piece = piece;
\r
10736 for (n = 0; n < nFrames; n++) {
\r
10737 animInfo.pos = frames[n];
\r
10738 DrawPosition(FALSE, NULL);
\r
10739 animInfo.lastpos = animInfo.pos;
\r
10740 Sleep(appData.animSpeed);
\r
10742 animInfo.pos = finish;
\r
10743 DrawPosition(FALSE, NULL);
\r
10744 animInfo.piece = EmptySquare;
\r
10745 if(gameInfo.variant == VariantAtomic &&
\r
10746 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10747 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10750 /* Convert board position to corner of screen rect and color */
\r
10753 ScreenSquare(column, row, pt)
\r
10754 int column; int row; POINT * pt;
\r
10757 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10758 pt->y = lineGap + row * (squareSize + lineGap);
\r
10760 pt->x = lineGap + column * (squareSize + lineGap);
\r
10761 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10765 /* Generate a series of frame coords from start->mid->finish.
\r
10766 The movement rate doubles until the half way point is
\r
10767 reached, then halves back down to the final destination,
\r
10768 which gives a nice slow in/out effect. The algorithmn
\r
10769 may seem to generate too many intermediates for short
\r
10770 moves, but remember that the purpose is to attract the
\r
10771 viewers attention to the piece about to be moved and
\r
10772 then to where it ends up. Too few frames would be less
\r
10776 Tween(start, mid, finish, factor, frames, nFrames)
\r
10777 POINT * start; POINT * mid;
\r
10778 POINT * finish; int factor;
\r
10779 POINT frames[]; int * nFrames;
\r
10781 int n, fraction = 1, count = 0;
\r
10783 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10784 for (n = 0; n < factor; n++)
\r
10786 for (n = 0; n < factor; n++) {
\r
10787 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10788 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10790 fraction = fraction / 2;
\r
10794 frames[count] = *mid;
\r
10797 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10799 for (n = 0; n < factor; n++) {
\r
10800 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10801 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10803 fraction = fraction * 2;
\r
10805 *nFrames = count;
\r
10809 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10814 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10815 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10817 OutputDebugString( buf );
\r
10820 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10822 EvalGraphSet( first, last, current, pvInfoList );
\r
10825 void SetProgramStats( FrontEndProgramStats * stats )
\r
10830 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10831 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10833 OutputDebugString( buf );
\r
10836 EngineOutputUpdate( stats );
\r