2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
83 #include "frontend.h"
\r
84 #include "backend.h"
\r
85 #include "winboard.h"
\r
87 #include "wclipbrd.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
101 extern HANDLE chatHandle[];
\r
102 extern int ics_type;
\r
104 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
105 VOID NewVariantPopup(HWND hwnd);
\r
106 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
107 /*char*/int promoChar));
\r
108 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
109 void DisplayMove P((int moveNumber));
\r
110 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
111 void ChatPopUp P(());
\r
113 ChessSquare piece;
\r
114 POINT pos; /* window coordinates of current pos */
\r
115 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
116 POINT from; /* board coordinates of the piece's orig pos */
\r
117 POINT to; /* board coordinates of the piece's new pos */
\r
120 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
123 POINT start; /* window coordinates of start pos */
\r
124 POINT pos; /* window coordinates of current pos */
\r
125 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
126 POINT from; /* board coordinates of the piece's orig pos */
\r
129 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
132 POINT sq[2]; /* board coordinates of from, to squares */
\r
135 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
136 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 typedef struct { // [HGM] atomic
\r
139 int fromX, fromY, toX, toY, radius;
\r
142 static ExplodeInfo explodeInfo;
\r
144 /* Window class names */
\r
145 char szAppName[] = "WinBoard";
\r
146 char szConsoleName[] = "WBConsole";
\r
148 /* Title bar text */
\r
149 char szTitle[] = "WinBoard";
\r
150 char szConsoleTitle[] = "I C S Interaction";
\r
153 char *settingsFileName;
\r
154 BOOLEAN saveSettingsOnExit;
\r
155 char installDir[MSG_SIZ];
\r
157 BoardSize boardSize;
\r
158 BOOLEAN chessProgram;
\r
159 //static int boardX, boardY;
\r
160 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
161 static int squareSize, lineGap, minorSize;
\r
162 static int winW, winH;
\r
163 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
164 static int logoHeight = 0;
\r
165 static char messageText[MESSAGE_TEXT_MAX];
\r
166 static int clockTimerEvent = 0;
\r
167 static int loadGameTimerEvent = 0;
\r
168 static int analysisTimerEvent = 0;
\r
169 static DelayedEventCallback delayedTimerCallback;
\r
170 static int delayedTimerEvent = 0;
\r
171 static int buttonCount = 2;
\r
172 char *icsTextMenuString;
\r
174 char *firstChessProgramNames;
\r
175 char *secondChessProgramNames;
\r
177 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
179 #define PALETTESIZE 256
\r
181 HINSTANCE hInst; /* current instance */
\r
182 BOOLEAN alwaysOnTop = FALSE;
\r
184 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
185 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
187 ColorClass currentColorClass;
\r
189 HWND hCommPort = NULL; /* currently open comm port */
\r
190 static HWND hwndPause; /* pause button */
\r
191 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
192 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
193 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
194 explodeBrush, /* [HGM] atomic */
\r
195 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
196 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
197 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
198 static HPEN gridPen = NULL;
\r
199 static HPEN highlightPen = NULL;
\r
200 static HPEN premovePen = NULL;
\r
201 static NPLOGPALETTE pLogPal;
\r
202 static BOOL paletteChanged = FALSE;
\r
203 static HICON iconWhite, iconBlack, iconCurrent;
\r
204 static int doingSizing = FALSE;
\r
205 static int lastSizing = 0;
\r
206 static int prevStderrPort;
\r
207 static HBITMAP userLogo;
\r
209 /* [AS] Support for background textures */
\r
210 #define BACK_TEXTURE_MODE_DISABLED 0
\r
211 #define BACK_TEXTURE_MODE_PLAIN 1
\r
212 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
214 static HBITMAP liteBackTexture = NULL;
\r
215 static HBITMAP darkBackTexture = NULL;
\r
216 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
217 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
218 static int backTextureSquareSize = 0;
\r
219 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
221 #if __GNUC__ && !defined(_winmajor)
\r
222 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
224 #if defined(_winmajor)
\r
225 #define oldDialog (_winmajor < 4)
\r
227 #define oldDialog 0
\r
231 char *defaultTextAttribs[] =
\r
233 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
234 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
244 int cliWidth, cliHeight;
\r
247 SizeInfo sizeInfo[] =
\r
249 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
250 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
251 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
252 { "petite", 33, 1, 1, 1, 0, 0 },
\r
253 { "slim", 37, 2, 1, 0, 0, 0 },
\r
254 { "small", 40, 2, 1, 0, 0, 0 },
\r
255 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
256 { "middling", 49, 2, 0, 0, 0, 0 },
\r
257 { "average", 54, 2, 0, 0, 0, 0 },
\r
258 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
259 { "medium", 64, 3, 0, 0, 0, 0 },
\r
260 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
261 { "large", 80, 3, 0, 0, 0, 0 },
\r
262 { "big", 87, 3, 0, 0, 0, 0 },
\r
263 { "huge", 95, 3, 0, 0, 0, 0 },
\r
264 { "giant", 108, 3, 0, 0, 0, 0 },
\r
265 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
266 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
267 { NULL, 0, 0, 0, 0, 0, 0 }
\r
270 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
271 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
273 { 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
274 { 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
275 { 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
276 { 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
277 { 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
278 { 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
279 { 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
280 { 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
281 { 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
282 { 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
283 { 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
284 { 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
285 { 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
286 { 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
287 { 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
288 { 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
289 { 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
290 { 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
293 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
302 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
303 #define N_BUTTONS 5
\r
305 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
307 {"<<", IDM_ToStart, NULL, NULL},
\r
308 {"<", IDM_Backward, NULL, NULL},
\r
309 {"P", IDM_Pause, NULL, NULL},
\r
310 {">", IDM_Forward, NULL, NULL},
\r
311 {">>", IDM_ToEnd, NULL, NULL},
\r
314 int tinyLayout = 0, smallLayout = 0;
\r
315 #define MENU_BAR_ITEMS 7
\r
316 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
317 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
318 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
322 MySound sounds[(int)NSoundClasses];
\r
323 MyTextAttribs textAttribs[(int)NColorClasses];
\r
325 MyColorizeAttribs colorizeAttribs[] = {
\r
326 { (COLORREF)0, 0, "Shout Text" },
\r
327 { (COLORREF)0, 0, "SShout/CShout" },
\r
328 { (COLORREF)0, 0, "Channel 1 Text" },
\r
329 { (COLORREF)0, 0, "Channel Text" },
\r
330 { (COLORREF)0, 0, "Kibitz Text" },
\r
331 { (COLORREF)0, 0, "Tell Text" },
\r
332 { (COLORREF)0, 0, "Challenge Text" },
\r
333 { (COLORREF)0, 0, "Request Text" },
\r
334 { (COLORREF)0, 0, "Seek Text" },
\r
335 { (COLORREF)0, 0, "Normal Text" },
\r
336 { (COLORREF)0, 0, "None" }
\r
341 static char *commentTitle;
\r
342 static char *commentText;
\r
343 static int commentIndex;
\r
344 static Boolean editComment = FALSE;
\r
347 char errorTitle[MSG_SIZ];
\r
348 char errorMessage[2*MSG_SIZ];
\r
349 HWND errorDialog = NULL;
\r
350 BOOLEAN moveErrorMessageUp = FALSE;
\r
351 BOOLEAN consoleEcho = TRUE;
\r
352 CHARFORMAT consoleCF;
\r
353 COLORREF consoleBackgroundColor;
\r
355 char *programVersion;
\r
361 typedef int CPKind;
\r
370 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
373 #define INPUT_SOURCE_BUF_SIZE 4096
\r
375 typedef struct _InputSource {
\r
382 char buf[INPUT_SOURCE_BUF_SIZE];
\r
386 InputCallback func;
\r
387 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
391 InputSource *consoleInputSource;
\r
396 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
397 VOID ConsoleCreate();
\r
399 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
400 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
401 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
402 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
404 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
405 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
406 void ParseIcsTextMenu(char *icsTextMenuString);
\r
407 VOID PopUpMoveDialog(char firstchar);
\r
408 VOID PopUpNameDialog(char firstchar);
\r
409 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
413 int GameListOptions();
\r
415 int dummy; // [HGM] for obsolete args
\r
417 HWND hwndMain = NULL; /* root window*/
\r
418 HWND hwndConsole = NULL;
\r
419 HWND commentDialog = NULL;
\r
420 HWND moveHistoryDialog = NULL;
\r
421 HWND evalGraphDialog = NULL;
\r
422 HWND engineOutputDialog = NULL;
\r
423 HWND gameListDialog = NULL;
\r
424 HWND editTagsDialog = NULL;
\r
426 int commentUp = FALSE;
\r
428 WindowPlacement wpMain;
\r
429 WindowPlacement wpConsole;
\r
430 WindowPlacement wpComment;
\r
431 WindowPlacement wpMoveHistory;
\r
432 WindowPlacement wpEvalGraph;
\r
433 WindowPlacement wpEngineOutput;
\r
434 WindowPlacement wpGameList;
\r
435 WindowPlacement wpTags;
\r
437 VOID EngineOptionsPopup(); // [HGM] settings
\r
439 VOID GothicPopUp(char *title, VariantClass variant);
\r
441 * Setting "frozen" should disable all user input other than deleting
\r
442 * the window. We do this while engines are initializing themselves.
\r
444 static int frozen = 0;
\r
445 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
451 if (frozen) return;
\r
453 hmenu = GetMenu(hwndMain);
\r
454 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
455 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
457 DrawMenuBar(hwndMain);
\r
460 /* Undo a FreezeUI */
\r
466 if (!frozen) return;
\r
468 hmenu = GetMenu(hwndMain);
\r
469 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
470 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
472 DrawMenuBar(hwndMain);
\r
475 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
477 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
483 #define JAWS_ALT_INTERCEPT
\r
484 #define JAWS_KB_NAVIGATION
\r
485 #define JAWS_MENU_ITEMS
\r
486 #define JAWS_SILENCE
\r
487 #define JAWS_REPLAY
\r
489 #define JAWS_COPYRIGHT
\r
490 #define JAWS_DELETE(X) X
\r
491 #define SAYMACHINEMOVE()
\r
495 /*---------------------------------------------------------------------------*\
\r
499 \*---------------------------------------------------------------------------*/
\r
502 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
503 LPSTR lpCmdLine, int nCmdShow)
\r
506 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
507 // INITCOMMONCONTROLSEX ex;
\r
511 LoadLibrary("RICHED32.DLL");
\r
512 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
514 if (!InitApplication(hInstance)) {
\r
517 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
523 // InitCommonControlsEx(&ex);
\r
524 InitCommonControls();
\r
526 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
527 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
528 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
530 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
532 while (GetMessage(&msg, /* message structure */
\r
533 NULL, /* handle of window receiving the message */
\r
534 0, /* lowest message to examine */
\r
535 0)) /* highest message to examine */
\r
538 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
539 // [HGM] navigate: switch between all windows with tab
\r
540 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
541 int i, currentElement = 0;
\r
543 // first determine what element of the chain we come from (if any)
\r
544 if(appData.icsActive) {
\r
545 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
546 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
548 if(engineOutputDialog && EngineOutputIsUp()) {
\r
549 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
550 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
552 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
553 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
555 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
556 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
557 if(msg.hwnd == e1) currentElement = 2; else
\r
558 if(msg.hwnd == e2) currentElement = 3; else
\r
559 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
560 if(msg.hwnd == mh) currentElement = 4; else
\r
561 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
562 if(msg.hwnd == hText) currentElement = 5; else
\r
563 if(msg.hwnd == hInput) currentElement = 6; else
\r
564 for (i = 0; i < N_BUTTONS; i++) {
\r
565 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
568 // determine where to go to
\r
569 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
571 currentElement = (currentElement + direction) % 7;
\r
572 switch(currentElement) {
\r
574 h = hwndMain; break; // passing this case always makes the loop exit
\r
576 h = buttonDesc[0].hwnd; break; // could be NULL
\r
578 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
581 if(!EngineOutputIsUp()) continue;
\r
584 if(!MoveHistoryIsUp()) continue;
\r
586 // case 6: // input to eval graph does not seem to get here!
\r
587 // if(!EvalGraphIsUp()) continue;
\r
588 // h = evalGraphDialog; break;
\r
590 if(!appData.icsActive) continue;
\r
594 if(!appData.icsActive) continue;
\r
600 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
601 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
604 continue; // this message now has been processed
\r
608 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
609 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
610 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
611 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
612 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
613 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
614 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
615 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
616 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
617 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
618 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
619 for(i=0; i<MAX_CHAT; i++)
\r
620 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
623 if(done) continue; // [HGM] chat: end patch
\r
624 TranslateMessage(&msg); /* Translates virtual key codes */
\r
625 DispatchMessage(&msg); /* Dispatches message to window */
\r
630 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
633 /*---------------------------------------------------------------------------*\
\r
635 * Initialization functions
\r
637 \*---------------------------------------------------------------------------*/
\r
641 { // update user logo if necessary
\r
642 static char oldUserName[MSG_SIZ], *curName;
\r
644 if(appData.autoLogo) {
\r
645 curName = UserName();
\r
646 if(strcmp(curName, oldUserName)) {
\r
647 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
648 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
649 strcpy(oldUserName, curName);
\r
655 InitApplication(HINSTANCE hInstance)
\r
659 /* Fill in window class structure with parameters that describe the */
\r
662 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
663 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
664 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
665 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
666 wc.hInstance = hInstance; /* Owner of this class */
\r
667 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
668 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
669 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
670 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
671 wc.lpszClassName = szAppName; /* Name to register as */
\r
673 /* Register the window class and return success/failure code. */
\r
674 if (!RegisterClass(&wc)) return FALSE;
\r
676 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
677 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
679 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
680 wc.hInstance = hInstance;
\r
681 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
682 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
683 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
684 wc.lpszMenuName = NULL;
\r
685 wc.lpszClassName = szConsoleName;
\r
687 if (!RegisterClass(&wc)) return FALSE;
\r
692 /* Set by InitInstance, used by EnsureOnScreen */
\r
693 int screenHeight, screenWidth;
\r
696 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
698 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
699 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
700 if (*x > screenWidth - 32) *x = 0;
\r
701 if (*y > screenHeight - 32) *y = 0;
\r
702 if (*x < minX) *x = minX;
\r
703 if (*y < minY) *y = minY;
\r
707 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
709 HWND hwnd; /* Main window handle. */
\r
711 WINDOWPLACEMENT wp;
\r
714 hInst = hInstance; /* Store instance handle in our global variable */
\r
716 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
717 *filepart = NULLCHAR;
\r
719 GetCurrentDirectory(MSG_SIZ, installDir);
\r
721 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
722 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
723 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
724 if (appData.debugMode) {
\r
725 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
726 setbuf(debugFP, NULL);
\r
731 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
732 // InitEngineUCI( installDir, &second );
\r
734 /* Create a main window for this application instance. */
\r
735 hwnd = CreateWindow(szAppName, szTitle,
\r
736 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
737 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
738 NULL, NULL, hInstance, NULL);
\r
741 /* If window could not be created, return "failure" */
\r
746 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
747 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
748 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
750 if (first.programLogo == NULL && appData.debugMode) {
\r
751 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
753 } else if(appData.autoLogo) {
\r
754 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
756 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
757 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
761 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
762 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
764 if (second.programLogo == NULL && appData.debugMode) {
\r
765 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
767 } else if(appData.autoLogo) {
\r
769 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
770 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
771 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
773 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
774 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
775 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
781 iconWhite = LoadIcon(hInstance, "icon_white");
\r
782 iconBlack = LoadIcon(hInstance, "icon_black");
\r
783 iconCurrent = iconWhite;
\r
784 InitDrawingColors();
\r
785 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
786 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
787 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
788 /* Compute window size for each board size, and use the largest
\r
789 size that fits on this screen as the default. */
\r
790 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
791 if (boardSize == (BoardSize)-1 &&
\r
792 winH <= screenHeight
\r
793 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
794 && winW <= screenWidth) {
\r
795 boardSize = (BoardSize)ibs;
\r
799 InitDrawingSizes(boardSize, 0);
\r
801 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
803 /* [AS] Load textures if specified */
\r
804 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
806 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
807 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
808 liteBackTextureMode = appData.liteBackTextureMode;
\r
810 if (liteBackTexture == NULL && appData.debugMode) {
\r
811 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
815 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
816 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
817 darkBackTextureMode = appData.darkBackTextureMode;
\r
819 if (darkBackTexture == NULL && appData.debugMode) {
\r
820 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
824 mysrandom( (unsigned) time(NULL) );
\r
826 /* [AS] Restore layout */
\r
827 if( wpMoveHistory.visible ) {
\r
828 MoveHistoryPopUp();
\r
831 if( wpEvalGraph.visible ) {
\r
835 if( wpEngineOutput.visible ) {
\r
836 EngineOutputPopUp();
\r
841 /* Make the window visible; update its client area; and return "success" */
\r
842 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
843 wp.length = sizeof(WINDOWPLACEMENT);
\r
845 wp.showCmd = nCmdShow;
\r
846 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
847 wp.rcNormalPosition.left = wpMain.x;
\r
848 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
849 wp.rcNormalPosition.top = wpMain.y;
\r
850 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
851 SetWindowPlacement(hwndMain, &wp);
\r
853 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
854 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
858 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
859 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
861 ShowWindow(hwndConsole, nCmdShow);
\r
863 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
864 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
872 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
873 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
874 ArgSettingsFilename,
\r
875 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
878 typedef void *ArgIniType;
\r
879 #define INVALID (ArgIniType) 6915 /* Some number unlikely to be needed as default for anything */
\r
886 String *pString; // ArgString
\r
887 int *pInt; // ArgInt
\r
888 float *pFloat; // ArgFloat
\r
889 Boolean *pBoolean; // ArgBoolean
\r
890 COLORREF *pColor; // ArgColor
\r
891 ColorClass cc; // ArgAttribs
\r
892 String *pFilename; // ArgFilename
\r
893 BoardSize *pBoardSize; // ArgBoardSize
\r
894 int whichFont; // ArgFont
\r
895 DCB *pDCB; // ArgCommSettings
\r
896 String *pFilename; // ArgSettingsFilename
\r
901 ArgIniType defaultValue;
\r
906 ArgDescriptor argDescriptors[] = {
\r
907 /* positional arguments */
\r
908 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE, INVALID },
\r
909 { "", ArgNone, NULL, FALSE, INVALID },
\r
910 /* keyword arguments */
\r
912 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE, INVALID },
\r
913 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE, INVALID },
\r
914 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE, INVALID },
\r
915 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE, INVALID },
\r
916 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE, INVALID },
\r
917 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE, INVALID },
\r
918 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE, INVALID },
\r
919 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE, INVALID },
\r
920 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE, INVALID },
\r
921 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE, INVALID },
\r
922 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE, INVALID },
\r
923 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE, INVALID },
\r
924 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE, (ArgIniType) MOVES_PER_SESSION },
\r
925 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE, INVALID },
\r
926 { "initString", ArgString, (LPVOID) &appData.initString, FALSE, INVALID },
\r
927 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE, (ArgIniType) INIT_STRING },
\r
928 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE, (ArgIniType) INIT_STRING },
\r
929 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
930 FALSE, (ArgIniType) COMPUTER_STRING },
\r
931 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
932 FALSE, (ArgIniType) COMPUTER_STRING },
\r
933 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
934 FALSE, (ArgIniType) FIRST_CHESS_PROGRAM },
\r
935 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE, INVALID },
\r
936 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
937 FALSE, (ArgIniType) SECOND_CHESS_PROGRAM },
\r
938 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE, INVALID },
\r
939 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE, FALSE },
\r
940 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE, FALSE },
\r
941 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE, INVALID },
\r
942 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE, INVALID },
\r
943 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE, FALSE },
\r
944 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE, INVALID },
\r
945 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE, INVALID },
\r
946 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE, INVALID },
\r
947 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE, (ArgIniType) FIRST_HOST },
\r
948 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE, INVALID },
\r
949 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE, (ArgIniType) SECOND_HOST },
\r
950 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE, INVALID },
\r
951 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE, (ArgIniType) FIRST_DIRECTORY },
\r
952 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE, INVALID },
\r
953 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE, (ArgIniType) SECOND_DIRECTORY },
\r
954 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE, INVALID },
\r
955 /*!!bitmapDirectory?*/
\r
956 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE, (ArgIniType) REMOTE_SHELL },
\r
957 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE, INVALID },
\r
958 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE, INVALID },
\r
959 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE, INVALID },
\r
960 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE, INVALID },
\r
961 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE, INVALID },
\r
962 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE, (ArgIniType) TIME_CONTROL },
\r
963 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE, INVALID },
\r
964 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE, (ArgIniType) TIME_INCREMENT },
\r
965 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE, INVALID },
\r
966 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE, INVALID },
\r
967 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE, (ArgIniType) FALSE },
\r
968 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE, INVALID },
\r
969 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE, INVALID },
\r
970 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE, (ArgIniType) "" },
\r
971 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE, INVALID },
\r
972 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE, (ArgIniType) ICS_PORT },
\r
973 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE, INVALID },
\r
974 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE, (ArgIniType) ICS_COMM_PORT },
\r
975 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE, INVALID },
\r
976 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE, INVALID },
\r
977 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE, INVALID },
\r
978 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE, (ArgIniType) ICS_LOGON },
\r
979 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE, INVALID },
\r
980 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE, INVALID },
\r
981 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE, INVALID },
\r
982 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE, INVALID },
\r
983 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE, INVALID },
\r
984 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE, (ArgIniType) TELNET_PROGRAM },
\r
985 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE, (ArgIniType) "" },
\r
986 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE, (ArgIniType) "" },
\r
987 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE, (ArgIniType) "" },
\r
988 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE, INVALID },
\r
989 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE, (ArgIniType) 0 },
\r
990 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE, INVALID },
\r
991 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE, (ArgIniType) "" },
\r
992 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE, INVALID },
\r
993 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE, (ArgIniType) FALSE },
\r
994 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE, INVALID },
\r
995 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE, INVALID },
\r
996 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE, INVALID },
\r
997 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE, (ArgIniType) "" },
\r
998 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE, INVALID },
\r
999 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE, (ArgIniType) 1 },
\r
1000 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE, INVALID },
\r
1001 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE, (ArgIniType) "" },
\r
1002 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE, INVALID },
\r
1003 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE, (ArgIniType) FALSE },
\r
1004 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE, INVALID },
\r
1005 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE, INVALID },
\r
1006 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE, INVALID },
\r
1007 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE, (ArgIniType) 0 },
\r
1008 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE, INVALID },
\r
1009 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE, (ArgIniType) FALSE },
\r
1010 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE, INVALID },
\r
1011 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE, INVALID },
\r
1012 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE, INVALID },
\r
1013 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE, (ArgIniType) FALSE },
\r
1014 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE, INVALID },
\r
1015 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE, INVALID },
\r
1016 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE, INVALID },
\r
1017 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE, (ArgIniType) TRUE },
\r
1018 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE, INVALID },
\r
1019 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE, INVALID },
\r
1020 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE, INVALID },
\r
1021 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE, (ArgIniType) "" },
\r
1022 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE, INVALID },
\r
1023 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE, (ArgIniType) 0 },
\r
1024 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE, INVALID },
\r
1025 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE, (ArgIniType) FALSE },
\r
1026 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE, INVALID },
\r
1027 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE, INVALID },
\r
1028 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE, INVALID },
\r
1029 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE, (ArgIniType) FALSE },
\r
1030 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE, INVALID },
\r
1031 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE, INVALID },
\r
1032 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE, INVALID },
\r
1033 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE, (ArgIniType) TRUE },
\r
1034 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE, INVALID },
\r
1035 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE, INVALID },
\r
1036 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE, INVALID },
\r
1037 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE, (ArgIniType) TRUE },
\r
1038 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE, INVALID },
\r
1039 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE, INVALID },
\r
1040 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE, INVALID },
\r
1041 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE, (ArgIniType) TRUE },
\r
1042 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE, INVALID },
\r
1043 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE, INVALID },
\r
1044 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE, INVALID },
\r
1045 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE, (ArgIniType) FALSE },
\r
1046 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE, INVALID },
\r
1047 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE, INVALID },
\r
1048 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE, INVALID },
\r
1049 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1050 FALSE, INVALID }, /* only so that old WinBoard.ini files from betas can be read */
\r
1051 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE, INVALID },
\r
1052 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE, INVALID },
\r
1053 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE, INVALID },
\r
1054 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE, INVALID },
\r
1055 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE, INVALID },
\r
1056 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE, INVALID },
\r
1057 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE, INVALID }, /* [AS] */
\r
1058 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1059 TRUE, (ArgIniType) -1 }, /* must come after all fonts */
\r
1060 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE, INVALID },
\r
1061 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1062 FALSE, (ArgIniType) TRUE }, /* historical; kept only so old winboard.ini files will parse */
\r
1063 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE, INVALID },
\r
1064 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE, INVALID },
\r
1065 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE, INVALID },
\r
1066 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE, INVALID },
\r
1067 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE, (ArgIniType) FALSE },
\r
1068 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE, INVALID },
\r
1069 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE, INVALID },
\r
1070 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE, INVALID },
\r
1071 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE, (ArgIniType) FALSE },
\r
1072 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE, INVALID },
\r
1073 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE, INVALID },
\r
1074 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE, INVALID },
\r
1075 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE, (ArgIniType) FALSE },
\r
1076 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE, INVALID },
\r
1077 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE, INVALID },
\r
1078 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE, INVALID },
\r
1079 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE, (ArgIniType) FALSE },
\r
1080 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE, INVALID },
\r
1081 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE, INVALID },
\r
1082 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE, INVALID },
\r
1083 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE, (ArgIniType) TRUE },
\r
1084 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE, INVALID },
\r
1085 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE, INVALID },
\r
1086 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE, INVALID },
\r
1087 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE, (ArgIniType) TRUE },
\r
1088 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE, INVALID },
\r
1089 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE, INVALID },
\r
1090 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE, INVALID },
\r
1091 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE, (ArgIniType) FALSE },
\r
1092 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE, INVALID },
\r
1093 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE, INVALID },
\r
1094 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE, INVALID },
\r
1095 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE, (ArgIniType) FALSE },
\r
1096 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE, INVALID },
\r
1097 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE, INVALID },
\r
1098 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE, INVALID },
\r
1099 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE, (ArgIniType) FALSE },
\r
1100 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE, INVALID },
\r
1101 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE, INVALID },
\r
1102 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE, INVALID },
\r
1103 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE, (ArgIniType) TRUE },
\r
1104 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE, INVALID },
\r
1105 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE, INVALID },
\r
1106 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE, INVALID },
\r
1107 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE, (ArgIniType) TRUE },
\r
1108 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE, INVALID },
\r
1109 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE, INVALID },
\r
1110 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE, INVALID },
\r
1111 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE, (ArgIniType) TRUE },
\r
1112 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE, INVALID },
\r
1113 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE, INVALID },
\r
1114 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE, INVALID },
\r
1115 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE, (ArgIniType) FALSE },
\r
1116 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE, INVALID },
\r
1117 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE, INVALID },
\r
1118 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE, INVALID },
\r
1119 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE, (ArgIniType) "" },
\r
1120 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE, (ArgIniType) FALSE },
\r
1121 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE, INVALID },
\r
1122 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE, INVALID },
\r
1123 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE, INVALID },
\r
1124 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE, (ArgIniType) "" },
\r
1125 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE, (ArgIniType) TRUE},
\r
1126 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1127 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1128 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1129 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE, (ArgIniType) 5000},
\r
1130 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE, (ArgIniType) TRUE},
\r
1131 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE, INVALID },
\r
1132 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE, INVALID },
\r
1133 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE, INVALID },
\r
1134 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE, (ArgIniType) TRUE },
\r
1135 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE, INVALID },
\r
1136 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE, INVALID },
\r
1137 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE, INVALID },
\r
1138 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE, (ArgIniType) 10 },
\r
1139 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE, (ArgIniType) TRUE },
\r
1140 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE, INVALID },
\r
1141 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE, INVALID },
\r
1142 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE, INVALID },
\r
1143 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE, (ArgIniType) FALSE },
\r
1144 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE, INVALID },
\r
1145 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE, INVALID },
\r
1146 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE, INVALID },
\r
1147 { "highlightLastMove", ArgBoolean,
\r
1148 (LPVOID) &appData.highlightLastMove, TRUE, (ArgIniType) TRUE },
\r
1149 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE, INVALID },
\r
1150 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE, INVALID },
\r
1151 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE, INVALID },
\r
1152 { "highlightDragging", ArgBoolean,
\r
1153 (LPVOID) &appData.highlightDragging, TRUE, INVALID },
\r
1154 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE, INVALID },
\r
1155 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE, INVALID },
\r
1156 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE, INVALID },
\r
1157 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE, (ArgIniType) TRUE },
\r
1158 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE, INVALID },
\r
1159 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE, INVALID },
\r
1160 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE, INVALID },
\r
1161 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE, INVALID },
\r
1162 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE, INVALID },
\r
1163 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE, INVALID },
\r
1164 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE, INVALID },
\r
1165 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE, INVALID },
\r
1166 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE, INVALID },
\r
1167 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE, INVALID },
\r
1168 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE, INVALID },
\r
1169 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE, INVALID },
\r
1170 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE, INVALID },
\r
1171 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE, INVALID },
\r
1172 { "soundShout", ArgFilename,
\r
1173 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE, INVALID },
\r
1174 { "soundSShout", ArgFilename,
\r
1175 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE, INVALID },
\r
1176 { "soundChannel1", ArgFilename,
\r
1177 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE, INVALID },
\r
1178 { "soundChannel", ArgFilename,
\r
1179 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE, INVALID },
\r
1180 { "soundKibitz", ArgFilename,
\r
1181 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE, INVALID },
\r
1182 { "soundTell", ArgFilename,
\r
1183 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE, INVALID },
\r
1184 { "soundChallenge", ArgFilename,
\r
1185 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE, INVALID },
\r
1186 { "soundRequest", ArgFilename,
\r
1187 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE, INVALID },
\r
1188 { "soundSeek", ArgFilename,
\r
1189 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE, INVALID },
\r
1190 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE, INVALID },
\r
1191 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE, INVALID },
\r
1192 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name, TRUE, INVALID },
\r
1193 { "soundIcsLoss", ArgFilename,
\r
1194 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE, INVALID },
\r
1195 { "soundIcsDraw", ArgFilename,
\r
1196 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE, INVALID },
\r
1197 { "soundIcsUnfinished", ArgFilename,
\r
1198 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE, INVALID },
\r
1199 { "soundIcsAlarm", ArgFilename,
\r
1200 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE, INVALID },
\r
1201 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE, (ArgIniType) TRUE },
\r
1202 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE, INVALID },
\r
1203 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE, INVALID },
\r
1204 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE, INVALID },
\r
1205 { "reuseChessPrograms", ArgBoolean,
\r
1206 (LPVOID) &appData.reuseFirst, FALSE, INVALID }, /* backward compat only */
\r
1207 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE, (ArgIniType) TRUE },
\r
1208 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE, INVALID },
\r
1209 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE, INVALID },
\r
1210 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE, INVALID },
\r
1211 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE, INVALID },
\r
1212 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE, (ArgIniType) SETTINGS_FILE },
\r
1213 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE, INVALID },
\r
1214 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE, (ArgIniType) TRUE },
\r
1215 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE, (ArgIniType) FALSE },
\r
1216 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE, INVALID },
\r
1217 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE, INVALID },
\r
1218 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE, INVALID },
\r
1219 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE, (ArgIniType) ICS_TEXT_MENU_DEFAULT },
\r
1220 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE, (ArgIniType) ICS_NAMES },
\r
1221 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1222 TRUE, (ArgIniType) FCP_NAMES },
\r
1223 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1224 TRUE, (ArgIniType) SCP_NAMES },
\r
1225 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE, (ArgIniType) "" },
\r
1226 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE, INVALID },
\r
1227 { "variant", ArgString, (LPVOID) &appData.variant, FALSE, (ArgIniType) "normal" },
\r
1228 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE, (ArgIniType) PROTOVER },
\r
1229 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE, (ArgIniType) PROTOVER },
\r
1230 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE, (ArgIniType) TRUE },
\r
1231 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE, INVALID },
\r
1232 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE, INVALID },
\r
1233 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE, INVALID },
\r
1235 /* [AS] New features */
\r
1236 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE, (ArgIniType) FALSE },
\r
1237 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE, (ArgIniType) FALSE },
\r
1238 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE, (ArgIniType) FALSE },
\r
1239 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE, (ArgIniType) FALSE },
\r
1240 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE, (ArgIniType) "" },
\r
1241 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE, (ArgIniType) "" },
\r
1242 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE, (ArgIniType) BACK_TEXTURE_MODE_PLAIN },
\r
1243 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE, (ArgIniType) BACK_TEXTURE_MODE_PLAIN },
\r
1244 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE, (ArgIniType) "" },
\r
1245 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE, (ArgIniType) "" },
\r
1246 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE, (ArgIniType) 0 },
\r
1247 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE, (ArgIniType) 0 },
\r
1248 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE, (ArgIniType) 0 },
\r
1249 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE, (ArgIniType) 0 },
\r
1250 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE, (ArgIniType) 80 },
\r
1251 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE, (ArgIniType) 1 },
\r
1252 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE, (ArgIniType) 0 },
\r
1253 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE, (ArgIniType) 0 },
\r
1254 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE, (ArgIniType) 0 },
\r
1255 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE, (ArgIniType) "winboard.debug" },
\r
1256 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE, INVALID },
\r
1257 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE, (ArgIniType) "Computer Chess Game" },
\r
1258 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE, (ArgIniType) -1 },
\r
1259 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE, (ArgIniType) GLT_DEFAULT_TAGS },
\r
1260 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE, (ArgIniType) TRUE },
\r
1261 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE, (ArgIniType) TRUE },
\r
1262 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE, INVALID },
\r
1263 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE, INVALID },
\r
1264 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE, (ArgIniType) FALSE },
\r
1265 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE, INVALID },
\r
1266 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE, (ArgIniType) TRUE },
\r
1267 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE, (ArgIniType) TRUE },
\r
1268 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE, (ArgIniType) TRUE },
\r
1269 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE, (ArgIniType) TRUE },
\r
1270 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE, (ArgIniType) FALSE },
\r
1271 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE, INVALID },
\r
1272 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE, (ArgIniType) FALSE },
\r
1273 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE, INVALID },
\r
1274 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE, (ArgIniType) TRUE },
\r
1275 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE, INVALID },
\r
1276 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE, INVALID },
\r
1277 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE, (ArgIniType) TRUE },
\r
1278 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE, INVALID },
\r
1279 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE, INVALID },
\r
1280 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE, (ArgIniType) "" },
\r
1281 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE, (ArgIniType) FALSE },
\r
1282 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE, (ArgIniType) "" },
\r
1283 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE, (ArgIniType) 64 },
\r
1284 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE, (ArgIniType) 4 },
\r
1285 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE, (ArgIniType) "c:\\egtb" },
\r
1287 /* [HGM] board-size, adjudication and misc. options */
\r
1288 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE, (ArgIniType) -1 },
\r
1289 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE, (ArgIniType) -1 },
\r
1290 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE, (ArgIniType) -1 },
\r
1291 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE, (ArgIniType) 10000 },
\r
1292 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE, INVALID },
\r
1293 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE, (ArgIniType) FALSE },
\r
1294 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE, (ArgIniType) FALSE },
\r
1295 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE, (ArgIniType) FALSE },
\r
1296 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE, (ArgIniType) FALSE },
\r
1297 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE, (ArgIniType) FALSE },
\r
1298 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE, (ArgIniType) FALSE },
\r
1299 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE, (ArgIniType) FALSE },
\r
1300 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE, (ArgIniType) FALSE },
\r
1301 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE, (ArgIniType) FALSE },
\r
1302 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE, (ArgIniType) 51 },
\r
1303 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE, (ArgIniType) 6 },
\r
1304 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE, INVALID },
\r
1305 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE, (ArgIniType) 1 },
\r
1306 { "userName", ArgString, (LPVOID) &appData.userName, FALSE, INVALID },
\r
1307 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE, INVALID },
\r
1308 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE, INVALID },
\r
1309 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE, (ArgIniType) 1 },
\r
1310 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE, (ArgIniType) "" },
\r
1311 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE, INVALID },
\r
1312 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE, INVALID },
\r
1313 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE, INVALID },
\r
1314 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE, INVALID },
\r
1315 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE, (ArgIniType) "" },
\r
1316 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE, (ArgIniType) "" },
\r
1317 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE, (ArgIniType) "" },
\r
1318 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE, (ArgIniType) "" },
\r
1319 { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE, INVALID },
\r
1320 { "icstype", ArgInt, (LPVOID) &ics_type, FALSE, INVALID },
\r
1321 { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE, INVALID },
\r
1324 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE, (ArgIniType) ZIPPY_TALK },
\r
1325 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE, INVALID },
\r
1326 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE, INVALID },
\r
1327 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE, INVALID },
\r
1328 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE, (ArgIniType) ZIPPY_PLAY },
\r
1329 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE, INVALID },
\r
1330 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE, INVALID },
\r
1331 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE, INVALID },
\r
1332 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE, (ArgIniType) ZIPPY_LINES },
\r
1333 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE, (ArgIniType) ZIPPY_PINHEAD },
\r
1334 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE, (ArgIniType) ZIPPY_PASSWORD },
\r
1335 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE, (ArgIniType) ZIPPY_PASSWORD2 },
\r
1336 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1337 FALSE, (ArgIniType) ZIPPY_WRONG_PASSWORD },
\r
1338 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE, (ArgIniType) ZIPPY_ACCEPT_ONLY },
\r
1339 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE, (ArgIniType) ZIPPY_USE_I },
\r
1340 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE, INVALID },
\r
1341 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE, INVALID },
\r
1342 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE, INVALID },
\r
1343 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE, (ArgIniType) ZIPPY_BUGHOUSE },
\r
1344 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1345 FALSE, (ArgIniType) ZIPPY_NOPLAY_CRAFTY },
\r
1346 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE, INVALID },
\r
1347 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE, INVALID },
\r
1348 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE, INVALID },
\r
1349 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE, (ArgIniType) ZIPPY_GAME_END },
\r
1350 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE, (ArgIniType) ZIPPY_GAME_START },
\r
1351 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE, (ArgIniType) ZIPPY_ADJOURN },
\r
1352 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE, INVALID },
\r
1353 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE, INVALID },
\r
1354 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE, INVALID },
\r
1355 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE, (ArgIniType) ZIPPY_ABORT },
\r
1356 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE, INVALID },
\r
1357 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE, INVALID },
\r
1358 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE, INVALID },
\r
1359 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE, (ArgIniType) ZIPPY_VARIANTS },
\r
1360 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE, (ArgIniType) ZIPPY_MAX_GAMES},
\r
1361 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE, (ArgIniType) ZIPPY_REPLAY_TIMEOUT },
\r
1362 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE, INVALID },
\r
1363 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1364 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE, INVALID },
\r
1366 /* [HGM] options for broadcasting and time odds */
\r
1367 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE, (ArgIniType) NULL },
\r
1368 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE, (ArgIniType) FALSE },
\r
1369 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE, (ArgIniType) 15 },
\r
1370 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE, (ArgIniType) 1 },
\r
1371 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE, (ArgIniType) 1 },
\r
1372 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE, INVALID },
\r
1373 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE, (ArgIniType) 1 },
\r
1374 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE, (ArgIniType) 1 },
\r
1375 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE, (ArgIniType) -1 },
\r
1376 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE, (ArgIniType) -1 },
\r
1377 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE, INVALID },
\r
1378 { "keepLineBreaksICS", ArgBoolean, (LPVOID) &appData.noJoin, TRUE, INVALID },
\r
1379 { "wrapContinuationSequence", ArgString, (LPVOID) &appData.wrapContSeq, FALSE, INVALID },
\r
1380 { "useInternalWrap", ArgTrue, (LPVOID) &appData.useInternalWrap, FALSE, INVALID }, /* noJoin usurps this if set */
\r
1382 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1383 { "minX", ArgZ, (LPVOID) &minX, FALSE, INVALID }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1384 { "minY", ArgZ, (LPVOID) &minY, FALSE, INVALID },
\r
1385 { "winWidth", ArgInt, (LPVOID) &wpMain.width, TRUE, INVALID }, // [HGM] placement: dummies to remember right & bottom
\r
1386 { "winHeight", ArgInt, (LPVOID) &wpMain.height, TRUE, INVALID }, // for attaching auxiliary windows to them
\r
1387 { "x", ArgInt, (LPVOID) &wpMain.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1388 { "y", ArgInt, (LPVOID) &wpMain.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1389 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1390 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1391 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1392 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1393 { "analysisX", ArgX, (LPVOID) &dummy, FALSE, INVALID }, // [HGM] placement: analysis window no longer exists
\r
1394 { "analysisY", ArgY, (LPVOID) &dummy, FALSE, INVALID }, // provided for compatibility with old ini files
\r
1395 { "analysisW", ArgInt, (LPVOID) &dummy, FALSE, INVALID },
\r
1396 { "analysisH", ArgInt, (LPVOID) &dummy, FALSE, INVALID },
\r
1397 { "commentX", ArgX, (LPVOID) &wpComment.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1398 { "commentY", ArgY, (LPVOID) &wpComment.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1399 { "commentW", ArgInt, (LPVOID) &wpComment.width, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1400 { "commentH", ArgInt, (LPVOID) &wpComment.height, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1401 { "tagsX", ArgX, (LPVOID) &wpTags.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1402 { "tagsY", ArgY, (LPVOID) &wpTags.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1403 { "tagsW", ArgInt, (LPVOID) &wpTags.width, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1404 { "tagsH", ArgInt, (LPVOID) &wpTags.height, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1405 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1406 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1407 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1408 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1409 /* [AS] Layout stuff */
\r
1410 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE, (ArgIniType) TRUE },
\r
1411 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1412 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1413 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1414 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1416 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE, (ArgIniType) TRUE },
\r
1417 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1418 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1419 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1420 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1422 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE, (ArgIniType) TRUE },
\r
1423 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1424 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1425 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1426 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE, (ArgIniType) CW_USEDEFAULT },
\r
1428 { NULL, ArgNone, NULL, FALSE, INVALID }
\r
1432 /* Kludge for indirection files on command line */
\r
1433 char* lastIndirectionFilename;
\r
1434 ArgDescriptor argDescriptorIndirection =
\r
1435 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1439 ExitArgError(char *msg, char *badArg)
\r
1441 char buf[MSG_SIZ];
\r
1443 sprintf(buf, "%s %s", msg, badArg);
\r
1444 DisplayFatalError(buf, 0, 2);
\r
1448 /* Command line font name parser. NULL name means do nothing.
\r
1449 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1450 For backward compatibility, syntax without the colon is also
\r
1451 accepted, but font names with digits in them won't work in that case.
\r
1454 ParseFontName(char *name, MyFontParams *mfp)
\r
1457 if (name == NULL) return;
\r
1459 q = strchr(p, ':');
\r
1461 if (q - p >= sizeof(mfp->faceName))
\r
1462 ExitArgError("Font name too long:", name);
\r
1463 memcpy(mfp->faceName, p, q - p);
\r
1464 mfp->faceName[q - p] = NULLCHAR;
\r
1467 q = mfp->faceName;
\r
1468 while (*p && !isdigit(*p)) {
\r
1470 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1471 ExitArgError("Font name too long:", name);
\r
1473 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1476 if (!*p) ExitArgError("Font point size missing:", name);
\r
1477 mfp->pointSize = (float) atof(p);
\r
1478 mfp->bold = (strchr(p, 'b') != NULL);
\r
1479 mfp->italic = (strchr(p, 'i') != NULL);
\r
1480 mfp->underline = (strchr(p, 'u') != NULL);
\r
1481 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1482 mfp->charset = DEFAULT_CHARSET;
\r
1483 q = strchr(p, 'c');
\r
1485 mfp->charset = (BYTE) atoi(q+1);
\r
1488 /* Color name parser.
\r
1489 X version accepts X color names, but this one
\r
1490 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1492 ParseColorName(char *name)
\r
1494 int red, green, blue, count;
\r
1495 char buf[MSG_SIZ];
\r
1497 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1499 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1500 &red, &green, &blue);
\r
1503 sprintf(buf, "Can't parse color name %s", name);
\r
1504 DisplayError(buf, 0);
\r
1505 return RGB(0, 0, 0);
\r
1507 return PALETTERGB(red, green, blue);
\r
1511 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1513 char *e = argValue;
\r
1517 if (*e == 'b') eff |= CFE_BOLD;
\r
1518 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1519 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1520 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1521 else if (*e == '#' || isdigit(*e)) break;
\r
1525 *color = ParseColorName(e);
\r
1530 ParseBoardSize(char *name)
\r
1532 BoardSize bs = SizeTiny;
\r
1533 while (sizeInfo[bs].name != NULL) {
\r
1534 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1537 ExitArgError("Unrecognized board size value", name);
\r
1538 return bs; /* not reached */
\r
1543 StringGet(void *getClosure)
\r
1545 char **p = (char **) getClosure;
\r
1550 FileGet(void *getClosure)
\r
1553 FILE* f = (FILE*) getClosure;
\r
1556 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1563 /* Parse settings file named "name". If file found, return the
\r
1564 full name in fullname and return TRUE; else return FALSE */
\r
1566 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1570 int ok; char buf[MSG_SIZ];
\r
1572 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1573 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1574 sprintf(buf, "%s.ini", name);
\r
1575 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1578 f = fopen(fullname, "r");
\r
1580 ParseArgs(FileGet, f);
\r
1589 ParseArgs(GetFunc get, void *cl)
\r
1591 char argName[ARG_MAX];
\r
1592 char argValue[ARG_MAX];
\r
1593 ArgDescriptor *ad;
\r
1602 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1603 if (ch == NULLCHAR) break;
\r
1605 /* Comment to end of line */
\r
1607 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1609 } else if (ch == '/' || ch == '-') {
\r
1612 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1613 ch != '\n' && ch != '\t') {
\r
1619 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1620 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1622 if (ad->argName == NULL)
\r
1623 ExitArgError("Unrecognized argument", argName);
\r
1625 } else if (ch == '@') {
\r
1626 /* Indirection file */
\r
1627 ad = &argDescriptorIndirection;
\r
1630 /* Positional argument */
\r
1631 ad = &argDescriptors[posarg++];
\r
1632 strcpy(argName, ad->argName);
\r
1635 if (ad->argType == ArgTrue) {
\r
1636 *(Boolean *) ad->argLoc = TRUE;
\r
1639 if (ad->argType == ArgFalse) {
\r
1640 *(Boolean *) ad->argLoc = FALSE;
\r
1644 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1645 if (ch == NULLCHAR || ch == '\n') {
\r
1646 ExitArgError("No value provided for argument", argName);
\r
1650 // Quoting with { }. No characters have to (or can) be escaped.
\r
1651 // Thus the string cannot contain a '}' character.
\r
1671 } else if (ch == '\'' || ch == '"') {
\r
1672 // Quoting with ' ' or " ", with \ as escape character.
\r
1673 // Inconvenient for long strings that may contain Windows filenames.
\r
1690 if (ch == start) {
\r
1699 if (ad->argType == ArgFilename
\r
1700 || ad->argType == ArgSettingsFilename) {
\r
1706 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1730 for (i = 0; i < 3; i++) {
\r
1731 if (ch >= '0' && ch <= '7') {
\r
1732 octval = octval*8 + (ch - '0');
\r
1739 *q++ = (char) octval;
\r
1750 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1757 switch (ad->argType) {
\r
1759 *(int *) ad->argLoc = atoi(argValue);
\r
1763 *(int *) ad->argLoc = atoi(argValue) + wpMain.x; // [HGM] placement: translate stored relative to absolute
\r
1767 *(int *) ad->argLoc = atoi(argValue) + wpMain.y; // (this is really kludgey, it should be done where used...)
\r
1771 *(int *) ad->argLoc = atoi(argValue);
\r
1772 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1776 *(float *) ad->argLoc = (float) atof(argValue);
\r
1781 *(char **) ad->argLoc = strdup(argValue);
\r
1784 case ArgSettingsFilename:
\r
1786 char fullname[MSG_SIZ];
\r
1787 if (ParseSettingsFile(argValue, fullname)) {
\r
1788 if (ad->argLoc != NULL) {
\r
1789 *(char **) ad->argLoc = strdup(fullname);
\r
1792 if (ad->argLoc != NULL) {
\r
1794 ExitArgError("Failed to open indirection file", argValue);
\r
1801 switch (argValue[0]) {
\r
1804 *(Boolean *) ad->argLoc = TRUE;
\r
1808 *(Boolean *) ad->argLoc = FALSE;
\r
1811 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1817 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1820 case ArgAttribs: {
\r
1821 ColorClass cc = (ColorClass)ad->argLoc;
\r
1822 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1826 case ArgBoardSize:
\r
1827 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1831 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1834 case ArgCommSettings:
\r
1835 ParseCommSettings(argValue, &dcb);
\r
1839 ExitArgError("Unrecognized argument", argValue);
\r
1848 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1850 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1851 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1854 lf->lfEscapement = 0;
\r
1855 lf->lfOrientation = 0;
\r
1856 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1857 lf->lfItalic = mfp->italic;
\r
1858 lf->lfUnderline = mfp->underline;
\r
1859 lf->lfStrikeOut = mfp->strikeout;
\r
1860 lf->lfCharSet = mfp->charset;
\r
1861 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1862 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1863 lf->lfQuality = DEFAULT_QUALITY;
\r
1864 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1865 strcpy(lf->lfFaceName, mfp->faceName);
\r
1869 CreateFontInMF(MyFont *mf)
\r
1871 LFfromMFP(&mf->lf, &mf->mfp);
\r
1872 if (mf->hf) DeleteObject(mf->hf);
\r
1873 mf->hf = CreateFontIndirect(&mf->lf);
\r
1877 SetDefaultTextAttribs()
\r
1880 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1881 ParseAttribs(&textAttribs[cc].color,
\r
1882 &textAttribs[cc].effects,
\r
1883 defaultTextAttribs[cc]);
\r
1888 SetDefaultSounds()
\r
1892 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1893 textAttribs[cc].sound.name = strdup("");
\r
1894 textAttribs[cc].sound.data = NULL;
\r
1896 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1897 sounds[sc].name = strdup("");
\r
1898 sounds[sc].data = NULL;
\r
1900 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1908 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1909 MyLoadSound(&textAttribs[cc].sound);
\r
1911 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1912 MyLoadSound(&sounds[sc]);
\r
1917 SetDefaultsFromList()
\r
1918 { // [HGM] ini: take defaults from argDescriptor list
\r
1921 for(i=0; argDescriptors[i].argName != NULL; i++) {
\r
1922 if(argDescriptors[i].defaultValue != INVALID)
\r
1923 switch(argDescriptors[i].argType) {
\r
1927 *(Boolean *) argDescriptors[i].argLoc = (int)argDescriptors[i].defaultValue;
\r
1933 *(int *) argDescriptors[i].argLoc = (int)argDescriptors[i].defaultValue;
\r
1937 case ArgSettingsFilename:
\r
1938 *(char **) argDescriptors[i].argLoc = (char *)argDescriptors[i].defaultValue;
\r
1940 case ArgBoardSize:
\r
1941 *(BoardSize *) argDescriptors[i].argLoc = (BoardSize)argDescriptors[i].defaultValue;
\r
1943 case ArgFloat: // floats cannot be casted to int without precision loss
\r
1944 default: ; // some arg types cannot be initialized through table
\r
1950 InitAppData(LPSTR lpCmdLine)
\r
1953 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1956 programName = szAppName;
\r
1958 /* Initialize to defaults */
\r
1959 SetDefaultsFromList(); // this sets most defaults
\r
1961 // some parameters for which there are no options!
\r
1962 appData.Iconic = FALSE; /*unused*/
\r
1963 appData.cmailGameName = "";
\r
1964 appData.icsEngineAnalyze = FALSE;
\r
1966 // float: casting to int is not harmless, so default cannot be contained in table
\r
1967 appData.timeDelay = TIME_DELAY;
\r
1969 // colors have platform-dependent option format and internal representation
\r
1970 // their setting and parsing must remain in front-end
\r
1971 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1972 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1973 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1974 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1975 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1976 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1977 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1978 // the following must be moved out of appData to front-end variables
\r
1979 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1980 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1981 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1983 // some complex, platform-dependent stuff
\r
1984 SetDefaultTextAttribs();
\r
1985 SetDefaultSounds();
\r
1987 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1988 dcb.DCBlength = sizeof(DCB);
\r
1989 dcb.BaudRate = 9600;
\r
1990 dcb.fBinary = TRUE;
\r
1991 dcb.fParity = FALSE;
\r
1992 dcb.fOutxCtsFlow = FALSE;
\r
1993 dcb.fOutxDsrFlow = FALSE;
\r
1994 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1995 dcb.fDsrSensitivity = FALSE;
\r
1996 dcb.fTXContinueOnXoff = TRUE;
\r
1997 dcb.fOutX = FALSE;
\r
1999 dcb.fNull = FALSE;
\r
2000 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2001 dcb.fAbortOnError = FALSE;
\r
2003 dcb.Parity = SPACEPARITY;
\r
2004 dcb.StopBits = ONESTOPBIT;
\r
2006 /* Point font array elements to structures and
\r
2007 parse default font names */
\r
2008 for (i=0; i<NUM_FONTS; i++) {
\r
2009 for (j=0; j<NUM_SIZES; j++) {
\r
2010 font[j][i] = &fontRec[j][i];
\r
2011 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2015 /* Parse default settings file if any */
\r
2016 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2017 settingsFileName = strdup(buf);
\r
2020 /* Parse command line */
\r
2021 ParseArgs(StringGet, &lpCmdLine);
\r
2023 /* [HGM] make sure board size is acceptable */
\r
2024 if(appData.NrFiles > BOARD_FILES ||
\r
2025 appData.NrRanks > BOARD_RANKS )
\r
2026 DisplayFatalError("Recompile with BOARD_RANKS or BOARD_FILES, to support this size", 0, 2);
\r
2028 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2029 * with options from the command line, we now make an even higher priority
\r
2030 * overrule by WB options attached to the engine command line. This so that
\r
2031 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2034 if(appData.firstChessProgram != NULL) {
\r
2035 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2036 static char *f = "first";
\r
2037 char buf[MSG_SIZ], *q = buf;
\r
2038 if(p != NULL) { // engine command line contains WinBoard options
\r
2039 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2040 ParseArgs(StringGet, &q);
\r
2041 p[-1] = 0; // cut them offengine command line
\r
2044 // now do same for second chess program
\r
2045 if(appData.secondChessProgram != NULL) {
\r
2046 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2047 static char *s = "second";
\r
2048 char buf[MSG_SIZ], *q = buf;
\r
2049 if(p != NULL) { // engine command line contains WinBoard options
\r
2050 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2051 ParseArgs(StringGet, &q);
\r
2052 p[-1] = 0; // cut them offengine command line
\r
2057 /* Propagate options that affect others */
\r
2058 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2059 if (appData.icsActive || appData.noChessProgram) {
\r
2060 chessProgram = FALSE; /* not local chess program mode */
\r
2063 /* Open startup dialog if needed */
\r
2064 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2065 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2066 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2067 *appData.secondChessProgram == NULLCHAR))) {
\r
2070 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2071 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2072 FreeProcInstance(lpProc);
\r
2075 /* Make sure save files land in the right (?) directory */
\r
2076 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2077 appData.saveGameFile = strdup(buf);
\r
2079 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2080 appData.savePositionFile = strdup(buf);
\r
2083 /* Finish initialization for fonts and sounds */
\r
2084 for (i=0; i<NUM_FONTS; i++) {
\r
2085 for (j=0; j<NUM_SIZES; j++) {
\r
2086 CreateFontInMF(font[j][i]);
\r
2089 /* xboard, and older WinBoards, controlled the move sound with the
\r
2090 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2091 always turn the option on (so that the backend will call us),
\r
2092 then let the user turn the sound off by setting it to silence if
\r
2093 desired. To accommodate old winboard.ini files saved by old
\r
2094 versions of WinBoard, we also turn off the sound if the option
\r
2095 was initially set to false. */
\r
2096 if (!appData.ringBellAfterMoves) {
\r
2097 sounds[(int)SoundMove].name = strdup("");
\r
2098 appData.ringBellAfterMoves = TRUE;
\r
2100 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2101 SetCurrentDirectory(installDir);
\r
2103 SetCurrentDirectory(currDir);
\r
2105 p = icsTextMenuString;
\r
2106 if (p[0] == '@') {
\r
2107 FILE* f = fopen(p + 1, "r");
\r
2109 DisplayFatalError(p + 1, errno, 2);
\r
2112 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2114 buf[i] = NULLCHAR;
\r
2117 ParseIcsTextMenu(strdup(p));
\r
2124 HMENU hmenu = GetMenu(hwndMain);
\r
2126 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2127 MF_BYCOMMAND|((appData.icsActive &&
\r
2128 *appData.icsCommPort != NULLCHAR) ?
\r
2129 MF_ENABLED : MF_GRAYED));
\r
2130 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2131 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2132 MF_CHECKED : MF_UNCHECKED));
\r
2135 // [HGM] args: these three cases taken out to stay in front-end
\r
2137 SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
2138 { // in WinBoard every board size has its own font, and the "argLoc" identifies the table,
\r
2139 // while the curent board size determines the element. This system should be ported to XBoard.
\r
2140 // What the table contains pointers to, and how to print the font description, remains platform-dependent
\r
2142 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2143 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2144 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2145 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
2146 ad->argName, mfp->faceName, mfp->pointSize,
\r
2147 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2148 mfp->bold ? "b" : "",
\r
2149 mfp->italic ? "i" : "",
\r
2150 mfp->underline ? "u" : "",
\r
2151 mfp->strikeout ? "s" : "",
\r
2152 (int)mfp->charset);
\r
2157 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
2158 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
\r
2159 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2160 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2161 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2162 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2163 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2164 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2165 (ta->effects) ? " " : "",
\r
2166 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2170 SaveColor(FILE *f, ArgDescriptor *ad)
\r
2171 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
\r
2172 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2173 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2174 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2179 { // [HGM] args: allows testing if main window is realized from back-end
\r
2180 return hwndMain != NULL;
\r
2184 SaveSettings(char* name)
\r
2187 ArgDescriptor *ad;
\r
2188 char dir[MSG_SIZ];
\r
2190 if (!MainWindowUp()) return;
\r
2192 GetCurrentDirectory(MSG_SIZ, dir);
\r
2193 SetCurrentDirectory(installDir);
\r
2194 f = fopen(name, "w");
\r
2195 SetCurrentDirectory(dir);
\r
2197 DisplayError(name, errno);
\r
2200 fprintf(f, ";\n");
\r
2201 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2202 fprintf(f, ";\n");
\r
2203 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2204 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2205 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2206 fprintf(f, ";\n");
\r
2208 GetActualPlacement(hwndMain, &wpMain);
\r
2209 GetActualPlacement(hwndConsole, &wpConsole);
\r
2210 GetActualPlacement(commentDialog, &wpComment);
\r
2211 GetActualPlacement(editTagsDialog, &wpTags);
\r
2212 GetActualPlacement(gameListDialog, &wpGameList);
\r
2214 /* [AS] Move history */
\r
2215 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2216 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
2218 /* [AS] Eval graph */
\r
2219 wpEvalGraph.visible = EvalGraphIsUp();
\r
2220 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
2222 /* [AS] Engine output */
\r
2223 wpEngineOutput.visible = EngineOutputIsUp();
\r
2224 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
2226 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2227 if (!ad->save) continue;
\r
2228 switch (ad->argType) {
\r
2231 char *p = *(char **)ad->argLoc;
\r
2232 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2233 /* Quote multiline values or \-containing values
\r
2234 with { } if possible */
\r
2235 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2237 /* Else quote with " " */
\r
2238 fprintf(f, "/%s=\"", ad->argName);
\r
2240 if (*p == '\n') fprintf(f, "\n");
\r
2241 else if (*p == '\r') fprintf(f, "\\r");
\r
2242 else if (*p == '\t') fprintf(f, "\\t");
\r
2243 else if (*p == '\b') fprintf(f, "\\b");
\r
2244 else if (*p == '\f') fprintf(f, "\\f");
\r
2245 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2246 else if (*p == '\"') fprintf(f, "\\\"");
\r
2247 else if (*p == '\\') fprintf(f, "\\\\");
\r
2251 fprintf(f, "\"\n");
\r
2257 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2260 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - wpMain.x); // [HGM] placement: stor relative value
\r
2263 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - wpMain.y);
\r
2266 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2269 fprintf(f, "/%s=%s\n", ad->argName,
\r
2270 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2273 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2276 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2284 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2285 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2287 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2290 case ArgBoardSize:
\r
2291 fprintf(f, "/%s=%s\n", ad->argName,
\r
2292 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2295 SaveFontArg(f, ad);
\r
2297 case ArgCommSettings:
\r
2298 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2300 case ArgSettingsFilename: ;
\r
2308 /*---------------------------------------------------------------------------*\
\r
2310 * GDI board drawing routines
\r
2312 \*---------------------------------------------------------------------------*/
\r
2314 /* [AS] Draw square using background texture */
\r
2315 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2320 return; /* Should never happen! */
\r
2323 SetGraphicsMode( dst, GM_ADVANCED );
\r
2330 /* X reflection */
\r
2335 x.eDx = (FLOAT) dw + dx - 1;
\r
2338 SetWorldTransform( dst, &x );
\r
2341 /* Y reflection */
\r
2347 x.eDy = (FLOAT) dh + dy - 1;
\r
2349 SetWorldTransform( dst, &x );
\r
2357 x.eDx = (FLOAT) dx;
\r
2358 x.eDy = (FLOAT) dy;
\r
2361 SetWorldTransform( dst, &x );
\r
2365 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2373 SetWorldTransform( dst, &x );
\r
2375 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2378 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2380 PM_WP = (int) WhitePawn,
\r
2381 PM_WN = (int) WhiteKnight,
\r
2382 PM_WB = (int) WhiteBishop,
\r
2383 PM_WR = (int) WhiteRook,
\r
2384 PM_WQ = (int) WhiteQueen,
\r
2385 PM_WF = (int) WhiteFerz,
\r
2386 PM_WW = (int) WhiteWazir,
\r
2387 PM_WE = (int) WhiteAlfil,
\r
2388 PM_WM = (int) WhiteMan,
\r
2389 PM_WO = (int) WhiteCannon,
\r
2390 PM_WU = (int) WhiteUnicorn,
\r
2391 PM_WH = (int) WhiteNightrider,
\r
2392 PM_WA = (int) WhiteAngel,
\r
2393 PM_WC = (int) WhiteMarshall,
\r
2394 PM_WAB = (int) WhiteCardinal,
\r
2395 PM_WD = (int) WhiteDragon,
\r
2396 PM_WL = (int) WhiteLance,
\r
2397 PM_WS = (int) WhiteCobra,
\r
2398 PM_WV = (int) WhiteFalcon,
\r
2399 PM_WSG = (int) WhiteSilver,
\r
2400 PM_WG = (int) WhiteGrasshopper,
\r
2401 PM_WK = (int) WhiteKing,
\r
2402 PM_BP = (int) BlackPawn,
\r
2403 PM_BN = (int) BlackKnight,
\r
2404 PM_BB = (int) BlackBishop,
\r
2405 PM_BR = (int) BlackRook,
\r
2406 PM_BQ = (int) BlackQueen,
\r
2407 PM_BF = (int) BlackFerz,
\r
2408 PM_BW = (int) BlackWazir,
\r
2409 PM_BE = (int) BlackAlfil,
\r
2410 PM_BM = (int) BlackMan,
\r
2411 PM_BO = (int) BlackCannon,
\r
2412 PM_BU = (int) BlackUnicorn,
\r
2413 PM_BH = (int) BlackNightrider,
\r
2414 PM_BA = (int) BlackAngel,
\r
2415 PM_BC = (int) BlackMarshall,
\r
2416 PM_BG = (int) BlackGrasshopper,
\r
2417 PM_BAB = (int) BlackCardinal,
\r
2418 PM_BD = (int) BlackDragon,
\r
2419 PM_BL = (int) BlackLance,
\r
2420 PM_BS = (int) BlackCobra,
\r
2421 PM_BV = (int) BlackFalcon,
\r
2422 PM_BSG = (int) BlackSilver,
\r
2423 PM_BK = (int) BlackKing
\r
2426 static HFONT hPieceFont = NULL;
\r
2427 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2428 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2429 static int fontBitmapSquareSize = 0;
\r
2430 static char pieceToFontChar[(int) EmptySquare] =
\r
2431 { 'p', 'n', 'b', 'r', 'q',
\r
2432 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2433 'k', 'o', 'm', 'v', 't', 'w',
\r
2434 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2437 extern BOOL SetCharTable( char *table, const char * map );
\r
2438 /* [HGM] moved to backend.c */
\r
2440 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2443 BYTE r1 = GetRValue( color );
\r
2444 BYTE g1 = GetGValue( color );
\r
2445 BYTE b1 = GetBValue( color );
\r
2451 /* Create a uniform background first */
\r
2452 hbrush = CreateSolidBrush( color );
\r
2453 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2454 FillRect( hdc, &rc, hbrush );
\r
2455 DeleteObject( hbrush );
\r
2458 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2459 int steps = squareSize / 2;
\r
2462 for( i=0; i<steps; i++ ) {
\r
2463 BYTE r = r1 - (r1-r2) * i / steps;
\r
2464 BYTE g = g1 - (g1-g2) * i / steps;
\r
2465 BYTE b = b1 - (b1-b2) * i / steps;
\r
2467 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2468 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2469 FillRect( hdc, &rc, hbrush );
\r
2470 DeleteObject(hbrush);
\r
2473 else if( mode == 2 ) {
\r
2474 /* Diagonal gradient, good more or less for every piece */
\r
2475 POINT triangle[3];
\r
2476 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2477 HBRUSH hbrush_old;
\r
2478 int steps = squareSize;
\r
2481 triangle[0].x = squareSize - steps;
\r
2482 triangle[0].y = squareSize;
\r
2483 triangle[1].x = squareSize;
\r
2484 triangle[1].y = squareSize;
\r
2485 triangle[2].x = squareSize;
\r
2486 triangle[2].y = squareSize - steps;
\r
2488 for( i=0; i<steps; i++ ) {
\r
2489 BYTE r = r1 - (r1-r2) * i / steps;
\r
2490 BYTE g = g1 - (g1-g2) * i / steps;
\r
2491 BYTE b = b1 - (b1-b2) * i / steps;
\r
2493 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2494 hbrush_old = SelectObject( hdc, hbrush );
\r
2495 Polygon( hdc, triangle, 3 );
\r
2496 SelectObject( hdc, hbrush_old );
\r
2497 DeleteObject(hbrush);
\r
2502 SelectObject( hdc, hpen );
\r
2507 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2508 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2509 piece: follow the steps as explained below.
\r
2511 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2515 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2519 int backColor = whitePieceColor;
\r
2520 int foreColor = blackPieceColor;
\r
2522 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2523 backColor = appData.fontBackColorWhite;
\r
2524 foreColor = appData.fontForeColorWhite;
\r
2526 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2527 backColor = appData.fontBackColorBlack;
\r
2528 foreColor = appData.fontForeColorBlack;
\r
2532 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2534 hbm_old = SelectObject( hdc, hbm );
\r
2538 rc.right = squareSize;
\r
2539 rc.bottom = squareSize;
\r
2541 /* Step 1: background is now black */
\r
2542 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2544 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2546 pt.x = (squareSize - sz.cx) / 2;
\r
2547 pt.y = (squareSize - sz.cy) / 2;
\r
2549 SetBkMode( hdc, TRANSPARENT );
\r
2550 SetTextColor( hdc, chroma );
\r
2551 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2552 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2554 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2555 /* Step 3: the area outside the piece is filled with white */
\r
2556 // FloodFill( hdc, 0, 0, chroma );
\r
2557 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2558 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2559 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2560 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2561 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2563 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2564 but if the start point is not inside the piece we're lost!
\r
2565 There should be a better way to do this... if we could create a region or path
\r
2566 from the fill operation we would be fine for example.
\r
2568 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2569 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2571 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2572 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2573 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2575 SelectObject( dc2, bm2 );
\r
2576 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2577 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2578 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2579 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2580 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2583 DeleteObject( bm2 );
\r
2586 SetTextColor( hdc, 0 );
\r
2588 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2589 draw the piece again in black for safety.
\r
2591 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2593 SelectObject( hdc, hbm_old );
\r
2595 if( hPieceMask[index] != NULL ) {
\r
2596 DeleteObject( hPieceMask[index] );
\r
2599 hPieceMask[index] = hbm;
\r
2602 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2604 SelectObject( hdc, hbm );
\r
2607 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2608 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2609 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2611 SelectObject( dc1, hPieceMask[index] );
\r
2612 SelectObject( dc2, bm2 );
\r
2613 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2614 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2617 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2618 the piece background and deletes (makes transparent) the rest.
\r
2619 Thanks to that mask, we are free to paint the background with the greates
\r
2620 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2621 We use this, to make gradients and give the pieces a "roundish" look.
\r
2623 SetPieceBackground( hdc, backColor, 2 );
\r
2624 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2628 DeleteObject( bm2 );
\r
2631 SetTextColor( hdc, foreColor );
\r
2632 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2634 SelectObject( hdc, hbm_old );
\r
2636 if( hPieceFace[index] != NULL ) {
\r
2637 DeleteObject( hPieceFace[index] );
\r
2640 hPieceFace[index] = hbm;
\r
2643 static int TranslatePieceToFontPiece( int piece )
\r
2673 case BlackMarshall:
\r
2677 case BlackNightrider:
\r
2683 case BlackUnicorn:
\r
2687 case BlackGrasshopper:
\r
2699 case BlackCardinal:
\r
2706 case WhiteMarshall:
\r
2710 case WhiteNightrider:
\r
2716 case WhiteUnicorn:
\r
2720 case WhiteGrasshopper:
\r
2732 case WhiteCardinal:
\r
2741 void CreatePiecesFromFont()
\r
2744 HDC hdc_window = NULL;
\r
2750 if( fontBitmapSquareSize < 0 ) {
\r
2751 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2755 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2756 fontBitmapSquareSize = -1;
\r
2760 if( fontBitmapSquareSize != squareSize ) {
\r
2761 hdc_window = GetDC( hwndMain );
\r
2762 hdc = CreateCompatibleDC( hdc_window );
\r
2764 if( hPieceFont != NULL ) {
\r
2765 DeleteObject( hPieceFont );
\r
2768 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2769 hPieceMask[i] = NULL;
\r
2770 hPieceFace[i] = NULL;
\r
2776 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2777 fontHeight = appData.fontPieceSize;
\r
2780 fontHeight = (fontHeight * squareSize) / 100;
\r
2782 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2784 lf.lfEscapement = 0;
\r
2785 lf.lfOrientation = 0;
\r
2786 lf.lfWeight = FW_NORMAL;
\r
2788 lf.lfUnderline = 0;
\r
2789 lf.lfStrikeOut = 0;
\r
2790 lf.lfCharSet = DEFAULT_CHARSET;
\r
2791 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2792 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2793 lf.lfQuality = PROOF_QUALITY;
\r
2794 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2795 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2796 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2798 hPieceFont = CreateFontIndirect( &lf );
\r
2800 if( hPieceFont == NULL ) {
\r
2801 fontBitmapSquareSize = -2;
\r
2804 /* Setup font-to-piece character table */
\r
2805 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2806 /* No (or wrong) global settings, try to detect the font */
\r
2807 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2809 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2811 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2812 /* DiagramTT* family */
\r
2813 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2815 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2816 /* Fairy symbols */
\r
2817 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2819 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2820 /* Good Companion (Some characters get warped as literal :-( */
\r
2821 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2822 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2823 SetCharTable(pieceToFontChar, s);
\r
2826 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2827 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2831 /* Create bitmaps */
\r
2832 hfont_old = SelectObject( hdc, hPieceFont );
\r
2833 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2834 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2835 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2837 SelectObject( hdc, hfont_old );
\r
2839 fontBitmapSquareSize = squareSize;
\r
2843 if( hdc != NULL ) {
\r
2847 if( hdc_window != NULL ) {
\r
2848 ReleaseDC( hwndMain, hdc_window );
\r
2853 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2857 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2858 if (gameInfo.event &&
\r
2859 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2860 strcmp(name, "k80s") == 0) {
\r
2861 strcpy(name, "tim");
\r
2863 return LoadBitmap(hinst, name);
\r
2867 /* Insert a color into the program's logical palette
\r
2868 structure. This code assumes the given color is
\r
2869 the result of the RGB or PALETTERGB macro, and it
\r
2870 knows how those macros work (which is documented).
\r
2873 InsertInPalette(COLORREF color)
\r
2875 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2877 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2878 DisplayFatalError("Too many colors", 0, 1);
\r
2879 pLogPal->palNumEntries--;
\r
2883 pe->peFlags = (char) 0;
\r
2884 pe->peRed = (char) (0xFF & color);
\r
2885 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2886 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2892 InitDrawingColors()
\r
2894 if (pLogPal == NULL) {
\r
2895 /* Allocate enough memory for a logical palette with
\r
2896 * PALETTESIZE entries and set the size and version fields
\r
2897 * of the logical palette structure.
\r
2899 pLogPal = (NPLOGPALETTE)
\r
2900 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2901 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2902 pLogPal->palVersion = 0x300;
\r
2904 pLogPal->palNumEntries = 0;
\r
2906 InsertInPalette(lightSquareColor);
\r
2907 InsertInPalette(darkSquareColor);
\r
2908 InsertInPalette(whitePieceColor);
\r
2909 InsertInPalette(blackPieceColor);
\r
2910 InsertInPalette(highlightSquareColor);
\r
2911 InsertInPalette(premoveHighlightColor);
\r
2913 /* create a logical color palette according the information
\r
2914 * in the LOGPALETTE structure.
\r
2916 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2918 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2919 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2920 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2921 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2922 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2923 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2924 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
2925 /* [AS] Force rendering of the font-based pieces */
\r
2926 if( fontBitmapSquareSize > 0 ) {
\r
2927 fontBitmapSquareSize = 0;
\r
2933 BoardWidth(int boardSize, int n)
\r
2934 { /* [HGM] argument n added to allow different width and height */
\r
2935 int lineGap = sizeInfo[boardSize].lineGap;
\r
2937 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2938 lineGap = appData.overrideLineGap;
\r
2941 return (n + 1) * lineGap +
\r
2942 n * sizeInfo[boardSize].squareSize;
\r
2945 /* Respond to board resize by dragging edge */
\r
2947 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2949 BoardSize newSize = NUM_SIZES - 1;
\r
2950 static int recurse = 0;
\r
2951 if (IsIconic(hwndMain)) return;
\r
2952 if (recurse > 0) return;
\r
2954 while (newSize > 0) {
\r
2955 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
2956 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
2957 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2960 boardSize = newSize;
\r
2961 InitDrawingSizes(boardSize, flags);
\r
2968 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2970 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2971 ChessSquare piece;
\r
2972 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2974 SIZE clockSize, messageSize;
\r
2976 char buf[MSG_SIZ];
\r
2978 HMENU hmenu = GetMenu(hwndMain);
\r
2979 RECT crect, wrect, oldRect;
\r
2981 LOGBRUSH logbrush;
\r
2983 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
2984 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
2986 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
2987 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2989 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
2990 oldRect.top = wpMain.y;
\r
2991 oldRect.right = wpMain.x + wpMain.width;
\r
2992 oldRect.bottom = wpMain.y + wpMain.height;
\r
2994 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2995 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2996 squareSize = sizeInfo[boardSize].squareSize;
\r
2997 lineGap = sizeInfo[boardSize].lineGap;
\r
2998 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3000 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3001 lineGap = appData.overrideLineGap;
\r
3004 if (tinyLayout != oldTinyLayout) {
\r
3005 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3007 style &= ~WS_SYSMENU;
\r
3008 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3009 "&Minimize\tCtrl+F4");
\r
3011 style |= WS_SYSMENU;
\r
3012 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3014 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3016 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3017 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3018 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3020 DrawMenuBar(hwndMain);
\r
3023 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3024 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3026 /* Get text area sizes */
\r
3027 hdc = GetDC(hwndMain);
\r
3028 if (appData.clockMode) {
\r
3029 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3031 sprintf(buf, "White");
\r
3033 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3034 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3035 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3036 str = "We only care about the height here";
\r
3037 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3038 SelectObject(hdc, oldFont);
\r
3039 ReleaseDC(hwndMain, hdc);
\r
3041 /* Compute where everything goes */
\r
3042 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3043 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3044 logoHeight = 2*clockSize.cy;
\r
3045 leftLogoRect.left = OUTER_MARGIN;
\r
3046 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3047 leftLogoRect.top = OUTER_MARGIN;
\r
3048 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3050 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3051 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3052 rightLogoRect.top = OUTER_MARGIN;
\r
3053 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3056 whiteRect.left = leftLogoRect.right;
\r
3057 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3058 whiteRect.top = OUTER_MARGIN;
\r
3059 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3061 blackRect.right = rightLogoRect.left;
\r
3062 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3063 blackRect.top = whiteRect.top;
\r
3064 blackRect.bottom = whiteRect.bottom;
\r
3066 whiteRect.left = OUTER_MARGIN;
\r
3067 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3068 whiteRect.top = OUTER_MARGIN;
\r
3069 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3071 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3072 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3073 blackRect.top = whiteRect.top;
\r
3074 blackRect.bottom = whiteRect.bottom;
\r
3077 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3078 if (appData.showButtonBar) {
\r
3079 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3080 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3082 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3084 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3085 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3087 boardRect.left = OUTER_MARGIN;
\r
3088 boardRect.right = boardRect.left + boardWidth;
\r
3089 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3090 boardRect.bottom = boardRect.top + boardHeight;
\r
3092 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3093 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3094 oldBoardSize = boardSize;
\r
3095 oldTinyLayout = tinyLayout;
\r
3096 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3097 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3098 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3099 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3100 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3101 wpMain.height = winH; // without disturbing window attachments
\r
3102 GetWindowRect(hwndMain, &wrect);
\r
3103 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
3104 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3106 // [HGM] placement: let attached windows follow size change.
\r
3107 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
3108 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
3109 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
3110 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
3111 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
3113 /* compensate if menu bar wrapped */
\r
3114 GetClientRect(hwndMain, &crect);
\r
3115 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3116 wpMain.height += offby;
\r
3118 case WMSZ_TOPLEFT:
\r
3119 SetWindowPos(hwndMain, NULL,
\r
3120 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
3121 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3124 case WMSZ_TOPRIGHT:
\r
3126 SetWindowPos(hwndMain, NULL,
\r
3127 wrect.left, wrect.bottom - wpMain.height,
\r
3128 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3131 case WMSZ_BOTTOMLEFT:
\r
3133 SetWindowPos(hwndMain, NULL,
\r
3134 wrect.right - wpMain.width, wrect.top,
\r
3135 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3138 case WMSZ_BOTTOMRIGHT:
\r
3142 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
3143 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3148 for (i = 0; i < N_BUTTONS; i++) {
\r
3149 if (buttonDesc[i].hwnd != NULL) {
\r
3150 DestroyWindow(buttonDesc[i].hwnd);
\r
3151 buttonDesc[i].hwnd = NULL;
\r
3153 if (appData.showButtonBar) {
\r
3154 buttonDesc[i].hwnd =
\r
3155 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3156 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3157 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3158 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3159 (HMENU) buttonDesc[i].id,
\r
3160 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3162 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3163 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3164 MAKELPARAM(FALSE, 0));
\r
3166 if (buttonDesc[i].id == IDM_Pause)
\r
3167 hwndPause = buttonDesc[i].hwnd;
\r
3168 buttonDesc[i].wndproc = (WNDPROC)
\r
3169 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3172 if (gridPen != NULL) DeleteObject(gridPen);
\r
3173 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3174 if (premovePen != NULL) DeleteObject(premovePen);
\r
3175 if (lineGap != 0) {
\r
3176 logbrush.lbStyle = BS_SOLID;
\r
3177 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3179 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3180 lineGap, &logbrush, 0, NULL);
\r
3181 logbrush.lbColor = highlightSquareColor;
\r
3183 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3184 lineGap, &logbrush, 0, NULL);
\r
3186 logbrush.lbColor = premoveHighlightColor;
\r
3188 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3189 lineGap, &logbrush, 0, NULL);
\r
3191 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3192 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3193 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3194 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3195 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3196 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3197 BOARD_WIDTH * (squareSize + lineGap);
\r
3198 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3200 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3201 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3202 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3203 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3204 lineGap / 2 + (i * (squareSize + lineGap));
\r
3205 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3206 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3207 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3211 /* [HGM] Licensing requirement */
\r
3213 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3216 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3218 GothicPopUp( "", VariantNormal);
\r
3221 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3223 /* Load piece bitmaps for this board size */
\r
3224 for (i=0; i<=2; i++) {
\r
3225 for (piece = WhitePawn;
\r
3226 (int) piece < (int) BlackPawn;
\r
3227 piece = (ChessSquare) ((int) piece + 1)) {
\r
3228 if (pieceBitmap[i][piece] != NULL)
\r
3229 DeleteObject(pieceBitmap[i][piece]);
\r
3233 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3234 // Orthodox Chess pieces
\r
3235 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3236 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3237 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3238 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3239 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3240 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3241 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3242 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3243 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3244 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3245 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3246 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3247 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3248 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3249 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3250 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3251 // in Shogi, Hijack the unused Queen for Lance
\r
3252 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3253 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3254 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3256 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3257 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3258 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3261 if(squareSize <= 72 && squareSize >= 33) {
\r
3262 /* A & C are available in most sizes now */
\r
3263 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3264 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3265 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3266 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3267 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3268 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3269 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3270 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3271 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3272 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3273 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3274 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3275 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3276 } else { // Smirf-like
\r
3277 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3278 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3279 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3281 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3282 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3283 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3284 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3285 } else { // WinBoard standard
\r
3286 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3287 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3288 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3293 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3294 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3295 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3296 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3297 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3298 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3299 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3300 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3301 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3302 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3303 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3304 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3305 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3306 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3307 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3308 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3309 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3310 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3311 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3312 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3313 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3314 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3315 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3316 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3317 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3318 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3319 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3320 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3321 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3322 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3323 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3325 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3326 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3327 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3328 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3329 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3330 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3331 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3332 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3333 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3334 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3335 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3336 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3337 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3339 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3340 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3341 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3342 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3343 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3344 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3345 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3346 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3347 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3348 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3349 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3350 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3353 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3354 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3355 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3356 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3357 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3358 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3359 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3360 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3361 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3362 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3363 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3364 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3365 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3366 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3367 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3371 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3372 /* special Shogi support in this size */
\r
3373 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3374 for (piece = WhitePawn;
\r
3375 (int) piece < (int) BlackPawn;
\r
3376 piece = (ChessSquare) ((int) piece + 1)) {
\r
3377 if (pieceBitmap[i][piece] != NULL)
\r
3378 DeleteObject(pieceBitmap[i][piece]);
\r
3381 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3382 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3383 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3384 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3385 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3386 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3387 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3388 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3389 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3390 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3391 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3392 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3393 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3394 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3395 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3396 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3397 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3398 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3399 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3400 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3401 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3402 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3403 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3404 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3405 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3406 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3407 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3408 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3409 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3410 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3411 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3412 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3413 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3414 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3415 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3416 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3417 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3418 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3419 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3420 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3421 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3422 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3428 PieceBitmap(ChessSquare p, int kind)
\r
3430 if ((int) p >= (int) BlackPawn)
\r
3431 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3433 return pieceBitmap[kind][(int) p];
\r
3436 /***************************************************************/
\r
3438 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3439 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3441 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3442 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3446 SquareToPos(int row, int column, int * x, int * y)
\r
3449 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3450 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3452 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3453 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3458 DrawCoordsOnDC(HDC hdc)
\r
3460 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
3461 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
3462 char str[2] = { NULLCHAR, NULLCHAR };
\r
3463 int oldMode, oldAlign, x, y, start, i;
\r
3467 if (!appData.showCoords)
\r
3470 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3472 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3473 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3474 oldAlign = GetTextAlign(hdc);
\r
3475 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3477 y = boardRect.top + lineGap;
\r
3478 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3480 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3481 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3482 str[0] = files[start + i];
\r
3483 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3484 y += squareSize + lineGap;
\r
3487 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3489 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3490 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3491 str[0] = ranks[start + i];
\r
3492 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3493 x += squareSize + lineGap;
\r
3496 SelectObject(hdc, oldBrush);
\r
3497 SetBkMode(hdc, oldMode);
\r
3498 SetTextAlign(hdc, oldAlign);
\r
3499 SelectObject(hdc, oldFont);
\r
3503 DrawGridOnDC(HDC hdc)
\r
3507 if (lineGap != 0) {
\r
3508 oldPen = SelectObject(hdc, gridPen);
\r
3509 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3510 SelectObject(hdc, oldPen);
\r
3514 #define HIGHLIGHT_PEN 0
\r
3515 #define PREMOVE_PEN 1
\r
3518 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3521 HPEN oldPen, hPen;
\r
3522 if (lineGap == 0) return;
\r
3524 x1 = boardRect.left +
\r
3525 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3526 y1 = boardRect.top +
\r
3527 lineGap/2 + y * (squareSize + lineGap);
\r
3529 x1 = boardRect.left +
\r
3530 lineGap/2 + x * (squareSize + lineGap);
\r
3531 y1 = boardRect.top +
\r
3532 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3534 hPen = pen ? premovePen : highlightPen;
\r
3535 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3536 MoveToEx(hdc, x1, y1, NULL);
\r
3537 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3538 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3539 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3540 LineTo(hdc, x1, y1);
\r
3541 SelectObject(hdc, oldPen);
\r
3545 DrawHighlightsOnDC(HDC hdc)
\r
3548 for (i=0; i<2; i++) {
\r
3549 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3550 DrawHighlightOnDC(hdc, TRUE,
\r
3551 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3554 for (i=0; i<2; i++) {
\r
3555 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3556 premoveHighlightInfo.sq[i].y >= 0) {
\r
3557 DrawHighlightOnDC(hdc, TRUE,
\r
3558 premoveHighlightInfo.sq[i].x,
\r
3559 premoveHighlightInfo.sq[i].y,
\r
3565 /* Note: sqcolor is used only in monoMode */
\r
3566 /* Note that this code is largely duplicated in woptions.c,
\r
3567 function DrawSampleSquare, so that needs to be updated too */
\r
3569 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3571 HBITMAP oldBitmap;
\r
3575 if (appData.blindfold) return;
\r
3577 /* [AS] Use font-based pieces if needed */
\r
3578 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3579 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3580 CreatePiecesFromFont();
\r
3582 if( fontBitmapSquareSize == squareSize ) {
\r
3583 int index = TranslatePieceToFontPiece(piece);
\r
3585 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3589 squareSize, squareSize,
\r
3594 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3598 squareSize, squareSize,
\r
3607 if (appData.monoMode) {
\r
3608 SelectObject(tmphdc, PieceBitmap(piece,
\r
3609 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3610 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3611 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3613 tmpSize = squareSize;
\r
3615 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3616 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3617 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3618 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3619 x += (squareSize - minorSize)>>1;
\r
3620 y += squareSize - minorSize - 2;
\r
3621 tmpSize = minorSize;
\r
3623 if (color || appData.allWhite ) {
\r
3624 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3626 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3627 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3628 if(appData.upsideDown && color==flipView)
\r
3629 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3631 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3632 /* Use black for outline of white pieces */
\r
3633 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3634 if(appData.upsideDown && color==flipView)
\r
3635 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3637 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3639 /* Use square color for details of black pieces */
\r
3640 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3641 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3642 if(appData.upsideDown && !flipView)
\r
3643 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3645 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3647 SelectObject(hdc, oldBrush);
\r
3648 SelectObject(tmphdc, oldBitmap);
\r
3652 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3653 int GetBackTextureMode( int algo )
\r
3655 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3659 case BACK_TEXTURE_MODE_PLAIN:
\r
3660 result = 1; /* Always use identity map */
\r
3662 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3663 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3671 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3672 to handle redraws cleanly (as random numbers would always be different).
\r
3674 VOID RebuildTextureSquareInfo()
\r
3684 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3686 if( liteBackTexture != NULL ) {
\r
3687 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3688 lite_w = bi.bmWidth;
\r
3689 lite_h = bi.bmHeight;
\r
3693 if( darkBackTexture != NULL ) {
\r
3694 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3695 dark_w = bi.bmWidth;
\r
3696 dark_h = bi.bmHeight;
\r
3700 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3701 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3702 if( (col + row) & 1 ) {
\r
3704 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3705 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3706 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3707 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3712 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3713 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3714 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3715 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3722 /* [AS] Arrow highlighting support */
\r
3724 static int A_WIDTH = 5; /* Width of arrow body */
\r
3726 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3727 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3729 static double Sqr( double x )
\r
3734 static int Round( double x )
\r
3736 return (int) (x + 0.5);
\r
3739 /* Draw an arrow between two points using current settings */
\r
3740 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3743 double dx, dy, j, k, x, y;
\r
3745 if( d_x == s_x ) {
\r
3746 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3748 arrow[0].x = s_x + A_WIDTH;
\r
3751 arrow[1].x = s_x + A_WIDTH;
\r
3752 arrow[1].y = d_y - h;
\r
3754 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3755 arrow[2].y = d_y - h;
\r
3760 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3761 arrow[4].y = d_y - h;
\r
3763 arrow[5].x = s_x - A_WIDTH;
\r
3764 arrow[5].y = d_y - h;
\r
3766 arrow[6].x = s_x - A_WIDTH;
\r
3769 else if( d_y == s_y ) {
\r
3770 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3773 arrow[0].y = s_y + A_WIDTH;
\r
3775 arrow[1].x = d_x - w;
\r
3776 arrow[1].y = s_y + A_WIDTH;
\r
3778 arrow[2].x = d_x - w;
\r
3779 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3784 arrow[4].x = d_x - w;
\r
3785 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3787 arrow[5].x = d_x - w;
\r
3788 arrow[5].y = s_y - A_WIDTH;
\r
3791 arrow[6].y = s_y - A_WIDTH;
\r
3794 /* [AS] Needed a lot of paper for this! :-) */
\r
3795 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3796 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3798 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3800 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3805 arrow[0].x = Round(x - j);
\r
3806 arrow[0].y = Round(y + j*dx);
\r
3808 arrow[1].x = Round(x + j);
\r
3809 arrow[1].y = Round(y - j*dx);
\r
3812 x = (double) d_x - k;
\r
3813 y = (double) d_y - k*dy;
\r
3816 x = (double) d_x + k;
\r
3817 y = (double) d_y + k*dy;
\r
3820 arrow[2].x = Round(x + j);
\r
3821 arrow[2].y = Round(y - j*dx);
\r
3823 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3824 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3829 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3830 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3832 arrow[6].x = Round(x - j);
\r
3833 arrow[6].y = Round(y + j*dx);
\r
3836 Polygon( hdc, arrow, 7 );
\r
3839 /* [AS] Draw an arrow between two squares */
\r
3840 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3842 int s_x, s_y, d_x, d_y;
\r
3849 if( s_col == d_col && s_row == d_row ) {
\r
3853 /* Get source and destination points */
\r
3854 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3855 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3858 d_y += squareSize / 4;
\r
3860 else if( d_y < s_y ) {
\r
3861 d_y += 3 * squareSize / 4;
\r
3864 d_y += squareSize / 2;
\r
3868 d_x += squareSize / 4;
\r
3870 else if( d_x < s_x ) {
\r
3871 d_x += 3 * squareSize / 4;
\r
3874 d_x += squareSize / 2;
\r
3877 s_x += squareSize / 2;
\r
3878 s_y += squareSize / 2;
\r
3880 /* Adjust width */
\r
3881 A_WIDTH = squareSize / 14;
\r
3884 stLB.lbStyle = BS_SOLID;
\r
3885 stLB.lbColor = appData.highlightArrowColor;
\r
3888 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3889 holdpen = SelectObject( hdc, hpen );
\r
3890 hbrush = CreateBrushIndirect( &stLB );
\r
3891 holdbrush = SelectObject( hdc, hbrush );
\r
3893 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3895 SelectObject( hdc, holdpen );
\r
3896 SelectObject( hdc, holdbrush );
\r
3897 DeleteObject( hpen );
\r
3898 DeleteObject( hbrush );
\r
3901 BOOL HasHighlightInfo()
\r
3903 BOOL result = FALSE;
\r
3905 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3906 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3914 BOOL IsDrawArrowEnabled()
\r
3916 BOOL result = FALSE;
\r
3918 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3925 VOID DrawArrowHighlight( HDC hdc )
\r
3927 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3928 DrawArrowBetweenSquares( hdc,
\r
3929 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3930 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3934 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3936 HRGN result = NULL;
\r
3938 if( HasHighlightInfo() ) {
\r
3939 int x1, y1, x2, y2;
\r
3940 int sx, sy, dx, dy;
\r
3942 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3943 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3945 sx = MIN( x1, x2 );
\r
3946 sy = MIN( y1, y2 );
\r
3947 dx = MAX( x1, x2 ) + squareSize;
\r
3948 dy = MAX( y1, y2 ) + squareSize;
\r
3950 result = CreateRectRgn( sx, sy, dx, dy );
\r
3957 Warning: this function modifies the behavior of several other functions.
\r
3959 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3960 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3961 repaint is scattered all over the place, which is not good for features such as
\r
3962 "arrow highlighting" that require a full repaint of the board.
\r
3964 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3965 user interaction, when speed is not so important) but especially to avoid errors
\r
3966 in the displayed graphics.
\r
3968 In such patched places, I always try refer to this function so there is a single
\r
3969 place to maintain knowledge.
\r
3971 To restore the original behavior, just return FALSE unconditionally.
\r
3973 BOOL IsFullRepaintPreferrable()
\r
3975 BOOL result = FALSE;
\r
3977 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3978 /* Arrow may appear on the board */
\r
3986 This function is called by DrawPosition to know whether a full repaint must
\r
3989 Only DrawPosition may directly call this function, which makes use of
\r
3990 some state information. Other function should call DrawPosition specifying
\r
3991 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3993 BOOL DrawPositionNeedsFullRepaint()
\r
3995 BOOL result = FALSE;
\r
3998 Probably a slightly better policy would be to trigger a full repaint
\r
3999 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4000 but animation is fast enough that it's difficult to notice.
\r
4002 if( animInfo.piece == EmptySquare ) {
\r
4003 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
4012 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4014 int row, column, x, y, square_color, piece_color;
\r
4015 ChessSquare piece;
\r
4017 HDC texture_hdc = NULL;
\r
4019 /* [AS] Initialize background textures if needed */
\r
4020 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4021 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4022 if( backTextureSquareSize != squareSize
\r
4023 || backTextureBoardSize != BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT) {
\r
4024 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*BOARD_HEIGHT;
\r
4025 backTextureSquareSize = squareSize;
\r
4026 RebuildTextureSquareInfo();
\r
4029 texture_hdc = CreateCompatibleDC( hdc );
\r
4032 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4033 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4035 SquareToPos(row, column, &x, &y);
\r
4037 piece = board[row][column];
\r
4039 square_color = ((column + row) % 2) == 1;
\r
4040 if( gameInfo.variant == VariantXiangqi ) {
\r
4041 square_color = !InPalace(row, column);
\r
4042 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4043 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4045 piece_color = (int) piece < (int) BlackPawn;
\r
4048 /* [HGM] holdings file: light square or black */
\r
4049 if(column == BOARD_LEFT-2) {
\r
4050 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4053 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4057 if(column == BOARD_RGHT + 1 ) {
\r
4058 if( row < gameInfo.holdingsSize )
\r
4061 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4065 if(column == BOARD_LEFT-1 ) /* left align */
\r
4066 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4067 else if( column == BOARD_RGHT) /* right align */
\r
4068 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4070 if (appData.monoMode) {
\r
4071 if (piece == EmptySquare) {
\r
4072 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4073 square_color ? WHITENESS : BLACKNESS);
\r
4075 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4078 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4079 /* [AS] Draw the square using a texture bitmap */
\r
4080 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4081 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4082 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4085 squareSize, squareSize,
\r
4088 backTextureSquareInfo[r][c].mode,
\r
4089 backTextureSquareInfo[r][c].x,
\r
4090 backTextureSquareInfo[r][c].y );
\r
4092 SelectObject( texture_hdc, hbm );
\r
4094 if (piece != EmptySquare) {
\r
4095 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4099 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4101 oldBrush = SelectObject(hdc, brush );
\r
4102 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4103 SelectObject(hdc, oldBrush);
\r
4104 if (piece != EmptySquare)
\r
4105 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4110 if( texture_hdc != NULL ) {
\r
4111 DeleteDC( texture_hdc );
\r
4115 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4116 void fputDW(FILE *f, int x)
\r
4118 fputc(x & 255, f);
\r
4119 fputc(x>>8 & 255, f);
\r
4120 fputc(x>>16 & 255, f);
\r
4121 fputc(x>>24 & 255, f);
\r
4124 #define MAX_CLIPS 200 /* more than enough */
\r
4127 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4129 // HBITMAP bufferBitmap;
\r
4134 int w = 100, h = 50;
\r
4136 if(logo == NULL) return;
\r
4137 // GetClientRect(hwndMain, &Rect);
\r
4138 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4139 // Rect.bottom-Rect.top+1);
\r
4140 tmphdc = CreateCompatibleDC(hdc);
\r
4141 hbm = SelectObject(tmphdc, logo);
\r
4142 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4146 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4147 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4148 SelectObject(tmphdc, hbm);
\r
4153 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4155 static Board lastReq, lastDrawn;
\r
4156 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4157 static int lastDrawnFlipView = 0;
\r
4158 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4159 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4162 HBITMAP bufferBitmap;
\r
4163 HBITMAP oldBitmap;
\r
4165 HRGN clips[MAX_CLIPS];
\r
4166 ChessSquare dragged_piece = EmptySquare;
\r
4168 /* I'm undecided on this - this function figures out whether a full
\r
4169 * repaint is necessary on its own, so there's no real reason to have the
\r
4170 * caller tell it that. I think this can safely be set to FALSE - but
\r
4171 * if we trust the callers not to request full repaints unnessesarily, then
\r
4172 * we could skip some clipping work. In other words, only request a full
\r
4173 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4174 * gamestart and similar) --Hawk
\r
4176 Boolean fullrepaint = repaint;
\r
4178 if( DrawPositionNeedsFullRepaint() ) {
\r
4179 fullrepaint = TRUE;
\r
4182 if (board == NULL) {
\r
4183 if (!lastReqValid) {
\r
4188 CopyBoard(lastReq, board);
\r
4192 if (doingSizing) {
\r
4196 if (IsIconic(hwndMain)) {
\r
4200 if (hdc == NULL) {
\r
4201 hdc = GetDC(hwndMain);
\r
4202 if (!appData.monoMode) {
\r
4203 SelectPalette(hdc, hPal, FALSE);
\r
4204 RealizePalette(hdc);
\r
4208 releaseDC = FALSE;
\r
4211 /* Create some work-DCs */
\r
4212 hdcmem = CreateCompatibleDC(hdc);
\r
4213 tmphdc = CreateCompatibleDC(hdc);
\r
4215 /* If dragging is in progress, we temporarely remove the piece */
\r
4216 /* [HGM] or temporarily decrease count if stacked */
\r
4217 /* !! Moved to before board compare !! */
\r
4218 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4219 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4220 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4221 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4222 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4224 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4225 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4226 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4228 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4231 /* Figure out which squares need updating by comparing the
\r
4232 * newest board with the last drawn board and checking if
\r
4233 * flipping has changed.
\r
4235 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4236 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4237 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4238 if (lastDrawn[row][column] != board[row][column]) {
\r
4239 SquareToPos(row, column, &x, &y);
\r
4240 clips[num_clips++] =
\r
4241 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4245 for (i=0; i<2; i++) {
\r
4246 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4247 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4248 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4249 lastDrawnHighlight.sq[i].y >= 0) {
\r
4250 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4251 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4252 clips[num_clips++] =
\r
4253 CreateRectRgn(x - lineGap, y - lineGap,
\r
4254 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4256 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4257 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4258 clips[num_clips++] =
\r
4259 CreateRectRgn(x - lineGap, y - lineGap,
\r
4260 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4264 for (i=0; i<2; i++) {
\r
4265 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4266 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4267 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4268 lastDrawnPremove.sq[i].y >= 0) {
\r
4269 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4270 lastDrawnPremove.sq[i].x, &x, &y);
\r
4271 clips[num_clips++] =
\r
4272 CreateRectRgn(x - lineGap, y - lineGap,
\r
4273 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4275 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4276 premoveHighlightInfo.sq[i].y >= 0) {
\r
4277 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4278 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4279 clips[num_clips++] =
\r
4280 CreateRectRgn(x - lineGap, y - lineGap,
\r
4281 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4286 fullrepaint = TRUE;
\r
4289 /* Create a buffer bitmap - this is the actual bitmap
\r
4290 * being written to. When all the work is done, we can
\r
4291 * copy it to the real DC (the screen). This avoids
\r
4292 * the problems with flickering.
\r
4294 GetClientRect(hwndMain, &Rect);
\r
4295 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4296 Rect.bottom-Rect.top+1);
\r
4297 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4298 if (!appData.monoMode) {
\r
4299 SelectPalette(hdcmem, hPal, FALSE);
\r
4302 /* Create clips for dragging */
\r
4303 if (!fullrepaint) {
\r
4304 if (dragInfo.from.x >= 0) {
\r
4305 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4306 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4308 if (dragInfo.start.x >= 0) {
\r
4309 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4310 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4312 if (dragInfo.pos.x >= 0) {
\r
4313 x = dragInfo.pos.x - squareSize / 2;
\r
4314 y = dragInfo.pos.y - squareSize / 2;
\r
4315 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4317 if (dragInfo.lastpos.x >= 0) {
\r
4318 x = dragInfo.lastpos.x - squareSize / 2;
\r
4319 y = dragInfo.lastpos.y - squareSize / 2;
\r
4320 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4324 /* Are we animating a move?
\r
4326 * - remove the piece from the board (temporarely)
\r
4327 * - calculate the clipping region
\r
4329 if (!fullrepaint) {
\r
4330 if (animInfo.piece != EmptySquare) {
\r
4331 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4332 x = boardRect.left + animInfo.lastpos.x;
\r
4333 y = boardRect.top + animInfo.lastpos.y;
\r
4334 x2 = boardRect.left + animInfo.pos.x;
\r
4335 y2 = boardRect.top + animInfo.pos.y;
\r
4336 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4337 /* Slight kludge. The real problem is that after AnimateMove is
\r
4338 done, the position on the screen does not match lastDrawn.
\r
4339 This currently causes trouble only on e.p. captures in
\r
4340 atomic, where the piece moves to an empty square and then
\r
4341 explodes. The old and new positions both had an empty square
\r
4342 at the destination, but animation has drawn a piece there and
\r
4343 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4344 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4348 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4349 if (num_clips == 0)
\r
4350 fullrepaint = TRUE;
\r
4352 /* Set clipping on the memory DC */
\r
4353 if (!fullrepaint) {
\r
4354 SelectClipRgn(hdcmem, clips[0]);
\r
4355 for (x = 1; x < num_clips; x++) {
\r
4356 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4357 abort(); // this should never ever happen!
\r
4361 /* Do all the drawing to the memory DC */
\r
4362 if(explodeInfo.radius) { // [HGM] atomic
\r
4364 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4365 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4366 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4367 x += squareSize/2;
\r
4368 y += squareSize/2;
\r
4369 if(!fullrepaint) {
\r
4370 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4371 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4373 DrawGridOnDC(hdcmem);
\r
4374 DrawHighlightsOnDC(hdcmem);
\r
4375 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4376 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4377 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4378 SelectObject(hdcmem, oldBrush);
\r
4380 DrawGridOnDC(hdcmem);
\r
4381 DrawHighlightsOnDC(hdcmem);
\r
4382 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4385 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4386 if(appData.autoLogo) {
\r
4388 switch(gameMode) { // pick logos based on game mode
\r
4389 case IcsObserving:
\r
4390 whiteLogo = second.programLogo; // ICS logo
\r
4391 blackLogo = second.programLogo;
\r
4394 case IcsPlayingWhite:
\r
4395 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4396 blackLogo = second.programLogo; // ICS logo
\r
4398 case IcsPlayingBlack:
\r
4399 whiteLogo = second.programLogo; // ICS logo
\r
4400 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4402 case TwoMachinesPlay:
\r
4403 if(first.twoMachinesColor[0] == 'b') {
\r
4404 whiteLogo = second.programLogo;
\r
4405 blackLogo = first.programLogo;
\r
4408 case MachinePlaysWhite:
\r
4409 blackLogo = userLogo;
\r
4411 case MachinePlaysBlack:
\r
4412 whiteLogo = userLogo;
\r
4413 blackLogo = first.programLogo;
\r
4416 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4417 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4420 if( appData.highlightMoveWithArrow ) {
\r
4421 DrawArrowHighlight(hdcmem);
\r
4424 DrawCoordsOnDC(hdcmem);
\r
4426 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4427 /* to make sure lastDrawn contains what is actually drawn */
\r
4429 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4430 if (dragged_piece != EmptySquare) {
\r
4431 /* [HGM] or restack */
\r
4432 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4433 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4435 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4436 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4437 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4438 x = dragInfo.pos.x - squareSize / 2;
\r
4439 y = dragInfo.pos.y - squareSize / 2;
\r
4440 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4441 ((int) dragged_piece < (int) BlackPawn),
\r
4442 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4445 /* Put the animated piece back into place and draw it */
\r
4446 if (animInfo.piece != EmptySquare) {
\r
4447 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4448 x = boardRect.left + animInfo.pos.x;
\r
4449 y = boardRect.top + animInfo.pos.y;
\r
4450 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4451 ((int) animInfo.piece < (int) BlackPawn),
\r
4452 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4455 /* Release the bufferBitmap by selecting in the old bitmap
\r
4456 * and delete the memory DC
\r
4458 SelectObject(hdcmem, oldBitmap);
\r
4461 /* Set clipping on the target DC */
\r
4462 if (!fullrepaint) {
\r
4463 SelectClipRgn(hdc, clips[0]);
\r
4464 for (x = 1; x < num_clips; x++) {
\r
4465 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4466 abort(); // this should never ever happen!
\r
4470 /* Copy the new bitmap onto the screen in one go.
\r
4471 * This way we avoid any flickering
\r
4473 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4474 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4475 boardRect.right - boardRect.left,
\r
4476 boardRect.bottom - boardRect.top,
\r
4477 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4478 if(saveDiagFlag) {
\r
4479 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4480 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4482 GetObject(bufferBitmap, sizeof(b), &b);
\r
4483 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4484 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4485 bih.biWidth = b.bmWidth;
\r
4486 bih.biHeight = b.bmHeight;
\r
4488 bih.biBitCount = b.bmBitsPixel;
\r
4489 bih.biCompression = 0;
\r
4490 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4491 bih.biXPelsPerMeter = 0;
\r
4492 bih.biYPelsPerMeter = 0;
\r
4493 bih.biClrUsed = 0;
\r
4494 bih.biClrImportant = 0;
\r
4495 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4496 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4497 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4498 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4500 wb = b.bmWidthBytes;
\r
4502 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4503 int k = ((int*) pData)[i];
\r
4504 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4505 if(j >= 16) break;
\r
4507 if(j >= nrColors) nrColors = j+1;
\r
4509 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4511 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4512 for(w=0; w<(wb>>2); w+=2) {
\r
4513 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4514 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4515 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4516 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4517 pData[p++] = m | j<<4;
\r
4519 while(p&3) pData[p++] = 0;
\r
4522 wb = ((wb+31)>>5)<<2;
\r
4524 // write BITMAPFILEHEADER
\r
4525 fprintf(diagFile, "BM");
\r
4526 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4527 fputDW(diagFile, 0);
\r
4528 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4529 // write BITMAPINFOHEADER
\r
4530 fputDW(diagFile, 40);
\r
4531 fputDW(diagFile, b.bmWidth);
\r
4532 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4533 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4534 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4535 fputDW(diagFile, 0);
\r
4536 fputDW(diagFile, 0);
\r
4537 fputDW(diagFile, 0);
\r
4538 fputDW(diagFile, 0);
\r
4539 fputDW(diagFile, 0);
\r
4540 fputDW(diagFile, 0);
\r
4541 // write color table
\r
4543 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4544 // write bitmap data
\r
4545 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4546 fputc(pData[i], diagFile);
\r
4550 SelectObject(tmphdc, oldBitmap);
\r
4552 /* Massive cleanup */
\r
4553 for (x = 0; x < num_clips; x++)
\r
4554 DeleteObject(clips[x]);
\r
4557 DeleteObject(bufferBitmap);
\r
4560 ReleaseDC(hwndMain, hdc);
\r
4562 if (lastDrawnFlipView != flipView) {
\r
4564 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4566 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4569 /* CopyBoard(lastDrawn, board);*/
\r
4570 lastDrawnHighlight = highlightInfo;
\r
4571 lastDrawnPremove = premoveHighlightInfo;
\r
4572 lastDrawnFlipView = flipView;
\r
4573 lastDrawnValid = 1;
\r
4576 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4581 saveDiagFlag = 1; diagFile = f;
\r
4582 HDCDrawPosition(NULL, TRUE, NULL);
\r
4586 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4593 /*---------------------------------------------------------------------------*\
\r
4594 | CLIENT PAINT PROCEDURE
\r
4595 | This is the main event-handler for the WM_PAINT message.
\r
4597 \*---------------------------------------------------------------------------*/
\r
4599 PaintProc(HWND hwnd)
\r
4605 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4606 if (IsIconic(hwnd)) {
\r
4607 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4609 if (!appData.monoMode) {
\r
4610 SelectPalette(hdc, hPal, FALSE);
\r
4611 RealizePalette(hdc);
\r
4613 HDCDrawPosition(hdc, 1, NULL);
\r
4615 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4616 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4617 ETO_CLIPPED|ETO_OPAQUE,
\r
4618 &messageRect, messageText, strlen(messageText), NULL);
\r
4619 SelectObject(hdc, oldFont);
\r
4620 DisplayBothClocks();
\r
4622 EndPaint(hwnd,&ps);
\r
4630 * If the user selects on a border boundary, return -1; if off the board,
\r
4631 * return -2. Otherwise map the event coordinate to the square.
\r
4632 * The offset boardRect.left or boardRect.top must already have been
\r
4633 * subtracted from x.
\r
4635 int EventToSquare(x, limit)
\r
4643 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4645 x /= (squareSize + lineGap);
\r
4657 DropEnable dropEnables[] = {
\r
4658 { 'P', DP_Pawn, "Pawn" },
\r
4659 { 'N', DP_Knight, "Knight" },
\r
4660 { 'B', DP_Bishop, "Bishop" },
\r
4661 { 'R', DP_Rook, "Rook" },
\r
4662 { 'Q', DP_Queen, "Queen" },
\r
4666 SetupDropMenu(HMENU hmenu)
\r
4668 int i, count, enable;
\r
4670 extern char white_holding[], black_holding[];
\r
4671 char item[MSG_SIZ];
\r
4673 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4674 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4675 dropEnables[i].piece);
\r
4677 while (p && *p++ == dropEnables[i].piece) count++;
\r
4678 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4679 enable = count > 0 || !appData.testLegality
\r
4680 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4681 && !appData.icsActive);
\r
4682 ModifyMenu(hmenu, dropEnables[i].command,
\r
4683 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4684 dropEnables[i].command, item);
\r
4688 void DragPieceBegin(int x, int y)
\r
4690 dragInfo.lastpos.x = boardRect.left + x;
\r
4691 dragInfo.lastpos.y = boardRect.top + y;
\r
4692 dragInfo.from.x = fromX;
\r
4693 dragInfo.from.y = fromY;
\r
4694 dragInfo.start = dragInfo.from;
\r
4695 SetCapture(hwndMain);
\r
4698 void DragPieceEnd(int x, int y)
\r
4701 dragInfo.start.x = dragInfo.start.y = -1;
\r
4702 dragInfo.from = dragInfo.start;
\r
4703 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4706 /* Event handler for mouse messages */
\r
4708 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4712 static int recursive = 0;
\r
4714 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4717 if (message == WM_MBUTTONUP) {
\r
4718 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4719 to the middle button: we simulate pressing the left button too!
\r
4721 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4722 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4728 pt.x = LOWORD(lParam);
\r
4729 pt.y = HIWORD(lParam);
\r
4730 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4731 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4732 if (!flipView && y >= 0) {
\r
4733 y = BOARD_HEIGHT - 1 - y;
\r
4735 if (flipView && x >= 0) {
\r
4736 x = BOARD_WIDTH - 1 - x;
\r
4739 switch (message) {
\r
4740 case WM_LBUTTONDOWN:
\r
4741 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4742 if (gameMode == EditPosition) {
\r
4743 SetWhiteToPlayEvent();
\r
4744 } else if (gameMode == IcsPlayingBlack ||
\r
4745 gameMode == MachinePlaysWhite) {
\r
4747 } else if (gameMode == EditGame) {
\r
4748 AdjustClock(flipClock, -1);
\r
4750 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4751 if (gameMode == EditPosition) {
\r
4752 SetBlackToPlayEvent();
\r
4753 } else if (gameMode == IcsPlayingWhite ||
\r
4754 gameMode == MachinePlaysBlack) {
\r
4756 } else if (gameMode == EditGame) {
\r
4757 AdjustClock(!flipClock, -1);
\r
4760 dragInfo.start.x = dragInfo.start.y = -1;
\r
4761 dragInfo.from = dragInfo.start;
\r
4762 if(fromX == -1 && frozen) { // not sure where this is for
\r
4763 fromX = fromY = -1;
\r
4764 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4767 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4768 DrawPosition(TRUE, NULL);
\r
4771 case WM_LBUTTONUP:
\r
4772 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4773 DrawPosition(TRUE, NULL);
\r
4776 case WM_MOUSEMOVE:
\r
4777 if ((appData.animateDragging || appData.highlightDragging)
\r
4778 && (wParam & MK_LBUTTON)
\r
4779 && dragInfo.from.x >= 0)
\r
4781 BOOL full_repaint = FALSE;
\r
4783 if (appData.animateDragging) {
\r
4784 dragInfo.pos = pt;
\r
4786 if (appData.highlightDragging) {
\r
4787 SetHighlights(fromX, fromY, x, y);
\r
4788 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4789 full_repaint = TRUE;
\r
4793 DrawPosition( full_repaint, NULL);
\r
4795 dragInfo.lastpos = dragInfo.pos;
\r
4799 case WM_MOUSEWHEEL: // [DM]
\r
4800 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4801 /* Mouse Wheel is being rolled forward
\r
4802 * Play moves forward
\r
4804 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
4805 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4806 /* Mouse Wheel is being rolled backward
\r
4807 * Play moves backward
\r
4809 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
4810 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4814 case WM_MBUTTONDOWN:
\r
4815 case WM_RBUTTONDOWN:
\r
4818 fromX = fromY = -1;
\r
4819 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4820 dragInfo.start.x = dragInfo.start.y = -1;
\r
4821 dragInfo.from = dragInfo.start;
\r
4822 dragInfo.lastpos = dragInfo.pos;
\r
4823 if (appData.highlightDragging) {
\r
4824 ClearHighlights();
\r
4827 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4828 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4829 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
4830 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4831 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
4834 DrawPosition(TRUE, NULL);
\r
4836 switch (gameMode) {
\r
4837 case EditPosition:
\r
4838 case IcsExamining:
\r
4839 if (x < 0 || y < 0) break;
\r
4842 if (message == WM_MBUTTONDOWN) {
\r
4843 buttonCount = 3; /* even if system didn't think so */
\r
4844 if (wParam & MK_SHIFT)
\r
4845 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4847 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4848 } else { /* message == WM_RBUTTONDOWN */
\r
4849 /* Just have one menu, on the right button. Windows users don't
\r
4850 think to try the middle one, and sometimes other software steals
\r
4851 it, or it doesn't really exist. */
\r
4852 if(gameInfo.variant != VariantShogi)
\r
4853 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4855 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4858 case IcsPlayingWhite:
\r
4859 case IcsPlayingBlack:
\r
4861 case MachinePlaysWhite:
\r
4862 case MachinePlaysBlack:
\r
4863 if (appData.testLegality &&
\r
4864 gameInfo.variant != VariantBughouse &&
\r
4865 gameInfo.variant != VariantCrazyhouse) break;
\r
4866 if (x < 0 || y < 0) break;
\r
4869 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4870 SetupDropMenu(hmenu);
\r
4871 MenuPopup(hwnd, pt, hmenu, -1);
\r
4882 /* Preprocess messages for buttons in main window */
\r
4884 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4886 int id = GetWindowLong(hwnd, GWL_ID);
\r
4889 for (i=0; i<N_BUTTONS; i++) {
\r
4890 if (buttonDesc[i].id == id) break;
\r
4892 if (i == N_BUTTONS) return 0;
\r
4893 switch (message) {
\r
4898 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4899 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4906 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4909 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
4910 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
4911 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4912 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4914 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4916 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4917 PopUpMoveDialog((char)wParam);
\r
4923 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4926 /* Process messages for Promotion dialog box */
\r
4928 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4932 switch (message) {
\r
4933 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4934 /* Center the dialog over the application window */
\r
4935 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4936 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4937 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4938 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
4939 SW_SHOW : SW_HIDE);
\r
4940 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4941 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4942 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
4943 PieceToChar(WhiteAngel) != '~') ||
\r
4944 (PieceToChar(BlackAngel) >= 'A' &&
\r
4945 PieceToChar(BlackAngel) != '~') ) ?
\r
4946 SW_SHOW : SW_HIDE);
\r
4947 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4948 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
4949 PieceToChar(WhiteMarshall) != '~') ||
\r
4950 (PieceToChar(BlackMarshall) >= 'A' &&
\r
4951 PieceToChar(BlackMarshall) != '~') ) ?
\r
4952 SW_SHOW : SW_HIDE);
\r
4953 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4954 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
4955 gameInfo.variant != VariantShogi ?
\r
4956 SW_SHOW : SW_HIDE);
\r
4957 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
4958 gameInfo.variant != VariantShogi ?
\r
4959 SW_SHOW : SW_HIDE);
\r
4960 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
4961 gameInfo.variant == VariantShogi ?
\r
4962 SW_SHOW : SW_HIDE);
\r
4963 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
4964 gameInfo.variant == VariantShogi ?
\r
4965 SW_SHOW : SW_HIDE);
\r
4966 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
4967 gameInfo.variant == VariantSuper ?
\r
4968 SW_SHOW : SW_HIDE);
\r
4971 case WM_COMMAND: /* message: received a command */
\r
4972 switch (LOWORD(wParam)) {
\r
4974 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4975 ClearHighlights();
\r
4976 DrawPosition(FALSE, NULL);
\r
4979 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
4982 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
4985 promoChar = PieceToChar(BlackRook);
\r
4988 promoChar = PieceToChar(BlackBishop);
\r
4990 case PB_Chancellor:
\r
4991 promoChar = PieceToChar(BlackMarshall);
\r
4993 case PB_Archbishop:
\r
4994 promoChar = PieceToChar(BlackAngel);
\r
4997 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5002 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5003 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5004 only show the popup when we are already sure the move is valid or
\r
5005 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5006 will figure out it is a promotion from the promoChar. */
\r
5007 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
5008 fromX = fromY = -1;
\r
5009 if (!appData.highlightLastMove) {
\r
5010 ClearHighlights();
\r
5011 DrawPosition(FALSE, NULL);
\r
5018 /* Pop up promotion dialog */
\r
5020 PromotionPopup(HWND hwnd)
\r
5024 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5025 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5026 hwnd, (DLGPROC)lpProc);
\r
5027 FreeProcInstance(lpProc);
\r
5033 DrawPosition(TRUE, NULL);
\r
5034 PromotionPopup(hwndMain);
\r
5037 /* Toggle ShowThinking */
\r
5039 ToggleShowThinking()
\r
5041 appData.showThinking = !appData.showThinking;
\r
5042 ShowThinkingEvent();
\r
5046 LoadGameDialog(HWND hwnd, char* title)
\r
5050 char fileTitle[MSG_SIZ];
\r
5051 f = OpenFileDialog(hwnd, "rb", "",
\r
5052 appData.oldSaveStyle ? "gam" : "pgn",
\r
5054 title, &number, fileTitle, NULL);
\r
5056 cmailMsgLoaded = FALSE;
\r
5057 if (number == 0) {
\r
5058 int error = GameListBuild(f);
\r
5060 DisplayError("Cannot build game list", error);
\r
5061 } else if (!ListEmpty(&gameList) &&
\r
5062 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5063 GameListPopUp(f, fileTitle);
\r
5066 GameListDestroy();
\r
5069 LoadGame(f, number, fileTitle, FALSE);
\r
5073 int get_term_width()
\r
5078 HFONT hfont, hold_font;
\r
5083 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5087 // get the text metrics
\r
5088 hdc = GetDC(hText);
\r
5089 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
5090 if (consoleCF.dwEffects & CFE_BOLD)
\r
5091 lf.lfWeight = FW_BOLD;
\r
5092 if (consoleCF.dwEffects & CFE_ITALIC)
\r
5093 lf.lfItalic = TRUE;
\r
5094 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
5095 lf.lfStrikeOut = TRUE;
\r
5096 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
5097 lf.lfUnderline = TRUE;
\r
5098 hfont = CreateFontIndirect(&lf);
\r
5099 hold_font = SelectObject(hdc, hfont);
\r
5100 GetTextMetrics(hdc, &tm);
\r
5101 SelectObject(hdc, hold_font);
\r
5102 DeleteObject(hfont);
\r
5103 ReleaseDC(hText, hdc);
\r
5105 // get the rectangle
\r
5106 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
5108 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
5111 void UpdateICSWidth(HWND hText)
\r
5113 LONG old_width, new_width;
\r
5115 new_width = get_term_width(hText, FALSE);
\r
5116 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
5117 if (new_width != old_width)
\r
5119 ics_update_width(new_width);
\r
5120 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
5125 ChangedConsoleFont()
\r
5128 CHARRANGE tmpsel, sel;
\r
5129 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5130 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5131 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5134 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5135 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5136 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5137 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5138 * size. This was undocumented in the version of MSVC++ that I had
\r
5139 * when I wrote the code, but is apparently documented now.
\r
5141 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5142 cfmt.bCharSet = f->lf.lfCharSet;
\r
5143 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5144 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5145 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5146 /* Why are the following seemingly needed too? */
\r
5147 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5148 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5149 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5151 tmpsel.cpMax = -1; /*999999?*/
\r
5152 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5153 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5154 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5155 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5157 paraf.cbSize = sizeof(paraf);
\r
5158 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5159 paraf.dxStartIndent = 0;
\r
5160 paraf.dxOffset = WRAP_INDENT;
\r
5161 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5162 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5163 UpdateICSWidth(hText);
\r
5166 /*---------------------------------------------------------------------------*\
\r
5168 * Window Proc for main window
\r
5170 \*---------------------------------------------------------------------------*/
\r
5172 /* Process messages for main window, etc. */
\r
5174 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5177 int wmId, wmEvent;
\r
5181 char fileTitle[MSG_SIZ];
\r
5182 char buf[MSG_SIZ];
\r
5183 static SnapData sd;
\r
5185 switch (message) {
\r
5187 case WM_PAINT: /* message: repaint portion of window */
\r
5191 case WM_ERASEBKGND:
\r
5192 if (IsIconic(hwnd)) {
\r
5193 /* Cheat; change the message */
\r
5194 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5196 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5200 case WM_LBUTTONDOWN:
\r
5201 case WM_MBUTTONDOWN:
\r
5202 case WM_RBUTTONDOWN:
\r
5203 case WM_LBUTTONUP:
\r
5204 case WM_MBUTTONUP:
\r
5205 case WM_RBUTTONUP:
\r
5206 case WM_MOUSEMOVE:
\r
5207 case WM_MOUSEWHEEL:
\r
5208 MouseEvent(hwnd, message, wParam, lParam);
\r
5211 JAWS_KB_NAVIGATION
\r
5215 JAWS_ALT_INTERCEPT
\r
5217 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
5218 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5219 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5220 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5222 SendMessage(h, message, wParam, lParam);
\r
5223 } else if(lParam != KF_REPEAT) {
\r
5224 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5225 PopUpMoveDialog((char)wParam);
\r
5226 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5227 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5232 case WM_PALETTECHANGED:
\r
5233 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5235 HDC hdc = GetDC(hwndMain);
\r
5236 SelectPalette(hdc, hPal, TRUE);
\r
5237 nnew = RealizePalette(hdc);
\r
5239 paletteChanged = TRUE;
\r
5240 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5242 ReleaseDC(hwnd, hdc);
\r
5246 case WM_QUERYNEWPALETTE:
\r
5247 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5249 HDC hdc = GetDC(hwndMain);
\r
5250 paletteChanged = FALSE;
\r
5251 SelectPalette(hdc, hPal, FALSE);
\r
5252 nnew = RealizePalette(hdc);
\r
5254 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5256 ReleaseDC(hwnd, hdc);
\r
5261 case WM_COMMAND: /* message: command from application menu */
\r
5262 wmId = LOWORD(wParam);
\r
5263 wmEvent = HIWORD(wParam);
\r
5268 SAY("new game enter a move to play against the computer with white");
\r
5271 case IDM_NewGameFRC:
\r
5272 if( NewGameFRC() == 0 ) {
\r
5277 case IDM_NewVariant:
\r
5278 NewVariantPopup(hwnd);
\r
5281 case IDM_LoadGame:
\r
5282 LoadGameDialog(hwnd, "Load Game from File");
\r
5285 case IDM_LoadNextGame:
\r
5289 case IDM_LoadPrevGame:
\r
5293 case IDM_ReloadGame:
\r
5297 case IDM_LoadPosition:
\r
5298 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5299 Reset(FALSE, TRUE);
\r
5302 f = OpenFileDialog(hwnd, "rb", "",
\r
5303 appData.oldSaveStyle ? "pos" : "fen",
\r
5305 "Load Position from File", &number, fileTitle, NULL);
\r
5307 LoadPosition(f, number, fileTitle);
\r
5311 case IDM_LoadNextPosition:
\r
5312 ReloadPosition(1);
\r
5315 case IDM_LoadPrevPosition:
\r
5316 ReloadPosition(-1);
\r
5319 case IDM_ReloadPosition:
\r
5320 ReloadPosition(0);
\r
5323 case IDM_SaveGame:
\r
5324 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5325 f = OpenFileDialog(hwnd, "a", defName,
\r
5326 appData.oldSaveStyle ? "gam" : "pgn",
\r
5328 "Save Game to File", NULL, fileTitle, NULL);
\r
5330 SaveGame(f, 0, "");
\r
5334 case IDM_SavePosition:
\r
5335 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5336 f = OpenFileDialog(hwnd, "a", defName,
\r
5337 appData.oldSaveStyle ? "pos" : "fen",
\r
5339 "Save Position to File", NULL, fileTitle, NULL);
\r
5341 SavePosition(f, 0, "");
\r
5345 case IDM_SaveDiagram:
\r
5346 defName = "diagram";
\r
5347 f = OpenFileDialog(hwnd, "wb", defName,
\r
5350 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5356 case IDM_CopyGame:
\r
5357 CopyGameToClipboard();
\r
5360 case IDM_PasteGame:
\r
5361 PasteGameFromClipboard();
\r
5364 case IDM_CopyGameListToClipboard:
\r
5365 CopyGameListToClipboard();
\r
5368 /* [AS] Autodetect FEN or PGN data */
\r
5369 case IDM_PasteAny:
\r
5370 PasteGameOrFENFromClipboard();
\r
5373 /* [AS] Move history */
\r
5374 case IDM_ShowMoveHistory:
\r
5375 if( MoveHistoryIsUp() ) {
\r
5376 MoveHistoryPopDown();
\r
5379 MoveHistoryPopUp();
\r
5383 /* [AS] Eval graph */
\r
5384 case IDM_ShowEvalGraph:
\r
5385 if( EvalGraphIsUp() ) {
\r
5386 EvalGraphPopDown();
\r
5390 SetFocus(hwndMain);
\r
5394 /* [AS] Engine output */
\r
5395 case IDM_ShowEngineOutput:
\r
5396 if( EngineOutputIsUp() ) {
\r
5397 EngineOutputPopDown();
\r
5400 EngineOutputPopUp();
\r
5404 /* [AS] User adjudication */
\r
5405 case IDM_UserAdjudication_White:
\r
5406 UserAdjudicationEvent( +1 );
\r
5409 case IDM_UserAdjudication_Black:
\r
5410 UserAdjudicationEvent( -1 );
\r
5413 case IDM_UserAdjudication_Draw:
\r
5414 UserAdjudicationEvent( 0 );
\r
5417 /* [AS] Game list options dialog */
\r
5418 case IDM_GameListOptions:
\r
5419 GameListOptions();
\r
5426 case IDM_CopyPosition:
\r
5427 CopyFENToClipboard();
\r
5430 case IDM_PastePosition:
\r
5431 PasteFENFromClipboard();
\r
5434 case IDM_MailMove:
\r
5438 case IDM_ReloadCMailMsg:
\r
5439 Reset(TRUE, TRUE);
\r
5440 ReloadCmailMsgEvent(FALSE);
\r
5443 case IDM_Minimize:
\r
5444 ShowWindow(hwnd, SW_MINIMIZE);
\r
5451 case IDM_MachineWhite:
\r
5452 MachineWhiteEvent();
\r
5454 * refresh the tags dialog only if it's visible
\r
5456 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5458 tags = PGNTags(&gameInfo);
\r
5459 TagsPopUp(tags, CmailMsg());
\r
5462 SAY("computer starts playing white");
\r
5465 case IDM_MachineBlack:
\r
5466 MachineBlackEvent();
\r
5468 * refresh the tags dialog only if it's visible
\r
5470 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5472 tags = PGNTags(&gameInfo);
\r
5473 TagsPopUp(tags, CmailMsg());
\r
5476 SAY("computer starts playing black");
\r
5479 case IDM_TwoMachines:
\r
5480 TwoMachinesEvent();
\r
5482 * refresh the tags dialog only if it's visible
\r
5484 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5486 tags = PGNTags(&gameInfo);
\r
5487 TagsPopUp(tags, CmailMsg());
\r
5490 SAY("programs start playing each other");
\r
5493 case IDM_AnalysisMode:
\r
5494 if (!first.analysisSupport) {
\r
5495 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5496 DisplayError(buf, 0);
\r
5498 SAY("analyzing current position");
\r
5499 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5500 if (appData.icsActive) {
\r
5501 if (gameMode != IcsObserving) {
\r
5502 sprintf(buf, "You are not observing a game");
\r
5503 DisplayError(buf, 0);
\r
5504 /* secure check */
\r
5505 if (appData.icsEngineAnalyze) {
\r
5506 if (appData.debugMode)
\r
5507 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5508 ExitAnalyzeMode();
\r
5514 /* if enable, user want disable icsEngineAnalyze */
\r
5515 if (appData.icsEngineAnalyze) {
\r
5516 ExitAnalyzeMode();
\r
5520 appData.icsEngineAnalyze = TRUE;
\r
5521 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5524 if (!appData.showThinking) ToggleShowThinking();
\r
5525 AnalyzeModeEvent();
\r
5529 case IDM_AnalyzeFile:
\r
5530 if (!first.analysisSupport) {
\r
5531 char buf[MSG_SIZ];
\r
5532 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5533 DisplayError(buf, 0);
\r
5535 if (!appData.showThinking) ToggleShowThinking();
\r
5536 AnalyzeFileEvent();
\r
5537 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5538 AnalysisPeriodicEvent(1);
\r
5542 case IDM_IcsClient:
\r
5546 case IDM_EditGame:
\r
5551 case IDM_EditPosition:
\r
5552 EditPositionEvent();
\r
5553 SAY("to set up a position type a FEN");
\r
5556 case IDM_Training:
\r
5560 case IDM_ShowGameList:
\r
5561 ShowGameListProc();
\r
5564 case IDM_EditTags:
\r
5568 case IDM_EditComment:
\r
5569 if (commentUp && editComment) {
\r
5572 EditCommentEvent();
\r
5592 case IDM_CallFlag:
\r
5612 case IDM_StopObserving:
\r
5613 StopObservingEvent();
\r
5616 case IDM_StopExamining:
\r
5617 StopExaminingEvent();
\r
5620 case IDM_TypeInMove:
\r
5621 PopUpMoveDialog('\000');
\r
5624 case IDM_TypeInName:
\r
5625 PopUpNameDialog('\000');
\r
5628 case IDM_Backward:
\r
5630 SetFocus(hwndMain);
\r
5637 SetFocus(hwndMain);
\r
5642 SetFocus(hwndMain);
\r
5647 SetFocus(hwndMain);
\r
5654 case IDM_TruncateGame:
\r
5655 TruncateGameEvent();
\r
5662 case IDM_RetractMove:
\r
5663 RetractMoveEvent();
\r
5666 case IDM_FlipView:
\r
5667 flipView = !flipView;
\r
5668 DrawPosition(FALSE, NULL);
\r
5671 case IDM_FlipClock:
\r
5672 flipClock = !flipClock;
\r
5673 DisplayBothClocks();
\r
5674 DrawPosition(FALSE, NULL);
\r
5677 case IDM_MuteSounds:
\r
5678 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5679 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5680 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5683 case IDM_GeneralOptions:
\r
5684 GeneralOptionsPopup(hwnd);
\r
5685 DrawPosition(TRUE, NULL);
\r
5688 case IDM_BoardOptions:
\r
5689 BoardOptionsPopup(hwnd);
\r
5692 case IDM_EnginePlayOptions:
\r
5693 EnginePlayOptionsPopup(hwnd);
\r
5696 case IDM_Engine1Options:
\r
5697 EngineOptionsPopup(hwnd, &first);
\r
5700 case IDM_Engine2Options:
\r
5701 EngineOptionsPopup(hwnd, &second);
\r
5704 case IDM_OptionsUCI:
\r
5705 UciOptionsPopup(hwnd);
\r
5708 case IDM_IcsOptions:
\r
5709 IcsOptionsPopup(hwnd);
\r
5713 FontsOptionsPopup(hwnd);
\r
5717 SoundOptionsPopup(hwnd);
\r
5720 case IDM_CommPort:
\r
5721 CommPortOptionsPopup(hwnd);
\r
5724 case IDM_LoadOptions:
\r
5725 LoadOptionsPopup(hwnd);
\r
5728 case IDM_SaveOptions:
\r
5729 SaveOptionsPopup(hwnd);
\r
5732 case IDM_TimeControl:
\r
5733 TimeControlOptionsPopup(hwnd);
\r
5736 case IDM_SaveSettings:
\r
5737 SaveSettings(settingsFileName);
\r
5740 case IDM_SaveSettingsOnExit:
\r
5741 saveSettingsOnExit = !saveSettingsOnExit;
\r
5742 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5743 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5744 MF_CHECKED : MF_UNCHECKED));
\r
5755 case IDM_AboutGame:
\r
5760 appData.debugMode = !appData.debugMode;
\r
5761 if (appData.debugMode) {
\r
5762 char dir[MSG_SIZ];
\r
5763 GetCurrentDirectory(MSG_SIZ, dir);
\r
5764 SetCurrentDirectory(installDir);
\r
5765 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5766 SetCurrentDirectory(dir);
\r
5767 setbuf(debugFP, NULL);
\r
5774 case IDM_HELPCONTENTS:
\r
5775 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5776 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5777 MessageBox (GetFocus(),
\r
5778 "Unable to activate help",
\r
5779 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5783 case IDM_HELPSEARCH:
\r
5784 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5785 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5786 MessageBox (GetFocus(),
\r
5787 "Unable to activate help",
\r
5788 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5792 case IDM_HELPHELP:
\r
5793 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5794 MessageBox (GetFocus(),
\r
5795 "Unable to activate help",
\r
5796 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5801 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5803 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5804 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5805 FreeProcInstance(lpProc);
\r
5808 case IDM_DirectCommand1:
\r
5809 AskQuestionEvent("Direct Command",
\r
5810 "Send to chess program:", "", "1");
\r
5812 case IDM_DirectCommand2:
\r
5813 AskQuestionEvent("Direct Command",
\r
5814 "Send to second chess program:", "", "2");
\r
5817 case EP_WhitePawn:
\r
5818 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5819 fromX = fromY = -1;
\r
5822 case EP_WhiteKnight:
\r
5823 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5824 fromX = fromY = -1;
\r
5827 case EP_WhiteBishop:
\r
5828 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5829 fromX = fromY = -1;
\r
5832 case EP_WhiteRook:
\r
5833 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5834 fromX = fromY = -1;
\r
5837 case EP_WhiteQueen:
\r
5838 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5839 fromX = fromY = -1;
\r
5842 case EP_WhiteFerz:
\r
5843 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5844 fromX = fromY = -1;
\r
5847 case EP_WhiteWazir:
\r
5848 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5849 fromX = fromY = -1;
\r
5852 case EP_WhiteAlfil:
\r
5853 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5854 fromX = fromY = -1;
\r
5857 case EP_WhiteCannon:
\r
5858 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5859 fromX = fromY = -1;
\r
5862 case EP_WhiteCardinal:
\r
5863 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5864 fromX = fromY = -1;
\r
5867 case EP_WhiteMarshall:
\r
5868 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5869 fromX = fromY = -1;
\r
5872 case EP_WhiteKing:
\r
5873 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5874 fromX = fromY = -1;
\r
5877 case EP_BlackPawn:
\r
5878 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5879 fromX = fromY = -1;
\r
5882 case EP_BlackKnight:
\r
5883 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5884 fromX = fromY = -1;
\r
5887 case EP_BlackBishop:
\r
5888 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5889 fromX = fromY = -1;
\r
5892 case EP_BlackRook:
\r
5893 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5894 fromX = fromY = -1;
\r
5897 case EP_BlackQueen:
\r
5898 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5899 fromX = fromY = -1;
\r
5902 case EP_BlackFerz:
\r
5903 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5904 fromX = fromY = -1;
\r
5907 case EP_BlackWazir:
\r
5908 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5909 fromX = fromY = -1;
\r
5912 case EP_BlackAlfil:
\r
5913 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5914 fromX = fromY = -1;
\r
5917 case EP_BlackCannon:
\r
5918 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5919 fromX = fromY = -1;
\r
5922 case EP_BlackCardinal:
\r
5923 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5924 fromX = fromY = -1;
\r
5927 case EP_BlackMarshall:
\r
5928 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5929 fromX = fromY = -1;
\r
5932 case EP_BlackKing:
\r
5933 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5934 fromX = fromY = -1;
\r
5937 case EP_EmptySquare:
\r
5938 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5939 fromX = fromY = -1;
\r
5942 case EP_ClearBoard:
\r
5943 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5944 fromX = fromY = -1;
\r
5948 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5949 fromX = fromY = -1;
\r
5953 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5954 fromX = fromY = -1;
\r
5958 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5959 fromX = fromY = -1;
\r
5963 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5964 fromX = fromY = -1;
\r
5968 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5969 fromX = fromY = -1;
\r
5973 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5974 fromX = fromY = -1;
\r
5978 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5979 fromX = fromY = -1;
\r
5983 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5984 fromX = fromY = -1;
\r
5988 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5989 fromX = fromY = -1;
\r
5993 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5999 case CLOCK_TIMER_ID:
\r
6000 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6001 clockTimerEvent = 0;
\r
6002 DecrementClocks(); /* call into back end */
\r
6004 case LOAD_GAME_TIMER_ID:
\r
6005 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6006 loadGameTimerEvent = 0;
\r
6007 AutoPlayGameLoop(); /* call into back end */
\r
6009 case ANALYSIS_TIMER_ID:
\r
6010 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6011 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6012 AnalysisPeriodicEvent(0);
\r
6014 KillTimer(hwnd, analysisTimerEvent);
\r
6015 analysisTimerEvent = 0;
\r
6018 case DELAYED_TIMER_ID:
\r
6019 KillTimer(hwnd, delayedTimerEvent);
\r
6020 delayedTimerEvent = 0;
\r
6021 delayedTimerCallback();
\r
6026 case WM_USER_Input:
\r
6027 InputEvent(hwnd, message, wParam, lParam);
\r
6030 /* [AS] Also move "attached" child windows */
\r
6031 case WM_WINDOWPOSCHANGING:
\r
6033 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6034 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6036 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6037 /* Window is moving */
\r
6040 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6041 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
6042 rcMain.right = wpMain.x + wpMain.width;
\r
6043 rcMain.top = wpMain.y;
\r
6044 rcMain.bottom = wpMain.y + wpMain.height;
\r
6046 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6047 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6048 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6049 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6050 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6051 wpMain.x = lpwp->x;
\r
6052 wpMain.y = lpwp->y;
\r
6057 /* [AS] Snapping */
\r
6058 case WM_ENTERSIZEMOVE:
\r
6059 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6060 if (hwnd == hwndMain) {
\r
6061 doingSizing = TRUE;
\r
6064 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6068 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6069 if (hwnd == hwndMain) {
\r
6070 lastSizing = wParam;
\r
6075 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6076 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6078 case WM_EXITSIZEMOVE:
\r
6079 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6080 if (hwnd == hwndMain) {
\r
6082 doingSizing = FALSE;
\r
6083 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6084 GetClientRect(hwnd, &client);
\r
6085 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6087 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6089 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6092 case WM_DESTROY: /* message: window being destroyed */
\r
6093 PostQuitMessage(0);
\r
6097 if (hwnd == hwndMain) {
\r
6102 default: /* Passes it on if unprocessed */
\r
6103 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6108 /*---------------------------------------------------------------------------*\
\r
6110 * Misc utility routines
\r
6112 \*---------------------------------------------------------------------------*/
\r
6115 * Decent random number generator, at least not as bad as Windows
\r
6116 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6118 unsigned int randstate;
\r
6123 randstate = randstate * 1664525 + 1013904223;
\r
6124 return (int) randstate & 0x7fffffff;
\r
6128 mysrandom(unsigned int seed)
\r
6135 * returns TRUE if user selects a different color, FALSE otherwise
\r
6139 ChangeColor(HWND hwnd, COLORREF *which)
\r
6141 static BOOL firstTime = TRUE;
\r
6142 static DWORD customColors[16];
\r
6144 COLORREF newcolor;
\r
6149 /* Make initial colors in use available as custom colors */
\r
6150 /* Should we put the compiled-in defaults here instead? */
\r
6152 customColors[i++] = lightSquareColor & 0xffffff;
\r
6153 customColors[i++] = darkSquareColor & 0xffffff;
\r
6154 customColors[i++] = whitePieceColor & 0xffffff;
\r
6155 customColors[i++] = blackPieceColor & 0xffffff;
\r
6156 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6157 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6159 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6160 customColors[i++] = textAttribs[ccl].color;
\r
6162 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6163 firstTime = FALSE;
\r
6166 cc.lStructSize = sizeof(cc);
\r
6167 cc.hwndOwner = hwnd;
\r
6168 cc.hInstance = NULL;
\r
6169 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6170 cc.lpCustColors = (LPDWORD) customColors;
\r
6171 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6173 if (!ChooseColor(&cc)) return FALSE;
\r
6175 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6176 if (newcolor == *which) return FALSE;
\r
6177 *which = newcolor;
\r
6181 InitDrawingColors();
\r
6182 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6187 MyLoadSound(MySound *ms)
\r
6193 if (ms->data) free(ms->data);
\r
6196 switch (ms->name[0]) {
\r
6202 /* System sound from Control Panel. Don't preload here. */
\r
6206 if (ms->name[1] == NULLCHAR) {
\r
6207 /* "!" alone = silence */
\r
6210 /* Builtin wave resource. Error if not found. */
\r
6211 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6212 if (h == NULL) break;
\r
6213 ms->data = (void *)LoadResource(hInst, h);
\r
6214 if (h == NULL) break;
\r
6219 /* .wav file. Error if not found. */
\r
6220 f = fopen(ms->name, "rb");
\r
6221 if (f == NULL) break;
\r
6222 if (fstat(fileno(f), &st) < 0) break;
\r
6223 ms->data = malloc(st.st_size);
\r
6224 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6230 char buf[MSG_SIZ];
\r
6231 sprintf(buf, "Error loading sound %s", ms->name);
\r
6232 DisplayError(buf, GetLastError());
\r
6238 MyPlaySound(MySound *ms)
\r
6240 BOOLEAN ok = FALSE;
\r
6242 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6243 switch (ms->name[0]) {
\r
6245 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6250 /* System sound from Control Panel (deprecated feature).
\r
6251 "$" alone or an unset sound name gets default beep (still in use). */
\r
6252 if (ms->name[1]) {
\r
6253 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6255 if (!ok) ok = MessageBeep(MB_OK);
\r
6258 /* Builtin wave resource, or "!" alone for silence */
\r
6259 if (ms->name[1]) {
\r
6260 if (ms->data == NULL) return FALSE;
\r
6261 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6267 /* .wav file. Error if not found. */
\r
6268 if (ms->data == NULL) return FALSE;
\r
6269 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6272 /* Don't print an error: this can happen innocently if the sound driver
\r
6273 is busy; for instance, if another instance of WinBoard is playing
\r
6274 a sound at about the same time. */
\r
6280 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6283 OPENFILENAME *ofn;
\r
6284 static UINT *number; /* gross that this is static */
\r
6286 switch (message) {
\r
6287 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6288 /* Center the dialog over the application window */
\r
6289 ofn = (OPENFILENAME *) lParam;
\r
6290 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6291 number = (UINT *) ofn->lCustData;
\r
6292 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6296 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6297 return FALSE; /* Allow for further processing */
\r
6300 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6301 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6303 return FALSE; /* Allow for further processing */
\r
6309 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6311 static UINT *number;
\r
6312 OPENFILENAME *ofname;
\r
6315 case WM_INITDIALOG:
\r
6316 ofname = (OPENFILENAME *)lParam;
\r
6317 number = (UINT *)(ofname->lCustData);
\r
6320 ofnot = (OFNOTIFY *)lParam;
\r
6321 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6322 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6331 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6332 char *nameFilt, char *dlgTitle, UINT *number,
\r
6333 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6335 OPENFILENAME openFileName;
\r
6336 char buf1[MSG_SIZ];
\r
6339 if (fileName == NULL) fileName = buf1;
\r
6340 if (defName == NULL) {
\r
6341 strcpy(fileName, "*.");
\r
6342 strcat(fileName, defExt);
\r
6344 strcpy(fileName, defName);
\r
6346 if (fileTitle) strcpy(fileTitle, "");
\r
6347 if (number) *number = 0;
\r
6349 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6350 openFileName.hwndOwner = hwnd;
\r
6351 openFileName.hInstance = (HANDLE) hInst;
\r
6352 openFileName.lpstrFilter = nameFilt;
\r
6353 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6354 openFileName.nMaxCustFilter = 0L;
\r
6355 openFileName.nFilterIndex = 1L;
\r
6356 openFileName.lpstrFile = fileName;
\r
6357 openFileName.nMaxFile = MSG_SIZ;
\r
6358 openFileName.lpstrFileTitle = fileTitle;
\r
6359 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6360 openFileName.lpstrInitialDir = NULL;
\r
6361 openFileName.lpstrTitle = dlgTitle;
\r
6362 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6363 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6364 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6365 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6366 openFileName.nFileOffset = 0;
\r
6367 openFileName.nFileExtension = 0;
\r
6368 openFileName.lpstrDefExt = defExt;
\r
6369 openFileName.lCustData = (LONG) number;
\r
6370 openFileName.lpfnHook = oldDialog ?
\r
6371 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6372 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6374 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6375 GetOpenFileName(&openFileName)) {
\r
6376 /* open the file */
\r
6377 f = fopen(openFileName.lpstrFile, write);
\r
6379 MessageBox(hwnd, "File open failed", NULL,
\r
6380 MB_OK|MB_ICONEXCLAMATION);
\r
6384 int err = CommDlgExtendedError();
\r
6385 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6394 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6396 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6399 * Get the first pop-up menu in the menu template. This is the
\r
6400 * menu that TrackPopupMenu displays.
\r
6402 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6404 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6407 * TrackPopup uses screen coordinates, so convert the
\r
6408 * coordinates of the mouse click to screen coordinates.
\r
6410 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6412 /* Draw and track the floating pop-up menu. */
\r
6413 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6414 pt.x, pt.y, 0, hwnd, NULL);
\r
6416 /* Destroy the menu.*/
\r
6417 DestroyMenu(hmenu);
\r
6422 int sizeX, sizeY, newSizeX, newSizeY;
\r
6424 } ResizeEditPlusButtonsClosure;
\r
6427 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6429 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6433 if (hChild == cl->hText) return TRUE;
\r
6434 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6435 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6436 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6437 ScreenToClient(cl->hDlg, &pt);
\r
6438 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6439 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6443 /* Resize a dialog that has a (rich) edit field filling most of
\r
6444 the top, with a row of buttons below */
\r
6446 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6449 int newTextHeight, newTextWidth;
\r
6450 ResizeEditPlusButtonsClosure cl;
\r
6452 /*if (IsIconic(hDlg)) return;*/
\r
6453 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6455 cl.hdwp = BeginDeferWindowPos(8);
\r
6457 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6458 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6459 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6460 if (newTextHeight < 0) {
\r
6461 newSizeY += -newTextHeight;
\r
6462 newTextHeight = 0;
\r
6464 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6465 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6471 cl.newSizeX = newSizeX;
\r
6472 cl.newSizeY = newSizeY;
\r
6473 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6475 EndDeferWindowPos(cl.hdwp);
\r
6478 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6480 RECT rChild, rParent;
\r
6481 int wChild, hChild, wParent, hParent;
\r
6482 int wScreen, hScreen, xNew, yNew;
\r
6485 /* Get the Height and Width of the child window */
\r
6486 GetWindowRect (hwndChild, &rChild);
\r
6487 wChild = rChild.right - rChild.left;
\r
6488 hChild = rChild.bottom - rChild.top;
\r
6490 /* Get the Height and Width of the parent window */
\r
6491 GetWindowRect (hwndParent, &rParent);
\r
6492 wParent = rParent.right - rParent.left;
\r
6493 hParent = rParent.bottom - rParent.top;
\r
6495 /* Get the display limits */
\r
6496 hdc = GetDC (hwndChild);
\r
6497 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6498 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6499 ReleaseDC(hwndChild, hdc);
\r
6501 /* Calculate new X position, then adjust for screen */
\r
6502 xNew = rParent.left + ((wParent - wChild) /2);
\r
6505 } else if ((xNew+wChild) > wScreen) {
\r
6506 xNew = wScreen - wChild;
\r
6509 /* Calculate new Y position, then adjust for screen */
\r
6511 yNew = rParent.top + ((hParent - hChild) /2);
\r
6514 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6519 } else if ((yNew+hChild) > hScreen) {
\r
6520 yNew = hScreen - hChild;
\r
6523 /* Set it, and return */
\r
6524 return SetWindowPos (hwndChild, NULL,
\r
6525 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6528 /* Center one window over another */
\r
6529 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6531 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6534 /*---------------------------------------------------------------------------*\
\r
6536 * Startup Dialog functions
\r
6538 \*---------------------------------------------------------------------------*/
\r
6540 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6542 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6544 while (*cd != NULL) {
\r
6545 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6551 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6553 char buf1[ARG_MAX];
\r
6556 if (str[0] == '@') {
\r
6557 FILE* f = fopen(str + 1, "r");
\r
6559 DisplayFatalError(str + 1, errno, 2);
\r
6562 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6564 buf1[len] = NULLCHAR;
\r
6568 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6571 char buf[MSG_SIZ];
\r
6572 char *end = strchr(str, '\n');
\r
6573 if (end == NULL) return;
\r
6574 memcpy(buf, str, end - str);
\r
6575 buf[end - str] = NULLCHAR;
\r
6576 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6582 SetStartupDialogEnables(HWND hDlg)
\r
6584 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6585 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6586 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6587 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6588 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6589 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6590 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6591 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6592 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6593 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6594 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6595 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6596 IsDlgButtonChecked(hDlg, OPT_View));
\r
6600 QuoteForFilename(char *filename)
\r
6602 int dquote, space;
\r
6603 dquote = strchr(filename, '"') != NULL;
\r
6604 space = strchr(filename, ' ') != NULL;
\r
6605 if (dquote || space) {
\r
6617 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6619 char buf[MSG_SIZ];
\r
6622 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6623 q = QuoteForFilename(nthcp);
\r
6624 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6625 if (*nthdir != NULLCHAR) {
\r
6626 q = QuoteForFilename(nthdir);
\r
6627 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6629 if (*nthcp == NULLCHAR) {
\r
6630 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6631 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6632 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6633 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6638 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6640 char buf[MSG_SIZ];
\r
6644 switch (message) {
\r
6645 case WM_INITDIALOG:
\r
6646 /* Center the dialog */
\r
6647 CenterWindow (hDlg, GetDesktopWindow());
\r
6648 /* Initialize the dialog items */
\r
6649 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6650 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6651 firstChessProgramNames);
\r
6652 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6653 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6654 secondChessProgramNames);
\r
6655 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6656 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6657 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6658 if (*appData.icsHelper != NULLCHAR) {
\r
6659 char *q = QuoteForFilename(appData.icsHelper);
\r
6660 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6662 if (*appData.icsHost == NULLCHAR) {
\r
6663 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6664 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6665 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6666 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6667 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6670 if (appData.icsActive) {
\r
6671 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6673 else if (appData.noChessProgram) {
\r
6674 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6677 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6680 SetStartupDialogEnables(hDlg);
\r
6684 switch (LOWORD(wParam)) {
\r
6686 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6687 strcpy(buf, "/fcp=");
\r
6688 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6690 ParseArgs(StringGet, &p);
\r
6691 strcpy(buf, "/scp=");
\r
6692 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6694 ParseArgs(StringGet, &p);
\r
6695 appData.noChessProgram = FALSE;
\r
6696 appData.icsActive = FALSE;
\r
6697 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6698 strcpy(buf, "/ics /icshost=");
\r
6699 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6701 ParseArgs(StringGet, &p);
\r
6702 if (appData.zippyPlay) {
\r
6703 strcpy(buf, "/fcp=");
\r
6704 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6706 ParseArgs(StringGet, &p);
\r
6708 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6709 appData.noChessProgram = TRUE;
\r
6710 appData.icsActive = FALSE;
\r
6712 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6713 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6716 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6717 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6719 ParseArgs(StringGet, &p);
\r
6721 EndDialog(hDlg, TRUE);
\r
6728 case IDM_HELPCONTENTS:
\r
6729 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6730 MessageBox (GetFocus(),
\r
6731 "Unable to activate help",
\r
6732 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6737 SetStartupDialogEnables(hDlg);
\r
6745 /*---------------------------------------------------------------------------*\
\r
6747 * About box dialog functions
\r
6749 \*---------------------------------------------------------------------------*/
\r
6751 /* Process messages for "About" dialog box */
\r
6753 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6755 switch (message) {
\r
6756 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6757 /* Center the dialog over the application window */
\r
6758 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6759 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6763 case WM_COMMAND: /* message: received a command */
\r
6764 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6765 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6766 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6774 /*---------------------------------------------------------------------------*\
\r
6776 * Comment Dialog functions
\r
6778 \*---------------------------------------------------------------------------*/
\r
6781 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6783 static HANDLE hwndText = NULL;
\r
6784 int len, newSizeX, newSizeY, flags;
\r
6785 static int sizeX, sizeY;
\r
6790 switch (message) {
\r
6791 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6792 /* Initialize the dialog items */
\r
6793 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6794 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6795 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6796 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6797 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6798 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6799 SetWindowText(hDlg, commentTitle);
\r
6800 if (editComment) {
\r
6801 SetFocus(hwndText);
\r
6803 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6805 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6806 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6807 MAKELPARAM(FALSE, 0));
\r
6808 /* Size and position the dialog */
\r
6809 if (!commentDialog) {
\r
6810 commentDialog = hDlg;
\r
6811 flags = SWP_NOZORDER;
\r
6812 GetClientRect(hDlg, &rect);
\r
6813 sizeX = rect.right;
\r
6814 sizeY = rect.bottom;
\r
6815 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6816 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6817 WINDOWPLACEMENT wp;
\r
6818 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6819 wp.length = sizeof(WINDOWPLACEMENT);
\r
6821 wp.showCmd = SW_SHOW;
\r
6822 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6823 wp.rcNormalPosition.left = wpComment.x;
\r
6824 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6825 wp.rcNormalPosition.top = wpComment.y;
\r
6826 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6827 SetWindowPlacement(hDlg, &wp);
\r
6829 GetClientRect(hDlg, &rect);
\r
6830 newSizeX = rect.right;
\r
6831 newSizeY = rect.bottom;
\r
6832 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6833 newSizeX, newSizeY);
\r
6840 case WM_COMMAND: /* message: received a command */
\r
6841 switch (LOWORD(wParam)) {
\r
6843 if (editComment) {
\r
6845 /* Read changed options from the dialog box */
\r
6846 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6847 len = GetWindowTextLength(hwndText);
\r
6848 str = (char *) malloc(len + 1);
\r
6849 GetWindowText(hwndText, str, len + 1);
\r
6858 ReplaceComment(commentIndex, str);
\r
6865 case OPT_CancelComment:
\r
6869 case OPT_ClearComment:
\r
6870 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6873 case OPT_EditComment:
\r
6874 EditCommentEvent();
\r
6883 newSizeX = LOWORD(lParam);
\r
6884 newSizeY = HIWORD(lParam);
\r
6885 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6890 case WM_GETMINMAXINFO:
\r
6891 /* Prevent resizing window too small */
\r
6892 mmi = (MINMAXINFO *) lParam;
\r
6893 mmi->ptMinTrackSize.x = 100;
\r
6894 mmi->ptMinTrackSize.y = 100;
\r
6901 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6906 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6908 if (str == NULL) str = "";
\r
6909 p = (char *) malloc(2 * strlen(str) + 2);
\r
6912 if (*str == '\n') *q++ = '\r';
\r
6916 if (commentText != NULL) free(commentText);
\r
6918 commentIndex = index;
\r
6919 commentTitle = title;
\r
6921 editComment = edit;
\r
6923 if (commentDialog) {
\r
6924 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6925 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
6927 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6928 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6929 hwndMain, (DLGPROC)lpProc);
\r
6930 FreeProcInstance(lpProc);
\r
6936 /*---------------------------------------------------------------------------*\
\r
6938 * Type-in move dialog functions
\r
6940 \*---------------------------------------------------------------------------*/
\r
6943 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6945 char move[MSG_SIZ];
\r
6947 ChessMove moveType;
\r
6948 int fromX, fromY, toX, toY;
\r
6951 switch (message) {
\r
6952 case WM_INITDIALOG:
\r
6953 move[0] = (char) lParam;
\r
6954 move[1] = NULLCHAR;
\r
6955 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6956 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6957 SetWindowText(hInput, move);
\r
6959 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6963 switch (LOWORD(wParam)) {
\r
6965 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6966 { int n; Board board;
\r
6968 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
6969 EditPositionPasteFEN(move);
\r
6970 EndDialog(hDlg, TRUE);
\r
6973 // [HGM] movenum: allow move number to be typed in any mode
\r
6974 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
6976 EndDialog(hDlg, TRUE);
\r
6980 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
6981 gameMode != Training) {
\r
6982 DisplayMoveError("Displayed move is not current");
\r
6984 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
6985 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
6986 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
6987 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
6988 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
6989 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
6990 if (gameMode != Training)
\r
6991 forwardMostMove = currentMove;
\r
6992 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
6994 DisplayMoveError("Could not parse move");
\r
6997 EndDialog(hDlg, TRUE);
\r
7000 EndDialog(hDlg, FALSE);
\r
7011 PopUpMoveDialog(char firstchar)
\r
7015 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7016 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7017 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7018 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7019 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7020 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7021 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7022 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7023 gameMode == Training) {
\r
7024 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7025 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7026 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7027 FreeProcInstance(lpProc);
\r
7031 /*---------------------------------------------------------------------------*\
\r
7033 * Type-in name dialog functions
\r
7035 \*---------------------------------------------------------------------------*/
\r
7038 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7040 char move[MSG_SIZ];
\r
7043 switch (message) {
\r
7044 case WM_INITDIALOG:
\r
7045 move[0] = (char) lParam;
\r
7046 move[1] = NULLCHAR;
\r
7047 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7048 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7049 SetWindowText(hInput, move);
\r
7051 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7055 switch (LOWORD(wParam)) {
\r
7057 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7058 appData.userName = strdup(move);
\r
7061 EndDialog(hDlg, TRUE);
\r
7064 EndDialog(hDlg, FALSE);
\r
7075 PopUpNameDialog(char firstchar)
\r
7079 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7080 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7081 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7082 FreeProcInstance(lpProc);
\r
7085 /*---------------------------------------------------------------------------*\
\r
7089 \*---------------------------------------------------------------------------*/
\r
7091 /* Nonmodal error box */
\r
7092 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7093 WPARAM wParam, LPARAM lParam);
\r
7096 ErrorPopUp(char *title, char *content)
\r
7100 BOOLEAN modal = hwndMain == NULL;
\r
7118 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7119 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7122 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7124 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7125 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7126 hwndMain, (DLGPROC)lpProc);
\r
7127 FreeProcInstance(lpProc);
\r
7134 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7135 if (errorDialog == NULL) return;
\r
7136 DestroyWindow(errorDialog);
\r
7137 errorDialog = NULL;
\r
7141 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7146 switch (message) {
\r
7147 case WM_INITDIALOG:
\r
7148 GetWindowRect(hDlg, &rChild);
\r
7151 SetWindowPos(hDlg, NULL, rChild.left,
\r
7152 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7153 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7157 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7158 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7159 and it doesn't work when you resize the dialog.
\r
7160 For now, just give it a default position.
\r
7162 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7164 errorDialog = hDlg;
\r
7165 SetWindowText(hDlg, errorTitle);
\r
7166 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7167 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7171 switch (LOWORD(wParam)) {
\r
7174 if (errorDialog == hDlg) errorDialog = NULL;
\r
7175 DestroyWindow(hDlg);
\r
7187 HWND gothicDialog = NULL;
\r
7190 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7194 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7196 switch (message) {
\r
7197 case WM_INITDIALOG:
\r
7198 GetWindowRect(hDlg, &rChild);
\r
7200 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
7204 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7205 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7206 and it doesn't work when you resize the dialog.
\r
7207 For now, just give it a default position.
\r
7209 gothicDialog = hDlg;
\r
7210 SetWindowText(hDlg, errorTitle);
\r
7211 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7212 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7216 switch (LOWORD(wParam)) {
\r
7219 if (errorDialog == hDlg) errorDialog = NULL;
\r
7220 DestroyWindow(hDlg);
\r
7232 GothicPopUp(char *title, VariantClass variant)
\r
7235 static char *lastTitle;
\r
7237 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7238 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7240 if(lastTitle != title && gothicDialog != NULL) {
\r
7241 DestroyWindow(gothicDialog);
\r
7242 gothicDialog = NULL;
\r
7244 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7245 title = lastTitle;
\r
7246 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7247 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7248 hwndMain, (DLGPROC)lpProc);
\r
7249 FreeProcInstance(lpProc);
\r
7254 /*---------------------------------------------------------------------------*\
\r
7256 * Ics Interaction console functions
\r
7258 \*---------------------------------------------------------------------------*/
\r
7260 #define HISTORY_SIZE 64
\r
7261 static char *history[HISTORY_SIZE];
\r
7262 int histIn = 0, histP = 0;
\r
7265 SaveInHistory(char *cmd)
\r
7267 if (history[histIn] != NULL) {
\r
7268 free(history[histIn]);
\r
7269 history[histIn] = NULL;
\r
7271 if (*cmd == NULLCHAR) return;
\r
7272 history[histIn] = StrSave(cmd);
\r
7273 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7274 if (history[histIn] != NULL) {
\r
7275 free(history[histIn]);
\r
7276 history[histIn] = NULL;
\r
7282 PrevInHistory(char *cmd)
\r
7285 if (histP == histIn) {
\r
7286 if (history[histIn] != NULL) free(history[histIn]);
\r
7287 history[histIn] = StrSave(cmd);
\r
7289 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7290 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7292 return history[histP];
\r
7298 if (histP == histIn) return NULL;
\r
7299 histP = (histP + 1) % HISTORY_SIZE;
\r
7300 return history[histP];
\r
7307 BOOLEAN immediate;
\r
7308 } IcsTextMenuEntry;
\r
7309 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7310 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7313 ParseIcsTextMenu(char *icsTextMenuString)
\r
7316 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7317 char *p = icsTextMenuString;
\r
7318 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7321 if (e->command != NULL) {
\r
7323 e->command = NULL;
\r
7327 e = icsTextMenuEntry;
\r
7328 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7329 if (*p == ';' || *p == '\n') {
\r
7330 e->item = strdup("-");
\r
7331 e->command = NULL;
\r
7333 } else if (*p == '-') {
\r
7334 e->item = strdup("-");
\r
7335 e->command = NULL;
\r
7339 char *q, *r, *s, *t;
\r
7341 q = strchr(p, ',');
\r
7342 if (q == NULL) break;
\r
7344 r = strchr(q + 1, ',');
\r
7345 if (r == NULL) break;
\r
7347 s = strchr(r + 1, ',');
\r
7348 if (s == NULL) break;
\r
7351 t = strchr(s + 1, c);
\r
7354 t = strchr(s + 1, c);
\r
7356 if (t != NULL) *t = NULLCHAR;
\r
7357 e->item = strdup(p);
\r
7358 e->command = strdup(q + 1);
\r
7359 e->getname = *(r + 1) != '0';
\r
7360 e->immediate = *(s + 1) != '0';
\r
7364 if (t == NULL) break;
\r
7373 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7377 hmenu = LoadMenu(hInst, "TextMenu");
\r
7378 h = GetSubMenu(hmenu, 0);
\r
7380 if (strcmp(e->item, "-") == 0) {
\r
7381 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7383 if (e->item[0] == '|') {
\r
7384 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7385 IDM_CommandX + i, &e->item[1]);
\r
7387 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7396 WNDPROC consoleTextWindowProc;
\r
7399 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7401 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7402 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7406 SetWindowText(hInput, command);
\r
7408 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7410 sel.cpMin = 999999;
\r
7411 sel.cpMax = 999999;
\r
7412 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7417 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7418 if (sel.cpMin == sel.cpMax) {
\r
7419 /* Expand to surrounding word */
\r
7422 tr.chrg.cpMax = sel.cpMin;
\r
7423 tr.chrg.cpMin = --sel.cpMin;
\r
7424 if (sel.cpMin < 0) break;
\r
7425 tr.lpstrText = name;
\r
7426 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7427 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7431 tr.chrg.cpMin = sel.cpMax;
\r
7432 tr.chrg.cpMax = ++sel.cpMax;
\r
7433 tr.lpstrText = name;
\r
7434 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7435 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7438 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7439 MessageBeep(MB_ICONEXCLAMATION);
\r
7443 tr.lpstrText = name;
\r
7444 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7446 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7447 MessageBeep(MB_ICONEXCLAMATION);
\r
7450 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7453 sprintf(buf, "%s %s", command, name);
\r
7454 SetWindowText(hInput, buf);
\r
7455 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7457 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7458 SetWindowText(hInput, buf);
\r
7459 sel.cpMin = 999999;
\r
7460 sel.cpMax = 999999;
\r
7461 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7467 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7472 switch (message) {
\r
7474 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7477 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7480 sel.cpMin = 999999;
\r
7481 sel.cpMax = 999999;
\r
7482 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7483 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7488 if(wParam != '\022') {
\r
7489 if (wParam == '\t') {
\r
7490 if (GetKeyState(VK_SHIFT) < 0) {
\r
7492 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7493 if (buttonDesc[0].hwnd) {
\r
7494 SetFocus(buttonDesc[0].hwnd);
\r
7496 SetFocus(hwndMain);
\r
7500 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7503 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7504 JAWS_DELETE( SetFocus(hInput); )
\r
7505 SendMessage(hInput, message, wParam, lParam);
\r
7508 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7509 case WM_RBUTTONUP:
\r
7510 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7511 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7512 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7515 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7516 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7517 if (sel.cpMin == sel.cpMax) {
\r
7518 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7519 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7521 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7522 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7524 pt.x = LOWORD(lParam);
\r
7525 pt.y = HIWORD(lParam);
\r
7526 MenuPopup(hwnd, pt, hmenu, -1);
\r
7530 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7532 return SendMessage(hInput, message, wParam, lParam);
\r
7533 case WM_MBUTTONDOWN:
\r
7534 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7535 case WM_RBUTTONDOWN:
\r
7536 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7537 /* Move selection here if it was empty */
\r
7539 pt.x = LOWORD(lParam);
\r
7540 pt.y = HIWORD(lParam);
\r
7541 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7542 if (sel.cpMin == sel.cpMax) {
\r
7543 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7544 sel.cpMax = sel.cpMin;
\r
7545 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7547 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7551 switch (LOWORD(wParam)) {
\r
7552 case IDM_QuickPaste:
\r
7554 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7555 if (sel.cpMin == sel.cpMax) {
\r
7556 MessageBeep(MB_ICONEXCLAMATION);
\r
7559 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7560 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7561 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7566 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7569 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7572 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7576 int i = LOWORD(wParam) - IDM_CommandX;
\r
7577 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7578 icsTextMenuEntry[i].command != NULL) {
\r
7579 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7580 icsTextMenuEntry[i].getname,
\r
7581 icsTextMenuEntry[i].immediate);
\r
7589 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7592 WNDPROC consoleInputWindowProc;
\r
7595 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7597 char buf[MSG_SIZ];
\r
7599 static BOOL sendNextChar = FALSE;
\r
7600 static BOOL quoteNextChar = FALSE;
\r
7601 InputSource *is = consoleInputSource;
\r
7605 switch (message) {
\r
7607 if (!appData.localLineEditing || sendNextChar) {
\r
7608 is->buf[0] = (CHAR) wParam;
\r
7610 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7611 sendNextChar = FALSE;
\r
7614 if (quoteNextChar) {
\r
7615 buf[0] = (char) wParam;
\r
7616 buf[1] = NULLCHAR;
\r
7617 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7618 quoteNextChar = FALSE;
\r
7622 case '\r': /* Enter key */
\r
7623 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7624 if (consoleEcho) SaveInHistory(is->buf);
\r
7625 is->buf[is->count++] = '\n';
\r
7626 is->buf[is->count] = NULLCHAR;
\r
7627 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7628 if (consoleEcho) {
\r
7629 ConsoleOutput(is->buf, is->count, TRUE);
\r
7630 } else if (appData.localLineEditing) {
\r
7631 ConsoleOutput("\n", 1, TRUE);
\r
7634 case '\033': /* Escape key */
\r
7635 SetWindowText(hwnd, "");
\r
7636 cf.cbSize = sizeof(CHARFORMAT);
\r
7637 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7638 if (consoleEcho) {
\r
7639 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7641 cf.crTextColor = COLOR_ECHOOFF;
\r
7643 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7644 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7646 case '\t': /* Tab key */
\r
7647 if (GetKeyState(VK_SHIFT) < 0) {
\r
7649 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7652 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7653 if (buttonDesc[0].hwnd) {
\r
7654 SetFocus(buttonDesc[0].hwnd);
\r
7656 SetFocus(hwndMain);
\r
7660 case '\023': /* Ctrl+S */
\r
7661 sendNextChar = TRUE;
\r
7663 case '\021': /* Ctrl+Q */
\r
7664 quoteNextChar = TRUE;
\r
7674 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7675 p = PrevInHistory(buf);
\r
7677 SetWindowText(hwnd, p);
\r
7678 sel.cpMin = 999999;
\r
7679 sel.cpMax = 999999;
\r
7680 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7685 p = NextInHistory();
\r
7687 SetWindowText(hwnd, p);
\r
7688 sel.cpMin = 999999;
\r
7689 sel.cpMax = 999999;
\r
7690 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7696 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7700 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7704 case WM_MBUTTONDOWN:
\r
7705 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7706 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7708 case WM_RBUTTONUP:
\r
7709 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7710 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7711 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7715 hmenu = LoadMenu(hInst, "InputMenu");
\r
7716 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7717 if (sel.cpMin == sel.cpMax) {
\r
7718 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7719 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7721 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7722 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7724 pt.x = LOWORD(lParam);
\r
7725 pt.y = HIWORD(lParam);
\r
7726 MenuPopup(hwnd, pt, hmenu, -1);
\r
7730 switch (LOWORD(wParam)) {
\r
7732 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7734 case IDM_SelectAll:
\r
7736 sel.cpMax = -1; /*999999?*/
\r
7737 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7740 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7743 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7746 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7751 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7754 #define CO_MAX 100000
\r
7755 #define CO_TRIM 1000
\r
7758 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7760 static SnapData sd;
\r
7761 HWND hText, hInput;
\r
7763 static int sizeX, sizeY;
\r
7764 int newSizeX, newSizeY;
\r
7768 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7769 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7771 switch (message) {
\r
7773 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7775 ENLINK *pLink = (ENLINK*)lParam;
\r
7776 if (pLink->msg == WM_LBUTTONUP)
\r
7780 tr.chrg = pLink->chrg;
\r
7781 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7782 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7783 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7784 free(tr.lpstrText);
\r
7788 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7789 hwndConsole = hDlg;
\r
7791 consoleTextWindowProc = (WNDPROC)
\r
7792 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7793 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7794 consoleInputWindowProc = (WNDPROC)
\r
7795 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7796 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7797 Colorize(ColorNormal, TRUE);
\r
7798 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7799 ChangedConsoleFont();
\r
7800 GetClientRect(hDlg, &rect);
\r
7801 sizeX = rect.right;
\r
7802 sizeY = rect.bottom;
\r
7803 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7804 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7805 WINDOWPLACEMENT wp;
\r
7806 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7807 wp.length = sizeof(WINDOWPLACEMENT);
\r
7809 wp.showCmd = SW_SHOW;
\r
7810 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7811 wp.rcNormalPosition.left = wpConsole.x;
\r
7812 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7813 wp.rcNormalPosition.top = wpConsole.y;
\r
7814 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7815 SetWindowPlacement(hDlg, &wp);
\r
7818 // [HGM] Chessknight's change 2004-07-13
\r
7819 else { /* Determine Defaults */
\r
7820 WINDOWPLACEMENT wp;
\r
7821 wpConsole.x = wpMain.width + 1;
\r
7822 wpConsole.y = wpMain.y;
\r
7823 wpConsole.width = screenWidth - wpMain.width;
\r
7824 wpConsole.height = wpMain.height;
\r
7825 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7826 wp.length = sizeof(WINDOWPLACEMENT);
\r
7828 wp.showCmd = SW_SHOW;
\r
7829 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7830 wp.rcNormalPosition.left = wpConsole.x;
\r
7831 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7832 wp.rcNormalPosition.top = wpConsole.y;
\r
7833 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7834 SetWindowPlacement(hDlg, &wp);
\r
7837 // Allow hText to highlight URLs and send notifications on them
\r
7838 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7839 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7840 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7841 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
7855 if (IsIconic(hDlg)) break;
\r
7856 newSizeX = LOWORD(lParam);
\r
7857 newSizeY = HIWORD(lParam);
\r
7858 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7859 RECT rectText, rectInput;
\r
7861 int newTextHeight, newTextWidth;
\r
7862 GetWindowRect(hText, &rectText);
\r
7863 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7864 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7865 if (newTextHeight < 0) {
\r
7866 newSizeY += -newTextHeight;
\r
7867 newTextHeight = 0;
\r
7869 SetWindowPos(hText, NULL, 0, 0,
\r
7870 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7871 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7872 pt.x = rectInput.left;
\r
7873 pt.y = rectInput.top + newSizeY - sizeY;
\r
7874 ScreenToClient(hDlg, &pt);
\r
7875 SetWindowPos(hInput, NULL,
\r
7876 pt.x, pt.y, /* needs client coords */
\r
7877 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7878 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7884 case WM_GETMINMAXINFO:
\r
7885 /* Prevent resizing window too small */
\r
7886 mmi = (MINMAXINFO *) lParam;
\r
7887 mmi->ptMinTrackSize.x = 100;
\r
7888 mmi->ptMinTrackSize.y = 100;
\r
7891 /* [AS] Snapping */
\r
7892 case WM_ENTERSIZEMOVE:
\r
7893 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7896 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7899 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7901 case WM_EXITSIZEMOVE:
\r
7902 UpdateICSWidth(hText);
\r
7903 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7906 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7914 if (hwndConsole) return;
\r
7915 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7916 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7921 ConsoleOutput(char* data, int length, int forceVisible)
\r
7926 char buf[CO_MAX+1];
\r
7929 static int delayLF = 0;
\r
7930 CHARRANGE savesel, sel;
\r
7932 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7940 while (length--) {
\r
7948 } else if (*p == '\007') {
\r
7949 MyPlaySound(&sounds[(int)SoundBell]);
\r
7956 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7957 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7958 /* Save current selection */
\r
7959 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7960 exlen = GetWindowTextLength(hText);
\r
7961 /* Find out whether current end of text is visible */
\r
7962 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7963 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7964 /* Trim existing text if it's too long */
\r
7965 if (exlen + (q - buf) > CO_MAX) {
\r
7966 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7969 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7970 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7972 savesel.cpMin -= trim;
\r
7973 savesel.cpMax -= trim;
\r
7974 if (exlen < 0) exlen = 0;
\r
7975 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7976 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7978 /* Append the new text */
\r
7979 sel.cpMin = exlen;
\r
7980 sel.cpMax = exlen;
\r
7981 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7982 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7983 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7984 if (forceVisible || exlen == 0 ||
\r
7985 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7986 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7987 /* Scroll to make new end of text visible if old end of text
\r
7988 was visible or new text is an echo of user typein */
\r
7989 sel.cpMin = 9999999;
\r
7990 sel.cpMax = 9999999;
\r
7991 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7992 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7993 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7994 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7996 if (savesel.cpMax == exlen || forceVisible) {
\r
7997 /* Move insert point to new end of text if it was at the old
\r
7998 end of text or if the new text is an echo of user typein */
\r
7999 sel.cpMin = 9999999;
\r
8000 sel.cpMax = 9999999;
\r
8001 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8003 /* Restore previous selection */
\r
8004 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8006 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8013 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8017 COLORREF oldFg, oldBg;
\r
8021 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8023 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8024 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8025 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8028 rect.right = x + squareSize;
\r
8030 rect.bottom = y + squareSize;
\r
8033 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8034 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8035 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8036 &rect, str, strlen(str), NULL);
\r
8038 (void) SetTextColor(hdc, oldFg);
\r
8039 (void) SetBkColor(hdc, oldBg);
\r
8040 (void) SelectObject(hdc, oldFont);
\r
8044 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8045 RECT *rect, char *color, char *flagFell)
\r
8049 COLORREF oldFg, oldBg;
\r
8052 if (appData.clockMode) {
\r
8054 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8056 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8063 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8064 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8066 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8067 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8069 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8073 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8074 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8075 rect, str, strlen(str), NULL);
\r
8076 if(logoHeight > 0 && appData.clockMode) {
\r
8078 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8079 r.top = rect->top + logoHeight/2;
\r
8080 r.left = rect->left;
\r
8081 r.right = rect->right;
\r
8082 r.bottom = rect->bottom;
\r
8083 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8084 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8085 &r, str, strlen(str), NULL);
\r
8087 (void) SetTextColor(hdc, oldFg);
\r
8088 (void) SetBkColor(hdc, oldBg);
\r
8089 (void) SelectObject(hdc, oldFont);
\r
8094 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8100 if( count <= 0 ) {
\r
8101 if (appData.debugMode) {
\r
8102 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8105 return ERROR_INVALID_USER_BUFFER;
\r
8108 ResetEvent(ovl->hEvent);
\r
8109 ovl->Offset = ovl->OffsetHigh = 0;
\r
8110 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8114 err = GetLastError();
\r
8115 if (err == ERROR_IO_PENDING) {
\r
8116 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8120 err = GetLastError();
\r
8127 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8132 ResetEvent(ovl->hEvent);
\r
8133 ovl->Offset = ovl->OffsetHigh = 0;
\r
8134 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8138 err = GetLastError();
\r
8139 if (err == ERROR_IO_PENDING) {
\r
8140 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8144 err = GetLastError();
\r
8150 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8151 void CheckForInputBufferFull( InputSource * is )
\r
8153 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8154 /* Look for end of line */
\r
8155 char * p = is->buf;
\r
8157 while( p < is->next && *p != '\n' ) {
\r
8161 if( p >= is->next ) {
\r
8162 if (appData.debugMode) {
\r
8163 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8166 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8167 is->count = (DWORD) -1;
\r
8168 is->next = is->buf;
\r
8174 InputThread(LPVOID arg)
\r
8179 is = (InputSource *) arg;
\r
8180 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8181 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8182 while (is->hThread != NULL) {
\r
8183 is->error = DoReadFile(is->hFile, is->next,
\r
8184 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8185 &is->count, &ovl);
\r
8186 if (is->error == NO_ERROR) {
\r
8187 is->next += is->count;
\r
8189 if (is->error == ERROR_BROKEN_PIPE) {
\r
8190 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8193 is->count = (DWORD) -1;
\r
8194 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8199 CheckForInputBufferFull( is );
\r
8201 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8203 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8205 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8208 CloseHandle(ovl.hEvent);
\r
8209 CloseHandle(is->hFile);
\r
8211 if (appData.debugMode) {
\r
8212 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8219 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8221 NonOvlInputThread(LPVOID arg)
\r
8228 is = (InputSource *) arg;
\r
8229 while (is->hThread != NULL) {
\r
8230 is->error = ReadFile(is->hFile, is->next,
\r
8231 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8232 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8233 if (is->error == NO_ERROR) {
\r
8234 /* Change CRLF to LF */
\r
8235 if (is->next > is->buf) {
\r
8237 i = is->count + 1;
\r
8245 if (prev == '\r' && *p == '\n') {
\r
8257 if (is->error == ERROR_BROKEN_PIPE) {
\r
8258 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8261 is->count = (DWORD) -1;
\r
8265 CheckForInputBufferFull( is );
\r
8267 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8269 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8271 if (is->count < 0) break; /* Quit on error */
\r
8273 CloseHandle(is->hFile);
\r
8278 SocketInputThread(LPVOID arg)
\r
8282 is = (InputSource *) arg;
\r
8283 while (is->hThread != NULL) {
\r
8284 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8285 if ((int)is->count == SOCKET_ERROR) {
\r
8286 is->count = (DWORD) -1;
\r
8287 is->error = WSAGetLastError();
\r
8289 is->error = NO_ERROR;
\r
8290 is->next += is->count;
\r
8291 if (is->count == 0 && is->second == is) {
\r
8292 /* End of file on stderr; quit with no message */
\r
8296 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8298 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8300 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8306 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8310 is = (InputSource *) lParam;
\r
8311 if (is->lineByLine) {
\r
8312 /* Feed in lines one by one */
\r
8313 char *p = is->buf;
\r
8315 while (q < is->next) {
\r
8316 if (*q++ == '\n') {
\r
8317 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8322 /* Move any partial line to the start of the buffer */
\r
8324 while (p < is->next) {
\r
8329 if (is->error != NO_ERROR || is->count == 0) {
\r
8330 /* Notify backend of the error. Note: If there was a partial
\r
8331 line at the end, it is not flushed through. */
\r
8332 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8335 /* Feed in the whole chunk of input at once */
\r
8336 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8337 is->next = is->buf;
\r
8341 /*---------------------------------------------------------------------------*\
\r
8343 * Menu enables. Used when setting various modes.
\r
8345 \*---------------------------------------------------------------------------*/
\r
8353 GreyRevert(Boolean grey)
\r
8354 { // [HGM] vari: for retracting variations in local mode
\r
8355 HMENU hmenu = GetMenu(hwndMain);
\r
8356 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
8360 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8362 while (enab->item > 0) {
\r
8363 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8368 Enables gnuEnables[] = {
\r
8369 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8370 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8371 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8372 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8373 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8374 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8375 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8376 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8377 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8378 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8379 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8383 Enables icsEnables[] = {
\r
8384 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8385 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8386 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8387 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8388 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8389 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8390 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8391 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8392 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8393 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8394 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8395 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8396 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8397 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8398 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8403 Enables zippyEnables[] = {
\r
8404 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8405 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8406 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8407 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8412 Enables ncpEnables[] = {
\r
8413 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8414 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8415 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8416 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8417 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8418 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8419 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8420 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8421 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8422 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8423 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8424 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8425 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8426 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8427 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8428 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8429 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8430 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8431 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8435 Enables trainingOnEnables[] = {
\r
8436 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8437 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8438 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8439 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8440 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8441 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8442 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8443 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8447 Enables trainingOffEnables[] = {
\r
8448 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8449 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8450 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8451 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8452 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8453 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8454 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8455 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8459 /* These modify either ncpEnables or gnuEnables */
\r
8460 Enables cmailEnables[] = {
\r
8461 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8462 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8463 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8464 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8465 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8466 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8467 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8471 Enables machineThinkingEnables[] = {
\r
8472 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8473 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8474 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8475 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8476 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8477 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8478 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8479 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8480 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8481 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8482 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8483 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8484 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8485 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8486 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8490 Enables userThinkingEnables[] = {
\r
8491 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8492 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8493 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8494 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8495 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8496 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8497 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8498 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8499 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8500 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8501 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8502 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8503 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8504 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8505 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8509 /*---------------------------------------------------------------------------*\
\r
8511 * Front-end interface functions exported by XBoard.
\r
8512 * Functions appear in same order as prototypes in frontend.h.
\r
8514 \*---------------------------------------------------------------------------*/
\r
8518 static UINT prevChecked = 0;
\r
8519 static int prevPausing = 0;
\r
8522 if (pausing != prevPausing) {
\r
8523 prevPausing = pausing;
\r
8524 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8525 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8526 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8529 switch (gameMode) {
\r
8530 case BeginningOfGame:
\r
8531 if (appData.icsActive)
\r
8532 nowChecked = IDM_IcsClient;
\r
8533 else if (appData.noChessProgram)
\r
8534 nowChecked = IDM_EditGame;
\r
8536 nowChecked = IDM_MachineBlack;
\r
8538 case MachinePlaysBlack:
\r
8539 nowChecked = IDM_MachineBlack;
\r
8541 case MachinePlaysWhite:
\r
8542 nowChecked = IDM_MachineWhite;
\r
8544 case TwoMachinesPlay:
\r
8545 nowChecked = IDM_TwoMachines;
\r
8548 nowChecked = IDM_AnalysisMode;
\r
8551 nowChecked = IDM_AnalyzeFile;
\r
8554 nowChecked = IDM_EditGame;
\r
8556 case PlayFromGameFile:
\r
8557 nowChecked = IDM_LoadGame;
\r
8559 case EditPosition:
\r
8560 nowChecked = IDM_EditPosition;
\r
8563 nowChecked = IDM_Training;
\r
8565 case IcsPlayingWhite:
\r
8566 case IcsPlayingBlack:
\r
8567 case IcsObserving:
\r
8569 nowChecked = IDM_IcsClient;
\r
8576 if (prevChecked != 0)
\r
8577 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8578 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8579 if (nowChecked != 0)
\r
8580 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8581 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8583 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8584 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8585 MF_BYCOMMAND|MF_ENABLED);
\r
8587 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8588 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8591 prevChecked = nowChecked;
\r
8593 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8594 if (appData.icsActive) {
\r
8595 if (appData.icsEngineAnalyze) {
\r
8596 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8597 MF_BYCOMMAND|MF_CHECKED);
\r
8599 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8600 MF_BYCOMMAND|MF_UNCHECKED);
\r
8608 HMENU hmenu = GetMenu(hwndMain);
\r
8609 SetMenuEnables(hmenu, icsEnables);
\r
8610 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8611 MF_BYPOSITION|MF_ENABLED);
\r
8613 if (appData.zippyPlay) {
\r
8614 SetMenuEnables(hmenu, zippyEnables);
\r
8615 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8616 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8617 MF_BYCOMMAND|MF_ENABLED);
\r
8625 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8631 HMENU hmenu = GetMenu(hwndMain);
\r
8632 SetMenuEnables(hmenu, ncpEnables);
\r
8633 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8634 MF_BYPOSITION|MF_GRAYED);
\r
8635 DrawMenuBar(hwndMain);
\r
8641 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8645 SetTrainingModeOn()
\r
8648 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8649 for (i = 0; i < N_BUTTONS; i++) {
\r
8650 if (buttonDesc[i].hwnd != NULL)
\r
8651 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8656 VOID SetTrainingModeOff()
\r
8659 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8660 for (i = 0; i < N_BUTTONS; i++) {
\r
8661 if (buttonDesc[i].hwnd != NULL)
\r
8662 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8668 SetUserThinkingEnables()
\r
8670 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8674 SetMachineThinkingEnables()
\r
8676 HMENU hMenu = GetMenu(hwndMain);
\r
8677 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8679 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8681 if (gameMode == MachinePlaysBlack) {
\r
8682 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8683 } else if (gameMode == MachinePlaysWhite) {
\r
8684 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8685 } else if (gameMode == TwoMachinesPlay) {
\r
8686 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8692 DisplayTitle(char *str)
\r
8694 char title[MSG_SIZ], *host;
\r
8695 if (str[0] != NULLCHAR) {
\r
8696 strcpy(title, str);
\r
8697 } else if (appData.icsActive) {
\r
8698 if (appData.icsCommPort[0] != NULLCHAR)
\r
8701 host = appData.icsHost;
\r
8702 sprintf(title, "%s: %s", szTitle, host);
\r
8703 } else if (appData.noChessProgram) {
\r
8704 strcpy(title, szTitle);
\r
8706 strcpy(title, szTitle);
\r
8707 strcat(title, ": ");
\r
8708 strcat(title, first.tidy);
\r
8710 SetWindowText(hwndMain, title);
\r
8715 DisplayMessage(char *str1, char *str2)
\r
8719 int remain = MESSAGE_TEXT_MAX - 1;
\r
8722 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8723 messageText[0] = NULLCHAR;
\r
8725 len = strlen(str1);
\r
8726 if (len > remain) len = remain;
\r
8727 strncpy(messageText, str1, len);
\r
8728 messageText[len] = NULLCHAR;
\r
8731 if (*str2 && remain >= 2) {
\r
8733 strcat(messageText, " ");
\r
8736 len = strlen(str2);
\r
8737 if (len > remain) len = remain;
\r
8738 strncat(messageText, str2, len);
\r
8740 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8742 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8746 hdc = GetDC(hwndMain);
\r
8747 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8748 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8749 &messageRect, messageText, strlen(messageText), NULL);
\r
8750 (void) SelectObject(hdc, oldFont);
\r
8751 (void) ReleaseDC(hwndMain, hdc);
\r
8755 DisplayError(char *str, int error)
\r
8757 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8763 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8764 NULL, error, LANG_NEUTRAL,
\r
8765 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8767 sprintf(buf, "%s:\n%s", str, buf2);
\r
8769 ErrorMap *em = errmap;
\r
8770 while (em->err != 0 && em->err != error) em++;
\r
8771 if (em->err != 0) {
\r
8772 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8774 sprintf(buf, "%s:\nError code %d", str, error);
\r
8779 ErrorPopUp("Error", buf);
\r
8784 DisplayMoveError(char *str)
\r
8786 fromX = fromY = -1;
\r
8787 ClearHighlights();
\r
8788 DrawPosition(FALSE, NULL);
\r
8789 if (appData.popupMoveErrors) {
\r
8790 ErrorPopUp("Error", str);
\r
8792 DisplayMessage(str, "");
\r
8793 moveErrorMessageUp = TRUE;
\r
8798 DisplayFatalError(char *str, int error, int exitStatus)
\r
8800 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8802 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8805 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8806 NULL, error, LANG_NEUTRAL,
\r
8807 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8809 sprintf(buf, "%s:\n%s", str, buf2);
\r
8811 ErrorMap *em = errmap;
\r
8812 while (em->err != 0 && em->err != error) em++;
\r
8813 if (em->err != 0) {
\r
8814 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8816 sprintf(buf, "%s:\nError code %d", str, error);
\r
8821 if (appData.debugMode) {
\r
8822 fprintf(debugFP, "%s: %s\n", label, str);
\r
8824 if (appData.popupExitMessage) {
\r
8825 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8826 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8828 ExitEvent(exitStatus);
\r
8833 DisplayInformation(char *str)
\r
8835 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8840 DisplayNote(char *str)
\r
8842 ErrorPopUp("Note", str);
\r
8847 char *title, *question, *replyPrefix;
\r
8852 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8854 static QuestionParams *qp;
\r
8855 char reply[MSG_SIZ];
\r
8858 switch (message) {
\r
8859 case WM_INITDIALOG:
\r
8860 qp = (QuestionParams *) lParam;
\r
8861 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8862 SetWindowText(hDlg, qp->title);
\r
8863 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8864 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8868 switch (LOWORD(wParam)) {
\r
8870 strcpy(reply, qp->replyPrefix);
\r
8871 if (*reply) strcat(reply, " ");
\r
8872 len = strlen(reply);
\r
8873 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8874 strcat(reply, "\n");
\r
8875 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8876 EndDialog(hDlg, TRUE);
\r
8877 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
8880 EndDialog(hDlg, FALSE);
\r
8891 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8893 QuestionParams qp;
\r
8897 qp.question = question;
\r
8898 qp.replyPrefix = replyPrefix;
\r
8900 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8901 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8902 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8903 FreeProcInstance(lpProc);
\r
8906 /* [AS] Pick FRC position */
\r
8907 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8909 static int * lpIndexFRC;
\r
8915 case WM_INITDIALOG:
\r
8916 lpIndexFRC = (int *) lParam;
\r
8918 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8920 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8921 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8922 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8923 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8928 switch( LOWORD(wParam) ) {
\r
8930 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8931 EndDialog( hDlg, 0 );
\r
8932 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8935 EndDialog( hDlg, 1 );
\r
8937 case IDC_NFG_Edit:
\r
8938 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8939 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8941 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8944 case IDC_NFG_Random:
\r
8945 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8946 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8959 int index = appData.defaultFrcPosition;
\r
8960 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8962 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8964 if( result == 0 ) {
\r
8965 appData.defaultFrcPosition = index;
\r
8971 /* [AS] Game list options */
\r
8977 static GLT_Item GLT_ItemInfo[] = {
\r
8978 { GLT_EVENT, "Event" },
\r
8979 { GLT_SITE, "Site" },
\r
8980 { GLT_DATE, "Date" },
\r
8981 { GLT_ROUND, "Round" },
\r
8982 { GLT_PLAYERS, "Players" },
\r
8983 { GLT_RESULT, "Result" },
\r
8984 { GLT_WHITE_ELO, "White Rating" },
\r
8985 { GLT_BLACK_ELO, "Black Rating" },
\r
8986 { GLT_TIME_CONTROL,"Time Control" },
\r
8987 { GLT_VARIANT, "Variant" },
\r
8988 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
8989 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
8993 const char * GLT_FindItem( char id )
\r
8995 const char * result = 0;
\r
8997 GLT_Item * list = GLT_ItemInfo;
\r
8999 while( list->id != 0 ) {
\r
9000 if( list->id == id ) {
\r
9001 result = list->name;
\r
9011 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9013 const char * name = GLT_FindItem( id );
\r
9016 if( index >= 0 ) {
\r
9017 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9020 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9025 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9029 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9032 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9036 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9038 pc = GLT_ALL_TAGS;
\r
9041 if( strchr( tags, *pc ) == 0 ) {
\r
9042 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9047 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9050 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9052 char result = '\0';
\r
9055 GLT_Item * list = GLT_ItemInfo;
\r
9057 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9058 while( list->id != 0 ) {
\r
9059 if( strcmp( list->name, name ) == 0 ) {
\r
9060 result = list->id;
\r
9071 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9073 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9074 int idx2 = idx1 + delta;
\r
9075 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9077 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9080 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9081 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9082 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9083 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9087 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9089 static char glt[64];
\r
9090 static char * lpUserGLT;
\r
9094 case WM_INITDIALOG:
\r
9095 lpUserGLT = (char *) lParam;
\r
9097 strcpy( glt, lpUserGLT );
\r
9099 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9101 /* Initialize list */
\r
9102 GLT_TagsToList( hDlg, glt );
\r
9104 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9109 switch( LOWORD(wParam) ) {
\r
9112 char * pc = lpUserGLT;
\r
9114 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9118 id = GLT_ListItemToTag( hDlg, idx );
\r
9122 } while( id != '\0' );
\r
9124 EndDialog( hDlg, 0 );
\r
9127 EndDialog( hDlg, 1 );
\r
9130 case IDC_GLT_Default:
\r
9131 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9132 GLT_TagsToList( hDlg, glt );
\r
9135 case IDC_GLT_Restore:
\r
9136 strcpy( glt, lpUserGLT );
\r
9137 GLT_TagsToList( hDlg, glt );
\r
9141 GLT_MoveSelection( hDlg, -1 );
\r
9144 case IDC_GLT_Down:
\r
9145 GLT_MoveSelection( hDlg, +1 );
\r
9155 int GameListOptions()
\r
9159 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9161 strcpy( glt, appData.gameListTags );
\r
9163 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9165 if( result == 0 ) {
\r
9166 /* [AS] Memory leak here! */
\r
9167 appData.gameListTags = strdup( glt );
\r
9175 DisplayIcsInteractionTitle(char *str)
\r
9177 char consoleTitle[MSG_SIZ];
\r
9179 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9180 SetWindowText(hwndConsole, consoleTitle);
\r
9184 DrawPosition(int fullRedraw, Board board)
\r
9186 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9189 void NotifyFrontendLogin()
\r
9192 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
9198 fromX = fromY = -1;
\r
9199 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9200 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9201 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9202 dragInfo.lastpos = dragInfo.pos;
\r
9203 dragInfo.start.x = dragInfo.start.y = -1;
\r
9204 dragInfo.from = dragInfo.start;
\r
9206 DrawPosition(TRUE, NULL);
\r
9212 CommentPopUp(char *title, char *str)
\r
9214 HWND hwnd = GetActiveWindow();
\r
9215 EitherCommentPopUp(0, title, str, FALSE);
\r
9217 SetActiveWindow(hwnd);
\r
9221 CommentPopDown(void)
\r
9223 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9224 if (commentDialog) {
\r
9225 ShowWindow(commentDialog, SW_HIDE);
\r
9227 commentUp = FALSE;
\r
9231 EditCommentPopUp(int index, char *title, char *str)
\r
9233 EitherCommentPopUp(index, title, str, TRUE);
\r
9240 MyPlaySound(&sounds[(int)SoundMove]);
\r
9243 VOID PlayIcsWinSound()
\r
9245 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9248 VOID PlayIcsLossSound()
\r
9250 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9253 VOID PlayIcsDrawSound()
\r
9255 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9258 VOID PlayIcsUnfinishedSound()
\r
9260 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9266 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9274 consoleEcho = TRUE;
\r
9275 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9276 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9277 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9286 consoleEcho = FALSE;
\r
9287 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9288 /* This works OK: set text and background both to the same color */
\r
9290 cf.crTextColor = COLOR_ECHOOFF;
\r
9291 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9292 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9295 /* No Raw()...? */
\r
9297 void Colorize(ColorClass cc, int continuation)
\r
9299 currentColorClass = cc;
\r
9300 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9301 consoleCF.crTextColor = textAttribs[cc].color;
\r
9302 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9303 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9309 static char buf[MSG_SIZ];
\r
9310 DWORD bufsiz = MSG_SIZ;
\r
9312 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9313 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9315 if (!GetUserName(buf, &bufsiz)) {
\r
9316 /*DisplayError("Error getting user name", GetLastError());*/
\r
9317 strcpy(buf, "User");
\r
9325 static char buf[MSG_SIZ];
\r
9326 DWORD bufsiz = MSG_SIZ;
\r
9328 if (!GetComputerName(buf, &bufsiz)) {
\r
9329 /*DisplayError("Error getting host name", GetLastError());*/
\r
9330 strcpy(buf, "Unknown");
\r
9337 ClockTimerRunning()
\r
9339 return clockTimerEvent != 0;
\r
9345 if (clockTimerEvent == 0) return FALSE;
\r
9346 KillTimer(hwndMain, clockTimerEvent);
\r
9347 clockTimerEvent = 0;
\r
9352 StartClockTimer(long millisec)
\r
9354 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9355 (UINT) millisec, NULL);
\r
9359 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9362 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9364 if(appData.noGUI) return;
\r
9365 hdc = GetDC(hwndMain);
\r
9366 if (!IsIconic(hwndMain)) {
\r
9367 DisplayAClock(hdc, timeRemaining, highlight,
\r
9368 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9370 if (highlight && iconCurrent == iconBlack) {
\r
9371 iconCurrent = iconWhite;
\r
9372 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9373 if (IsIconic(hwndMain)) {
\r
9374 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9377 (void) ReleaseDC(hwndMain, hdc);
\r
9379 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9383 DisplayBlackClock(long timeRemaining, int highlight)
\r
9386 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9388 if(appData.noGUI) return;
\r
9389 hdc = GetDC(hwndMain);
\r
9390 if (!IsIconic(hwndMain)) {
\r
9391 DisplayAClock(hdc, timeRemaining, highlight,
\r
9392 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9394 if (highlight && iconCurrent == iconWhite) {
\r
9395 iconCurrent = iconBlack;
\r
9396 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9397 if (IsIconic(hwndMain)) {
\r
9398 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9401 (void) ReleaseDC(hwndMain, hdc);
\r
9403 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9408 LoadGameTimerRunning()
\r
9410 return loadGameTimerEvent != 0;
\r
9414 StopLoadGameTimer()
\r
9416 if (loadGameTimerEvent == 0) return FALSE;
\r
9417 KillTimer(hwndMain, loadGameTimerEvent);
\r
9418 loadGameTimerEvent = 0;
\r
9423 StartLoadGameTimer(long millisec)
\r
9425 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9426 (UINT) millisec, NULL);
\r
9434 char fileTitle[MSG_SIZ];
\r
9436 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9437 f = OpenFileDialog(hwndMain, "a", defName,
\r
9438 appData.oldSaveStyle ? "gam" : "pgn",
\r
9440 "Save Game to File", NULL, fileTitle, NULL);
\r
9442 SaveGame(f, 0, "");
\r
9449 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9451 if (delayedTimerEvent != 0) {
\r
9452 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9453 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9455 KillTimer(hwndMain, delayedTimerEvent);
\r
9456 delayedTimerEvent = 0;
\r
9457 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9458 delayedTimerCallback();
\r
9460 delayedTimerCallback = cb;
\r
9461 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9462 (UINT) millisec, NULL);
\r
9465 DelayedEventCallback
\r
9468 if (delayedTimerEvent) {
\r
9469 return delayedTimerCallback;
\r
9476 CancelDelayedEvent()
\r
9478 if (delayedTimerEvent) {
\r
9479 KillTimer(hwndMain, delayedTimerEvent);
\r
9480 delayedTimerEvent = 0;
\r
9484 DWORD GetWin32Priority(int nice)
\r
9485 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9487 REALTIME_PRIORITY_CLASS 0x00000100
\r
9488 HIGH_PRIORITY_CLASS 0x00000080
\r
9489 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9490 NORMAL_PRIORITY_CLASS 0x00000020
\r
9491 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9492 IDLE_PRIORITY_CLASS 0x00000040
\r
9494 if (nice < -15) return 0x00000080;
\r
9495 if (nice < 0) return 0x00008000;
\r
9496 if (nice == 0) return 0x00000020;
\r
9497 if (nice < 15) return 0x00004000;
\r
9498 return 0x00000040;
\r
9501 /* Start a child process running the given program.
\r
9502 The process's standard output can be read from "from", and its
\r
9503 standard input can be written to "to".
\r
9504 Exit with fatal error if anything goes wrong.
\r
9505 Returns an opaque pointer that can be used to destroy the process
\r
9509 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9511 #define BUFSIZE 4096
\r
9513 HANDLE hChildStdinRd, hChildStdinWr,
\r
9514 hChildStdoutRd, hChildStdoutWr;
\r
9515 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9516 SECURITY_ATTRIBUTES saAttr;
\r
9518 PROCESS_INFORMATION piProcInfo;
\r
9519 STARTUPINFO siStartInfo;
\r
9521 char buf[MSG_SIZ];
\r
9524 if (appData.debugMode) {
\r
9525 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9530 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9531 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9532 saAttr.bInheritHandle = TRUE;
\r
9533 saAttr.lpSecurityDescriptor = NULL;
\r
9536 * The steps for redirecting child's STDOUT:
\r
9537 * 1. Create anonymous pipe to be STDOUT for child.
\r
9538 * 2. Create a noninheritable duplicate of read handle,
\r
9539 * and close the inheritable read handle.
\r
9542 /* Create a pipe for the child's STDOUT. */
\r
9543 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9544 return GetLastError();
\r
9547 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9548 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9549 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9550 FALSE, /* not inherited */
\r
9551 DUPLICATE_SAME_ACCESS);
\r
9553 return GetLastError();
\r
9555 CloseHandle(hChildStdoutRd);
\r
9558 * The steps for redirecting child's STDIN:
\r
9559 * 1. Create anonymous pipe to be STDIN for child.
\r
9560 * 2. Create a noninheritable duplicate of write handle,
\r
9561 * and close the inheritable write handle.
\r
9564 /* Create a pipe for the child's STDIN. */
\r
9565 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9566 return GetLastError();
\r
9569 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9570 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9571 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9572 FALSE, /* not inherited */
\r
9573 DUPLICATE_SAME_ACCESS);
\r
9575 return GetLastError();
\r
9577 CloseHandle(hChildStdinWr);
\r
9579 /* Arrange to (1) look in dir for the child .exe file, and
\r
9580 * (2) have dir be the child's working directory. Interpret
\r
9581 * dir relative to the directory WinBoard loaded from. */
\r
9582 GetCurrentDirectory(MSG_SIZ, buf);
\r
9583 SetCurrentDirectory(installDir);
\r
9584 SetCurrentDirectory(dir);
\r
9586 /* Now create the child process. */
\r
9588 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9589 siStartInfo.lpReserved = NULL;
\r
9590 siStartInfo.lpDesktop = NULL;
\r
9591 siStartInfo.lpTitle = NULL;
\r
9592 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9593 siStartInfo.cbReserved2 = 0;
\r
9594 siStartInfo.lpReserved2 = NULL;
\r
9595 siStartInfo.hStdInput = hChildStdinRd;
\r
9596 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9597 siStartInfo.hStdError = hChildStdoutWr;
\r
9599 fSuccess = CreateProcess(NULL,
\r
9600 cmdLine, /* command line */
\r
9601 NULL, /* process security attributes */
\r
9602 NULL, /* primary thread security attrs */
\r
9603 TRUE, /* handles are inherited */
\r
9604 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9605 NULL, /* use parent's environment */
\r
9607 &siStartInfo, /* STARTUPINFO pointer */
\r
9608 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9610 err = GetLastError();
\r
9611 SetCurrentDirectory(buf); /* return to prev directory */
\r
9616 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9617 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9618 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9621 /* Close the handles we don't need in the parent */
\r
9622 CloseHandle(piProcInfo.hThread);
\r
9623 CloseHandle(hChildStdinRd);
\r
9624 CloseHandle(hChildStdoutWr);
\r
9626 /* Prepare return value */
\r
9627 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9628 cp->kind = CPReal;
\r
9629 cp->hProcess = piProcInfo.hProcess;
\r
9630 cp->pid = piProcInfo.dwProcessId;
\r
9631 cp->hFrom = hChildStdoutRdDup;
\r
9632 cp->hTo = hChildStdinWrDup;
\r
9634 *pr = (void *) cp;
\r
9636 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9637 2000 where engines sometimes don't see the initial command(s)
\r
9638 from WinBoard and hang. I don't understand how that can happen,
\r
9639 but the Sleep is harmless, so I've put it in. Others have also
\r
9640 reported what may be the same problem, so hopefully this will fix
\r
9641 it for them too. */
\r
9649 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9651 ChildProc *cp; int result;
\r
9653 cp = (ChildProc *) pr;
\r
9654 if (cp == NULL) return;
\r
9656 switch (cp->kind) {
\r
9658 /* TerminateProcess is considered harmful, so... */
\r
9659 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9660 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9661 /* The following doesn't work because the chess program
\r
9662 doesn't "have the same console" as WinBoard. Maybe
\r
9663 we could arrange for this even though neither WinBoard
\r
9664 nor the chess program uses a console for stdio? */
\r
9665 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9667 /* [AS] Special termination modes for misbehaving programs... */
\r
9668 if( signal == 9 ) {
\r
9669 result = TerminateProcess( cp->hProcess, 0 );
\r
9671 if ( appData.debugMode) {
\r
9672 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9675 else if( signal == 10 ) {
\r
9676 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9678 if( dw != WAIT_OBJECT_0 ) {
\r
9679 result = TerminateProcess( cp->hProcess, 0 );
\r
9681 if ( appData.debugMode) {
\r
9682 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9688 CloseHandle(cp->hProcess);
\r
9692 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9696 closesocket(cp->sock);
\r
9701 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9702 closesocket(cp->sock);
\r
9703 closesocket(cp->sock2);
\r
9711 InterruptChildProcess(ProcRef pr)
\r
9715 cp = (ChildProc *) pr;
\r
9716 if (cp == NULL) return;
\r
9717 switch (cp->kind) {
\r
9719 /* The following doesn't work because the chess program
\r
9720 doesn't "have the same console" as WinBoard. Maybe
\r
9721 we could arrange for this even though neither WinBoard
\r
9722 nor the chess program uses a console for stdio */
\r
9723 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9728 /* Can't interrupt */
\r
9732 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9739 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9741 char cmdLine[MSG_SIZ];
\r
9743 if (port[0] == NULLCHAR) {
\r
9744 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9746 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9748 return StartChildProcess(cmdLine, "", pr);
\r
9752 /* Code to open TCP sockets */
\r
9755 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9760 struct sockaddr_in sa, mysa;
\r
9761 struct hostent FAR *hp;
\r
9762 unsigned short uport;
\r
9763 WORD wVersionRequested;
\r
9766 /* Initialize socket DLL */
\r
9767 wVersionRequested = MAKEWORD(1, 1);
\r
9768 err = WSAStartup(wVersionRequested, &wsaData);
\r
9769 if (err != 0) return err;
\r
9772 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9773 err = WSAGetLastError();
\r
9778 /* Bind local address using (mostly) don't-care values.
\r
9780 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9781 mysa.sin_family = AF_INET;
\r
9782 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9783 uport = (unsigned short) 0;
\r
9784 mysa.sin_port = htons(uport);
\r
9785 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9786 == SOCKET_ERROR) {
\r
9787 err = WSAGetLastError();
\r
9792 /* Resolve remote host name */
\r
9793 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9794 if (!(hp = gethostbyname(host))) {
\r
9795 unsigned int b0, b1, b2, b3;
\r
9797 err = WSAGetLastError();
\r
9799 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9800 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9801 hp->h_addrtype = AF_INET;
\r
9803 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9804 hp->h_addr_list[0] = (char *) malloc(4);
\r
9805 hp->h_addr_list[0][0] = (char) b0;
\r
9806 hp->h_addr_list[0][1] = (char) b1;
\r
9807 hp->h_addr_list[0][2] = (char) b2;
\r
9808 hp->h_addr_list[0][3] = (char) b3;
\r
9814 sa.sin_family = hp->h_addrtype;
\r
9815 uport = (unsigned short) atoi(port);
\r
9816 sa.sin_port = htons(uport);
\r
9817 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9819 /* Make connection */
\r
9820 if (connect(s, (struct sockaddr *) &sa,
\r
9821 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9822 err = WSAGetLastError();
\r
9827 /* Prepare return value */
\r
9828 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9829 cp->kind = CPSock;
\r
9831 *pr = (ProcRef *) cp;
\r
9837 OpenCommPort(char *name, ProcRef *pr)
\r
9842 char fullname[MSG_SIZ];
\r
9844 if (*name != '\\')
\r
9845 sprintf(fullname, "\\\\.\\%s", name);
\r
9847 strcpy(fullname, name);
\r
9849 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9850 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9851 if (h == (HANDLE) -1) {
\r
9852 return GetLastError();
\r
9856 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9858 /* Accumulate characters until a 100ms pause, then parse */
\r
9859 ct.ReadIntervalTimeout = 100;
\r
9860 ct.ReadTotalTimeoutMultiplier = 0;
\r
9861 ct.ReadTotalTimeoutConstant = 0;
\r
9862 ct.WriteTotalTimeoutMultiplier = 0;
\r
9863 ct.WriteTotalTimeoutConstant = 0;
\r
9864 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9866 /* Prepare return value */
\r
9867 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9868 cp->kind = CPComm;
\r
9871 *pr = (ProcRef *) cp;
\r
9877 OpenLoopback(ProcRef *pr)
\r
9879 DisplayFatalError("Not implemented", 0, 1);
\r
9885 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9890 struct sockaddr_in sa, mysa;
\r
9891 struct hostent FAR *hp;
\r
9892 unsigned short uport;
\r
9893 WORD wVersionRequested;
\r
9896 char stderrPortStr[MSG_SIZ];
\r
9898 /* Initialize socket DLL */
\r
9899 wVersionRequested = MAKEWORD(1, 1);
\r
9900 err = WSAStartup(wVersionRequested, &wsaData);
\r
9901 if (err != 0) return err;
\r
9903 /* Resolve remote host name */
\r
9904 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9905 if (!(hp = gethostbyname(host))) {
\r
9906 unsigned int b0, b1, b2, b3;
\r
9908 err = WSAGetLastError();
\r
9910 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9911 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9912 hp->h_addrtype = AF_INET;
\r
9914 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9915 hp->h_addr_list[0] = (char *) malloc(4);
\r
9916 hp->h_addr_list[0][0] = (char) b0;
\r
9917 hp->h_addr_list[0][1] = (char) b1;
\r
9918 hp->h_addr_list[0][2] = (char) b2;
\r
9919 hp->h_addr_list[0][3] = (char) b3;
\r
9925 sa.sin_family = hp->h_addrtype;
\r
9926 uport = (unsigned short) 514;
\r
9927 sa.sin_port = htons(uport);
\r
9928 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9930 /* Bind local socket to unused "privileged" port address
\r
9932 s = INVALID_SOCKET;
\r
9933 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9934 mysa.sin_family = AF_INET;
\r
9935 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9936 for (fromPort = 1023;; fromPort--) {
\r
9937 if (fromPort < 0) {
\r
9939 return WSAEADDRINUSE;
\r
9941 if (s == INVALID_SOCKET) {
\r
9942 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9943 err = WSAGetLastError();
\r
9948 uport = (unsigned short) fromPort;
\r
9949 mysa.sin_port = htons(uport);
\r
9950 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9951 == SOCKET_ERROR) {
\r
9952 err = WSAGetLastError();
\r
9953 if (err == WSAEADDRINUSE) continue;
\r
9957 if (connect(s, (struct sockaddr *) &sa,
\r
9958 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9959 err = WSAGetLastError();
\r
9960 if (err == WSAEADDRINUSE) {
\r
9971 /* Bind stderr local socket to unused "privileged" port address
\r
9973 s2 = INVALID_SOCKET;
\r
9974 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9975 mysa.sin_family = AF_INET;
\r
9976 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9977 for (fromPort = 1023;; fromPort--) {
\r
9978 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9979 if (fromPort < 0) {
\r
9980 (void) closesocket(s);
\r
9982 return WSAEADDRINUSE;
\r
9984 if (s2 == INVALID_SOCKET) {
\r
9985 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9986 err = WSAGetLastError();
\r
9992 uport = (unsigned short) fromPort;
\r
9993 mysa.sin_port = htons(uport);
\r
9994 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9995 == SOCKET_ERROR) {
\r
9996 err = WSAGetLastError();
\r
9997 if (err == WSAEADDRINUSE) continue;
\r
9998 (void) closesocket(s);
\r
10002 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10003 err = WSAGetLastError();
\r
10004 if (err == WSAEADDRINUSE) {
\r
10006 s2 = INVALID_SOCKET;
\r
10009 (void) closesocket(s);
\r
10010 (void) closesocket(s2);
\r
10016 prevStderrPort = fromPort; // remember port used
\r
10017 sprintf(stderrPortStr, "%d", fromPort);
\r
10019 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10020 err = WSAGetLastError();
\r
10021 (void) closesocket(s);
\r
10022 (void) closesocket(s2);
\r
10027 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10028 err = WSAGetLastError();
\r
10029 (void) closesocket(s);
\r
10030 (void) closesocket(s2);
\r
10034 if (*user == NULLCHAR) user = UserName();
\r
10035 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10036 err = WSAGetLastError();
\r
10037 (void) closesocket(s);
\r
10038 (void) closesocket(s2);
\r
10042 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10043 err = WSAGetLastError();
\r
10044 (void) closesocket(s);
\r
10045 (void) closesocket(s2);
\r
10050 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10051 err = WSAGetLastError();
\r
10052 (void) closesocket(s);
\r
10053 (void) closesocket(s2);
\r
10057 (void) closesocket(s2); /* Stop listening */
\r
10059 /* Prepare return value */
\r
10060 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10061 cp->kind = CPRcmd;
\r
10064 *pr = (ProcRef *) cp;
\r
10071 AddInputSource(ProcRef pr, int lineByLine,
\r
10072 InputCallback func, VOIDSTAR closure)
\r
10074 InputSource *is, *is2 = NULL;
\r
10075 ChildProc *cp = (ChildProc *) pr;
\r
10077 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10078 is->lineByLine = lineByLine;
\r
10080 is->closure = closure;
\r
10081 is->second = NULL;
\r
10082 is->next = is->buf;
\r
10083 if (pr == NoProc) {
\r
10084 is->kind = CPReal;
\r
10085 consoleInputSource = is;
\r
10087 is->kind = cp->kind;
\r
10089 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10090 we create all threads suspended so that the is->hThread variable can be
\r
10091 safely assigned, then let the threads start with ResumeThread.
\r
10093 switch (cp->kind) {
\r
10095 is->hFile = cp->hFrom;
\r
10096 cp->hFrom = NULL; /* now owned by InputThread */
\r
10098 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10099 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10103 is->hFile = cp->hFrom;
\r
10104 cp->hFrom = NULL; /* now owned by InputThread */
\r
10106 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10107 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10111 is->sock = cp->sock;
\r
10113 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10114 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10118 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10120 is->sock = cp->sock;
\r
10121 is->second = is2;
\r
10122 is2->sock = cp->sock2;
\r
10123 is2->second = is2;
\r
10125 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10126 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10128 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10129 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10133 if( is->hThread != NULL ) {
\r
10134 ResumeThread( is->hThread );
\r
10137 if( is2 != NULL && is2->hThread != NULL ) {
\r
10138 ResumeThread( is2->hThread );
\r
10142 return (InputSourceRef) is;
\r
10146 RemoveInputSource(InputSourceRef isr)
\r
10150 is = (InputSource *) isr;
\r
10151 is->hThread = NULL; /* tell thread to stop */
\r
10152 CloseHandle(is->hThread);
\r
10153 if (is->second != NULL) {
\r
10154 is->second->hThread = NULL;
\r
10155 CloseHandle(is->second->hThread);
\r
10159 int no_wrap(char *message, int count)
\r
10161 ConsoleOutput(message, count, FALSE);
\r
10166 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10169 int outCount = SOCKET_ERROR;
\r
10170 ChildProc *cp = (ChildProc *) pr;
\r
10171 static OVERLAPPED ovl;
\r
10172 static int line = 0;
\r
10174 if (pr == NoProc)
\r
10176 if (appData.noJoin || !appData.useInternalWrap)
\r
10177 return no_wrap(message, count);
\r
10180 int width = get_term_width();
\r
10181 int len = wrap(NULL, message, count, width, &line);
\r
10182 char *msg = malloc(len);
\r
10186 return no_wrap(message, count);
\r
10189 dbgchk = wrap(msg, message, count, width, &line);
\r
10190 if (dbgchk != len && appData.debugMode)
\r
10191 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
10192 ConsoleOutput(msg, len, FALSE);
\r
10199 if (ovl.hEvent == NULL) {
\r
10200 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10202 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10204 switch (cp->kind) {
\r
10207 outCount = send(cp->sock, message, count, 0);
\r
10208 if (outCount == SOCKET_ERROR) {
\r
10209 *outError = WSAGetLastError();
\r
10211 *outError = NO_ERROR;
\r
10216 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10217 &dOutCount, NULL)) {
\r
10218 *outError = NO_ERROR;
\r
10219 outCount = (int) dOutCount;
\r
10221 *outError = GetLastError();
\r
10226 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10227 &dOutCount, &ovl);
\r
10228 if (*outError == NO_ERROR) {
\r
10229 outCount = (int) dOutCount;
\r
10237 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10240 /* Ignore delay, not implemented for WinBoard */
\r
10241 return OutputToProcess(pr, message, count, outError);
\r
10246 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10247 char *buf, int count, int error)
\r
10249 DisplayFatalError("Not implemented", 0, 1);
\r
10252 /* see wgamelist.c for Game List functions */
\r
10253 /* see wedittags.c for Edit Tags functions */
\r
10260 char buf[MSG_SIZ];
\r
10263 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10264 f = fopen(buf, "r");
\r
10266 ProcessICSInitScript(f);
\r
10274 StartAnalysisClock()
\r
10276 if (analysisTimerEvent) return;
\r
10277 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10278 (UINT) 2000, NULL);
\r
10282 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10284 highlightInfo.sq[0].x = fromX;
\r
10285 highlightInfo.sq[0].y = fromY;
\r
10286 highlightInfo.sq[1].x = toX;
\r
10287 highlightInfo.sq[1].y = toY;
\r
10291 ClearHighlights()
\r
10293 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10294 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10298 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10300 premoveHighlightInfo.sq[0].x = fromX;
\r
10301 premoveHighlightInfo.sq[0].y = fromY;
\r
10302 premoveHighlightInfo.sq[1].x = toX;
\r
10303 premoveHighlightInfo.sq[1].y = toY;
\r
10307 ClearPremoveHighlights()
\r
10309 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10310 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10314 ShutDownFrontEnd()
\r
10316 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10317 DeleteClipboardTempFiles();
\r
10323 if (IsIconic(hwndMain))
\r
10324 ShowWindow(hwndMain, SW_RESTORE);
\r
10326 SetActiveWindow(hwndMain);
\r
10330 * Prototypes for animation support routines
\r
10332 static void ScreenSquare(int column, int row, POINT * pt);
\r
10333 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10334 POINT frames[], int * nFrames);
\r
10338 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10339 { // [HGM] atomic: animate blast wave
\r
10341 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10342 explodeInfo.fromX = fromX;
\r
10343 explodeInfo.fromY = fromY;
\r
10344 explodeInfo.toX = toX;
\r
10345 explodeInfo.toY = toY;
\r
10346 for(i=1; i<nFrames; i++) {
\r
10347 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10348 DrawPosition(FALSE, NULL);
\r
10349 Sleep(appData.animSpeed);
\r
10351 explodeInfo.radius = 0;
\r
10352 DrawPosition(TRUE, NULL);
\r
10355 #define kFactor 4
\r
10358 AnimateMove(board, fromX, fromY, toX, toY)
\r
10365 ChessSquare piece;
\r
10366 POINT start, finish, mid;
\r
10367 POINT frames[kFactor * 2 + 1];
\r
10370 if (!appData.animate) return;
\r
10371 if (doingSizing) return;
\r
10372 if (fromY < 0 || fromX < 0) return;
\r
10373 piece = board[fromY][fromX];
\r
10374 if (piece >= EmptySquare) return;
\r
10376 ScreenSquare(fromX, fromY, &start);
\r
10377 ScreenSquare(toX, toY, &finish);
\r
10379 /* All pieces except knights move in straight line */
\r
10380 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10381 mid.x = start.x + (finish.x - start.x) / 2;
\r
10382 mid.y = start.y + (finish.y - start.y) / 2;
\r
10384 /* Knight: make diagonal movement then straight */
\r
10385 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10386 mid.x = start.x + (finish.x - start.x) / 2;
\r
10387 mid.y = finish.y;
\r
10389 mid.x = finish.x;
\r
10390 mid.y = start.y + (finish.y - start.y) / 2;
\r
10394 /* Don't use as many frames for very short moves */
\r
10395 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10396 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10398 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10400 animInfo.from.x = fromX;
\r
10401 animInfo.from.y = fromY;
\r
10402 animInfo.to.x = toX;
\r
10403 animInfo.to.y = toY;
\r
10404 animInfo.lastpos = start;
\r
10405 animInfo.piece = piece;
\r
10406 for (n = 0; n < nFrames; n++) {
\r
10407 animInfo.pos = frames[n];
\r
10408 DrawPosition(FALSE, NULL);
\r
10409 animInfo.lastpos = animInfo.pos;
\r
10410 Sleep(appData.animSpeed);
\r
10412 animInfo.pos = finish;
\r
10413 DrawPosition(FALSE, NULL);
\r
10414 animInfo.piece = EmptySquare;
\r
10415 if(gameInfo.variant == VariantAtomic &&
\r
10416 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10417 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10420 /* Convert board position to corner of screen rect and color */
\r
10423 ScreenSquare(column, row, pt)
\r
10424 int column; int row; POINT * pt;
\r
10427 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10428 pt->y = lineGap + row * (squareSize + lineGap);
\r
10430 pt->x = lineGap + column * (squareSize + lineGap);
\r
10431 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10435 /* Generate a series of frame coords from start->mid->finish.
\r
10436 The movement rate doubles until the half way point is
\r
10437 reached, then halves back down to the final destination,
\r
10438 which gives a nice slow in/out effect. The algorithmn
\r
10439 may seem to generate too many intermediates for short
\r
10440 moves, but remember that the purpose is to attract the
\r
10441 viewers attention to the piece about to be moved and
\r
10442 then to where it ends up. Too few frames would be less
\r
10446 Tween(start, mid, finish, factor, frames, nFrames)
\r
10447 POINT * start; POINT * mid;
\r
10448 POINT * finish; int factor;
\r
10449 POINT frames[]; int * nFrames;
\r
10451 int n, fraction = 1, count = 0;
\r
10453 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10454 for (n = 0; n < factor; n++)
\r
10456 for (n = 0; n < factor; n++) {
\r
10457 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10458 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10460 fraction = fraction / 2;
\r
10464 frames[count] = *mid;
\r
10467 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10469 for (n = 0; n < factor; n++) {
\r
10470 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10471 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10473 fraction = fraction * 2;
\r
10475 *nFrames = count;
\r
10479 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10481 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10483 EvalGraphSet( first, last, current, pvInfoList );
\r