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_SIZE + 1) * 4];
\r
197 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 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_SIZE][BOARD_SIZE];
\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
883 String *pString; // ArgString
\r
884 int *pInt; // ArgInt
\r
885 float *pFloat; // ArgFloat
\r
886 Boolean *pBoolean; // ArgBoolean
\r
887 COLORREF *pColor; // ArgColor
\r
888 ColorClass cc; // ArgAttribs
\r
889 String *pFilename; // ArgFilename
\r
890 BoardSize *pBoardSize; // ArgBoardSize
\r
891 int whichFont; // ArgFont
\r
892 DCB *pDCB; // ArgCommSettings
\r
893 String *pFilename; // ArgSettingsFilename
\r
901 ArgDescriptor argDescriptors[] = {
\r
902 /* positional arguments */
\r
903 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
904 { "", ArgNone, NULL },
\r
905 /* keyword arguments */
\r
907 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
908 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
909 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
910 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
911 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
912 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
913 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
914 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
915 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
916 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
917 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
918 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
919 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
920 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
921 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
922 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
923 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
924 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
926 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
928 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
930 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
931 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
933 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
934 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
935 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
936 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
937 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
938 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
939 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
940 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
941 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
942 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
943 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
944 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
945 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
946 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
947 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
948 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
949 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
950 /*!!bitmapDirectory?*/
\r
951 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
952 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
953 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
954 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
955 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
956 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
957 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
958 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
959 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
960 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
961 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
962 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
963 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
964 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
965 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
966 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
967 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
968 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
969 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
970 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
971 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
972 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
973 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
974 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
975 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
976 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
977 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
978 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
979 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
980 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
981 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
982 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
983 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
984 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
985 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
986 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
987 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
988 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
989 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
990 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
991 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
992 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
993 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
994 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
995 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
996 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
997 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
998 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
999 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1000 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1001 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1002 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1003 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1004 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1005 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1006 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1007 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1008 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1009 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1010 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1011 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1012 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1013 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1014 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1015 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1016 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1017 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1018 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1019 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1020 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1021 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1022 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1023 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1024 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1025 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1026 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1027 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1028 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1029 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1030 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1031 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1032 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1033 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1034 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1035 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1036 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1037 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1038 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1039 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1040 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1041 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1042 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1043 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1044 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1045 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1046 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1047 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1048 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1049 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1050 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1051 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1052 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1053 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1054 TRUE }, /* must come after all fonts */
\r
1055 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1056 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1057 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1058 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1059 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1060 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1061 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1062 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1063 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1064 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1065 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1066 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1067 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1068 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1069 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1070 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1071 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1072 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1073 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1074 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1075 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1076 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1077 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1078 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1079 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1080 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1081 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1082 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1083 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1084 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1085 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1086 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1087 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1088 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1089 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1090 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1091 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1092 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1093 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1094 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1095 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1096 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1097 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1098 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1099 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1100 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1101 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1102 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1103 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1104 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1105 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1106 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1107 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1108 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1109 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1110 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1111 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1112 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1113 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1114 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1115 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1116 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1117 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1118 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1119 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1120 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1121 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1122 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1123 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1124 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1125 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1126 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1127 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1128 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1129 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1130 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1131 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1132 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1133 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1134 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1135 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1136 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1137 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1138 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1139 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1140 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1141 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1142 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1143 { "highlightLastMove", ArgBoolean,
\r
1144 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1145 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1146 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1147 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1148 { "highlightDragging", ArgBoolean,
\r
1149 (LPVOID) &appData.highlightDragging, TRUE },
\r
1150 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1151 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1152 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1153 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1154 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1155 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1156 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1157 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1158 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1159 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1160 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1161 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1162 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1163 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1164 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1165 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1166 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1167 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1168 { "soundShout", ArgFilename,
\r
1169 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1170 { "soundSShout", ArgFilename,
\r
1171 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1172 { "soundChannel1", ArgFilename,
\r
1173 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1174 { "soundChannel", ArgFilename,
\r
1175 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1176 { "soundKibitz", ArgFilename,
\r
1177 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1178 { "soundTell", ArgFilename,
\r
1179 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1180 { "soundChallenge", ArgFilename,
\r
1181 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1182 { "soundRequest", ArgFilename,
\r
1183 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1184 { "soundSeek", ArgFilename,
\r
1185 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1186 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1187 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1188 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1189 { "soundIcsLoss", ArgFilename,
\r
1190 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1191 { "soundIcsDraw", ArgFilename,
\r
1192 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1193 { "soundIcsUnfinished", ArgFilename,
\r
1194 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1195 { "soundIcsAlarm", ArgFilename,
\r
1196 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1197 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1198 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1199 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1200 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1201 { "reuseChessPrograms", ArgBoolean,
\r
1202 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1203 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1204 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1205 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1206 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1207 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1208 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1209 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1210 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1211 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1212 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1213 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1214 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1215 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1216 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1217 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1219 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1221 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1222 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1223 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1224 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1225 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1226 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1227 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1228 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1229 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1230 /* [AS] New features */
\r
1231 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1232 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1233 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1234 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1235 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1236 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1237 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1238 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1239 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1240 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1241 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1242 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1243 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1244 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1245 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1246 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1247 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1248 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1249 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1250 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1251 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1252 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1253 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1254 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1255 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1256 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1257 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1258 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1259 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1260 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1261 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1262 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1263 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1264 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1265 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1266 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1267 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1268 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1269 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1270 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1271 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1272 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1273 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1274 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1275 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1276 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1277 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1278 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1279 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1280 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1282 /* [HGM] board-size, adjudication and misc. options */
\r
1283 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1284 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1285 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1286 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1287 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1288 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1289 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1290 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1291 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1292 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1293 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1294 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1295 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1296 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1297 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1298 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1299 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1300 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1301 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1302 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1303 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1304 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1305 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1306 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1307 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1308 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1309 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1310 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1311 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1312 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1313 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1314 { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },
\r
1315 { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },
\r
1316 { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE },
\r
1319 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1320 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1321 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1322 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1323 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1324 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1325 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1326 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1327 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1328 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1329 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1330 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1331 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1333 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1334 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1335 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1336 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1337 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1338 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1339 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1341 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1342 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1343 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1344 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1345 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1346 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1347 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1348 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1349 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1350 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1351 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1352 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1353 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1354 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1355 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1356 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1357 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1358 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1359 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1361 /* [HGM] options for broadcasting and time odds */
\r
1362 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1363 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1364 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1365 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1366 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1367 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1368 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1369 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1370 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1371 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1372 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1373 { "keepLineBreaksICS", ArgBoolean, (LPVOID) &appData.noJoin, TRUE },
\r
1374 { "wrapContinuationSequence", ArgString, (LPVOID) &appData.wrapContSeq, FALSE },
\r
1375 { "useInternalWrap", ArgTrue, (LPVOID) &appData.useInternalWrap, FALSE }, /* noJoin usurps this if set */
\r
1377 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1378 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1379 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1380 { "winWidth", ArgInt, (LPVOID) &wpMain.width, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1381 { "winHeight", ArgInt, (LPVOID) &wpMain.height, TRUE }, // for attaching auxiliary windows to them
\r
1382 { "x", ArgInt, (LPVOID) &wpMain.x, TRUE },
\r
1383 { "y", ArgInt, (LPVOID) &wpMain.y, TRUE },
\r
1384 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1385 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1386 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1387 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1388 { "analysisX", ArgX, (LPVOID) &dummy, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1389 { "analysisY", ArgY, (LPVOID) &dummy, FALSE }, // provided for compatibility with old ini files
\r
1390 { "analysisW", ArgInt, (LPVOID) &dummy, FALSE },
\r
1391 { "analysisH", ArgInt, (LPVOID) &dummy, FALSE },
\r
1392 { "commentX", ArgX, (LPVOID) &wpComment.x, TRUE },
\r
1393 { "commentY", ArgY, (LPVOID) &wpComment.y, TRUE },
\r
1394 { "commentW", ArgInt, (LPVOID) &wpComment.width, TRUE },
\r
1395 { "commentH", ArgInt, (LPVOID) &wpComment.height, TRUE },
\r
1396 { "tagsX", ArgX, (LPVOID) &wpTags.x, TRUE },
\r
1397 { "tagsY", ArgY, (LPVOID) &wpTags.y, TRUE },
\r
1398 { "tagsW", ArgInt, (LPVOID) &wpTags.width, TRUE },
\r
1399 { "tagsH", ArgInt, (LPVOID) &wpTags.height, TRUE },
\r
1400 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1401 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1402 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1403 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1404 /* [AS] Layout stuff */
\r
1405 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1406 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1407 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1408 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1409 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1411 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1412 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1413 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1414 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1415 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1417 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1418 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1419 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1420 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1421 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1423 { NULL, ArgNone, NULL, FALSE }
\r
1427 /* Kludge for indirection files on command line */
\r
1428 char* lastIndirectionFilename;
\r
1429 ArgDescriptor argDescriptorIndirection =
\r
1430 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1434 ExitArgError(char *msg, char *badArg)
\r
1436 char buf[MSG_SIZ];
\r
1438 sprintf(buf, "%s %s", msg, badArg);
\r
1439 DisplayFatalError(buf, 0, 2);
\r
1443 /* Command line font name parser. NULL name means do nothing.
\r
1444 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1445 For backward compatibility, syntax without the colon is also
\r
1446 accepted, but font names with digits in them won't work in that case.
\r
1449 ParseFontName(char *name, MyFontParams *mfp)
\r
1452 if (name == NULL) return;
\r
1454 q = strchr(p, ':');
\r
1456 if (q - p >= sizeof(mfp->faceName))
\r
1457 ExitArgError("Font name too long:", name);
\r
1458 memcpy(mfp->faceName, p, q - p);
\r
1459 mfp->faceName[q - p] = NULLCHAR;
\r
1462 q = mfp->faceName;
\r
1463 while (*p && !isdigit(*p)) {
\r
1465 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1466 ExitArgError("Font name too long:", name);
\r
1468 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1471 if (!*p) ExitArgError("Font point size missing:", name);
\r
1472 mfp->pointSize = (float) atof(p);
\r
1473 mfp->bold = (strchr(p, 'b') != NULL);
\r
1474 mfp->italic = (strchr(p, 'i') != NULL);
\r
1475 mfp->underline = (strchr(p, 'u') != NULL);
\r
1476 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1477 mfp->charset = DEFAULT_CHARSET;
\r
1478 q = strchr(p, 'c');
\r
1480 mfp->charset = (BYTE) atoi(q+1);
\r
1483 /* Color name parser.
\r
1484 X version accepts X color names, but this one
\r
1485 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1487 ParseColorName(char *name)
\r
1489 int red, green, blue, count;
\r
1490 char buf[MSG_SIZ];
\r
1492 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1494 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1495 &red, &green, &blue);
\r
1498 sprintf(buf, "Can't parse color name %s", name);
\r
1499 DisplayError(buf, 0);
\r
1500 return RGB(0, 0, 0);
\r
1502 return PALETTERGB(red, green, blue);
\r
1506 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1508 char *e = argValue;
\r
1512 if (*e == 'b') eff |= CFE_BOLD;
\r
1513 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1514 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1515 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1516 else if (*e == '#' || isdigit(*e)) break;
\r
1520 *color = ParseColorName(e);
\r
1525 ParseBoardSize(char *name)
\r
1527 BoardSize bs = SizeTiny;
\r
1528 while (sizeInfo[bs].name != NULL) {
\r
1529 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1532 ExitArgError("Unrecognized board size value", name);
\r
1533 return bs; /* not reached */
\r
1538 StringGet(void *getClosure)
\r
1540 char **p = (char **) getClosure;
\r
1545 FileGet(void *getClosure)
\r
1548 FILE* f = (FILE*) getClosure;
\r
1551 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1558 /* Parse settings file named "name". If file found, return the
\r
1559 full name in fullname and return TRUE; else return FALSE */
\r
1561 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1565 int ok; char buf[MSG_SIZ];
\r
1567 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1568 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1569 sprintf(buf, "%s.ini", name);
\r
1570 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1573 f = fopen(fullname, "r");
\r
1575 ParseArgs(FileGet, f);
\r
1584 ParseArgs(GetFunc get, void *cl)
\r
1586 char argName[ARG_MAX];
\r
1587 char argValue[ARG_MAX];
\r
1588 ArgDescriptor *ad;
\r
1597 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1598 if (ch == NULLCHAR) break;
\r
1600 /* Comment to end of line */
\r
1602 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1604 } else if (ch == '/' || ch == '-') {
\r
1607 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1608 ch != '\n' && ch != '\t') {
\r
1614 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1615 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1617 if (ad->argName == NULL)
\r
1618 ExitArgError("Unrecognized argument", argName);
\r
1620 } else if (ch == '@') {
\r
1621 /* Indirection file */
\r
1622 ad = &argDescriptorIndirection;
\r
1625 /* Positional argument */
\r
1626 ad = &argDescriptors[posarg++];
\r
1627 strcpy(argName, ad->argName);
\r
1630 if (ad->argType == ArgTrue) {
\r
1631 *(Boolean *) ad->argLoc = TRUE;
\r
1634 if (ad->argType == ArgFalse) {
\r
1635 *(Boolean *) ad->argLoc = FALSE;
\r
1639 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1640 if (ch == NULLCHAR || ch == '\n') {
\r
1641 ExitArgError("No value provided for argument", argName);
\r
1645 // Quoting with { }. No characters have to (or can) be escaped.
\r
1646 // Thus the string cannot contain a '}' character.
\r
1666 } else if (ch == '\'' || ch == '"') {
\r
1667 // Quoting with ' ' or " ", with \ as escape character.
\r
1668 // Inconvenient for long strings that may contain Windows filenames.
\r
1685 if (ch == start) {
\r
1694 if (ad->argType == ArgFilename
\r
1695 || ad->argType == ArgSettingsFilename) {
\r
1701 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1725 for (i = 0; i < 3; i++) {
\r
1726 if (ch >= '0' && ch <= '7') {
\r
1727 octval = octval*8 + (ch - '0');
\r
1734 *q++ = (char) octval;
\r
1745 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1752 switch (ad->argType) {
\r
1754 *(int *) ad->argLoc = atoi(argValue);
\r
1758 *(int *) ad->argLoc = atoi(argValue) + wpMain.x; // [HGM] placement: translate stored relative to absolute
\r
1762 *(int *) ad->argLoc = atoi(argValue) + wpMain.y; // (this is really kludgey, it should be done where used...)
\r
1766 *(int *) ad->argLoc = atoi(argValue);
\r
1767 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
1771 *(float *) ad->argLoc = (float) atof(argValue);
\r
1776 *(char **) ad->argLoc = strdup(argValue);
\r
1779 case ArgSettingsFilename:
\r
1781 char fullname[MSG_SIZ];
\r
1782 if (ParseSettingsFile(argValue, fullname)) {
\r
1783 if (ad->argLoc != NULL) {
\r
1784 *(char **) ad->argLoc = strdup(fullname);
\r
1787 if (ad->argLoc != NULL) {
\r
1789 ExitArgError("Failed to open indirection file", argValue);
\r
1796 switch (argValue[0]) {
\r
1799 *(Boolean *) ad->argLoc = TRUE;
\r
1803 *(Boolean *) ad->argLoc = FALSE;
\r
1806 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1812 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1815 case ArgAttribs: {
\r
1816 ColorClass cc = (ColorClass)ad->argLoc;
\r
1817 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1821 case ArgBoardSize:
\r
1822 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1826 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1829 case ArgCommSettings:
\r
1830 ParseCommSettings(argValue, &dcb);
\r
1834 ExitArgError("Unrecognized argument", argValue);
\r
1843 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1845 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1846 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1849 lf->lfEscapement = 0;
\r
1850 lf->lfOrientation = 0;
\r
1851 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1852 lf->lfItalic = mfp->italic;
\r
1853 lf->lfUnderline = mfp->underline;
\r
1854 lf->lfStrikeOut = mfp->strikeout;
\r
1855 lf->lfCharSet = mfp->charset;
\r
1856 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1857 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1858 lf->lfQuality = DEFAULT_QUALITY;
\r
1859 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1860 strcpy(lf->lfFaceName, mfp->faceName);
\r
1864 CreateFontInMF(MyFont *mf)
\r
1866 LFfromMFP(&mf->lf, &mf->mfp);
\r
1867 if (mf->hf) DeleteObject(mf->hf);
\r
1868 mf->hf = CreateFontIndirect(&mf->lf);
\r
1872 SetDefaultTextAttribs()
\r
1875 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1876 ParseAttribs(&textAttribs[cc].color,
\r
1877 &textAttribs[cc].effects,
\r
1878 defaultTextAttribs[cc]);
\r
1883 SetDefaultSounds()
\r
1887 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1888 textAttribs[cc].sound.name = strdup("");
\r
1889 textAttribs[cc].sound.data = NULL;
\r
1891 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1892 sounds[sc].name = strdup("");
\r
1893 sounds[sc].data = NULL;
\r
1895 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1903 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1904 MyLoadSound(&textAttribs[cc].sound);
\r
1906 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1907 MyLoadSound(&sounds[sc]);
\r
1912 InitAppData(LPSTR lpCmdLine)
\r
1915 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1918 programName = szAppName;
\r
1920 /* Initialize to defaults */
\r
1921 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1922 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1923 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1924 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1925 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1926 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1927 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1928 SetDefaultTextAttribs();
\r
1929 SetDefaultSounds();
\r
1930 appData.movesPerSession = MOVES_PER_SESSION;
\r
1931 appData.initString = INIT_STRING;
\r
1932 appData.secondInitString = INIT_STRING;
\r
1933 appData.firstComputerString = COMPUTER_STRING;
\r
1934 appData.secondComputerString = COMPUTER_STRING;
\r
1935 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1936 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1937 appData.firstPlaysBlack = FALSE;
\r
1938 appData.noChessProgram = FALSE;
\r
1939 chessProgram = FALSE;
\r
1940 appData.firstHost = FIRST_HOST;
\r
1941 appData.secondHost = SECOND_HOST;
\r
1942 appData.firstDirectory = FIRST_DIRECTORY;
\r
1943 appData.secondDirectory = SECOND_DIRECTORY;
\r
1944 appData.bitmapDirectory = "";
\r
1945 appData.remoteShell = REMOTE_SHELL;
\r
1946 appData.remoteUser = "";
\r
1947 appData.timeDelay = TIME_DELAY;
\r
1948 appData.timeControl = TIME_CONTROL;
\r
1949 appData.timeIncrement = TIME_INCREMENT;
\r
1950 appData.icsActive = FALSE;
\r
1951 appData.icsHost = "";
\r
1952 appData.icsPort = ICS_PORT;
\r
1953 appData.icsCommPort = ICS_COMM_PORT;
\r
1954 appData.icsLogon = ICS_LOGON;
\r
1955 appData.icsHelper = "";
\r
1956 appData.useTelnet = FALSE;
\r
1957 appData.telnetProgram = TELNET_PROGRAM;
\r
1958 appData.gateway = "";
\r
1959 appData.loadGameFile = "";
\r
1960 appData.loadGameIndex = 0;
\r
1961 appData.saveGameFile = "";
\r
1962 appData.autoSaveGames = FALSE;
\r
1963 appData.loadPositionFile = "";
\r
1964 appData.loadPositionIndex = 1;
\r
1965 appData.savePositionFile = "";
\r
1966 appData.matchMode = FALSE;
\r
1967 appData.matchGames = 0;
\r
1968 appData.monoMode = FALSE;
\r
1969 appData.debugMode = FALSE;
\r
1970 appData.clockMode = TRUE;
\r
1971 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1972 appData.Iconic = FALSE; /*unused*/
\r
1973 appData.searchTime = "";
\r
1974 appData.searchDepth = 0;
\r
1975 appData.showCoords = FALSE;
\r
1976 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1977 appData.autoCallFlag = FALSE;
\r
1978 appData.flipView = FALSE;
\r
1979 appData.autoFlipView = TRUE;
\r
1980 appData.cmailGameName = "";
\r
1981 appData.alwaysPromoteToQueen = FALSE;
\r
1982 appData.oldSaveStyle = FALSE;
\r
1983 appData.quietPlay = FALSE;
\r
1984 appData.showThinking = FALSE;
\r
1985 appData.ponderNextMove = TRUE;
\r
1986 appData.periodicUpdates = TRUE;
\r
1987 appData.popupExitMessage = TRUE;
\r
1988 appData.popupMoveErrors = FALSE;
\r
1989 appData.autoObserve = FALSE;
\r
1990 appData.autoComment = FALSE;
\r
1991 appData.animate = TRUE;
\r
1992 appData.animSpeed = 10;
\r
1993 appData.animateDragging = TRUE;
\r
1994 appData.highlightLastMove = TRUE;
\r
1995 appData.getMoveList = TRUE;
\r
1996 appData.testLegality = TRUE;
\r
1997 appData.premove = TRUE;
\r
1998 appData.premoveWhite = FALSE;
\r
1999 appData.premoveWhiteText = "";
\r
2000 appData.premoveBlack = FALSE;
\r
2001 appData.premoveBlackText = "";
\r
2002 appData.icsAlarm = TRUE;
\r
2003 appData.icsAlarmTime = 5000;
\r
2004 appData.autoRaiseBoard = TRUE;
\r
2005 appData.localLineEditing = TRUE;
\r
2006 appData.colorize = TRUE;
\r
2007 appData.reuseFirst = TRUE;
\r
2008 appData.reuseSecond = TRUE;
\r
2009 appData.blindfold = FALSE;
\r
2010 appData.icsEngineAnalyze = FALSE;
\r
2011 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2012 dcb.DCBlength = sizeof(DCB);
\r
2013 dcb.BaudRate = 9600;
\r
2014 dcb.fBinary = TRUE;
\r
2015 dcb.fParity = FALSE;
\r
2016 dcb.fOutxCtsFlow = FALSE;
\r
2017 dcb.fOutxDsrFlow = FALSE;
\r
2018 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2019 dcb.fDsrSensitivity = FALSE;
\r
2020 dcb.fTXContinueOnXoff = TRUE;
\r
2021 dcb.fOutX = FALSE;
\r
2023 dcb.fNull = FALSE;
\r
2024 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2025 dcb.fAbortOnError = FALSE;
\r
2027 dcb.Parity = SPACEPARITY;
\r
2028 dcb.StopBits = ONESTOPBIT;
\r
2029 settingsFileName = SETTINGS_FILE;
\r
2030 saveSettingsOnExit = TRUE;
\r
2031 wpMain.x = CW_USEDEFAULT;
\r
2032 wpMain.y = CW_USEDEFAULT;
\r
2033 wpComment.x = CW_USEDEFAULT;
\r
2034 wpComment.y = CW_USEDEFAULT;
\r
2035 wpComment.width = CW_USEDEFAULT;
\r
2036 wpComment.height = CW_USEDEFAULT;
\r
2037 wpTags.x = CW_USEDEFAULT;
\r
2038 wpTags.y = CW_USEDEFAULT;
\r
2039 wpTags.width = CW_USEDEFAULT;
\r
2040 wpTags.height = CW_USEDEFAULT;
\r
2041 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2042 icsNames = ICS_NAMES;
\r
2043 firstChessProgramNames = FCP_NAMES;
\r
2044 secondChessProgramNames = SCP_NAMES;
\r
2045 appData.initialMode = "";
\r
2046 appData.variant = "normal";
\r
2047 appData.firstProtocolVersion = PROTOVER;
\r
2048 appData.secondProtocolVersion = PROTOVER;
\r
2049 appData.showButtonBar = TRUE;
\r
2051 /* [AS] New properties (see comments in header file) */
\r
2052 appData.firstScoreIsAbsolute = FALSE;
\r
2053 appData.secondScoreIsAbsolute = FALSE;
\r
2054 appData.saveExtendedInfoInPGN = FALSE;
\r
2055 appData.hideThinkingFromHuman = FALSE;
\r
2056 appData.liteBackTextureFile = "";
\r
2057 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2058 appData.darkBackTextureFile = "";
\r
2059 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2060 appData.renderPiecesWithFont = "";
\r
2061 appData.fontToPieceTable = "";
\r
2062 appData.fontBackColorWhite = 0;
\r
2063 appData.fontForeColorWhite = 0;
\r
2064 appData.fontBackColorBlack = 0;
\r
2065 appData.fontForeColorBlack = 0;
\r
2066 appData.fontPieceSize = 80;
\r
2067 appData.overrideLineGap = 1;
\r
2068 appData.adjudicateLossThreshold = 0;
\r
2069 appData.delayBeforeQuit = 0;
\r
2070 appData.delayAfterQuit = 0;
\r
2071 appData.nameOfDebugFile = "winboard.debug";
\r
2072 appData.pgnEventHeader = "Computer Chess Game";
\r
2073 appData.defaultFrcPosition = -1;
\r
2074 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2075 appData.saveOutOfBookInfo = TRUE;
\r
2076 appData.showEvalInMoveHistory = TRUE;
\r
2077 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2078 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2079 appData.highlightMoveWithArrow = FALSE;
\r
2080 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2081 appData.useStickyWindows = TRUE;
\r
2082 appData.adjudicateDrawMoves = 0;
\r
2083 appData.autoDisplayComment = TRUE;
\r
2084 appData.autoDisplayTags = TRUE;
\r
2085 appData.firstIsUCI = FALSE;
\r
2086 appData.secondIsUCI = FALSE;
\r
2087 appData.firstHasOwnBookUCI = TRUE;
\r
2088 appData.secondHasOwnBookUCI = TRUE;
\r
2089 appData.polyglotDir = "";
\r
2090 appData.usePolyglotBook = FALSE;
\r
2091 appData.polyglotBook = "";
\r
2092 appData.defaultHashSize = 64;
\r
2093 appData.defaultCacheSizeEGTB = 4;
\r
2094 appData.defaultPathEGTB = "c:\\egtb";
\r
2095 appData.firstOptions = "";
\r
2096 appData.secondOptions = "";
\r
2098 InitWindowPlacement( &wpGameList );
\r
2099 InitWindowPlacement( &wpMoveHistory );
\r
2100 InitWindowPlacement( &wpEvalGraph );
\r
2101 InitWindowPlacement( &wpEngineOutput );
\r
2102 InitWindowPlacement( &wpConsole );
\r
2104 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2105 appData.NrFiles = -1;
\r
2106 appData.NrRanks = -1;
\r
2107 appData.holdingsSize = -1;
\r
2108 appData.testClaims = FALSE;
\r
2109 appData.checkMates = FALSE;
\r
2110 appData.materialDraws= FALSE;
\r
2111 appData.trivialDraws = FALSE;
\r
2112 appData.ruleMoves = 51;
\r
2113 appData.drawRepeats = 6;
\r
2114 appData.matchPause = 10000;
\r
2115 appData.alphaRank = FALSE;
\r
2116 appData.allWhite = FALSE;
\r
2117 appData.upsideDown = FALSE;
\r
2118 appData.serverPause = 15;
\r
2119 appData.serverMovesName = NULL;
\r
2120 appData.suppressLoadMoves = FALSE;
\r
2121 appData.firstTimeOdds = 1;
\r
2122 appData.secondTimeOdds = 1;
\r
2123 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2124 appData.secondAccumulateTC = 1;
\r
2125 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2126 appData.secondNPS = -1;
\r
2127 appData.engineComments = 1;
\r
2128 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2129 appData.egtFormats = "";
\r
2132 appData.zippyTalk = ZIPPY_TALK;
\r
2133 appData.zippyPlay = ZIPPY_PLAY;
\r
2134 appData.zippyLines = ZIPPY_LINES;
\r
2135 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2136 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2137 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2138 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2139 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2140 appData.zippyUseI = ZIPPY_USE_I;
\r
2141 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2142 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2143 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2144 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2145 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2146 appData.zippyAbort = ZIPPY_ABORT;
\r
2147 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2148 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2149 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2152 /* Point font array elements to structures and
\r
2153 parse default font names */
\r
2154 for (i=0; i<NUM_FONTS; i++) {
\r
2155 for (j=0; j<NUM_SIZES; j++) {
\r
2156 font[j][i] = &fontRec[j][i];
\r
2157 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2161 /* Parse default settings file if any */
\r
2162 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2163 settingsFileName = strdup(buf);
\r
2166 /* Parse command line */
\r
2167 ParseArgs(StringGet, &lpCmdLine);
\r
2169 /* [HGM] make sure board size is acceptable */
\r
2170 if(appData.NrFiles > BOARD_SIZE ||
\r
2171 appData.NrRanks > BOARD_SIZE )
\r
2172 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2174 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2175 * with options from the command line, we now make an even higher priority
\r
2176 * overrule by WB options attached to the engine command line. This so that
\r
2177 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2180 if(appData.firstChessProgram != NULL) {
\r
2181 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2182 static char *f = "first";
\r
2183 char buf[MSG_SIZ], *q = buf;
\r
2184 if(p != NULL) { // engine command line contains WinBoard options
\r
2185 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2186 ParseArgs(StringGet, &q);
\r
2187 p[-1] = 0; // cut them offengine command line
\r
2190 // now do same for second chess program
\r
2191 if(appData.secondChessProgram != NULL) {
\r
2192 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2193 static char *s = "second";
\r
2194 char buf[MSG_SIZ], *q = buf;
\r
2195 if(p != NULL) { // engine command line contains WinBoard options
\r
2196 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2197 ParseArgs(StringGet, &q);
\r
2198 p[-1] = 0; // cut them offengine command line
\r
2203 /* Propagate options that affect others */
\r
2204 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2205 if (appData.icsActive || appData.noChessProgram) {
\r
2206 chessProgram = FALSE; /* not local chess program mode */
\r
2209 /* Open startup dialog if needed */
\r
2210 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2211 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2212 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2213 *appData.secondChessProgram == NULLCHAR))) {
\r
2216 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2217 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2218 FreeProcInstance(lpProc);
\r
2221 /* Make sure save files land in the right (?) directory */
\r
2222 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2223 appData.saveGameFile = strdup(buf);
\r
2225 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2226 appData.savePositionFile = strdup(buf);
\r
2229 /* Finish initialization for fonts and sounds */
\r
2230 for (i=0; i<NUM_FONTS; i++) {
\r
2231 for (j=0; j<NUM_SIZES; j++) {
\r
2232 CreateFontInMF(font[j][i]);
\r
2235 /* xboard, and older WinBoards, controlled the move sound with the
\r
2236 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2237 always turn the option on (so that the backend will call us),
\r
2238 then let the user turn the sound off by setting it to silence if
\r
2239 desired. To accommodate old winboard.ini files saved by old
\r
2240 versions of WinBoard, we also turn off the sound if the option
\r
2241 was initially set to false. */
\r
2242 if (!appData.ringBellAfterMoves) {
\r
2243 sounds[(int)SoundMove].name = strdup("");
\r
2244 appData.ringBellAfterMoves = TRUE;
\r
2246 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2247 SetCurrentDirectory(installDir);
\r
2249 SetCurrentDirectory(currDir);
\r
2251 p = icsTextMenuString;
\r
2252 if (p[0] == '@') {
\r
2253 FILE* f = fopen(p + 1, "r");
\r
2255 DisplayFatalError(p + 1, errno, 2);
\r
2258 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2260 buf[i] = NULLCHAR;
\r
2263 ParseIcsTextMenu(strdup(p));
\r
2270 HMENU hmenu = GetMenu(hwndMain);
\r
2272 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2273 MF_BYCOMMAND|((appData.icsActive &&
\r
2274 *appData.icsCommPort != NULLCHAR) ?
\r
2275 MF_ENABLED : MF_GRAYED));
\r
2276 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2277 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2278 MF_CHECKED : MF_UNCHECKED));
\r
2281 // [HGM] args: these two cases taken out to stay in front-end
\r
2282 void SaveFontArg(FILE *f, ArgDescriptor *ad)
\r
2285 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2286 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2287 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2288 fprintf(f, "/%s=\"%s:%g%s%s%s%s%sc%d\"\n",
\r
2289 ad->argName, mfp->faceName, mfp->pointSize,
\r
2290 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2291 mfp->bold ? "b" : "",
\r
2292 mfp->italic ? "i" : "",
\r
2293 mfp->underline ? "u" : "",
\r
2294 mfp->strikeout ? "s" : "",
\r
2295 (int)mfp->charset);
\r
2299 void SaveAttribsArg(FILE *f, ArgDescriptor *ad)
\r
2301 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2302 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2303 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2304 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2305 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2306 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2307 (ta->effects) ? " " : "",
\r
2308 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2311 int MainWindowUp()
\r
2312 { // [HGM] args: allows testing if main window is realized from back-end
\r
2313 return hwndMain != NULL;
\r
2317 SaveSettings(char* name)
\r
2320 ArgDescriptor *ad;
\r
2321 char dir[MSG_SIZ];
\r
2323 if (!MainWindowUp()) return;
\r
2325 GetCurrentDirectory(MSG_SIZ, dir);
\r
2326 SetCurrentDirectory(installDir);
\r
2327 f = fopen(name, "w");
\r
2328 SetCurrentDirectory(dir);
\r
2330 DisplayError(name, errno);
\r
2333 fprintf(f, ";\n");
\r
2334 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2335 fprintf(f, ";\n");
\r
2336 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2337 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2338 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2339 fprintf(f, ";\n");
\r
2341 GetActualPlacement(hwndMain, &wpMain);
\r
2342 GetActualPlacement(hwndConsole, &wpConsole);
\r
2343 GetActualPlacement(commentDialog, &wpComment);
\r
2344 GetActualPlacement(editTagsDialog, &wpTags);
\r
2345 GetActualPlacement(gameListDialog, &wpGameList);
\r
2347 /* [AS] Move history */
\r
2348 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2349 GetActualPlacement(moveHistoryDialog, &wpMoveHistory);
\r
2351 /* [AS] Eval graph */
\r
2352 wpEvalGraph.visible = EvalGraphIsUp();
\r
2353 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
\r
2355 /* [AS] Engine output */
\r
2356 wpEngineOutput.visible = EngineOutputIsUp();
\r
2357 GetActualPlacement(engineOutputDialog, &wpEngineOutput);
\r
2359 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2360 if (!ad->save) continue;
\r
2361 switch (ad->argType) {
\r
2364 char *p = *(char **)ad->argLoc;
\r
2365 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2366 /* Quote multiline values or \-containing values
\r
2367 with { } if possible */
\r
2368 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2370 /* Else quote with " " */
\r
2371 fprintf(f, "/%s=\"", ad->argName);
\r
2373 if (*p == '\n') fprintf(f, "\n");
\r
2374 else if (*p == '\r') fprintf(f, "\\r");
\r
2375 else if (*p == '\t') fprintf(f, "\\t");
\r
2376 else if (*p == '\b') fprintf(f, "\\b");
\r
2377 else if (*p == '\f') fprintf(f, "\\f");
\r
2378 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2379 else if (*p == '\"') fprintf(f, "\\\"");
\r
2380 else if (*p == '\\') fprintf(f, "\\\\");
\r
2384 fprintf(f, "\"\n");
\r
2390 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2393 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - wpMain.x); // [HGM] placement: stor relative value
\r
2396 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - wpMain.y);
\r
2399 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2402 fprintf(f, "/%s=%s\n", ad->argName,
\r
2403 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2406 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2409 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2413 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2414 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2415 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2419 SaveAttribsArg(f, ad);
\r
2422 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2423 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2425 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2428 case ArgBoardSize:
\r
2429 fprintf(f, "/%s=%s\n", ad->argName,
\r
2430 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2433 SaveFontArg(f, ad);
\r
2435 case ArgCommSettings:
\r
2436 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2438 case ArgSettingsFilename: ;
\r
2446 /*---------------------------------------------------------------------------*\
\r
2448 * GDI board drawing routines
\r
2450 \*---------------------------------------------------------------------------*/
\r
2452 /* [AS] Draw square using background texture */
\r
2453 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2458 return; /* Should never happen! */
\r
2461 SetGraphicsMode( dst, GM_ADVANCED );
\r
2468 /* X reflection */
\r
2473 x.eDx = (FLOAT) dw + dx - 1;
\r
2476 SetWorldTransform( dst, &x );
\r
2479 /* Y reflection */
\r
2485 x.eDy = (FLOAT) dh + dy - 1;
\r
2487 SetWorldTransform( dst, &x );
\r
2495 x.eDx = (FLOAT) dx;
\r
2496 x.eDy = (FLOAT) dy;
\r
2499 SetWorldTransform( dst, &x );
\r
2503 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2511 SetWorldTransform( dst, &x );
\r
2513 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2516 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2518 PM_WP = (int) WhitePawn,
\r
2519 PM_WN = (int) WhiteKnight,
\r
2520 PM_WB = (int) WhiteBishop,
\r
2521 PM_WR = (int) WhiteRook,
\r
2522 PM_WQ = (int) WhiteQueen,
\r
2523 PM_WF = (int) WhiteFerz,
\r
2524 PM_WW = (int) WhiteWazir,
\r
2525 PM_WE = (int) WhiteAlfil,
\r
2526 PM_WM = (int) WhiteMan,
\r
2527 PM_WO = (int) WhiteCannon,
\r
2528 PM_WU = (int) WhiteUnicorn,
\r
2529 PM_WH = (int) WhiteNightrider,
\r
2530 PM_WA = (int) WhiteAngel,
\r
2531 PM_WC = (int) WhiteMarshall,
\r
2532 PM_WAB = (int) WhiteCardinal,
\r
2533 PM_WD = (int) WhiteDragon,
\r
2534 PM_WL = (int) WhiteLance,
\r
2535 PM_WS = (int) WhiteCobra,
\r
2536 PM_WV = (int) WhiteFalcon,
\r
2537 PM_WSG = (int) WhiteSilver,
\r
2538 PM_WG = (int) WhiteGrasshopper,
\r
2539 PM_WK = (int) WhiteKing,
\r
2540 PM_BP = (int) BlackPawn,
\r
2541 PM_BN = (int) BlackKnight,
\r
2542 PM_BB = (int) BlackBishop,
\r
2543 PM_BR = (int) BlackRook,
\r
2544 PM_BQ = (int) BlackQueen,
\r
2545 PM_BF = (int) BlackFerz,
\r
2546 PM_BW = (int) BlackWazir,
\r
2547 PM_BE = (int) BlackAlfil,
\r
2548 PM_BM = (int) BlackMan,
\r
2549 PM_BO = (int) BlackCannon,
\r
2550 PM_BU = (int) BlackUnicorn,
\r
2551 PM_BH = (int) BlackNightrider,
\r
2552 PM_BA = (int) BlackAngel,
\r
2553 PM_BC = (int) BlackMarshall,
\r
2554 PM_BG = (int) BlackGrasshopper,
\r
2555 PM_BAB = (int) BlackCardinal,
\r
2556 PM_BD = (int) BlackDragon,
\r
2557 PM_BL = (int) BlackLance,
\r
2558 PM_BS = (int) BlackCobra,
\r
2559 PM_BV = (int) BlackFalcon,
\r
2560 PM_BSG = (int) BlackSilver,
\r
2561 PM_BK = (int) BlackKing
\r
2564 static HFONT hPieceFont = NULL;
\r
2565 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2566 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2567 static int fontBitmapSquareSize = 0;
\r
2568 static char pieceToFontChar[(int) EmptySquare] =
\r
2569 { 'p', 'n', 'b', 'r', 'q',
\r
2570 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2571 'k', 'o', 'm', 'v', 't', 'w',
\r
2572 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2575 extern BOOL SetCharTable( char *table, const char * map );
\r
2576 /* [HGM] moved to backend.c */
\r
2578 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2581 BYTE r1 = GetRValue( color );
\r
2582 BYTE g1 = GetGValue( color );
\r
2583 BYTE b1 = GetBValue( color );
\r
2589 /* Create a uniform background first */
\r
2590 hbrush = CreateSolidBrush( color );
\r
2591 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2592 FillRect( hdc, &rc, hbrush );
\r
2593 DeleteObject( hbrush );
\r
2596 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2597 int steps = squareSize / 2;
\r
2600 for( i=0; i<steps; i++ ) {
\r
2601 BYTE r = r1 - (r1-r2) * i / steps;
\r
2602 BYTE g = g1 - (g1-g2) * i / steps;
\r
2603 BYTE b = b1 - (b1-b2) * i / steps;
\r
2605 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2606 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2607 FillRect( hdc, &rc, hbrush );
\r
2608 DeleteObject(hbrush);
\r
2611 else if( mode == 2 ) {
\r
2612 /* Diagonal gradient, good more or less for every piece */
\r
2613 POINT triangle[3];
\r
2614 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2615 HBRUSH hbrush_old;
\r
2616 int steps = squareSize;
\r
2619 triangle[0].x = squareSize - steps;
\r
2620 triangle[0].y = squareSize;
\r
2621 triangle[1].x = squareSize;
\r
2622 triangle[1].y = squareSize;
\r
2623 triangle[2].x = squareSize;
\r
2624 triangle[2].y = squareSize - steps;
\r
2626 for( i=0; i<steps; i++ ) {
\r
2627 BYTE r = r1 - (r1-r2) * i / steps;
\r
2628 BYTE g = g1 - (g1-g2) * i / steps;
\r
2629 BYTE b = b1 - (b1-b2) * i / steps;
\r
2631 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2632 hbrush_old = SelectObject( hdc, hbrush );
\r
2633 Polygon( hdc, triangle, 3 );
\r
2634 SelectObject( hdc, hbrush_old );
\r
2635 DeleteObject(hbrush);
\r
2640 SelectObject( hdc, hpen );
\r
2645 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2646 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2647 piece: follow the steps as explained below.
\r
2649 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2653 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2657 int backColor = whitePieceColor;
\r
2658 int foreColor = blackPieceColor;
\r
2660 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2661 backColor = appData.fontBackColorWhite;
\r
2662 foreColor = appData.fontForeColorWhite;
\r
2664 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2665 backColor = appData.fontBackColorBlack;
\r
2666 foreColor = appData.fontForeColorBlack;
\r
2670 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2672 hbm_old = SelectObject( hdc, hbm );
\r
2676 rc.right = squareSize;
\r
2677 rc.bottom = squareSize;
\r
2679 /* Step 1: background is now black */
\r
2680 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2682 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2684 pt.x = (squareSize - sz.cx) / 2;
\r
2685 pt.y = (squareSize - sz.cy) / 2;
\r
2687 SetBkMode( hdc, TRANSPARENT );
\r
2688 SetTextColor( hdc, chroma );
\r
2689 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2690 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2692 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2693 /* Step 3: the area outside the piece is filled with white */
\r
2694 // FloodFill( hdc, 0, 0, chroma );
\r
2695 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2696 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2697 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2698 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2699 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2701 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2702 but if the start point is not inside the piece we're lost!
\r
2703 There should be a better way to do this... if we could create a region or path
\r
2704 from the fill operation we would be fine for example.
\r
2706 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2707 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2709 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2710 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2711 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2713 SelectObject( dc2, bm2 );
\r
2714 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2715 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2716 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2717 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2718 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2721 DeleteObject( bm2 );
\r
2724 SetTextColor( hdc, 0 );
\r
2726 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2727 draw the piece again in black for safety.
\r
2729 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2731 SelectObject( hdc, hbm_old );
\r
2733 if( hPieceMask[index] != NULL ) {
\r
2734 DeleteObject( hPieceMask[index] );
\r
2737 hPieceMask[index] = hbm;
\r
2740 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2742 SelectObject( hdc, hbm );
\r
2745 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2746 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2747 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2749 SelectObject( dc1, hPieceMask[index] );
\r
2750 SelectObject( dc2, bm2 );
\r
2751 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2752 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2755 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2756 the piece background and deletes (makes transparent) the rest.
\r
2757 Thanks to that mask, we are free to paint the background with the greates
\r
2758 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2759 We use this, to make gradients and give the pieces a "roundish" look.
\r
2761 SetPieceBackground( hdc, backColor, 2 );
\r
2762 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2766 DeleteObject( bm2 );
\r
2769 SetTextColor( hdc, foreColor );
\r
2770 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2772 SelectObject( hdc, hbm_old );
\r
2774 if( hPieceFace[index] != NULL ) {
\r
2775 DeleteObject( hPieceFace[index] );
\r
2778 hPieceFace[index] = hbm;
\r
2781 static int TranslatePieceToFontPiece( int piece )
\r
2811 case BlackMarshall:
\r
2815 case BlackNightrider:
\r
2821 case BlackUnicorn:
\r
2825 case BlackGrasshopper:
\r
2837 case BlackCardinal:
\r
2844 case WhiteMarshall:
\r
2848 case WhiteNightrider:
\r
2854 case WhiteUnicorn:
\r
2858 case WhiteGrasshopper:
\r
2870 case WhiteCardinal:
\r
2879 void CreatePiecesFromFont()
\r
2882 HDC hdc_window = NULL;
\r
2888 if( fontBitmapSquareSize < 0 ) {
\r
2889 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2893 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2894 fontBitmapSquareSize = -1;
\r
2898 if( fontBitmapSquareSize != squareSize ) {
\r
2899 hdc_window = GetDC( hwndMain );
\r
2900 hdc = CreateCompatibleDC( hdc_window );
\r
2902 if( hPieceFont != NULL ) {
\r
2903 DeleteObject( hPieceFont );
\r
2906 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2907 hPieceMask[i] = NULL;
\r
2908 hPieceFace[i] = NULL;
\r
2914 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2915 fontHeight = appData.fontPieceSize;
\r
2918 fontHeight = (fontHeight * squareSize) / 100;
\r
2920 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2922 lf.lfEscapement = 0;
\r
2923 lf.lfOrientation = 0;
\r
2924 lf.lfWeight = FW_NORMAL;
\r
2926 lf.lfUnderline = 0;
\r
2927 lf.lfStrikeOut = 0;
\r
2928 lf.lfCharSet = DEFAULT_CHARSET;
\r
2929 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2930 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2931 lf.lfQuality = PROOF_QUALITY;
\r
2932 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2933 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2934 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2936 hPieceFont = CreateFontIndirect( &lf );
\r
2938 if( hPieceFont == NULL ) {
\r
2939 fontBitmapSquareSize = -2;
\r
2942 /* Setup font-to-piece character table */
\r
2943 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2944 /* No (or wrong) global settings, try to detect the font */
\r
2945 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2947 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2949 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2950 /* DiagramTT* family */
\r
2951 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2953 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2954 /* Fairy symbols */
\r
2955 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2957 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2958 /* Good Companion (Some characters get warped as literal :-( */
\r
2959 char s[] = "1cmWG0??S??oYI23wgQU";
\r
2960 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2961 SetCharTable(pieceToFontChar, s);
\r
2964 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2965 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2969 /* Create bitmaps */
\r
2970 hfont_old = SelectObject( hdc, hPieceFont );
\r
2971 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2972 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2973 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2975 SelectObject( hdc, hfont_old );
\r
2977 fontBitmapSquareSize = squareSize;
\r
2981 if( hdc != NULL ) {
\r
2985 if( hdc_window != NULL ) {
\r
2986 ReleaseDC( hwndMain, hdc_window );
\r
2991 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2995 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2996 if (gameInfo.event &&
\r
2997 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2998 strcmp(name, "k80s") == 0) {
\r
2999 strcpy(name, "tim");
\r
3001 return LoadBitmap(hinst, name);
\r
3005 /* Insert a color into the program's logical palette
\r
3006 structure. This code assumes the given color is
\r
3007 the result of the RGB or PALETTERGB macro, and it
\r
3008 knows how those macros work (which is documented).
\r
3011 InsertInPalette(COLORREF color)
\r
3013 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3015 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3016 DisplayFatalError("Too many colors", 0, 1);
\r
3017 pLogPal->palNumEntries--;
\r
3021 pe->peFlags = (char) 0;
\r
3022 pe->peRed = (char) (0xFF & color);
\r
3023 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3024 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3030 InitDrawingColors()
\r
3032 if (pLogPal == NULL) {
\r
3033 /* Allocate enough memory for a logical palette with
\r
3034 * PALETTESIZE entries and set the size and version fields
\r
3035 * of the logical palette structure.
\r
3037 pLogPal = (NPLOGPALETTE)
\r
3038 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3039 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3040 pLogPal->palVersion = 0x300;
\r
3042 pLogPal->palNumEntries = 0;
\r
3044 InsertInPalette(lightSquareColor);
\r
3045 InsertInPalette(darkSquareColor);
\r
3046 InsertInPalette(whitePieceColor);
\r
3047 InsertInPalette(blackPieceColor);
\r
3048 InsertInPalette(highlightSquareColor);
\r
3049 InsertInPalette(premoveHighlightColor);
\r
3051 /* create a logical color palette according the information
\r
3052 * in the LOGPALETTE structure.
\r
3054 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3056 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3057 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3058 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3059 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3060 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3061 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3062 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3063 /* [AS] Force rendering of the font-based pieces */
\r
3064 if( fontBitmapSquareSize > 0 ) {
\r
3065 fontBitmapSquareSize = 0;
\r
3071 BoardWidth(int boardSize, int n)
\r
3072 { /* [HGM] argument n added to allow different width and height */
\r
3073 int lineGap = sizeInfo[boardSize].lineGap;
\r
3075 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3076 lineGap = appData.overrideLineGap;
\r
3079 return (n + 1) * lineGap +
\r
3080 n * sizeInfo[boardSize].squareSize;
\r
3083 /* Respond to board resize by dragging edge */
\r
3085 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3087 BoardSize newSize = NUM_SIZES - 1;
\r
3088 static int recurse = 0;
\r
3089 if (IsIconic(hwndMain)) return;
\r
3090 if (recurse > 0) return;
\r
3092 while (newSize > 0) {
\r
3093 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3094 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3095 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3098 boardSize = newSize;
\r
3099 InitDrawingSizes(boardSize, flags);
\r
3106 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3108 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3109 ChessSquare piece;
\r
3110 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3112 SIZE clockSize, messageSize;
\r
3114 char buf[MSG_SIZ];
\r
3116 HMENU hmenu = GetMenu(hwndMain);
\r
3117 RECT crect, wrect, oldRect;
\r
3119 LOGBRUSH logbrush;
\r
3121 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3122 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3124 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3125 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3127 oldRect.left = wpMain.x; //[HGM] placement: remember previous window params
\r
3128 oldRect.top = wpMain.y;
\r
3129 oldRect.right = wpMain.x + wpMain.width;
\r
3130 oldRect.bottom = wpMain.y + wpMain.height;
\r
3132 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3133 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3134 squareSize = sizeInfo[boardSize].squareSize;
\r
3135 lineGap = sizeInfo[boardSize].lineGap;
\r
3136 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3138 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3139 lineGap = appData.overrideLineGap;
\r
3142 if (tinyLayout != oldTinyLayout) {
\r
3143 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3145 style &= ~WS_SYSMENU;
\r
3146 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3147 "&Minimize\tCtrl+F4");
\r
3149 style |= WS_SYSMENU;
\r
3150 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3152 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3154 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3155 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3156 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3158 DrawMenuBar(hwndMain);
\r
3161 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3162 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3164 /* Get text area sizes */
\r
3165 hdc = GetDC(hwndMain);
\r
3166 if (appData.clockMode) {
\r
3167 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3169 sprintf(buf, "White");
\r
3171 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3172 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3173 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3174 str = "We only care about the height here";
\r
3175 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3176 SelectObject(hdc, oldFont);
\r
3177 ReleaseDC(hwndMain, hdc);
\r
3179 /* Compute where everything goes */
\r
3180 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3181 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3182 logoHeight = 2*clockSize.cy;
\r
3183 leftLogoRect.left = OUTER_MARGIN;
\r
3184 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3185 leftLogoRect.top = OUTER_MARGIN;
\r
3186 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3188 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3189 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3190 rightLogoRect.top = OUTER_MARGIN;
\r
3191 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3194 whiteRect.left = leftLogoRect.right;
\r
3195 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3196 whiteRect.top = OUTER_MARGIN;
\r
3197 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3199 blackRect.right = rightLogoRect.left;
\r
3200 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3201 blackRect.top = whiteRect.top;
\r
3202 blackRect.bottom = whiteRect.bottom;
\r
3204 whiteRect.left = OUTER_MARGIN;
\r
3205 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3206 whiteRect.top = OUTER_MARGIN;
\r
3207 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3209 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3210 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3211 blackRect.top = whiteRect.top;
\r
3212 blackRect.bottom = whiteRect.bottom;
\r
3215 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3216 if (appData.showButtonBar) {
\r
3217 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3218 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3220 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3222 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3223 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3225 boardRect.left = OUTER_MARGIN;
\r
3226 boardRect.right = boardRect.left + boardWidth;
\r
3227 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3228 boardRect.bottom = boardRect.top + boardHeight;
\r
3230 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3231 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3232 oldBoardSize = boardSize;
\r
3233 oldTinyLayout = tinyLayout;
\r
3234 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3235 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3236 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3237 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3238 wpMain.width = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3239 wpMain.height = winH; // without disturbing window attachments
\r
3240 GetWindowRect(hwndMain, &wrect);
\r
3241 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
3242 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3244 // [HGM] placement: let attached windows follow size change.
\r
3245 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, moveHistoryDialog, &wpMoveHistory );
\r
3246 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, evalGraphDialog, &wpEvalGraph );
\r
3247 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, engineOutputDialog, &wpEngineOutput );
\r
3248 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, gameListDialog, &wpGameList );
\r
3249 ReattachAfterSize( &oldRect, wpMain.width, wpMain.height, hwndConsole, &wpConsole );
\r
3251 /* compensate if menu bar wrapped */
\r
3252 GetClientRect(hwndMain, &crect);
\r
3253 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3254 wpMain.height += offby;
\r
3256 case WMSZ_TOPLEFT:
\r
3257 SetWindowPos(hwndMain, NULL,
\r
3258 wrect.right - wpMain.width, wrect.bottom - wpMain.height,
\r
3259 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3262 case WMSZ_TOPRIGHT:
\r
3264 SetWindowPos(hwndMain, NULL,
\r
3265 wrect.left, wrect.bottom - wpMain.height,
\r
3266 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3269 case WMSZ_BOTTOMLEFT:
\r
3271 SetWindowPos(hwndMain, NULL,
\r
3272 wrect.right - wpMain.width, wrect.top,
\r
3273 wpMain.width, wpMain.height, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3276 case WMSZ_BOTTOMRIGHT:
\r
3280 SetWindowPos(hwndMain, NULL, 0, 0, wpMain.width, wpMain.height,
\r
3281 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3286 for (i = 0; i < N_BUTTONS; i++) {
\r
3287 if (buttonDesc[i].hwnd != NULL) {
\r
3288 DestroyWindow(buttonDesc[i].hwnd);
\r
3289 buttonDesc[i].hwnd = NULL;
\r
3291 if (appData.showButtonBar) {
\r
3292 buttonDesc[i].hwnd =
\r
3293 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3294 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3295 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3296 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3297 (HMENU) buttonDesc[i].id,
\r
3298 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3300 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3301 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3302 MAKELPARAM(FALSE, 0));
\r
3304 if (buttonDesc[i].id == IDM_Pause)
\r
3305 hwndPause = buttonDesc[i].hwnd;
\r
3306 buttonDesc[i].wndproc = (WNDPROC)
\r
3307 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3310 if (gridPen != NULL) DeleteObject(gridPen);
\r
3311 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3312 if (premovePen != NULL) DeleteObject(premovePen);
\r
3313 if (lineGap != 0) {
\r
3314 logbrush.lbStyle = BS_SOLID;
\r
3315 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3317 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3318 lineGap, &logbrush, 0, NULL);
\r
3319 logbrush.lbColor = highlightSquareColor;
\r
3321 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3322 lineGap, &logbrush, 0, NULL);
\r
3324 logbrush.lbColor = premoveHighlightColor;
\r
3326 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3327 lineGap, &logbrush, 0, NULL);
\r
3329 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3330 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3331 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3332 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3333 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3334 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3335 BOARD_WIDTH * (squareSize + lineGap);
\r
3336 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3338 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3339 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3340 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3341 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3342 lineGap / 2 + (i * (squareSize + lineGap));
\r
3343 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3344 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3345 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3349 /* [HGM] Licensing requirement */
\r
3351 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3354 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3356 GothicPopUp( "", VariantNormal);
\r
3359 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3361 /* Load piece bitmaps for this board size */
\r
3362 for (i=0; i<=2; i++) {
\r
3363 for (piece = WhitePawn;
\r
3364 (int) piece < (int) BlackPawn;
\r
3365 piece = (ChessSquare) ((int) piece + 1)) {
\r
3366 if (pieceBitmap[i][piece] != NULL)
\r
3367 DeleteObject(pieceBitmap[i][piece]);
\r
3371 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3372 // Orthodox Chess pieces
\r
3373 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3374 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3375 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3376 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3377 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3378 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3379 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3380 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3381 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3382 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3383 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3384 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3385 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3386 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3387 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3388 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3389 // in Shogi, Hijack the unused Queen for Lance
\r
3390 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3391 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3392 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3394 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3395 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3396 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3399 if(squareSize <= 72 && squareSize >= 33) {
\r
3400 /* A & C are available in most sizes now */
\r
3401 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3402 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3403 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3404 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3405 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3406 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3407 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3408 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3409 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3410 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3411 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3412 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3413 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3414 } else { // Smirf-like
\r
3415 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3416 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3417 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3419 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3420 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3421 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3422 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3423 } else { // WinBoard standard
\r
3424 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3425 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3426 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3431 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3432 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3433 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3434 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3435 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3436 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3437 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3438 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3439 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3440 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3441 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3442 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3443 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3444 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3445 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3446 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3447 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3448 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3449 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3450 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3451 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3452 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3453 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3454 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3455 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3456 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3457 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3458 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3459 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3460 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3461 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3463 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3464 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3465 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3466 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3467 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3468 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3469 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3470 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3471 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3472 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3473 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3474 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3475 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3477 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3478 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3479 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3480 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3481 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3482 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3483 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3484 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3485 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3486 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3487 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3488 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3491 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3492 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3493 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3494 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3495 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3496 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3497 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3498 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3499 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3500 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3501 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3502 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3503 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3504 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3505 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3509 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3510 /* special Shogi support in this size */
\r
3511 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3512 for (piece = WhitePawn;
\r
3513 (int) piece < (int) BlackPawn;
\r
3514 piece = (ChessSquare) ((int) piece + 1)) {
\r
3515 if (pieceBitmap[i][piece] != NULL)
\r
3516 DeleteObject(pieceBitmap[i][piece]);
\r
3519 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3520 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3521 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3522 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3523 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3524 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3525 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3526 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3527 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3528 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3529 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3530 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3531 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3532 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3533 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3534 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3535 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3536 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3537 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3538 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3539 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3540 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3541 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3542 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3543 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3544 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3545 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3546 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3547 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3548 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3549 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3550 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3551 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3552 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3553 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3554 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3555 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3556 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3557 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3558 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3559 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3560 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3566 PieceBitmap(ChessSquare p, int kind)
\r
3568 if ((int) p >= (int) BlackPawn)
\r
3569 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3571 return pieceBitmap[kind][(int) p];
\r
3574 /***************************************************************/
\r
3576 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3577 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3579 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3580 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3584 SquareToPos(int row, int column, int * x, int * y)
\r
3587 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3588 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3590 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3591 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3596 DrawCoordsOnDC(HDC hdc)
\r
3598 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
3599 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
3600 char str[2] = { NULLCHAR, NULLCHAR };
\r
3601 int oldMode, oldAlign, x, y, start, i;
\r
3605 if (!appData.showCoords)
\r
3608 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3610 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3611 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3612 oldAlign = GetTextAlign(hdc);
\r
3613 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3615 y = boardRect.top + lineGap;
\r
3616 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3618 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3619 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3620 str[0] = files[start + i];
\r
3621 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3622 y += squareSize + lineGap;
\r
3625 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3627 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3628 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3629 str[0] = ranks[start + i];
\r
3630 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3631 x += squareSize + lineGap;
\r
3634 SelectObject(hdc, oldBrush);
\r
3635 SetBkMode(hdc, oldMode);
\r
3636 SetTextAlign(hdc, oldAlign);
\r
3637 SelectObject(hdc, oldFont);
\r
3641 DrawGridOnDC(HDC hdc)
\r
3645 if (lineGap != 0) {
\r
3646 oldPen = SelectObject(hdc, gridPen);
\r
3647 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3648 SelectObject(hdc, oldPen);
\r
3652 #define HIGHLIGHT_PEN 0
\r
3653 #define PREMOVE_PEN 1
\r
3656 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3659 HPEN oldPen, hPen;
\r
3660 if (lineGap == 0) return;
\r
3662 x1 = boardRect.left +
\r
3663 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3664 y1 = boardRect.top +
\r
3665 lineGap/2 + y * (squareSize + lineGap);
\r
3667 x1 = boardRect.left +
\r
3668 lineGap/2 + x * (squareSize + lineGap);
\r
3669 y1 = boardRect.top +
\r
3670 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3672 hPen = pen ? premovePen : highlightPen;
\r
3673 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3674 MoveToEx(hdc, x1, y1, NULL);
\r
3675 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3676 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3677 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3678 LineTo(hdc, x1, y1);
\r
3679 SelectObject(hdc, oldPen);
\r
3683 DrawHighlightsOnDC(HDC hdc)
\r
3686 for (i=0; i<2; i++) {
\r
3687 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3688 DrawHighlightOnDC(hdc, TRUE,
\r
3689 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3692 for (i=0; i<2; i++) {
\r
3693 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3694 premoveHighlightInfo.sq[i].y >= 0) {
\r
3695 DrawHighlightOnDC(hdc, TRUE,
\r
3696 premoveHighlightInfo.sq[i].x,
\r
3697 premoveHighlightInfo.sq[i].y,
\r
3703 /* Note: sqcolor is used only in monoMode */
\r
3704 /* Note that this code is largely duplicated in woptions.c,
\r
3705 function DrawSampleSquare, so that needs to be updated too */
\r
3707 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3709 HBITMAP oldBitmap;
\r
3713 if (appData.blindfold) return;
\r
3715 /* [AS] Use font-based pieces if needed */
\r
3716 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3717 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3718 CreatePiecesFromFont();
\r
3720 if( fontBitmapSquareSize == squareSize ) {
\r
3721 int index = TranslatePieceToFontPiece(piece);
\r
3723 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3727 squareSize, squareSize,
\r
3732 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3736 squareSize, squareSize,
\r
3745 if (appData.monoMode) {
\r
3746 SelectObject(tmphdc, PieceBitmap(piece,
\r
3747 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3748 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3749 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3751 tmpSize = squareSize;
\r
3753 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3754 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3755 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3756 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3757 x += (squareSize - minorSize)>>1;
\r
3758 y += squareSize - minorSize - 2;
\r
3759 tmpSize = minorSize;
\r
3761 if (color || appData.allWhite ) {
\r
3762 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3764 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3765 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3766 if(appData.upsideDown && color==flipView)
\r
3767 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3769 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3770 /* Use black for outline of white pieces */
\r
3771 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3772 if(appData.upsideDown && color==flipView)
\r
3773 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3775 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3777 /* Use square color for details of black pieces */
\r
3778 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3779 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3780 if(appData.upsideDown && !flipView)
\r
3781 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3783 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3785 SelectObject(hdc, oldBrush);
\r
3786 SelectObject(tmphdc, oldBitmap);
\r
3790 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3791 int GetBackTextureMode( int algo )
\r
3793 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3797 case BACK_TEXTURE_MODE_PLAIN:
\r
3798 result = 1; /* Always use identity map */
\r
3800 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3801 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3809 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3810 to handle redraws cleanly (as random numbers would always be different).
\r
3812 VOID RebuildTextureSquareInfo()
\r
3822 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3824 if( liteBackTexture != NULL ) {
\r
3825 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3826 lite_w = bi.bmWidth;
\r
3827 lite_h = bi.bmHeight;
\r
3831 if( darkBackTexture != NULL ) {
\r
3832 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3833 dark_w = bi.bmWidth;
\r
3834 dark_h = bi.bmHeight;
\r
3838 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3839 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3840 if( (col + row) & 1 ) {
\r
3842 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3843 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3844 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3845 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3850 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3851 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3852 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3853 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3860 /* [AS] Arrow highlighting support */
\r
3862 static int A_WIDTH = 5; /* Width of arrow body */
\r
3864 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3865 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3867 static double Sqr( double x )
\r
3872 static int Round( double x )
\r
3874 return (int) (x + 0.5);
\r
3877 /* Draw an arrow between two points using current settings */
\r
3878 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3881 double dx, dy, j, k, x, y;
\r
3883 if( d_x == s_x ) {
\r
3884 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3886 arrow[0].x = s_x + A_WIDTH;
\r
3889 arrow[1].x = s_x + A_WIDTH;
\r
3890 arrow[1].y = d_y - h;
\r
3892 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3893 arrow[2].y = d_y - h;
\r
3898 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3899 arrow[4].y = d_y - h;
\r
3901 arrow[5].x = s_x - A_WIDTH;
\r
3902 arrow[5].y = d_y - h;
\r
3904 arrow[6].x = s_x - A_WIDTH;
\r
3907 else if( d_y == s_y ) {
\r
3908 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3911 arrow[0].y = s_y + A_WIDTH;
\r
3913 arrow[1].x = d_x - w;
\r
3914 arrow[1].y = s_y + A_WIDTH;
\r
3916 arrow[2].x = d_x - w;
\r
3917 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3922 arrow[4].x = d_x - w;
\r
3923 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3925 arrow[5].x = d_x - w;
\r
3926 arrow[5].y = s_y - A_WIDTH;
\r
3929 arrow[6].y = s_y - A_WIDTH;
\r
3932 /* [AS] Needed a lot of paper for this! :-) */
\r
3933 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3934 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3936 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3938 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3943 arrow[0].x = Round(x - j);
\r
3944 arrow[0].y = Round(y + j*dx);
\r
3946 arrow[1].x = Round(x + j);
\r
3947 arrow[1].y = Round(y - j*dx);
\r
3950 x = (double) d_x - k;
\r
3951 y = (double) d_y - k*dy;
\r
3954 x = (double) d_x + k;
\r
3955 y = (double) d_y + k*dy;
\r
3958 arrow[2].x = Round(x + j);
\r
3959 arrow[2].y = Round(y - j*dx);
\r
3961 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3962 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3967 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3968 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3970 arrow[6].x = Round(x - j);
\r
3971 arrow[6].y = Round(y + j*dx);
\r
3974 Polygon( hdc, arrow, 7 );
\r
3977 /* [AS] Draw an arrow between two squares */
\r
3978 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3980 int s_x, s_y, d_x, d_y;
\r
3987 if( s_col == d_col && s_row == d_row ) {
\r
3991 /* Get source and destination points */
\r
3992 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3993 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3996 d_y += squareSize / 4;
\r
3998 else if( d_y < s_y ) {
\r
3999 d_y += 3 * squareSize / 4;
\r
4002 d_y += squareSize / 2;
\r
4006 d_x += squareSize / 4;
\r
4008 else if( d_x < s_x ) {
\r
4009 d_x += 3 * squareSize / 4;
\r
4012 d_x += squareSize / 2;
\r
4015 s_x += squareSize / 2;
\r
4016 s_y += squareSize / 2;
\r
4018 /* Adjust width */
\r
4019 A_WIDTH = squareSize / 14;
\r
4022 stLB.lbStyle = BS_SOLID;
\r
4023 stLB.lbColor = appData.highlightArrowColor;
\r
4026 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4027 holdpen = SelectObject( hdc, hpen );
\r
4028 hbrush = CreateBrushIndirect( &stLB );
\r
4029 holdbrush = SelectObject( hdc, hbrush );
\r
4031 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4033 SelectObject( hdc, holdpen );
\r
4034 SelectObject( hdc, holdbrush );
\r
4035 DeleteObject( hpen );
\r
4036 DeleteObject( hbrush );
\r
4039 BOOL HasHighlightInfo()
\r
4041 BOOL result = FALSE;
\r
4043 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4044 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4052 BOOL IsDrawArrowEnabled()
\r
4054 BOOL result = FALSE;
\r
4056 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4063 VOID DrawArrowHighlight( HDC hdc )
\r
4065 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4066 DrawArrowBetweenSquares( hdc,
\r
4067 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4068 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4072 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4074 HRGN result = NULL;
\r
4076 if( HasHighlightInfo() ) {
\r
4077 int x1, y1, x2, y2;
\r
4078 int sx, sy, dx, dy;
\r
4080 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4081 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4083 sx = MIN( x1, x2 );
\r
4084 sy = MIN( y1, y2 );
\r
4085 dx = MAX( x1, x2 ) + squareSize;
\r
4086 dy = MAX( y1, y2 ) + squareSize;
\r
4088 result = CreateRectRgn( sx, sy, dx, dy );
\r
4095 Warning: this function modifies the behavior of several other functions.
\r
4097 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4098 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4099 repaint is scattered all over the place, which is not good for features such as
\r
4100 "arrow highlighting" that require a full repaint of the board.
\r
4102 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4103 user interaction, when speed is not so important) but especially to avoid errors
\r
4104 in the displayed graphics.
\r
4106 In such patched places, I always try refer to this function so there is a single
\r
4107 place to maintain knowledge.
\r
4109 To restore the original behavior, just return FALSE unconditionally.
\r
4111 BOOL IsFullRepaintPreferrable()
\r
4113 BOOL result = FALSE;
\r
4115 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4116 /* Arrow may appear on the board */
\r
4124 This function is called by DrawPosition to know whether a full repaint must
\r
4127 Only DrawPosition may directly call this function, which makes use of
\r
4128 some state information. Other function should call DrawPosition specifying
\r
4129 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4131 BOOL DrawPositionNeedsFullRepaint()
\r
4133 BOOL result = FALSE;
\r
4136 Probably a slightly better policy would be to trigger a full repaint
\r
4137 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4138 but animation is fast enough that it's difficult to notice.
\r
4140 if( animInfo.piece == EmptySquare ) {
\r
4141 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() /*&& HasHighlightInfo()*/ ) {
\r
4150 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4152 int row, column, x, y, square_color, piece_color;
\r
4153 ChessSquare piece;
\r
4155 HDC texture_hdc = NULL;
\r
4157 /* [AS] Initialize background textures if needed */
\r
4158 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4159 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4160 if( backTextureSquareSize != squareSize
\r
4161 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4162 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4163 backTextureSquareSize = squareSize;
\r
4164 RebuildTextureSquareInfo();
\r
4167 texture_hdc = CreateCompatibleDC( hdc );
\r
4170 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4171 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4173 SquareToPos(row, column, &x, &y);
\r
4175 piece = board[row][column];
\r
4177 square_color = ((column + row) % 2) == 1;
\r
4178 if( gameInfo.variant == VariantXiangqi ) {
\r
4179 square_color = !InPalace(row, column);
\r
4180 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4181 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4183 piece_color = (int) piece < (int) BlackPawn;
\r
4186 /* [HGM] holdings file: light square or black */
\r
4187 if(column == BOARD_LEFT-2) {
\r
4188 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4191 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4195 if(column == BOARD_RGHT + 1 ) {
\r
4196 if( row < gameInfo.holdingsSize )
\r
4199 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4203 if(column == BOARD_LEFT-1 ) /* left align */
\r
4204 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4205 else if( column == BOARD_RGHT) /* right align */
\r
4206 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4208 if (appData.monoMode) {
\r
4209 if (piece == EmptySquare) {
\r
4210 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4211 square_color ? WHITENESS : BLACKNESS);
\r
4213 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4216 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4217 /* [AS] Draw the square using a texture bitmap */
\r
4218 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4219 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4220 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4223 squareSize, squareSize,
\r
4226 backTextureSquareInfo[r][c].mode,
\r
4227 backTextureSquareInfo[r][c].x,
\r
4228 backTextureSquareInfo[r][c].y );
\r
4230 SelectObject( texture_hdc, hbm );
\r
4232 if (piece != EmptySquare) {
\r
4233 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4237 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4239 oldBrush = SelectObject(hdc, brush );
\r
4240 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4241 SelectObject(hdc, oldBrush);
\r
4242 if (piece != EmptySquare)
\r
4243 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4248 if( texture_hdc != NULL ) {
\r
4249 DeleteDC( texture_hdc );
\r
4253 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4254 void fputDW(FILE *f, int x)
\r
4256 fputc(x & 255, f);
\r
4257 fputc(x>>8 & 255, f);
\r
4258 fputc(x>>16 & 255, f);
\r
4259 fputc(x>>24 & 255, f);
\r
4262 #define MAX_CLIPS 200 /* more than enough */
\r
4265 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4267 // HBITMAP bufferBitmap;
\r
4272 int w = 100, h = 50;
\r
4274 if(logo == NULL) return;
\r
4275 // GetClientRect(hwndMain, &Rect);
\r
4276 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4277 // Rect.bottom-Rect.top+1);
\r
4278 tmphdc = CreateCompatibleDC(hdc);
\r
4279 hbm = SelectObject(tmphdc, logo);
\r
4280 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4284 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4285 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4286 SelectObject(tmphdc, hbm);
\r
4291 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4293 static Board lastReq, lastDrawn;
\r
4294 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4295 static int lastDrawnFlipView = 0;
\r
4296 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4297 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4300 HBITMAP bufferBitmap;
\r
4301 HBITMAP oldBitmap;
\r
4303 HRGN clips[MAX_CLIPS];
\r
4304 ChessSquare dragged_piece = EmptySquare;
\r
4306 /* I'm undecided on this - this function figures out whether a full
\r
4307 * repaint is necessary on its own, so there's no real reason to have the
\r
4308 * caller tell it that. I think this can safely be set to FALSE - but
\r
4309 * if we trust the callers not to request full repaints unnessesarily, then
\r
4310 * we could skip some clipping work. In other words, only request a full
\r
4311 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4312 * gamestart and similar) --Hawk
\r
4314 Boolean fullrepaint = repaint;
\r
4316 if( DrawPositionNeedsFullRepaint() ) {
\r
4317 fullrepaint = TRUE;
\r
4320 if (board == NULL) {
\r
4321 if (!lastReqValid) {
\r
4326 CopyBoard(lastReq, board);
\r
4330 if (doingSizing) {
\r
4334 if (IsIconic(hwndMain)) {
\r
4338 if (hdc == NULL) {
\r
4339 hdc = GetDC(hwndMain);
\r
4340 if (!appData.monoMode) {
\r
4341 SelectPalette(hdc, hPal, FALSE);
\r
4342 RealizePalette(hdc);
\r
4346 releaseDC = FALSE;
\r
4349 /* Create some work-DCs */
\r
4350 hdcmem = CreateCompatibleDC(hdc);
\r
4351 tmphdc = CreateCompatibleDC(hdc);
\r
4353 /* If dragging is in progress, we temporarely remove the piece */
\r
4354 /* [HGM] or temporarily decrease count if stacked */
\r
4355 /* !! Moved to before board compare !! */
\r
4356 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4357 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4358 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4359 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4360 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4362 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4363 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4364 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4366 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4369 /* Figure out which squares need updating by comparing the
\r
4370 * newest board with the last drawn board and checking if
\r
4371 * flipping has changed.
\r
4373 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4374 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4375 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4376 if (lastDrawn[row][column] != board[row][column]) {
\r
4377 SquareToPos(row, column, &x, &y);
\r
4378 clips[num_clips++] =
\r
4379 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4383 for (i=0; i<2; i++) {
\r
4384 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4385 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4386 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4387 lastDrawnHighlight.sq[i].y >= 0) {
\r
4388 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4389 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4390 clips[num_clips++] =
\r
4391 CreateRectRgn(x - lineGap, y - lineGap,
\r
4392 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4394 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4395 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4396 clips[num_clips++] =
\r
4397 CreateRectRgn(x - lineGap, y - lineGap,
\r
4398 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4402 for (i=0; i<2; i++) {
\r
4403 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4404 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4405 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4406 lastDrawnPremove.sq[i].y >= 0) {
\r
4407 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4408 lastDrawnPremove.sq[i].x, &x, &y);
\r
4409 clips[num_clips++] =
\r
4410 CreateRectRgn(x - lineGap, y - lineGap,
\r
4411 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4413 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4414 premoveHighlightInfo.sq[i].y >= 0) {
\r
4415 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4416 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4417 clips[num_clips++] =
\r
4418 CreateRectRgn(x - lineGap, y - lineGap,
\r
4419 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4424 fullrepaint = TRUE;
\r
4427 /* Create a buffer bitmap - this is the actual bitmap
\r
4428 * being written to. When all the work is done, we can
\r
4429 * copy it to the real DC (the screen). This avoids
\r
4430 * the problems with flickering.
\r
4432 GetClientRect(hwndMain, &Rect);
\r
4433 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4434 Rect.bottom-Rect.top+1);
\r
4435 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4436 if (!appData.monoMode) {
\r
4437 SelectPalette(hdcmem, hPal, FALSE);
\r
4440 /* Create clips for dragging */
\r
4441 if (!fullrepaint) {
\r
4442 if (dragInfo.from.x >= 0) {
\r
4443 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4444 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4446 if (dragInfo.start.x >= 0) {
\r
4447 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4448 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4450 if (dragInfo.pos.x >= 0) {
\r
4451 x = dragInfo.pos.x - squareSize / 2;
\r
4452 y = dragInfo.pos.y - squareSize / 2;
\r
4453 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4455 if (dragInfo.lastpos.x >= 0) {
\r
4456 x = dragInfo.lastpos.x - squareSize / 2;
\r
4457 y = dragInfo.lastpos.y - squareSize / 2;
\r
4458 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4462 /* Are we animating a move?
\r
4464 * - remove the piece from the board (temporarely)
\r
4465 * - calculate the clipping region
\r
4467 if (!fullrepaint) {
\r
4468 if (animInfo.piece != EmptySquare) {
\r
4469 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4470 x = boardRect.left + animInfo.lastpos.x;
\r
4471 y = boardRect.top + animInfo.lastpos.y;
\r
4472 x2 = boardRect.left + animInfo.pos.x;
\r
4473 y2 = boardRect.top + animInfo.pos.y;
\r
4474 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4475 /* Slight kludge. The real problem is that after AnimateMove is
\r
4476 done, the position on the screen does not match lastDrawn.
\r
4477 This currently causes trouble only on e.p. captures in
\r
4478 atomic, where the piece moves to an empty square and then
\r
4479 explodes. The old and new positions both had an empty square
\r
4480 at the destination, but animation has drawn a piece there and
\r
4481 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4482 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4486 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4487 if (num_clips == 0)
\r
4488 fullrepaint = TRUE;
\r
4490 /* Set clipping on the memory DC */
\r
4491 if (!fullrepaint) {
\r
4492 SelectClipRgn(hdcmem, clips[0]);
\r
4493 for (x = 1; x < num_clips; x++) {
\r
4494 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4495 abort(); // this should never ever happen!
\r
4499 /* Do all the drawing to the memory DC */
\r
4500 if(explodeInfo.radius) { // [HGM] atomic
\r
4502 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4503 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4504 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4505 x += squareSize/2;
\r
4506 y += squareSize/2;
\r
4507 if(!fullrepaint) {
\r
4508 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4509 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4511 DrawGridOnDC(hdcmem);
\r
4512 DrawHighlightsOnDC(hdcmem);
\r
4513 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4514 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4515 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4516 SelectObject(hdcmem, oldBrush);
\r
4518 DrawGridOnDC(hdcmem);
\r
4519 DrawHighlightsOnDC(hdcmem);
\r
4520 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4523 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4524 if(appData.autoLogo) {
\r
4526 switch(gameMode) { // pick logos based on game mode
\r
4527 case IcsObserving:
\r
4528 whiteLogo = second.programLogo; // ICS logo
\r
4529 blackLogo = second.programLogo;
\r
4532 case IcsPlayingWhite:
\r
4533 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4534 blackLogo = second.programLogo; // ICS logo
\r
4536 case IcsPlayingBlack:
\r
4537 whiteLogo = second.programLogo; // ICS logo
\r
4538 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4540 case TwoMachinesPlay:
\r
4541 if(first.twoMachinesColor[0] == 'b') {
\r
4542 whiteLogo = second.programLogo;
\r
4543 blackLogo = first.programLogo;
\r
4546 case MachinePlaysWhite:
\r
4547 blackLogo = userLogo;
\r
4549 case MachinePlaysBlack:
\r
4550 whiteLogo = userLogo;
\r
4551 blackLogo = first.programLogo;
\r
4554 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4555 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4558 if( appData.highlightMoveWithArrow ) {
\r
4559 DrawArrowHighlight(hdcmem);
\r
4562 DrawCoordsOnDC(hdcmem);
\r
4564 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4565 /* to make sure lastDrawn contains what is actually drawn */
\r
4567 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4568 if (dragged_piece != EmptySquare) {
\r
4569 /* [HGM] or restack */
\r
4570 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4571 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4573 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4574 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4575 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4576 x = dragInfo.pos.x - squareSize / 2;
\r
4577 y = dragInfo.pos.y - squareSize / 2;
\r
4578 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4579 ((int) dragged_piece < (int) BlackPawn),
\r
4580 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4583 /* Put the animated piece back into place and draw it */
\r
4584 if (animInfo.piece != EmptySquare) {
\r
4585 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4586 x = boardRect.left + animInfo.pos.x;
\r
4587 y = boardRect.top + animInfo.pos.y;
\r
4588 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4589 ((int) animInfo.piece < (int) BlackPawn),
\r
4590 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4593 /* Release the bufferBitmap by selecting in the old bitmap
\r
4594 * and delete the memory DC
\r
4596 SelectObject(hdcmem, oldBitmap);
\r
4599 /* Set clipping on the target DC */
\r
4600 if (!fullrepaint) {
\r
4601 SelectClipRgn(hdc, clips[0]);
\r
4602 for (x = 1; x < num_clips; x++) {
\r
4603 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4604 abort(); // this should never ever happen!
\r
4608 /* Copy the new bitmap onto the screen in one go.
\r
4609 * This way we avoid any flickering
\r
4611 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4612 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4613 boardRect.right - boardRect.left,
\r
4614 boardRect.bottom - boardRect.top,
\r
4615 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4616 if(saveDiagFlag) {
\r
4617 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4618 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4620 GetObject(bufferBitmap, sizeof(b), &b);
\r
4621 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4622 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4623 bih.biWidth = b.bmWidth;
\r
4624 bih.biHeight = b.bmHeight;
\r
4626 bih.biBitCount = b.bmBitsPixel;
\r
4627 bih.biCompression = 0;
\r
4628 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4629 bih.biXPelsPerMeter = 0;
\r
4630 bih.biYPelsPerMeter = 0;
\r
4631 bih.biClrUsed = 0;
\r
4632 bih.biClrImportant = 0;
\r
4633 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4634 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4635 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4636 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4638 wb = b.bmWidthBytes;
\r
4640 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4641 int k = ((int*) pData)[i];
\r
4642 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4643 if(j >= 16) break;
\r
4645 if(j >= nrColors) nrColors = j+1;
\r
4647 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4649 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4650 for(w=0; w<(wb>>2); w+=2) {
\r
4651 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4652 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4653 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4654 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4655 pData[p++] = m | j<<4;
\r
4657 while(p&3) pData[p++] = 0;
\r
4660 wb = ((wb+31)>>5)<<2;
\r
4662 // write BITMAPFILEHEADER
\r
4663 fprintf(diagFile, "BM");
\r
4664 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4665 fputDW(diagFile, 0);
\r
4666 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4667 // write BITMAPINFOHEADER
\r
4668 fputDW(diagFile, 40);
\r
4669 fputDW(diagFile, b.bmWidth);
\r
4670 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4671 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4672 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4673 fputDW(diagFile, 0);
\r
4674 fputDW(diagFile, 0);
\r
4675 fputDW(diagFile, 0);
\r
4676 fputDW(diagFile, 0);
\r
4677 fputDW(diagFile, 0);
\r
4678 fputDW(diagFile, 0);
\r
4679 // write color table
\r
4681 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4682 // write bitmap data
\r
4683 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4684 fputc(pData[i], diagFile);
\r
4688 SelectObject(tmphdc, oldBitmap);
\r
4690 /* Massive cleanup */
\r
4691 for (x = 0; x < num_clips; x++)
\r
4692 DeleteObject(clips[x]);
\r
4695 DeleteObject(bufferBitmap);
\r
4698 ReleaseDC(hwndMain, hdc);
\r
4700 if (lastDrawnFlipView != flipView) {
\r
4702 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4704 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4707 /* CopyBoard(lastDrawn, board);*/
\r
4708 lastDrawnHighlight = highlightInfo;
\r
4709 lastDrawnPremove = premoveHighlightInfo;
\r
4710 lastDrawnFlipView = flipView;
\r
4711 lastDrawnValid = 1;
\r
4714 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4719 saveDiagFlag = 1; diagFile = f;
\r
4720 HDCDrawPosition(NULL, TRUE, NULL);
\r
4724 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4731 /*---------------------------------------------------------------------------*\
\r
4732 | CLIENT PAINT PROCEDURE
\r
4733 | This is the main event-handler for the WM_PAINT message.
\r
4735 \*---------------------------------------------------------------------------*/
\r
4737 PaintProc(HWND hwnd)
\r
4743 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4744 if (IsIconic(hwnd)) {
\r
4745 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4747 if (!appData.monoMode) {
\r
4748 SelectPalette(hdc, hPal, FALSE);
\r
4749 RealizePalette(hdc);
\r
4751 HDCDrawPosition(hdc, 1, NULL);
\r
4753 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4754 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4755 ETO_CLIPPED|ETO_OPAQUE,
\r
4756 &messageRect, messageText, strlen(messageText), NULL);
\r
4757 SelectObject(hdc, oldFont);
\r
4758 DisplayBothClocks();
\r
4760 EndPaint(hwnd,&ps);
\r
4768 * If the user selects on a border boundary, return -1; if off the board,
\r
4769 * return -2. Otherwise map the event coordinate to the square.
\r
4770 * The offset boardRect.left or boardRect.top must already have been
\r
4771 * subtracted from x.
\r
4773 int EventToSquare(x, limit)
\r
4781 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4783 x /= (squareSize + lineGap);
\r
4795 DropEnable dropEnables[] = {
\r
4796 { 'P', DP_Pawn, "Pawn" },
\r
4797 { 'N', DP_Knight, "Knight" },
\r
4798 { 'B', DP_Bishop, "Bishop" },
\r
4799 { 'R', DP_Rook, "Rook" },
\r
4800 { 'Q', DP_Queen, "Queen" },
\r
4804 SetupDropMenu(HMENU hmenu)
\r
4806 int i, count, enable;
\r
4808 extern char white_holding[], black_holding[];
\r
4809 char item[MSG_SIZ];
\r
4811 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4812 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4813 dropEnables[i].piece);
\r
4815 while (p && *p++ == dropEnables[i].piece) count++;
\r
4816 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4817 enable = count > 0 || !appData.testLegality
\r
4818 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4819 && !appData.icsActive);
\r
4820 ModifyMenu(hmenu, dropEnables[i].command,
\r
4821 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4822 dropEnables[i].command, item);
\r
4826 void DragPieceBegin(int x, int y)
\r
4828 dragInfo.lastpos.x = boardRect.left + x;
\r
4829 dragInfo.lastpos.y = boardRect.top + y;
\r
4830 dragInfo.from.x = fromX;
\r
4831 dragInfo.from.y = fromY;
\r
4832 dragInfo.start = dragInfo.from;
\r
4833 SetCapture(hwndMain);
\r
4836 void DragPieceEnd(int x, int y)
\r
4839 dragInfo.start.x = dragInfo.start.y = -1;
\r
4840 dragInfo.from = dragInfo.start;
\r
4841 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4844 /* Event handler for mouse messages */
\r
4846 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4850 static int recursive = 0;
\r
4852 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4855 if (message == WM_MBUTTONUP) {
\r
4856 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4857 to the middle button: we simulate pressing the left button too!
\r
4859 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4860 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4866 pt.x = LOWORD(lParam);
\r
4867 pt.y = HIWORD(lParam);
\r
4868 x = EventToSquare(pt.x - boardRect.left, BOARD_WIDTH);
\r
4869 y = EventToSquare(pt.y - boardRect.top, BOARD_HEIGHT);
\r
4870 if (!flipView && y >= 0) {
\r
4871 y = BOARD_HEIGHT - 1 - y;
\r
4873 if (flipView && x >= 0) {
\r
4874 x = BOARD_WIDTH - 1 - x;
\r
4877 switch (message) {
\r
4878 case WM_LBUTTONDOWN:
\r
4879 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4880 if (gameMode == EditPosition) {
\r
4881 SetWhiteToPlayEvent();
\r
4882 } else if (gameMode == IcsPlayingBlack ||
\r
4883 gameMode == MachinePlaysWhite) {
\r
4885 } else if (gameMode == EditGame) {
\r
4886 AdjustClock(flipClock, -1);
\r
4888 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4889 if (gameMode == EditPosition) {
\r
4890 SetBlackToPlayEvent();
\r
4891 } else if (gameMode == IcsPlayingWhite ||
\r
4892 gameMode == MachinePlaysBlack) {
\r
4894 } else if (gameMode == EditGame) {
\r
4895 AdjustClock(!flipClock, -1);
\r
4898 dragInfo.start.x = dragInfo.start.y = -1;
\r
4899 dragInfo.from = dragInfo.start;
\r
4900 if(fromX == -1 && frozen) { // not sure where this is for
\r
4901 fromX = fromY = -1;
\r
4902 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4905 LeftClick(Press, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4906 DrawPosition(TRUE, NULL);
\r
4909 case WM_LBUTTONUP:
\r
4910 LeftClick(Release, pt.x - boardRect.left, pt.y - boardRect.top);
\r
4911 DrawPosition(TRUE, NULL);
\r
4914 case WM_MOUSEMOVE:
\r
4915 if ((appData.animateDragging || appData.highlightDragging)
\r
4916 && (wParam & MK_LBUTTON)
\r
4917 && dragInfo.from.x >= 0)
\r
4919 BOOL full_repaint = FALSE;
\r
4921 if (appData.animateDragging) {
\r
4922 dragInfo.pos = pt;
\r
4924 if (appData.highlightDragging) {
\r
4925 SetHighlights(fromX, fromY, x, y);
\r
4926 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4927 full_repaint = TRUE;
\r
4931 DrawPosition( full_repaint, NULL);
\r
4933 dragInfo.lastpos = dragInfo.pos;
\r
4937 case WM_MOUSEWHEEL: // [DM]
\r
4938 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
4939 /* Mouse Wheel is being rolled forward
\r
4940 * Play moves forward
\r
4942 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
4943 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
4944 /* Mouse Wheel is being rolled backward
\r
4945 * Play moves backward
\r
4947 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
4948 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
4952 case WM_MBUTTONDOWN:
\r
4953 case WM_RBUTTONDOWN:
\r
4956 fromX = fromY = -1;
\r
4957 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4958 dragInfo.start.x = dragInfo.start.y = -1;
\r
4959 dragInfo.from = dragInfo.start;
\r
4960 dragInfo.lastpos = dragInfo.pos;
\r
4961 if (appData.highlightDragging) {
\r
4962 ClearHighlights();
\r
4965 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4966 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4967 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
4968 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4969 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
4972 DrawPosition(TRUE, NULL);
\r
4974 switch (gameMode) {
\r
4975 case EditPosition:
\r
4976 case IcsExamining:
\r
4977 if (x < 0 || y < 0) break;
\r
4980 if (message == WM_MBUTTONDOWN) {
\r
4981 buttonCount = 3; /* even if system didn't think so */
\r
4982 if (wParam & MK_SHIFT)
\r
4983 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4985 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4986 } else { /* message == WM_RBUTTONDOWN */
\r
4987 /* Just have one menu, on the right button. Windows users don't
\r
4988 think to try the middle one, and sometimes other software steals
\r
4989 it, or it doesn't really exist. */
\r
4990 if(gameInfo.variant != VariantShogi)
\r
4991 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4993 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4996 case IcsPlayingWhite:
\r
4997 case IcsPlayingBlack:
\r
4999 case MachinePlaysWhite:
\r
5000 case MachinePlaysBlack:
\r
5001 if (appData.testLegality &&
\r
5002 gameInfo.variant != VariantBughouse &&
\r
5003 gameInfo.variant != VariantCrazyhouse) break;
\r
5004 if (x < 0 || y < 0) break;
\r
5007 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5008 SetupDropMenu(hmenu);
\r
5009 MenuPopup(hwnd, pt, hmenu, -1);
\r
5020 /* Preprocess messages for buttons in main window */
\r
5022 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5024 int id = GetWindowLong(hwnd, GWL_ID);
\r
5027 for (i=0; i<N_BUTTONS; i++) {
\r
5028 if (buttonDesc[i].id == id) break;
\r
5030 if (i == N_BUTTONS) return 0;
\r
5031 switch (message) {
\r
5036 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5037 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5044 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5047 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5048 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5049 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5050 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5052 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5054 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5055 PopUpMoveDialog((char)wParam);
\r
5061 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5064 /* Process messages for Promotion dialog box */
\r
5066 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5070 switch (message) {
\r
5071 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5072 /* Center the dialog over the application window */
\r
5073 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5074 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5075 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5076 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5077 SW_SHOW : SW_HIDE);
\r
5078 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5079 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5080 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5081 PieceToChar(WhiteAngel) != '~') ||
\r
5082 (PieceToChar(BlackAngel) >= 'A' &&
\r
5083 PieceToChar(BlackAngel) != '~') ) ?
\r
5084 SW_SHOW : SW_HIDE);
\r
5085 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5086 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5087 PieceToChar(WhiteMarshall) != '~') ||
\r
5088 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5089 PieceToChar(BlackMarshall) != '~') ) ?
\r
5090 SW_SHOW : SW_HIDE);
\r
5091 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5092 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5093 gameInfo.variant != VariantShogi ?
\r
5094 SW_SHOW : SW_HIDE);
\r
5095 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5096 gameInfo.variant != VariantShogi ?
\r
5097 SW_SHOW : SW_HIDE);
\r
5098 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5099 gameInfo.variant == VariantShogi ?
\r
5100 SW_SHOW : SW_HIDE);
\r
5101 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5102 gameInfo.variant == VariantShogi ?
\r
5103 SW_SHOW : SW_HIDE);
\r
5104 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5105 gameInfo.variant == VariantSuper ?
\r
5106 SW_SHOW : SW_HIDE);
\r
5109 case WM_COMMAND: /* message: received a command */
\r
5110 switch (LOWORD(wParam)) {
\r
5112 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5113 ClearHighlights();
\r
5114 DrawPosition(FALSE, NULL);
\r
5117 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5120 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5123 promoChar = PieceToChar(BlackRook);
\r
5126 promoChar = PieceToChar(BlackBishop);
\r
5128 case PB_Chancellor:
\r
5129 promoChar = PieceToChar(BlackMarshall);
\r
5131 case PB_Archbishop:
\r
5132 promoChar = PieceToChar(BlackAngel);
\r
5135 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5140 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5141 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5142 only show the popup when we are already sure the move is valid or
\r
5143 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5144 will figure out it is a promotion from the promoChar. */
\r
5145 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
5146 fromX = fromY = -1;
\r
5147 if (!appData.highlightLastMove) {
\r
5148 ClearHighlights();
\r
5149 DrawPosition(FALSE, NULL);
\r
5156 /* Pop up promotion dialog */
\r
5158 PromotionPopup(HWND hwnd)
\r
5162 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5163 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5164 hwnd, (DLGPROC)lpProc);
\r
5165 FreeProcInstance(lpProc);
\r
5171 DrawPosition(TRUE, NULL);
\r
5172 PromotionPopup(hwndMain);
\r
5175 /* Toggle ShowThinking */
\r
5177 ToggleShowThinking()
\r
5179 appData.showThinking = !appData.showThinking;
\r
5180 ShowThinkingEvent();
\r
5184 LoadGameDialog(HWND hwnd, char* title)
\r
5188 char fileTitle[MSG_SIZ];
\r
5189 f = OpenFileDialog(hwnd, "rb", "",
\r
5190 appData.oldSaveStyle ? "gam" : "pgn",
\r
5192 title, &number, fileTitle, NULL);
\r
5194 cmailMsgLoaded = FALSE;
\r
5195 if (number == 0) {
\r
5196 int error = GameListBuild(f);
\r
5198 DisplayError("Cannot build game list", error);
\r
5199 } else if (!ListEmpty(&gameList) &&
\r
5200 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5201 GameListPopUp(f, fileTitle);
\r
5204 GameListDestroy();
\r
5207 LoadGame(f, number, fileTitle, FALSE);
\r
5211 int get_term_width()
\r
5216 HFONT hfont, hold_font;
\r
5221 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5225 // get the text metrics
\r
5226 hdc = GetDC(hText);
\r
5227 lf = font[boardSize][CONSOLE_FONT]->lf;
\r
5228 if (consoleCF.dwEffects & CFE_BOLD)
\r
5229 lf.lfWeight = FW_BOLD;
\r
5230 if (consoleCF.dwEffects & CFE_ITALIC)
\r
5231 lf.lfItalic = TRUE;
\r
5232 if (consoleCF.dwEffects & CFE_STRIKEOUT)
\r
5233 lf.lfStrikeOut = TRUE;
\r
5234 if (consoleCF.dwEffects & CFE_UNDERLINE)
\r
5235 lf.lfUnderline = TRUE;
\r
5236 hfont = CreateFontIndirect(&lf);
\r
5237 hold_font = SelectObject(hdc, hfont);
\r
5238 GetTextMetrics(hdc, &tm);
\r
5239 SelectObject(hdc, hold_font);
\r
5240 DeleteObject(hfont);
\r
5241 ReleaseDC(hText, hdc);
\r
5243 // get the rectangle
\r
5244 SendMessage(hText, EM_GETRECT, 0, (LPARAM)&rc);
\r
5246 return (rc.right-rc.left) / tm.tmAveCharWidth;
\r
5249 void UpdateICSWidth(HWND hText)
\r
5251 LONG old_width, new_width;
\r
5253 new_width = get_term_width(hText, FALSE);
\r
5254 old_width = GetWindowLong(hText, GWL_USERDATA);
\r
5255 if (new_width != old_width)
\r
5257 ics_update_width(new_width);
\r
5258 SetWindowLong(hText, GWL_USERDATA, new_width);
\r
5263 ChangedConsoleFont()
\r
5266 CHARRANGE tmpsel, sel;
\r
5267 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5268 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5269 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5272 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5273 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5274 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5275 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5276 * size. This was undocumented in the version of MSVC++ that I had
\r
5277 * when I wrote the code, but is apparently documented now.
\r
5279 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5280 cfmt.bCharSet = f->lf.lfCharSet;
\r
5281 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5282 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5283 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5284 /* Why are the following seemingly needed too? */
\r
5285 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5286 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5287 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5289 tmpsel.cpMax = -1; /*999999?*/
\r
5290 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5291 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5292 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5293 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5295 paraf.cbSize = sizeof(paraf);
\r
5296 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5297 paraf.dxStartIndent = 0;
\r
5298 paraf.dxOffset = WRAP_INDENT;
\r
5299 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5300 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5301 UpdateICSWidth(hText);
\r
5304 /*---------------------------------------------------------------------------*\
\r
5306 * Window Proc for main window
\r
5308 \*---------------------------------------------------------------------------*/
\r
5310 /* Process messages for main window, etc. */
\r
5312 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5315 int wmId, wmEvent;
\r
5319 char fileTitle[MSG_SIZ];
\r
5320 char buf[MSG_SIZ];
\r
5321 static SnapData sd;
\r
5323 switch (message) {
\r
5325 case WM_PAINT: /* message: repaint portion of window */
\r
5329 case WM_ERASEBKGND:
\r
5330 if (IsIconic(hwnd)) {
\r
5331 /* Cheat; change the message */
\r
5332 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5334 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5338 case WM_LBUTTONDOWN:
\r
5339 case WM_MBUTTONDOWN:
\r
5340 case WM_RBUTTONDOWN:
\r
5341 case WM_LBUTTONUP:
\r
5342 case WM_MBUTTONUP:
\r
5343 case WM_RBUTTONUP:
\r
5344 case WM_MOUSEMOVE:
\r
5345 case WM_MOUSEWHEEL:
\r
5346 MouseEvent(hwnd, message, wParam, lParam);
\r
5349 JAWS_KB_NAVIGATION
\r
5353 JAWS_ALT_INTERCEPT
\r
5355 if (appData.icsActive && ((char)wParam == '\r' || (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9'))) {
\r
5356 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5357 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5358 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5360 SendMessage(h, message, wParam, lParam);
\r
5361 } else if(lParam != KF_REPEAT) {
\r
5362 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5363 PopUpMoveDialog((char)wParam);
\r
5364 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5365 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5370 case WM_PALETTECHANGED:
\r
5371 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5373 HDC hdc = GetDC(hwndMain);
\r
5374 SelectPalette(hdc, hPal, TRUE);
\r
5375 nnew = RealizePalette(hdc);
\r
5377 paletteChanged = TRUE;
\r
5378 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5380 ReleaseDC(hwnd, hdc);
\r
5384 case WM_QUERYNEWPALETTE:
\r
5385 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5387 HDC hdc = GetDC(hwndMain);
\r
5388 paletteChanged = FALSE;
\r
5389 SelectPalette(hdc, hPal, FALSE);
\r
5390 nnew = RealizePalette(hdc);
\r
5392 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5394 ReleaseDC(hwnd, hdc);
\r
5399 case WM_COMMAND: /* message: command from application menu */
\r
5400 wmId = LOWORD(wParam);
\r
5401 wmEvent = HIWORD(wParam);
\r
5406 SAY("new game enter a move to play against the computer with white");
\r
5409 case IDM_NewGameFRC:
\r
5410 if( NewGameFRC() == 0 ) {
\r
5415 case IDM_NewVariant:
\r
5416 NewVariantPopup(hwnd);
\r
5419 case IDM_LoadGame:
\r
5420 LoadGameDialog(hwnd, "Load Game from File");
\r
5423 case IDM_LoadNextGame:
\r
5427 case IDM_LoadPrevGame:
\r
5431 case IDM_ReloadGame:
\r
5435 case IDM_LoadPosition:
\r
5436 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5437 Reset(FALSE, TRUE);
\r
5440 f = OpenFileDialog(hwnd, "rb", "",
\r
5441 appData.oldSaveStyle ? "pos" : "fen",
\r
5443 "Load Position from File", &number, fileTitle, NULL);
\r
5445 LoadPosition(f, number, fileTitle);
\r
5449 case IDM_LoadNextPosition:
\r
5450 ReloadPosition(1);
\r
5453 case IDM_LoadPrevPosition:
\r
5454 ReloadPosition(-1);
\r
5457 case IDM_ReloadPosition:
\r
5458 ReloadPosition(0);
\r
5461 case IDM_SaveGame:
\r
5462 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5463 f = OpenFileDialog(hwnd, "a", defName,
\r
5464 appData.oldSaveStyle ? "gam" : "pgn",
\r
5466 "Save Game to File", NULL, fileTitle, NULL);
\r
5468 SaveGame(f, 0, "");
\r
5472 case IDM_SavePosition:
\r
5473 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5474 f = OpenFileDialog(hwnd, "a", defName,
\r
5475 appData.oldSaveStyle ? "pos" : "fen",
\r
5477 "Save Position to File", NULL, fileTitle, NULL);
\r
5479 SavePosition(f, 0, "");
\r
5483 case IDM_SaveDiagram:
\r
5484 defName = "diagram";
\r
5485 f = OpenFileDialog(hwnd, "wb", defName,
\r
5488 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5494 case IDM_CopyGame:
\r
5495 CopyGameToClipboard();
\r
5498 case IDM_PasteGame:
\r
5499 PasteGameFromClipboard();
\r
5502 case IDM_CopyGameListToClipboard:
\r
5503 CopyGameListToClipboard();
\r
5506 /* [AS] Autodetect FEN or PGN data */
\r
5507 case IDM_PasteAny:
\r
5508 PasteGameOrFENFromClipboard();
\r
5511 /* [AS] Move history */
\r
5512 case IDM_ShowMoveHistory:
\r
5513 if( MoveHistoryIsUp() ) {
\r
5514 MoveHistoryPopDown();
\r
5517 MoveHistoryPopUp();
\r
5521 /* [AS] Eval graph */
\r
5522 case IDM_ShowEvalGraph:
\r
5523 if( EvalGraphIsUp() ) {
\r
5524 EvalGraphPopDown();
\r
5528 SetFocus(hwndMain);
\r
5532 /* [AS] Engine output */
\r
5533 case IDM_ShowEngineOutput:
\r
5534 if( EngineOutputIsUp() ) {
\r
5535 EngineOutputPopDown();
\r
5538 EngineOutputPopUp();
\r
5542 /* [AS] User adjudication */
\r
5543 case IDM_UserAdjudication_White:
\r
5544 UserAdjudicationEvent( +1 );
\r
5547 case IDM_UserAdjudication_Black:
\r
5548 UserAdjudicationEvent( -1 );
\r
5551 case IDM_UserAdjudication_Draw:
\r
5552 UserAdjudicationEvent( 0 );
\r
5555 /* [AS] Game list options dialog */
\r
5556 case IDM_GameListOptions:
\r
5557 GameListOptions();
\r
5564 case IDM_CopyPosition:
\r
5565 CopyFENToClipboard();
\r
5568 case IDM_PastePosition:
\r
5569 PasteFENFromClipboard();
\r
5572 case IDM_MailMove:
\r
5576 case IDM_ReloadCMailMsg:
\r
5577 Reset(TRUE, TRUE);
\r
5578 ReloadCmailMsgEvent(FALSE);
\r
5581 case IDM_Minimize:
\r
5582 ShowWindow(hwnd, SW_MINIMIZE);
\r
5589 case IDM_MachineWhite:
\r
5590 MachineWhiteEvent();
\r
5592 * refresh the tags dialog only if it's visible
\r
5594 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5596 tags = PGNTags(&gameInfo);
\r
5597 TagsPopUp(tags, CmailMsg());
\r
5600 SAY("computer starts playing white");
\r
5603 case IDM_MachineBlack:
\r
5604 MachineBlackEvent();
\r
5606 * refresh the tags dialog only if it's visible
\r
5608 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5610 tags = PGNTags(&gameInfo);
\r
5611 TagsPopUp(tags, CmailMsg());
\r
5614 SAY("computer starts playing black");
\r
5617 case IDM_TwoMachines:
\r
5618 TwoMachinesEvent();
\r
5620 * refresh the tags dialog only if it's visible
\r
5622 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5624 tags = PGNTags(&gameInfo);
\r
5625 TagsPopUp(tags, CmailMsg());
\r
5628 SAY("programs start playing each other");
\r
5631 case IDM_AnalysisMode:
\r
5632 if (!first.analysisSupport) {
\r
5633 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5634 DisplayError(buf, 0);
\r
5636 SAY("analyzing current position");
\r
5637 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5638 if (appData.icsActive) {
\r
5639 if (gameMode != IcsObserving) {
\r
5640 sprintf(buf, "You are not observing a game");
\r
5641 DisplayError(buf, 0);
\r
5642 /* secure check */
\r
5643 if (appData.icsEngineAnalyze) {
\r
5644 if (appData.debugMode)
\r
5645 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5646 ExitAnalyzeMode();
\r
5652 /* if enable, user want disable icsEngineAnalyze */
\r
5653 if (appData.icsEngineAnalyze) {
\r
5654 ExitAnalyzeMode();
\r
5658 appData.icsEngineAnalyze = TRUE;
\r
5659 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5662 if (!appData.showThinking) ToggleShowThinking();
\r
5663 AnalyzeModeEvent();
\r
5667 case IDM_AnalyzeFile:
\r
5668 if (!first.analysisSupport) {
\r
5669 char buf[MSG_SIZ];
\r
5670 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5671 DisplayError(buf, 0);
\r
5673 if (!appData.showThinking) ToggleShowThinking();
\r
5674 AnalyzeFileEvent();
\r
5675 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5676 AnalysisPeriodicEvent(1);
\r
5680 case IDM_IcsClient:
\r
5684 case IDM_EditGame:
\r
5689 case IDM_EditPosition:
\r
5690 EditPositionEvent();
\r
5691 SAY("to set up a position type a FEN");
\r
5694 case IDM_Training:
\r
5698 case IDM_ShowGameList:
\r
5699 ShowGameListProc();
\r
5702 case IDM_EditTags:
\r
5706 case IDM_EditComment:
\r
5707 if (commentUp && editComment) {
\r
5710 EditCommentEvent();
\r
5730 case IDM_CallFlag:
\r
5750 case IDM_StopObserving:
\r
5751 StopObservingEvent();
\r
5754 case IDM_StopExamining:
\r
5755 StopExaminingEvent();
\r
5758 case IDM_TypeInMove:
\r
5759 PopUpMoveDialog('\000');
\r
5762 case IDM_TypeInName:
\r
5763 PopUpNameDialog('\000');
\r
5766 case IDM_Backward:
\r
5768 SetFocus(hwndMain);
\r
5775 SetFocus(hwndMain);
\r
5780 SetFocus(hwndMain);
\r
5785 SetFocus(hwndMain);
\r
5792 case IDM_TruncateGame:
\r
5793 TruncateGameEvent();
\r
5800 case IDM_RetractMove:
\r
5801 RetractMoveEvent();
\r
5804 case IDM_FlipView:
\r
5805 flipView = !flipView;
\r
5806 DrawPosition(FALSE, NULL);
\r
5809 case IDM_FlipClock:
\r
5810 flipClock = !flipClock;
\r
5811 DisplayBothClocks();
\r
5812 DrawPosition(FALSE, NULL);
\r
5815 case IDM_MuteSounds:
\r
5816 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
5817 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
5818 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
5821 case IDM_GeneralOptions:
\r
5822 GeneralOptionsPopup(hwnd);
\r
5823 DrawPosition(TRUE, NULL);
\r
5826 case IDM_BoardOptions:
\r
5827 BoardOptionsPopup(hwnd);
\r
5830 case IDM_EnginePlayOptions:
\r
5831 EnginePlayOptionsPopup(hwnd);
\r
5834 case IDM_Engine1Options:
\r
5835 EngineOptionsPopup(hwnd, &first);
\r
5838 case IDM_Engine2Options:
\r
5839 EngineOptionsPopup(hwnd, &second);
\r
5842 case IDM_OptionsUCI:
\r
5843 UciOptionsPopup(hwnd);
\r
5846 case IDM_IcsOptions:
\r
5847 IcsOptionsPopup(hwnd);
\r
5851 FontsOptionsPopup(hwnd);
\r
5855 SoundOptionsPopup(hwnd);
\r
5858 case IDM_CommPort:
\r
5859 CommPortOptionsPopup(hwnd);
\r
5862 case IDM_LoadOptions:
\r
5863 LoadOptionsPopup(hwnd);
\r
5866 case IDM_SaveOptions:
\r
5867 SaveOptionsPopup(hwnd);
\r
5870 case IDM_TimeControl:
\r
5871 TimeControlOptionsPopup(hwnd);
\r
5874 case IDM_SaveSettings:
\r
5875 SaveSettings(settingsFileName);
\r
5878 case IDM_SaveSettingsOnExit:
\r
5879 saveSettingsOnExit = !saveSettingsOnExit;
\r
5880 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5881 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5882 MF_CHECKED : MF_UNCHECKED));
\r
5893 case IDM_AboutGame:
\r
5898 appData.debugMode = !appData.debugMode;
\r
5899 if (appData.debugMode) {
\r
5900 char dir[MSG_SIZ];
\r
5901 GetCurrentDirectory(MSG_SIZ, dir);
\r
5902 SetCurrentDirectory(installDir);
\r
5903 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5904 SetCurrentDirectory(dir);
\r
5905 setbuf(debugFP, NULL);
\r
5912 case IDM_HELPCONTENTS:
\r
5913 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
5914 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5915 MessageBox (GetFocus(),
\r
5916 "Unable to activate help",
\r
5917 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5921 case IDM_HELPSEARCH:
\r
5922 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
5923 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
5924 MessageBox (GetFocus(),
\r
5925 "Unable to activate help",
\r
5926 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5930 case IDM_HELPHELP:
\r
5931 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5932 MessageBox (GetFocus(),
\r
5933 "Unable to activate help",
\r
5934 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5939 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5941 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5942 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5943 FreeProcInstance(lpProc);
\r
5946 case IDM_DirectCommand1:
\r
5947 AskQuestionEvent("Direct Command",
\r
5948 "Send to chess program:", "", "1");
\r
5950 case IDM_DirectCommand2:
\r
5951 AskQuestionEvent("Direct Command",
\r
5952 "Send to second chess program:", "", "2");
\r
5955 case EP_WhitePawn:
\r
5956 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5957 fromX = fromY = -1;
\r
5960 case EP_WhiteKnight:
\r
5961 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5962 fromX = fromY = -1;
\r
5965 case EP_WhiteBishop:
\r
5966 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5967 fromX = fromY = -1;
\r
5970 case EP_WhiteRook:
\r
5971 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5972 fromX = fromY = -1;
\r
5975 case EP_WhiteQueen:
\r
5976 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5977 fromX = fromY = -1;
\r
5980 case EP_WhiteFerz:
\r
5981 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5982 fromX = fromY = -1;
\r
5985 case EP_WhiteWazir:
\r
5986 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5987 fromX = fromY = -1;
\r
5990 case EP_WhiteAlfil:
\r
5991 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5992 fromX = fromY = -1;
\r
5995 case EP_WhiteCannon:
\r
5996 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5997 fromX = fromY = -1;
\r
6000 case EP_WhiteCardinal:
\r
6001 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6002 fromX = fromY = -1;
\r
6005 case EP_WhiteMarshall:
\r
6006 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6007 fromX = fromY = -1;
\r
6010 case EP_WhiteKing:
\r
6011 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6012 fromX = fromY = -1;
\r
6015 case EP_BlackPawn:
\r
6016 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6017 fromX = fromY = -1;
\r
6020 case EP_BlackKnight:
\r
6021 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6022 fromX = fromY = -1;
\r
6025 case EP_BlackBishop:
\r
6026 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6027 fromX = fromY = -1;
\r
6030 case EP_BlackRook:
\r
6031 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6032 fromX = fromY = -1;
\r
6035 case EP_BlackQueen:
\r
6036 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6037 fromX = fromY = -1;
\r
6040 case EP_BlackFerz:
\r
6041 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6042 fromX = fromY = -1;
\r
6045 case EP_BlackWazir:
\r
6046 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6047 fromX = fromY = -1;
\r
6050 case EP_BlackAlfil:
\r
6051 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6052 fromX = fromY = -1;
\r
6055 case EP_BlackCannon:
\r
6056 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6057 fromX = fromY = -1;
\r
6060 case EP_BlackCardinal:
\r
6061 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6062 fromX = fromY = -1;
\r
6065 case EP_BlackMarshall:
\r
6066 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6067 fromX = fromY = -1;
\r
6070 case EP_BlackKing:
\r
6071 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6072 fromX = fromY = -1;
\r
6075 case EP_EmptySquare:
\r
6076 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6077 fromX = fromY = -1;
\r
6080 case EP_ClearBoard:
\r
6081 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6082 fromX = fromY = -1;
\r
6086 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6087 fromX = fromY = -1;
\r
6091 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6092 fromX = fromY = -1;
\r
6096 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6097 fromX = fromY = -1;
\r
6101 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6102 fromX = fromY = -1;
\r
6106 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6107 fromX = fromY = -1;
\r
6111 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6112 fromX = fromY = -1;
\r
6116 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6117 fromX = fromY = -1;
\r
6121 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6122 fromX = fromY = -1;
\r
6126 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6127 fromX = fromY = -1;
\r
6131 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6137 case CLOCK_TIMER_ID:
\r
6138 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6139 clockTimerEvent = 0;
\r
6140 DecrementClocks(); /* call into back end */
\r
6142 case LOAD_GAME_TIMER_ID:
\r
6143 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6144 loadGameTimerEvent = 0;
\r
6145 AutoPlayGameLoop(); /* call into back end */
\r
6147 case ANALYSIS_TIMER_ID:
\r
6148 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6149 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6150 AnalysisPeriodicEvent(0);
\r
6152 KillTimer(hwnd, analysisTimerEvent);
\r
6153 analysisTimerEvent = 0;
\r
6156 case DELAYED_TIMER_ID:
\r
6157 KillTimer(hwnd, delayedTimerEvent);
\r
6158 delayedTimerEvent = 0;
\r
6159 delayedTimerCallback();
\r
6164 case WM_USER_Input:
\r
6165 InputEvent(hwnd, message, wParam, lParam);
\r
6168 /* [AS] Also move "attached" child windows */
\r
6169 case WM_WINDOWPOSCHANGING:
\r
6171 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6172 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6174 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6175 /* Window is moving */
\r
6178 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6179 rcMain.left = wpMain.x; // replace by these 4 lines to reconstruct old rect
\r
6180 rcMain.right = wpMain.x + wpMain.width;
\r
6181 rcMain.top = wpMain.y;
\r
6182 rcMain.bottom = wpMain.y + wpMain.height;
\r
6184 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6185 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6186 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6187 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6188 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6189 wpMain.x = lpwp->x;
\r
6190 wpMain.y = lpwp->y;
\r
6195 /* [AS] Snapping */
\r
6196 case WM_ENTERSIZEMOVE:
\r
6197 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6198 if (hwnd == hwndMain) {
\r
6199 doingSizing = TRUE;
\r
6202 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6206 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6207 if (hwnd == hwndMain) {
\r
6208 lastSizing = wParam;
\r
6213 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6214 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6216 case WM_EXITSIZEMOVE:
\r
6217 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6218 if (hwnd == hwndMain) {
\r
6220 doingSizing = FALSE;
\r
6221 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6222 GetClientRect(hwnd, &client);
\r
6223 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6225 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6227 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6230 case WM_DESTROY: /* message: window being destroyed */
\r
6231 PostQuitMessage(0);
\r
6235 if (hwnd == hwndMain) {
\r
6240 default: /* Passes it on if unprocessed */
\r
6241 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6246 /*---------------------------------------------------------------------------*\
\r
6248 * Misc utility routines
\r
6250 \*---------------------------------------------------------------------------*/
\r
6253 * Decent random number generator, at least not as bad as Windows
\r
6254 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6256 unsigned int randstate;
\r
6261 randstate = randstate * 1664525 + 1013904223;
\r
6262 return (int) randstate & 0x7fffffff;
\r
6266 mysrandom(unsigned int seed)
\r
6273 * returns TRUE if user selects a different color, FALSE otherwise
\r
6277 ChangeColor(HWND hwnd, COLORREF *which)
\r
6279 static BOOL firstTime = TRUE;
\r
6280 static DWORD customColors[16];
\r
6282 COLORREF newcolor;
\r
6287 /* Make initial colors in use available as custom colors */
\r
6288 /* Should we put the compiled-in defaults here instead? */
\r
6290 customColors[i++] = lightSquareColor & 0xffffff;
\r
6291 customColors[i++] = darkSquareColor & 0xffffff;
\r
6292 customColors[i++] = whitePieceColor & 0xffffff;
\r
6293 customColors[i++] = blackPieceColor & 0xffffff;
\r
6294 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6295 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6297 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6298 customColors[i++] = textAttribs[ccl].color;
\r
6300 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6301 firstTime = FALSE;
\r
6304 cc.lStructSize = sizeof(cc);
\r
6305 cc.hwndOwner = hwnd;
\r
6306 cc.hInstance = NULL;
\r
6307 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6308 cc.lpCustColors = (LPDWORD) customColors;
\r
6309 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6311 if (!ChooseColor(&cc)) return FALSE;
\r
6313 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6314 if (newcolor == *which) return FALSE;
\r
6315 *which = newcolor;
\r
6319 InitDrawingColors();
\r
6320 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6325 MyLoadSound(MySound *ms)
\r
6331 if (ms->data) free(ms->data);
\r
6334 switch (ms->name[0]) {
\r
6340 /* System sound from Control Panel. Don't preload here. */
\r
6344 if (ms->name[1] == NULLCHAR) {
\r
6345 /* "!" alone = silence */
\r
6348 /* Builtin wave resource. Error if not found. */
\r
6349 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6350 if (h == NULL) break;
\r
6351 ms->data = (void *)LoadResource(hInst, h);
\r
6352 if (h == NULL) break;
\r
6357 /* .wav file. Error if not found. */
\r
6358 f = fopen(ms->name, "rb");
\r
6359 if (f == NULL) break;
\r
6360 if (fstat(fileno(f), &st) < 0) break;
\r
6361 ms->data = malloc(st.st_size);
\r
6362 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6368 char buf[MSG_SIZ];
\r
6369 sprintf(buf, "Error loading sound %s", ms->name);
\r
6370 DisplayError(buf, GetLastError());
\r
6376 MyPlaySound(MySound *ms)
\r
6378 BOOLEAN ok = FALSE;
\r
6380 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6381 switch (ms->name[0]) {
\r
6383 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6388 /* System sound from Control Panel (deprecated feature).
\r
6389 "$" alone or an unset sound name gets default beep (still in use). */
\r
6390 if (ms->name[1]) {
\r
6391 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6393 if (!ok) ok = MessageBeep(MB_OK);
\r
6396 /* Builtin wave resource, or "!" alone for silence */
\r
6397 if (ms->name[1]) {
\r
6398 if (ms->data == NULL) return FALSE;
\r
6399 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6405 /* .wav file. Error if not found. */
\r
6406 if (ms->data == NULL) return FALSE;
\r
6407 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6410 /* Don't print an error: this can happen innocently if the sound driver
\r
6411 is busy; for instance, if another instance of WinBoard is playing
\r
6412 a sound at about the same time. */
\r
6418 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6421 OPENFILENAME *ofn;
\r
6422 static UINT *number; /* gross that this is static */
\r
6424 switch (message) {
\r
6425 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6426 /* Center the dialog over the application window */
\r
6427 ofn = (OPENFILENAME *) lParam;
\r
6428 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6429 number = (UINT *) ofn->lCustData;
\r
6430 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6434 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6435 return FALSE; /* Allow for further processing */
\r
6438 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6439 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6441 return FALSE; /* Allow for further processing */
\r
6447 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6449 static UINT *number;
\r
6450 OPENFILENAME *ofname;
\r
6453 case WM_INITDIALOG:
\r
6454 ofname = (OPENFILENAME *)lParam;
\r
6455 number = (UINT *)(ofname->lCustData);
\r
6458 ofnot = (OFNOTIFY *)lParam;
\r
6459 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6460 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6469 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6470 char *nameFilt, char *dlgTitle, UINT *number,
\r
6471 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6473 OPENFILENAME openFileName;
\r
6474 char buf1[MSG_SIZ];
\r
6477 if (fileName == NULL) fileName = buf1;
\r
6478 if (defName == NULL) {
\r
6479 strcpy(fileName, "*.");
\r
6480 strcat(fileName, defExt);
\r
6482 strcpy(fileName, defName);
\r
6484 if (fileTitle) strcpy(fileTitle, "");
\r
6485 if (number) *number = 0;
\r
6487 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6488 openFileName.hwndOwner = hwnd;
\r
6489 openFileName.hInstance = (HANDLE) hInst;
\r
6490 openFileName.lpstrFilter = nameFilt;
\r
6491 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6492 openFileName.nMaxCustFilter = 0L;
\r
6493 openFileName.nFilterIndex = 1L;
\r
6494 openFileName.lpstrFile = fileName;
\r
6495 openFileName.nMaxFile = MSG_SIZ;
\r
6496 openFileName.lpstrFileTitle = fileTitle;
\r
6497 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6498 openFileName.lpstrInitialDir = NULL;
\r
6499 openFileName.lpstrTitle = dlgTitle;
\r
6500 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6501 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6502 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6503 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6504 openFileName.nFileOffset = 0;
\r
6505 openFileName.nFileExtension = 0;
\r
6506 openFileName.lpstrDefExt = defExt;
\r
6507 openFileName.lCustData = (LONG) number;
\r
6508 openFileName.lpfnHook = oldDialog ?
\r
6509 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6510 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6512 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6513 GetOpenFileName(&openFileName)) {
\r
6514 /* open the file */
\r
6515 f = fopen(openFileName.lpstrFile, write);
\r
6517 MessageBox(hwnd, "File open failed", NULL,
\r
6518 MB_OK|MB_ICONEXCLAMATION);
\r
6522 int err = CommDlgExtendedError();
\r
6523 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6532 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6534 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6537 * Get the first pop-up menu in the menu template. This is the
\r
6538 * menu that TrackPopupMenu displays.
\r
6540 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6542 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6545 * TrackPopup uses screen coordinates, so convert the
\r
6546 * coordinates of the mouse click to screen coordinates.
\r
6548 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6550 /* Draw and track the floating pop-up menu. */
\r
6551 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6552 pt.x, pt.y, 0, hwnd, NULL);
\r
6554 /* Destroy the menu.*/
\r
6555 DestroyMenu(hmenu);
\r
6560 int sizeX, sizeY, newSizeX, newSizeY;
\r
6562 } ResizeEditPlusButtonsClosure;
\r
6565 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6567 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6571 if (hChild == cl->hText) return TRUE;
\r
6572 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6573 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6574 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6575 ScreenToClient(cl->hDlg, &pt);
\r
6576 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6577 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6581 /* Resize a dialog that has a (rich) edit field filling most of
\r
6582 the top, with a row of buttons below */
\r
6584 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6587 int newTextHeight, newTextWidth;
\r
6588 ResizeEditPlusButtonsClosure cl;
\r
6590 /*if (IsIconic(hDlg)) return;*/
\r
6591 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6593 cl.hdwp = BeginDeferWindowPos(8);
\r
6595 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6596 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6597 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6598 if (newTextHeight < 0) {
\r
6599 newSizeY += -newTextHeight;
\r
6600 newTextHeight = 0;
\r
6602 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6603 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6609 cl.newSizeX = newSizeX;
\r
6610 cl.newSizeY = newSizeY;
\r
6611 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6613 EndDeferWindowPos(cl.hdwp);
\r
6616 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6618 RECT rChild, rParent;
\r
6619 int wChild, hChild, wParent, hParent;
\r
6620 int wScreen, hScreen, xNew, yNew;
\r
6623 /* Get the Height and Width of the child window */
\r
6624 GetWindowRect (hwndChild, &rChild);
\r
6625 wChild = rChild.right - rChild.left;
\r
6626 hChild = rChild.bottom - rChild.top;
\r
6628 /* Get the Height and Width of the parent window */
\r
6629 GetWindowRect (hwndParent, &rParent);
\r
6630 wParent = rParent.right - rParent.left;
\r
6631 hParent = rParent.bottom - rParent.top;
\r
6633 /* Get the display limits */
\r
6634 hdc = GetDC (hwndChild);
\r
6635 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6636 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6637 ReleaseDC(hwndChild, hdc);
\r
6639 /* Calculate new X position, then adjust for screen */
\r
6640 xNew = rParent.left + ((wParent - wChild) /2);
\r
6643 } else if ((xNew+wChild) > wScreen) {
\r
6644 xNew = wScreen - wChild;
\r
6647 /* Calculate new Y position, then adjust for screen */
\r
6649 yNew = rParent.top + ((hParent - hChild) /2);
\r
6652 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6657 } else if ((yNew+hChild) > hScreen) {
\r
6658 yNew = hScreen - hChild;
\r
6661 /* Set it, and return */
\r
6662 return SetWindowPos (hwndChild, NULL,
\r
6663 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6666 /* Center one window over another */
\r
6667 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6669 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6672 /*---------------------------------------------------------------------------*\
\r
6674 * Startup Dialog functions
\r
6676 \*---------------------------------------------------------------------------*/
\r
6678 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6680 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6682 while (*cd != NULL) {
\r
6683 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6689 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6691 char buf1[ARG_MAX];
\r
6694 if (str[0] == '@') {
\r
6695 FILE* f = fopen(str + 1, "r");
\r
6697 DisplayFatalError(str + 1, errno, 2);
\r
6700 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6702 buf1[len] = NULLCHAR;
\r
6706 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6709 char buf[MSG_SIZ];
\r
6710 char *end = strchr(str, '\n');
\r
6711 if (end == NULL) return;
\r
6712 memcpy(buf, str, end - str);
\r
6713 buf[end - str] = NULLCHAR;
\r
6714 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6720 SetStartupDialogEnables(HWND hDlg)
\r
6722 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6723 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6724 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6725 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6726 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6727 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6728 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6729 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6730 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6731 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6732 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6733 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6734 IsDlgButtonChecked(hDlg, OPT_View));
\r
6738 QuoteForFilename(char *filename)
\r
6740 int dquote, space;
\r
6741 dquote = strchr(filename, '"') != NULL;
\r
6742 space = strchr(filename, ' ') != NULL;
\r
6743 if (dquote || space) {
\r
6755 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6757 char buf[MSG_SIZ];
\r
6760 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6761 q = QuoteForFilename(nthcp);
\r
6762 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6763 if (*nthdir != NULLCHAR) {
\r
6764 q = QuoteForFilename(nthdir);
\r
6765 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6767 if (*nthcp == NULLCHAR) {
\r
6768 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6769 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6770 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6771 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6776 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6778 char buf[MSG_SIZ];
\r
6782 switch (message) {
\r
6783 case WM_INITDIALOG:
\r
6784 /* Center the dialog */
\r
6785 CenterWindow (hDlg, GetDesktopWindow());
\r
6786 /* Initialize the dialog items */
\r
6787 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6788 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6789 firstChessProgramNames);
\r
6790 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6791 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6792 secondChessProgramNames);
\r
6793 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6794 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6795 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6796 if (*appData.icsHelper != NULLCHAR) {
\r
6797 char *q = QuoteForFilename(appData.icsHelper);
\r
6798 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6800 if (*appData.icsHost == NULLCHAR) {
\r
6801 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6802 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6803 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6804 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6805 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6808 if (appData.icsActive) {
\r
6809 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6811 else if (appData.noChessProgram) {
\r
6812 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6815 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6818 SetStartupDialogEnables(hDlg);
\r
6822 switch (LOWORD(wParam)) {
\r
6824 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6825 strcpy(buf, "/fcp=");
\r
6826 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6828 ParseArgs(StringGet, &p);
\r
6829 strcpy(buf, "/scp=");
\r
6830 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6832 ParseArgs(StringGet, &p);
\r
6833 appData.noChessProgram = FALSE;
\r
6834 appData.icsActive = FALSE;
\r
6835 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6836 strcpy(buf, "/ics /icshost=");
\r
6837 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6839 ParseArgs(StringGet, &p);
\r
6840 if (appData.zippyPlay) {
\r
6841 strcpy(buf, "/fcp=");
\r
6842 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6844 ParseArgs(StringGet, &p);
\r
6846 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6847 appData.noChessProgram = TRUE;
\r
6848 appData.icsActive = FALSE;
\r
6850 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6851 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6854 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6855 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6857 ParseArgs(StringGet, &p);
\r
6859 EndDialog(hDlg, TRUE);
\r
6866 case IDM_HELPCONTENTS:
\r
6867 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6868 MessageBox (GetFocus(),
\r
6869 "Unable to activate help",
\r
6870 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6875 SetStartupDialogEnables(hDlg);
\r
6883 /*---------------------------------------------------------------------------*\
\r
6885 * About box dialog functions
\r
6887 \*---------------------------------------------------------------------------*/
\r
6889 /* Process messages for "About" dialog box */
\r
6891 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6893 switch (message) {
\r
6894 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6895 /* Center the dialog over the application window */
\r
6896 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6897 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6901 case WM_COMMAND: /* message: received a command */
\r
6902 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6903 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6904 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6912 /*---------------------------------------------------------------------------*\
\r
6914 * Comment Dialog functions
\r
6916 \*---------------------------------------------------------------------------*/
\r
6919 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6921 static HANDLE hwndText = NULL;
\r
6922 int len, newSizeX, newSizeY, flags;
\r
6923 static int sizeX, sizeY;
\r
6928 switch (message) {
\r
6929 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6930 /* Initialize the dialog items */
\r
6931 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6932 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6933 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6934 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6935 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6936 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6937 SetWindowText(hDlg, commentTitle);
\r
6938 if (editComment) {
\r
6939 SetFocus(hwndText);
\r
6941 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6943 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6944 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6945 MAKELPARAM(FALSE, 0));
\r
6946 /* Size and position the dialog */
\r
6947 if (!commentDialog) {
\r
6948 commentDialog = hDlg;
\r
6949 flags = SWP_NOZORDER;
\r
6950 GetClientRect(hDlg, &rect);
\r
6951 sizeX = rect.right;
\r
6952 sizeY = rect.bottom;
\r
6953 if (wpComment.x != CW_USEDEFAULT && wpComment.y != CW_USEDEFAULT &&
\r
6954 wpComment.width != CW_USEDEFAULT && wpComment.height != CW_USEDEFAULT) {
\r
6955 WINDOWPLACEMENT wp;
\r
6956 EnsureOnScreen(&wpComment.x, &wpComment.y, 0, 0);
\r
6957 wp.length = sizeof(WINDOWPLACEMENT);
\r
6959 wp.showCmd = SW_SHOW;
\r
6960 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6961 wp.rcNormalPosition.left = wpComment.x;
\r
6962 wp.rcNormalPosition.right = wpComment.x + wpComment.width;
\r
6963 wp.rcNormalPosition.top = wpComment.y;
\r
6964 wp.rcNormalPosition.bottom = wpComment.y + wpComment.height;
\r
6965 SetWindowPlacement(hDlg, &wp);
\r
6967 GetClientRect(hDlg, &rect);
\r
6968 newSizeX = rect.right;
\r
6969 newSizeY = rect.bottom;
\r
6970 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6971 newSizeX, newSizeY);
\r
6978 case WM_COMMAND: /* message: received a command */
\r
6979 switch (LOWORD(wParam)) {
\r
6981 if (editComment) {
\r
6983 /* Read changed options from the dialog box */
\r
6984 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6985 len = GetWindowTextLength(hwndText);
\r
6986 str = (char *) malloc(len + 1);
\r
6987 GetWindowText(hwndText, str, len + 1);
\r
6996 ReplaceComment(commentIndex, str);
\r
7003 case OPT_CancelComment:
\r
7007 case OPT_ClearComment:
\r
7008 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7011 case OPT_EditComment:
\r
7012 EditCommentEvent();
\r
7021 newSizeX = LOWORD(lParam);
\r
7022 newSizeY = HIWORD(lParam);
\r
7023 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7028 case WM_GETMINMAXINFO:
\r
7029 /* Prevent resizing window too small */
\r
7030 mmi = (MINMAXINFO *) lParam;
\r
7031 mmi->ptMinTrackSize.x = 100;
\r
7032 mmi->ptMinTrackSize.y = 100;
\r
7039 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7044 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7046 if (str == NULL) str = "";
\r
7047 p = (char *) malloc(2 * strlen(str) + 2);
\r
7050 if (*str == '\n') *q++ = '\r';
\r
7054 if (commentText != NULL) free(commentText);
\r
7056 commentIndex = index;
\r
7057 commentTitle = title;
\r
7059 editComment = edit;
\r
7061 if (commentDialog) {
\r
7062 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7063 if (!commentUp) ShowWindow(commentDialog, SW_SHOW);
\r
7065 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7066 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7067 hwndMain, (DLGPROC)lpProc);
\r
7068 FreeProcInstance(lpProc);
\r
7074 /*---------------------------------------------------------------------------*\
\r
7076 * Type-in move dialog functions
\r
7078 \*---------------------------------------------------------------------------*/
\r
7081 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7083 char move[MSG_SIZ];
\r
7085 ChessMove moveType;
\r
7086 int fromX, fromY, toX, toY;
\r
7089 switch (message) {
\r
7090 case WM_INITDIALOG:
\r
7091 move[0] = (char) lParam;
\r
7092 move[1] = NULLCHAR;
\r
7093 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7094 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7095 SetWindowText(hInput, move);
\r
7097 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7101 switch (LOWORD(wParam)) {
\r
7103 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7104 { int n; Board board;
\r
7106 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7107 EditPositionPasteFEN(move);
\r
7108 EndDialog(hDlg, TRUE);
\r
7111 // [HGM] movenum: allow move number to be typed in any mode
\r
7112 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7113 currentMove = 2*n-1;
\r
7114 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7115 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7116 EndDialog(hDlg, TRUE);
\r
7117 DrawPosition(TRUE, boards[currentMove]);
\r
7118 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7119 else DisplayMessage("", "");
\r
7123 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7124 gameMode != Training) {
\r
7125 DisplayMoveError("Displayed move is not current");
\r
7127 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7128 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7129 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7130 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7131 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7132 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7133 if (gameMode != Training)
\r
7134 forwardMostMove = currentMove;
\r
7135 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7137 DisplayMoveError("Could not parse move");
\r
7140 EndDialog(hDlg, TRUE);
\r
7143 EndDialog(hDlg, FALSE);
\r
7154 PopUpMoveDialog(char firstchar)
\r
7158 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7159 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7160 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7161 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7162 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7163 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7164 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7165 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7166 gameMode == Training) {
\r
7167 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7168 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7169 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7170 FreeProcInstance(lpProc);
\r
7174 /*---------------------------------------------------------------------------*\
\r
7176 * Type-in name dialog functions
\r
7178 \*---------------------------------------------------------------------------*/
\r
7181 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7183 char move[MSG_SIZ];
\r
7186 switch (message) {
\r
7187 case WM_INITDIALOG:
\r
7188 move[0] = (char) lParam;
\r
7189 move[1] = NULLCHAR;
\r
7190 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7191 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7192 SetWindowText(hInput, move);
\r
7194 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7198 switch (LOWORD(wParam)) {
\r
7200 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7201 appData.userName = strdup(move);
\r
7204 EndDialog(hDlg, TRUE);
\r
7207 EndDialog(hDlg, FALSE);
\r
7218 PopUpNameDialog(char firstchar)
\r
7222 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7223 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7224 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7225 FreeProcInstance(lpProc);
\r
7228 /*---------------------------------------------------------------------------*\
\r
7232 \*---------------------------------------------------------------------------*/
\r
7234 /* Nonmodal error box */
\r
7235 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7236 WPARAM wParam, LPARAM lParam);
\r
7239 ErrorPopUp(char *title, char *content)
\r
7243 BOOLEAN modal = hwndMain == NULL;
\r
7261 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7262 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7265 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7267 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7268 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7269 hwndMain, (DLGPROC)lpProc);
\r
7270 FreeProcInstance(lpProc);
\r
7277 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7278 if (errorDialog == NULL) return;
\r
7279 DestroyWindow(errorDialog);
\r
7280 errorDialog = NULL;
\r
7284 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7289 switch (message) {
\r
7290 case WM_INITDIALOG:
\r
7291 GetWindowRect(hDlg, &rChild);
\r
7294 SetWindowPos(hDlg, NULL, rChild.left,
\r
7295 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7296 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7300 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7301 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7302 and it doesn't work when you resize the dialog.
\r
7303 For now, just give it a default position.
\r
7305 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7307 errorDialog = hDlg;
\r
7308 SetWindowText(hDlg, errorTitle);
\r
7309 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7310 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7314 switch (LOWORD(wParam)) {
\r
7317 if (errorDialog == hDlg) errorDialog = NULL;
\r
7318 DestroyWindow(hDlg);
\r
7330 HWND gothicDialog = NULL;
\r
7333 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7337 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7339 switch (message) {
\r
7340 case WM_INITDIALOG:
\r
7341 GetWindowRect(hDlg, &rChild);
\r
7343 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
7347 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7348 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7349 and it doesn't work when you resize the dialog.
\r
7350 For now, just give it a default position.
\r
7352 gothicDialog = hDlg;
\r
7353 SetWindowText(hDlg, errorTitle);
\r
7354 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7355 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7359 switch (LOWORD(wParam)) {
\r
7362 if (errorDialog == hDlg) errorDialog = NULL;
\r
7363 DestroyWindow(hDlg);
\r
7375 GothicPopUp(char *title, VariantClass variant)
\r
7378 static char *lastTitle;
\r
7380 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7381 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7383 if(lastTitle != title && gothicDialog != NULL) {
\r
7384 DestroyWindow(gothicDialog);
\r
7385 gothicDialog = NULL;
\r
7387 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7388 title = lastTitle;
\r
7389 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7390 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7391 hwndMain, (DLGPROC)lpProc);
\r
7392 FreeProcInstance(lpProc);
\r
7397 /*---------------------------------------------------------------------------*\
\r
7399 * Ics Interaction console functions
\r
7401 \*---------------------------------------------------------------------------*/
\r
7403 #define HISTORY_SIZE 64
\r
7404 static char *history[HISTORY_SIZE];
\r
7405 int histIn = 0, histP = 0;
\r
7408 SaveInHistory(char *cmd)
\r
7410 if (history[histIn] != NULL) {
\r
7411 free(history[histIn]);
\r
7412 history[histIn] = NULL;
\r
7414 if (*cmd == NULLCHAR) return;
\r
7415 history[histIn] = StrSave(cmd);
\r
7416 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7417 if (history[histIn] != NULL) {
\r
7418 free(history[histIn]);
\r
7419 history[histIn] = NULL;
\r
7425 PrevInHistory(char *cmd)
\r
7428 if (histP == histIn) {
\r
7429 if (history[histIn] != NULL) free(history[histIn]);
\r
7430 history[histIn] = StrSave(cmd);
\r
7432 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7433 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7435 return history[histP];
\r
7441 if (histP == histIn) return NULL;
\r
7442 histP = (histP + 1) % HISTORY_SIZE;
\r
7443 return history[histP];
\r
7450 BOOLEAN immediate;
\r
7451 } IcsTextMenuEntry;
\r
7452 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7453 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7456 ParseIcsTextMenu(char *icsTextMenuString)
\r
7459 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7460 char *p = icsTextMenuString;
\r
7461 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7464 if (e->command != NULL) {
\r
7466 e->command = NULL;
\r
7470 e = icsTextMenuEntry;
\r
7471 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7472 if (*p == ';' || *p == '\n') {
\r
7473 e->item = strdup("-");
\r
7474 e->command = NULL;
\r
7476 } else if (*p == '-') {
\r
7477 e->item = strdup("-");
\r
7478 e->command = NULL;
\r
7482 char *q, *r, *s, *t;
\r
7484 q = strchr(p, ',');
\r
7485 if (q == NULL) break;
\r
7487 r = strchr(q + 1, ',');
\r
7488 if (r == NULL) break;
\r
7490 s = strchr(r + 1, ',');
\r
7491 if (s == NULL) break;
\r
7494 t = strchr(s + 1, c);
\r
7497 t = strchr(s + 1, c);
\r
7499 if (t != NULL) *t = NULLCHAR;
\r
7500 e->item = strdup(p);
\r
7501 e->command = strdup(q + 1);
\r
7502 e->getname = *(r + 1) != '0';
\r
7503 e->immediate = *(s + 1) != '0';
\r
7507 if (t == NULL) break;
\r
7516 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7520 hmenu = LoadMenu(hInst, "TextMenu");
\r
7521 h = GetSubMenu(hmenu, 0);
\r
7523 if (strcmp(e->item, "-") == 0) {
\r
7524 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7526 if (e->item[0] == '|') {
\r
7527 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7528 IDM_CommandX + i, &e->item[1]);
\r
7530 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7539 WNDPROC consoleTextWindowProc;
\r
7542 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7544 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7545 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7549 SetWindowText(hInput, command);
\r
7551 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7553 sel.cpMin = 999999;
\r
7554 sel.cpMax = 999999;
\r
7555 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7560 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7561 if (sel.cpMin == sel.cpMax) {
\r
7562 /* Expand to surrounding word */
\r
7565 tr.chrg.cpMax = sel.cpMin;
\r
7566 tr.chrg.cpMin = --sel.cpMin;
\r
7567 if (sel.cpMin < 0) break;
\r
7568 tr.lpstrText = name;
\r
7569 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7570 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7574 tr.chrg.cpMin = sel.cpMax;
\r
7575 tr.chrg.cpMax = ++sel.cpMax;
\r
7576 tr.lpstrText = name;
\r
7577 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7578 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7581 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7582 MessageBeep(MB_ICONEXCLAMATION);
\r
7586 tr.lpstrText = name;
\r
7587 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7589 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7590 MessageBeep(MB_ICONEXCLAMATION);
\r
7593 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7596 sprintf(buf, "%s %s", command, name);
\r
7597 SetWindowText(hInput, buf);
\r
7598 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7600 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7601 SetWindowText(hInput, buf);
\r
7602 sel.cpMin = 999999;
\r
7603 sel.cpMax = 999999;
\r
7604 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7610 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7615 switch (message) {
\r
7617 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7620 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7623 sel.cpMin = 999999;
\r
7624 sel.cpMax = 999999;
\r
7625 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7626 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7631 if(wParam != '\022') {
\r
7632 if (wParam == '\t') {
\r
7633 if (GetKeyState(VK_SHIFT) < 0) {
\r
7635 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7636 if (buttonDesc[0].hwnd) {
\r
7637 SetFocus(buttonDesc[0].hwnd);
\r
7639 SetFocus(hwndMain);
\r
7643 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7646 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7647 JAWS_DELETE( SetFocus(hInput); )
\r
7648 SendMessage(hInput, message, wParam, lParam);
\r
7651 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7652 case WM_RBUTTONUP:
\r
7653 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7654 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7655 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7658 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7659 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7660 if (sel.cpMin == sel.cpMax) {
\r
7661 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7662 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7664 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7665 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7667 pt.x = LOWORD(lParam);
\r
7668 pt.y = HIWORD(lParam);
\r
7669 MenuPopup(hwnd, pt, hmenu, -1);
\r
7673 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7675 return SendMessage(hInput, message, wParam, lParam);
\r
7676 case WM_MBUTTONDOWN:
\r
7677 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7678 case WM_RBUTTONDOWN:
\r
7679 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7680 /* Move selection here if it was empty */
\r
7682 pt.x = LOWORD(lParam);
\r
7683 pt.y = HIWORD(lParam);
\r
7684 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7685 if (sel.cpMin == sel.cpMax) {
\r
7686 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7687 sel.cpMax = sel.cpMin;
\r
7688 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7690 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7694 switch (LOWORD(wParam)) {
\r
7695 case IDM_QuickPaste:
\r
7697 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7698 if (sel.cpMin == sel.cpMax) {
\r
7699 MessageBeep(MB_ICONEXCLAMATION);
\r
7702 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7703 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7704 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7709 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7712 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7715 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7719 int i = LOWORD(wParam) - IDM_CommandX;
\r
7720 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7721 icsTextMenuEntry[i].command != NULL) {
\r
7722 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7723 icsTextMenuEntry[i].getname,
\r
7724 icsTextMenuEntry[i].immediate);
\r
7732 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7735 WNDPROC consoleInputWindowProc;
\r
7738 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7740 char buf[MSG_SIZ];
\r
7742 static BOOL sendNextChar = FALSE;
\r
7743 static BOOL quoteNextChar = FALSE;
\r
7744 InputSource *is = consoleInputSource;
\r
7748 switch (message) {
\r
7750 if (!appData.localLineEditing || sendNextChar) {
\r
7751 is->buf[0] = (CHAR) wParam;
\r
7753 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7754 sendNextChar = FALSE;
\r
7757 if (quoteNextChar) {
\r
7758 buf[0] = (char) wParam;
\r
7759 buf[1] = NULLCHAR;
\r
7760 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7761 quoteNextChar = FALSE;
\r
7765 case '\r': /* Enter key */
\r
7766 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7767 if (consoleEcho) SaveInHistory(is->buf);
\r
7768 is->buf[is->count++] = '\n';
\r
7769 is->buf[is->count] = NULLCHAR;
\r
7770 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7771 if (consoleEcho) {
\r
7772 ConsoleOutput(is->buf, is->count, TRUE);
\r
7773 } else if (appData.localLineEditing) {
\r
7774 ConsoleOutput("\n", 1, TRUE);
\r
7777 case '\033': /* Escape key */
\r
7778 SetWindowText(hwnd, "");
\r
7779 cf.cbSize = sizeof(CHARFORMAT);
\r
7780 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7781 if (consoleEcho) {
\r
7782 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7784 cf.crTextColor = COLOR_ECHOOFF;
\r
7786 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7787 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7789 case '\t': /* Tab key */
\r
7790 if (GetKeyState(VK_SHIFT) < 0) {
\r
7792 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7795 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7796 if (buttonDesc[0].hwnd) {
\r
7797 SetFocus(buttonDesc[0].hwnd);
\r
7799 SetFocus(hwndMain);
\r
7803 case '\023': /* Ctrl+S */
\r
7804 sendNextChar = TRUE;
\r
7806 case '\021': /* Ctrl+Q */
\r
7807 quoteNextChar = TRUE;
\r
7817 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7818 p = PrevInHistory(buf);
\r
7820 SetWindowText(hwnd, p);
\r
7821 sel.cpMin = 999999;
\r
7822 sel.cpMax = 999999;
\r
7823 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7828 p = NextInHistory();
\r
7830 SetWindowText(hwnd, p);
\r
7831 sel.cpMin = 999999;
\r
7832 sel.cpMax = 999999;
\r
7833 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7839 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7843 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7847 case WM_MBUTTONDOWN:
\r
7848 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7849 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7851 case WM_RBUTTONUP:
\r
7852 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7853 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7854 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7858 hmenu = LoadMenu(hInst, "InputMenu");
\r
7859 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7860 if (sel.cpMin == sel.cpMax) {
\r
7861 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7862 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7864 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7865 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7867 pt.x = LOWORD(lParam);
\r
7868 pt.y = HIWORD(lParam);
\r
7869 MenuPopup(hwnd, pt, hmenu, -1);
\r
7873 switch (LOWORD(wParam)) {
\r
7875 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7877 case IDM_SelectAll:
\r
7879 sel.cpMax = -1; /*999999?*/
\r
7880 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7883 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7886 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7889 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7894 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7897 #define CO_MAX 100000
\r
7898 #define CO_TRIM 1000
\r
7901 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7903 static SnapData sd;
\r
7904 HWND hText, hInput;
\r
7906 static int sizeX, sizeY;
\r
7907 int newSizeX, newSizeY;
\r
7911 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7912 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7914 switch (message) {
\r
7916 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7918 ENLINK *pLink = (ENLINK*)lParam;
\r
7919 if (pLink->msg == WM_LBUTTONUP)
\r
7923 tr.chrg = pLink->chrg;
\r
7924 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7925 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7926 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7927 free(tr.lpstrText);
\r
7931 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7932 hwndConsole = hDlg;
\r
7934 consoleTextWindowProc = (WNDPROC)
\r
7935 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7936 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7937 consoleInputWindowProc = (WNDPROC)
\r
7938 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7939 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7940 Colorize(ColorNormal, TRUE);
\r
7941 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7942 ChangedConsoleFont();
\r
7943 GetClientRect(hDlg, &rect);
\r
7944 sizeX = rect.right;
\r
7945 sizeY = rect.bottom;
\r
7946 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7947 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7948 WINDOWPLACEMENT wp;
\r
7949 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7950 wp.length = sizeof(WINDOWPLACEMENT);
\r
7952 wp.showCmd = SW_SHOW;
\r
7953 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7954 wp.rcNormalPosition.left = wpConsole.x;
\r
7955 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7956 wp.rcNormalPosition.top = wpConsole.y;
\r
7957 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7958 SetWindowPlacement(hDlg, &wp);
\r
7961 // [HGM] Chessknight's change 2004-07-13
\r
7962 else { /* Determine Defaults */
\r
7963 WINDOWPLACEMENT wp;
\r
7964 wpConsole.x = wpMain.width + 1;
\r
7965 wpConsole.y = wpMain.y;
\r
7966 wpConsole.width = screenWidth - wpMain.width;
\r
7967 wpConsole.height = wpMain.height;
\r
7968 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7969 wp.length = sizeof(WINDOWPLACEMENT);
\r
7971 wp.showCmd = SW_SHOW;
\r
7972 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7973 wp.rcNormalPosition.left = wpConsole.x;
\r
7974 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7975 wp.rcNormalPosition.top = wpConsole.y;
\r
7976 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7977 SetWindowPlacement(hDlg, &wp);
\r
7980 // Allow hText to highlight URLs and send notifications on them
\r
7981 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7982 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7983 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7984 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
7998 if (IsIconic(hDlg)) break;
\r
7999 newSizeX = LOWORD(lParam);
\r
8000 newSizeY = HIWORD(lParam);
\r
8001 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8002 RECT rectText, rectInput;
\r
8004 int newTextHeight, newTextWidth;
\r
8005 GetWindowRect(hText, &rectText);
\r
8006 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8007 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8008 if (newTextHeight < 0) {
\r
8009 newSizeY += -newTextHeight;
\r
8010 newTextHeight = 0;
\r
8012 SetWindowPos(hText, NULL, 0, 0,
\r
8013 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8014 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8015 pt.x = rectInput.left;
\r
8016 pt.y = rectInput.top + newSizeY - sizeY;
\r
8017 ScreenToClient(hDlg, &pt);
\r
8018 SetWindowPos(hInput, NULL,
\r
8019 pt.x, pt.y, /* needs client coords */
\r
8020 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8021 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8027 case WM_GETMINMAXINFO:
\r
8028 /* Prevent resizing window too small */
\r
8029 mmi = (MINMAXINFO *) lParam;
\r
8030 mmi->ptMinTrackSize.x = 100;
\r
8031 mmi->ptMinTrackSize.y = 100;
\r
8034 /* [AS] Snapping */
\r
8035 case WM_ENTERSIZEMOVE:
\r
8036 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8039 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8042 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8044 case WM_EXITSIZEMOVE:
\r
8045 UpdateICSWidth(hText);
\r
8046 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8049 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8057 if (hwndConsole) return;
\r
8058 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8059 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8064 ConsoleOutput(char* data, int length, int forceVisible)
\r
8069 char buf[CO_MAX+1];
\r
8072 static int delayLF = 0;
\r
8073 CHARRANGE savesel, sel;
\r
8075 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8083 while (length--) {
\r
8091 } else if (*p == '\007') {
\r
8092 MyPlaySound(&sounds[(int)SoundBell]);
\r
8099 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8100 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8101 /* Save current selection */
\r
8102 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8103 exlen = GetWindowTextLength(hText);
\r
8104 /* Find out whether current end of text is visible */
\r
8105 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8106 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8107 /* Trim existing text if it's too long */
\r
8108 if (exlen + (q - buf) > CO_MAX) {
\r
8109 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8112 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8113 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8115 savesel.cpMin -= trim;
\r
8116 savesel.cpMax -= trim;
\r
8117 if (exlen < 0) exlen = 0;
\r
8118 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8119 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8121 /* Append the new text */
\r
8122 sel.cpMin = exlen;
\r
8123 sel.cpMax = exlen;
\r
8124 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8125 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8126 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8127 if (forceVisible || exlen == 0 ||
\r
8128 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8129 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8130 /* Scroll to make new end of text visible if old end of text
\r
8131 was visible or new text is an echo of user typein */
\r
8132 sel.cpMin = 9999999;
\r
8133 sel.cpMax = 9999999;
\r
8134 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8135 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8136 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8137 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8139 if (savesel.cpMax == exlen || forceVisible) {
\r
8140 /* Move insert point to new end of text if it was at the old
\r
8141 end of text or if the new text is an echo of user typein */
\r
8142 sel.cpMin = 9999999;
\r
8143 sel.cpMax = 9999999;
\r
8144 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8146 /* Restore previous selection */
\r
8147 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8149 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8156 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8160 COLORREF oldFg, oldBg;
\r
8164 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8166 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8167 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8168 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8171 rect.right = x + squareSize;
\r
8173 rect.bottom = y + squareSize;
\r
8176 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8177 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8178 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8179 &rect, str, strlen(str), NULL);
\r
8181 (void) SetTextColor(hdc, oldFg);
\r
8182 (void) SetBkColor(hdc, oldBg);
\r
8183 (void) SelectObject(hdc, oldFont);
\r
8187 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8188 RECT *rect, char *color, char *flagFell)
\r
8192 COLORREF oldFg, oldBg;
\r
8195 if (appData.clockMode) {
\r
8197 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8199 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8206 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8207 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8209 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8210 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8212 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8216 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8217 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8218 rect, str, strlen(str), NULL);
\r
8219 if(logoHeight > 0 && appData.clockMode) {
\r
8221 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8222 r.top = rect->top + logoHeight/2;
\r
8223 r.left = rect->left;
\r
8224 r.right = rect->right;
\r
8225 r.bottom = rect->bottom;
\r
8226 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8227 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8228 &r, str, strlen(str), NULL);
\r
8230 (void) SetTextColor(hdc, oldFg);
\r
8231 (void) SetBkColor(hdc, oldBg);
\r
8232 (void) SelectObject(hdc, oldFont);
\r
8237 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8243 if( count <= 0 ) {
\r
8244 if (appData.debugMode) {
\r
8245 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8248 return ERROR_INVALID_USER_BUFFER;
\r
8251 ResetEvent(ovl->hEvent);
\r
8252 ovl->Offset = ovl->OffsetHigh = 0;
\r
8253 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8257 err = GetLastError();
\r
8258 if (err == ERROR_IO_PENDING) {
\r
8259 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8263 err = GetLastError();
\r
8270 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8275 ResetEvent(ovl->hEvent);
\r
8276 ovl->Offset = ovl->OffsetHigh = 0;
\r
8277 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8281 err = GetLastError();
\r
8282 if (err == ERROR_IO_PENDING) {
\r
8283 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8287 err = GetLastError();
\r
8293 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8294 void CheckForInputBufferFull( InputSource * is )
\r
8296 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8297 /* Look for end of line */
\r
8298 char * p = is->buf;
\r
8300 while( p < is->next && *p != '\n' ) {
\r
8304 if( p >= is->next ) {
\r
8305 if (appData.debugMode) {
\r
8306 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8309 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8310 is->count = (DWORD) -1;
\r
8311 is->next = is->buf;
\r
8317 InputThread(LPVOID arg)
\r
8322 is = (InputSource *) arg;
\r
8323 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8324 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8325 while (is->hThread != NULL) {
\r
8326 is->error = DoReadFile(is->hFile, is->next,
\r
8327 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8328 &is->count, &ovl);
\r
8329 if (is->error == NO_ERROR) {
\r
8330 is->next += is->count;
\r
8332 if (is->error == ERROR_BROKEN_PIPE) {
\r
8333 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8336 is->count = (DWORD) -1;
\r
8337 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8342 CheckForInputBufferFull( is );
\r
8344 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8346 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8348 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8351 CloseHandle(ovl.hEvent);
\r
8352 CloseHandle(is->hFile);
\r
8354 if (appData.debugMode) {
\r
8355 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8362 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8364 NonOvlInputThread(LPVOID arg)
\r
8371 is = (InputSource *) arg;
\r
8372 while (is->hThread != NULL) {
\r
8373 is->error = ReadFile(is->hFile, is->next,
\r
8374 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8375 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8376 if (is->error == NO_ERROR) {
\r
8377 /* Change CRLF to LF */
\r
8378 if (is->next > is->buf) {
\r
8380 i = is->count + 1;
\r
8388 if (prev == '\r' && *p == '\n') {
\r
8400 if (is->error == ERROR_BROKEN_PIPE) {
\r
8401 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8404 is->count = (DWORD) -1;
\r
8408 CheckForInputBufferFull( is );
\r
8410 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8412 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8414 if (is->count < 0) break; /* Quit on error */
\r
8416 CloseHandle(is->hFile);
\r
8421 SocketInputThread(LPVOID arg)
\r
8425 is = (InputSource *) arg;
\r
8426 while (is->hThread != NULL) {
\r
8427 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8428 if ((int)is->count == SOCKET_ERROR) {
\r
8429 is->count = (DWORD) -1;
\r
8430 is->error = WSAGetLastError();
\r
8432 is->error = NO_ERROR;
\r
8433 is->next += is->count;
\r
8434 if (is->count == 0 && is->second == is) {
\r
8435 /* End of file on stderr; quit with no message */
\r
8439 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8441 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8443 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8449 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8453 is = (InputSource *) lParam;
\r
8454 if (is->lineByLine) {
\r
8455 /* Feed in lines one by one */
\r
8456 char *p = is->buf;
\r
8458 while (q < is->next) {
\r
8459 if (*q++ == '\n') {
\r
8460 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8465 /* Move any partial line to the start of the buffer */
\r
8467 while (p < is->next) {
\r
8472 if (is->error != NO_ERROR || is->count == 0) {
\r
8473 /* Notify backend of the error. Note: If there was a partial
\r
8474 line at the end, it is not flushed through. */
\r
8475 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8478 /* Feed in the whole chunk of input at once */
\r
8479 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8480 is->next = is->buf;
\r
8484 /*---------------------------------------------------------------------------*\
\r
8486 * Menu enables. Used when setting various modes.
\r
8488 \*---------------------------------------------------------------------------*/
\r
8496 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8498 while (enab->item > 0) {
\r
8499 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8504 Enables gnuEnables[] = {
\r
8505 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8506 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8507 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8508 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8509 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8510 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8511 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8512 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8513 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8514 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8515 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8519 Enables icsEnables[] = {
\r
8520 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8521 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8522 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8523 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8524 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8525 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8526 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8527 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8528 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8529 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8530 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8531 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8532 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8533 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8534 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8539 Enables zippyEnables[] = {
\r
8540 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8541 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8542 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8543 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8548 Enables ncpEnables[] = {
\r
8549 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8550 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8551 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8552 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8553 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8554 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8555 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8556 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8557 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8558 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8559 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8560 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8561 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8562 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8563 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8564 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8565 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8566 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8567 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8571 Enables trainingOnEnables[] = {
\r
8572 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8573 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8574 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8575 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8576 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8577 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8578 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8579 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8583 Enables trainingOffEnables[] = {
\r
8584 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8585 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8586 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8587 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8588 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8589 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8590 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8591 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8595 /* These modify either ncpEnables or gnuEnables */
\r
8596 Enables cmailEnables[] = {
\r
8597 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8598 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8599 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8600 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8601 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8602 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8603 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8607 Enables machineThinkingEnables[] = {
\r
8608 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8609 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8610 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8611 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8612 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8613 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8614 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8615 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8616 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8617 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8618 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8619 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8620 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8621 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8622 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8626 Enables userThinkingEnables[] = {
\r
8627 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8628 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8629 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8630 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8631 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8632 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8633 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8634 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8635 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8636 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8637 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8638 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8639 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8640 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8641 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8645 /*---------------------------------------------------------------------------*\
\r
8647 * Front-end interface functions exported by XBoard.
\r
8648 * Functions appear in same order as prototypes in frontend.h.
\r
8650 \*---------------------------------------------------------------------------*/
\r
8654 static UINT prevChecked = 0;
\r
8655 static int prevPausing = 0;
\r
8658 if (pausing != prevPausing) {
\r
8659 prevPausing = pausing;
\r
8660 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8661 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8662 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8665 switch (gameMode) {
\r
8666 case BeginningOfGame:
\r
8667 if (appData.icsActive)
\r
8668 nowChecked = IDM_IcsClient;
\r
8669 else if (appData.noChessProgram)
\r
8670 nowChecked = IDM_EditGame;
\r
8672 nowChecked = IDM_MachineBlack;
\r
8674 case MachinePlaysBlack:
\r
8675 nowChecked = IDM_MachineBlack;
\r
8677 case MachinePlaysWhite:
\r
8678 nowChecked = IDM_MachineWhite;
\r
8680 case TwoMachinesPlay:
\r
8681 nowChecked = IDM_TwoMachines;
\r
8684 nowChecked = IDM_AnalysisMode;
\r
8687 nowChecked = IDM_AnalyzeFile;
\r
8690 nowChecked = IDM_EditGame;
\r
8692 case PlayFromGameFile:
\r
8693 nowChecked = IDM_LoadGame;
\r
8695 case EditPosition:
\r
8696 nowChecked = IDM_EditPosition;
\r
8699 nowChecked = IDM_Training;
\r
8701 case IcsPlayingWhite:
\r
8702 case IcsPlayingBlack:
\r
8703 case IcsObserving:
\r
8705 nowChecked = IDM_IcsClient;
\r
8712 if (prevChecked != 0)
\r
8713 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8714 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8715 if (nowChecked != 0)
\r
8716 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8717 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8719 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8720 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8721 MF_BYCOMMAND|MF_ENABLED);
\r
8723 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8724 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8727 prevChecked = nowChecked;
\r
8729 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8730 if (appData.icsActive) {
\r
8731 if (appData.icsEngineAnalyze) {
\r
8732 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8733 MF_BYCOMMAND|MF_CHECKED);
\r
8735 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8736 MF_BYCOMMAND|MF_UNCHECKED);
\r
8744 HMENU hmenu = GetMenu(hwndMain);
\r
8745 SetMenuEnables(hmenu, icsEnables);
\r
8746 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8747 MF_BYPOSITION|MF_ENABLED);
\r
8749 if (appData.zippyPlay) {
\r
8750 SetMenuEnables(hmenu, zippyEnables);
\r
8751 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8752 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8753 MF_BYCOMMAND|MF_ENABLED);
\r
8761 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8767 HMENU hmenu = GetMenu(hwndMain);
\r
8768 SetMenuEnables(hmenu, ncpEnables);
\r
8769 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8770 MF_BYPOSITION|MF_GRAYED);
\r
8771 DrawMenuBar(hwndMain);
\r
8777 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8781 SetTrainingModeOn()
\r
8784 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8785 for (i = 0; i < N_BUTTONS; i++) {
\r
8786 if (buttonDesc[i].hwnd != NULL)
\r
8787 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8792 VOID SetTrainingModeOff()
\r
8795 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8796 for (i = 0; i < N_BUTTONS; i++) {
\r
8797 if (buttonDesc[i].hwnd != NULL)
\r
8798 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8804 SetUserThinkingEnables()
\r
8806 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8810 SetMachineThinkingEnables()
\r
8812 HMENU hMenu = GetMenu(hwndMain);
\r
8813 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8815 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8817 if (gameMode == MachinePlaysBlack) {
\r
8818 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8819 } else if (gameMode == MachinePlaysWhite) {
\r
8820 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8821 } else if (gameMode == TwoMachinesPlay) {
\r
8822 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8828 DisplayTitle(char *str)
\r
8830 char title[MSG_SIZ], *host;
\r
8831 if (str[0] != NULLCHAR) {
\r
8832 strcpy(title, str);
\r
8833 } else if (appData.icsActive) {
\r
8834 if (appData.icsCommPort[0] != NULLCHAR)
\r
8837 host = appData.icsHost;
\r
8838 sprintf(title, "%s: %s", szTitle, host);
\r
8839 } else if (appData.noChessProgram) {
\r
8840 strcpy(title, szTitle);
\r
8842 strcpy(title, szTitle);
\r
8843 strcat(title, ": ");
\r
8844 strcat(title, first.tidy);
\r
8846 SetWindowText(hwndMain, title);
\r
8851 DisplayMessage(char *str1, char *str2)
\r
8855 int remain = MESSAGE_TEXT_MAX - 1;
\r
8858 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8859 messageText[0] = NULLCHAR;
\r
8861 len = strlen(str1);
\r
8862 if (len > remain) len = remain;
\r
8863 strncpy(messageText, str1, len);
\r
8864 messageText[len] = NULLCHAR;
\r
8867 if (*str2 && remain >= 2) {
\r
8869 strcat(messageText, " ");
\r
8872 len = strlen(str2);
\r
8873 if (len > remain) len = remain;
\r
8874 strncat(messageText, str2, len);
\r
8876 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8878 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8882 hdc = GetDC(hwndMain);
\r
8883 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8884 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8885 &messageRect, messageText, strlen(messageText), NULL);
\r
8886 (void) SelectObject(hdc, oldFont);
\r
8887 (void) ReleaseDC(hwndMain, hdc);
\r
8891 DisplayError(char *str, int error)
\r
8893 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8899 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8900 NULL, error, LANG_NEUTRAL,
\r
8901 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8903 sprintf(buf, "%s:\n%s", str, buf2);
\r
8905 ErrorMap *em = errmap;
\r
8906 while (em->err != 0 && em->err != error) em++;
\r
8907 if (em->err != 0) {
\r
8908 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8910 sprintf(buf, "%s:\nError code %d", str, error);
\r
8915 ErrorPopUp("Error", buf);
\r
8920 DisplayMoveError(char *str)
\r
8922 fromX = fromY = -1;
\r
8923 ClearHighlights();
\r
8924 DrawPosition(FALSE, NULL);
\r
8925 if (appData.popupMoveErrors) {
\r
8926 ErrorPopUp("Error", str);
\r
8928 DisplayMessage(str, "");
\r
8929 moveErrorMessageUp = TRUE;
\r
8934 DisplayFatalError(char *str, int error, int exitStatus)
\r
8936 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8938 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8941 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8942 NULL, error, LANG_NEUTRAL,
\r
8943 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8945 sprintf(buf, "%s:\n%s", str, buf2);
\r
8947 ErrorMap *em = errmap;
\r
8948 while (em->err != 0 && em->err != error) em++;
\r
8949 if (em->err != 0) {
\r
8950 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8952 sprintf(buf, "%s:\nError code %d", str, error);
\r
8957 if (appData.debugMode) {
\r
8958 fprintf(debugFP, "%s: %s\n", label, str);
\r
8960 if (appData.popupExitMessage) {
\r
8961 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8962 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8964 ExitEvent(exitStatus);
\r
8969 DisplayInformation(char *str)
\r
8971 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8976 DisplayNote(char *str)
\r
8978 ErrorPopUp("Note", str);
\r
8983 char *title, *question, *replyPrefix;
\r
8988 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8990 static QuestionParams *qp;
\r
8991 char reply[MSG_SIZ];
\r
8994 switch (message) {
\r
8995 case WM_INITDIALOG:
\r
8996 qp = (QuestionParams *) lParam;
\r
8997 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8998 SetWindowText(hDlg, qp->title);
\r
8999 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9000 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9004 switch (LOWORD(wParam)) {
\r
9006 strcpy(reply, qp->replyPrefix);
\r
9007 if (*reply) strcat(reply, " ");
\r
9008 len = strlen(reply);
\r
9009 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9010 strcat(reply, "\n");
\r
9011 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9012 EndDialog(hDlg, TRUE);
\r
9013 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9016 EndDialog(hDlg, FALSE);
\r
9027 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9029 QuestionParams qp;
\r
9033 qp.question = question;
\r
9034 qp.replyPrefix = replyPrefix;
\r
9036 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9037 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9038 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9039 FreeProcInstance(lpProc);
\r
9042 /* [AS] Pick FRC position */
\r
9043 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9045 static int * lpIndexFRC;
\r
9051 case WM_INITDIALOG:
\r
9052 lpIndexFRC = (int *) lParam;
\r
9054 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9056 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9057 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9058 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9059 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9064 switch( LOWORD(wParam) ) {
\r
9066 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9067 EndDialog( hDlg, 0 );
\r
9068 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9071 EndDialog( hDlg, 1 );
\r
9073 case IDC_NFG_Edit:
\r
9074 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9075 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9077 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9080 case IDC_NFG_Random:
\r
9081 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9082 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9095 int index = appData.defaultFrcPosition;
\r
9096 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9098 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9100 if( result == 0 ) {
\r
9101 appData.defaultFrcPosition = index;
\r
9107 /* [AS] Game list options */
\r
9113 static GLT_Item GLT_ItemInfo[] = {
\r
9114 { GLT_EVENT, "Event" },
\r
9115 { GLT_SITE, "Site" },
\r
9116 { GLT_DATE, "Date" },
\r
9117 { GLT_ROUND, "Round" },
\r
9118 { GLT_PLAYERS, "Players" },
\r
9119 { GLT_RESULT, "Result" },
\r
9120 { GLT_WHITE_ELO, "White Rating" },
\r
9121 { GLT_BLACK_ELO, "Black Rating" },
\r
9122 { GLT_TIME_CONTROL,"Time Control" },
\r
9123 { GLT_VARIANT, "Variant" },
\r
9124 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9125 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9129 const char * GLT_FindItem( char id )
\r
9131 const char * result = 0;
\r
9133 GLT_Item * list = GLT_ItemInfo;
\r
9135 while( list->id != 0 ) {
\r
9136 if( list->id == id ) {
\r
9137 result = list->name;
\r
9147 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9149 const char * name = GLT_FindItem( id );
\r
9152 if( index >= 0 ) {
\r
9153 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9156 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9161 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9165 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9168 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9172 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9174 pc = GLT_ALL_TAGS;
\r
9177 if( strchr( tags, *pc ) == 0 ) {
\r
9178 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9183 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9186 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9188 char result = '\0';
\r
9191 GLT_Item * list = GLT_ItemInfo;
\r
9193 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9194 while( list->id != 0 ) {
\r
9195 if( strcmp( list->name, name ) == 0 ) {
\r
9196 result = list->id;
\r
9207 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9209 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9210 int idx2 = idx1 + delta;
\r
9211 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9213 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9216 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9217 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9218 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9219 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9223 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9225 static char glt[64];
\r
9226 static char * lpUserGLT;
\r
9230 case WM_INITDIALOG:
\r
9231 lpUserGLT = (char *) lParam;
\r
9233 strcpy( glt, lpUserGLT );
\r
9235 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9237 /* Initialize list */
\r
9238 GLT_TagsToList( hDlg, glt );
\r
9240 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9245 switch( LOWORD(wParam) ) {
\r
9248 char * pc = lpUserGLT;
\r
9250 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9254 id = GLT_ListItemToTag( hDlg, idx );
\r
9258 } while( id != '\0' );
\r
9260 EndDialog( hDlg, 0 );
\r
9263 EndDialog( hDlg, 1 );
\r
9266 case IDC_GLT_Default:
\r
9267 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9268 GLT_TagsToList( hDlg, glt );
\r
9271 case IDC_GLT_Restore:
\r
9272 strcpy( glt, lpUserGLT );
\r
9273 GLT_TagsToList( hDlg, glt );
\r
9277 GLT_MoveSelection( hDlg, -1 );
\r
9280 case IDC_GLT_Down:
\r
9281 GLT_MoveSelection( hDlg, +1 );
\r
9291 int GameListOptions()
\r
9295 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9297 strcpy( glt, appData.gameListTags );
\r
9299 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9301 if( result == 0 ) {
\r
9302 /* [AS] Memory leak here! */
\r
9303 appData.gameListTags = strdup( glt );
\r
9311 DisplayIcsInteractionTitle(char *str)
\r
9313 char consoleTitle[MSG_SIZ];
\r
9315 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9316 SetWindowText(hwndConsole, consoleTitle);
\r
9320 DrawPosition(int fullRedraw, Board board)
\r
9322 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9325 void NotifyFrontendLogin()
\r
9328 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
9334 fromX = fromY = -1;
\r
9335 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9336 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9337 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9338 dragInfo.lastpos = dragInfo.pos;
\r
9339 dragInfo.start.x = dragInfo.start.y = -1;
\r
9340 dragInfo.from = dragInfo.start;
\r
9342 DrawPosition(TRUE, NULL);
\r
9348 CommentPopUp(char *title, char *str)
\r
9350 HWND hwnd = GetActiveWindow();
\r
9351 EitherCommentPopUp(0, title, str, FALSE);
\r
9353 SetActiveWindow(hwnd);
\r
9357 CommentPopDown(void)
\r
9359 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9360 if (commentDialog) {
\r
9361 ShowWindow(commentDialog, SW_HIDE);
\r
9363 commentUp = FALSE;
\r
9367 EditCommentPopUp(int index, char *title, char *str)
\r
9369 EitherCommentPopUp(index, title, str, TRUE);
\r
9376 MyPlaySound(&sounds[(int)SoundMove]);
\r
9379 VOID PlayIcsWinSound()
\r
9381 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9384 VOID PlayIcsLossSound()
\r
9386 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9389 VOID PlayIcsDrawSound()
\r
9391 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9394 VOID PlayIcsUnfinishedSound()
\r
9396 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9402 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9410 consoleEcho = TRUE;
\r
9411 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9412 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9413 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9422 consoleEcho = FALSE;
\r
9423 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9424 /* This works OK: set text and background both to the same color */
\r
9426 cf.crTextColor = COLOR_ECHOOFF;
\r
9427 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9428 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9431 /* No Raw()...? */
\r
9433 void Colorize(ColorClass cc, int continuation)
\r
9435 currentColorClass = cc;
\r
9436 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9437 consoleCF.crTextColor = textAttribs[cc].color;
\r
9438 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9439 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9445 static char buf[MSG_SIZ];
\r
9446 DWORD bufsiz = MSG_SIZ;
\r
9448 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9449 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9451 if (!GetUserName(buf, &bufsiz)) {
\r
9452 /*DisplayError("Error getting user name", GetLastError());*/
\r
9453 strcpy(buf, "User");
\r
9461 static char buf[MSG_SIZ];
\r
9462 DWORD bufsiz = MSG_SIZ;
\r
9464 if (!GetComputerName(buf, &bufsiz)) {
\r
9465 /*DisplayError("Error getting host name", GetLastError());*/
\r
9466 strcpy(buf, "Unknown");
\r
9473 ClockTimerRunning()
\r
9475 return clockTimerEvent != 0;
\r
9481 if (clockTimerEvent == 0) return FALSE;
\r
9482 KillTimer(hwndMain, clockTimerEvent);
\r
9483 clockTimerEvent = 0;
\r
9488 StartClockTimer(long millisec)
\r
9490 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9491 (UINT) millisec, NULL);
\r
9495 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9498 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9500 if(appData.noGUI) return;
\r
9501 hdc = GetDC(hwndMain);
\r
9502 if (!IsIconic(hwndMain)) {
\r
9503 DisplayAClock(hdc, timeRemaining, highlight,
\r
9504 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9506 if (highlight && iconCurrent == iconBlack) {
\r
9507 iconCurrent = iconWhite;
\r
9508 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9509 if (IsIconic(hwndMain)) {
\r
9510 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9513 (void) ReleaseDC(hwndMain, hdc);
\r
9515 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9519 DisplayBlackClock(long timeRemaining, int highlight)
\r
9522 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9524 if(appData.noGUI) return;
\r
9525 hdc = GetDC(hwndMain);
\r
9526 if (!IsIconic(hwndMain)) {
\r
9527 DisplayAClock(hdc, timeRemaining, highlight,
\r
9528 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9530 if (highlight && iconCurrent == iconWhite) {
\r
9531 iconCurrent = iconBlack;
\r
9532 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9533 if (IsIconic(hwndMain)) {
\r
9534 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9537 (void) ReleaseDC(hwndMain, hdc);
\r
9539 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9544 LoadGameTimerRunning()
\r
9546 return loadGameTimerEvent != 0;
\r
9550 StopLoadGameTimer()
\r
9552 if (loadGameTimerEvent == 0) return FALSE;
\r
9553 KillTimer(hwndMain, loadGameTimerEvent);
\r
9554 loadGameTimerEvent = 0;
\r
9559 StartLoadGameTimer(long millisec)
\r
9561 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9562 (UINT) millisec, NULL);
\r
9570 char fileTitle[MSG_SIZ];
\r
9572 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9573 f = OpenFileDialog(hwndMain, "a", defName,
\r
9574 appData.oldSaveStyle ? "gam" : "pgn",
\r
9576 "Save Game to File", NULL, fileTitle, NULL);
\r
9578 SaveGame(f, 0, "");
\r
9585 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9587 if (delayedTimerEvent != 0) {
\r
9588 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9589 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9591 KillTimer(hwndMain, delayedTimerEvent);
\r
9592 delayedTimerEvent = 0;
\r
9593 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9594 delayedTimerCallback();
\r
9596 delayedTimerCallback = cb;
\r
9597 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9598 (UINT) millisec, NULL);
\r
9601 DelayedEventCallback
\r
9604 if (delayedTimerEvent) {
\r
9605 return delayedTimerCallback;
\r
9612 CancelDelayedEvent()
\r
9614 if (delayedTimerEvent) {
\r
9615 KillTimer(hwndMain, delayedTimerEvent);
\r
9616 delayedTimerEvent = 0;
\r
9620 DWORD GetWin32Priority(int nice)
\r
9621 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9623 REALTIME_PRIORITY_CLASS 0x00000100
\r
9624 HIGH_PRIORITY_CLASS 0x00000080
\r
9625 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9626 NORMAL_PRIORITY_CLASS 0x00000020
\r
9627 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9628 IDLE_PRIORITY_CLASS 0x00000040
\r
9630 if (nice < -15) return 0x00000080;
\r
9631 if (nice < 0) return 0x00008000;
\r
9632 if (nice == 0) return 0x00000020;
\r
9633 if (nice < 15) return 0x00004000;
\r
9634 return 0x00000040;
\r
9637 /* Start a child process running the given program.
\r
9638 The process's standard output can be read from "from", and its
\r
9639 standard input can be written to "to".
\r
9640 Exit with fatal error if anything goes wrong.
\r
9641 Returns an opaque pointer that can be used to destroy the process
\r
9645 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9647 #define BUFSIZE 4096
\r
9649 HANDLE hChildStdinRd, hChildStdinWr,
\r
9650 hChildStdoutRd, hChildStdoutWr;
\r
9651 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9652 SECURITY_ATTRIBUTES saAttr;
\r
9654 PROCESS_INFORMATION piProcInfo;
\r
9655 STARTUPINFO siStartInfo;
\r
9657 char buf[MSG_SIZ];
\r
9660 if (appData.debugMode) {
\r
9661 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9666 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9667 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9668 saAttr.bInheritHandle = TRUE;
\r
9669 saAttr.lpSecurityDescriptor = NULL;
\r
9672 * The steps for redirecting child's STDOUT:
\r
9673 * 1. Create anonymous pipe to be STDOUT for child.
\r
9674 * 2. Create a noninheritable duplicate of read handle,
\r
9675 * and close the inheritable read handle.
\r
9678 /* Create a pipe for the child's STDOUT. */
\r
9679 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9680 return GetLastError();
\r
9683 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9684 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9685 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9686 FALSE, /* not inherited */
\r
9687 DUPLICATE_SAME_ACCESS);
\r
9689 return GetLastError();
\r
9691 CloseHandle(hChildStdoutRd);
\r
9694 * The steps for redirecting child's STDIN:
\r
9695 * 1. Create anonymous pipe to be STDIN for child.
\r
9696 * 2. Create a noninheritable duplicate of write handle,
\r
9697 * and close the inheritable write handle.
\r
9700 /* Create a pipe for the child's STDIN. */
\r
9701 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9702 return GetLastError();
\r
9705 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9706 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9707 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9708 FALSE, /* not inherited */
\r
9709 DUPLICATE_SAME_ACCESS);
\r
9711 return GetLastError();
\r
9713 CloseHandle(hChildStdinWr);
\r
9715 /* Arrange to (1) look in dir for the child .exe file, and
\r
9716 * (2) have dir be the child's working directory. Interpret
\r
9717 * dir relative to the directory WinBoard loaded from. */
\r
9718 GetCurrentDirectory(MSG_SIZ, buf);
\r
9719 SetCurrentDirectory(installDir);
\r
9720 SetCurrentDirectory(dir);
\r
9722 /* Now create the child process. */
\r
9724 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9725 siStartInfo.lpReserved = NULL;
\r
9726 siStartInfo.lpDesktop = NULL;
\r
9727 siStartInfo.lpTitle = NULL;
\r
9728 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9729 siStartInfo.cbReserved2 = 0;
\r
9730 siStartInfo.lpReserved2 = NULL;
\r
9731 siStartInfo.hStdInput = hChildStdinRd;
\r
9732 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9733 siStartInfo.hStdError = hChildStdoutWr;
\r
9735 fSuccess = CreateProcess(NULL,
\r
9736 cmdLine, /* command line */
\r
9737 NULL, /* process security attributes */
\r
9738 NULL, /* primary thread security attrs */
\r
9739 TRUE, /* handles are inherited */
\r
9740 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9741 NULL, /* use parent's environment */
\r
9743 &siStartInfo, /* STARTUPINFO pointer */
\r
9744 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9746 err = GetLastError();
\r
9747 SetCurrentDirectory(buf); /* return to prev directory */
\r
9752 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9753 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9754 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9757 /* Close the handles we don't need in the parent */
\r
9758 CloseHandle(piProcInfo.hThread);
\r
9759 CloseHandle(hChildStdinRd);
\r
9760 CloseHandle(hChildStdoutWr);
\r
9762 /* Prepare return value */
\r
9763 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9764 cp->kind = CPReal;
\r
9765 cp->hProcess = piProcInfo.hProcess;
\r
9766 cp->pid = piProcInfo.dwProcessId;
\r
9767 cp->hFrom = hChildStdoutRdDup;
\r
9768 cp->hTo = hChildStdinWrDup;
\r
9770 *pr = (void *) cp;
\r
9772 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9773 2000 where engines sometimes don't see the initial command(s)
\r
9774 from WinBoard and hang. I don't understand how that can happen,
\r
9775 but the Sleep is harmless, so I've put it in. Others have also
\r
9776 reported what may be the same problem, so hopefully this will fix
\r
9777 it for them too. */
\r
9785 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9787 ChildProc *cp; int result;
\r
9789 cp = (ChildProc *) pr;
\r
9790 if (cp == NULL) return;
\r
9792 switch (cp->kind) {
\r
9794 /* TerminateProcess is considered harmful, so... */
\r
9795 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9796 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9797 /* The following doesn't work because the chess program
\r
9798 doesn't "have the same console" as WinBoard. Maybe
\r
9799 we could arrange for this even though neither WinBoard
\r
9800 nor the chess program uses a console for stdio? */
\r
9801 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9803 /* [AS] Special termination modes for misbehaving programs... */
\r
9804 if( signal == 9 ) {
\r
9805 result = TerminateProcess( cp->hProcess, 0 );
\r
9807 if ( appData.debugMode) {
\r
9808 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9811 else if( signal == 10 ) {
\r
9812 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9814 if( dw != WAIT_OBJECT_0 ) {
\r
9815 result = TerminateProcess( cp->hProcess, 0 );
\r
9817 if ( appData.debugMode) {
\r
9818 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9824 CloseHandle(cp->hProcess);
\r
9828 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9832 closesocket(cp->sock);
\r
9837 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9838 closesocket(cp->sock);
\r
9839 closesocket(cp->sock2);
\r
9847 InterruptChildProcess(ProcRef pr)
\r
9851 cp = (ChildProc *) pr;
\r
9852 if (cp == NULL) return;
\r
9853 switch (cp->kind) {
\r
9855 /* The following doesn't work because the chess program
\r
9856 doesn't "have the same console" as WinBoard. Maybe
\r
9857 we could arrange for this even though neither WinBoard
\r
9858 nor the chess program uses a console for stdio */
\r
9859 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9864 /* Can't interrupt */
\r
9868 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9875 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9877 char cmdLine[MSG_SIZ];
\r
9879 if (port[0] == NULLCHAR) {
\r
9880 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9882 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9884 return StartChildProcess(cmdLine, "", pr);
\r
9888 /* Code to open TCP sockets */
\r
9891 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9896 struct sockaddr_in sa, mysa;
\r
9897 struct hostent FAR *hp;
\r
9898 unsigned short uport;
\r
9899 WORD wVersionRequested;
\r
9902 /* Initialize socket DLL */
\r
9903 wVersionRequested = MAKEWORD(1, 1);
\r
9904 err = WSAStartup(wVersionRequested, &wsaData);
\r
9905 if (err != 0) return err;
\r
9908 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9909 err = WSAGetLastError();
\r
9914 /* Bind local address using (mostly) don't-care values.
\r
9916 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9917 mysa.sin_family = AF_INET;
\r
9918 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9919 uport = (unsigned short) 0;
\r
9920 mysa.sin_port = htons(uport);
\r
9921 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9922 == SOCKET_ERROR) {
\r
9923 err = WSAGetLastError();
\r
9928 /* Resolve remote host name */
\r
9929 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9930 if (!(hp = gethostbyname(host))) {
\r
9931 unsigned int b0, b1, b2, b3;
\r
9933 err = WSAGetLastError();
\r
9935 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9936 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9937 hp->h_addrtype = AF_INET;
\r
9939 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9940 hp->h_addr_list[0] = (char *) malloc(4);
\r
9941 hp->h_addr_list[0][0] = (char) b0;
\r
9942 hp->h_addr_list[0][1] = (char) b1;
\r
9943 hp->h_addr_list[0][2] = (char) b2;
\r
9944 hp->h_addr_list[0][3] = (char) b3;
\r
9950 sa.sin_family = hp->h_addrtype;
\r
9951 uport = (unsigned short) atoi(port);
\r
9952 sa.sin_port = htons(uport);
\r
9953 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9955 /* Make connection */
\r
9956 if (connect(s, (struct sockaddr *) &sa,
\r
9957 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9958 err = WSAGetLastError();
\r
9963 /* Prepare return value */
\r
9964 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9965 cp->kind = CPSock;
\r
9967 *pr = (ProcRef *) cp;
\r
9973 OpenCommPort(char *name, ProcRef *pr)
\r
9978 char fullname[MSG_SIZ];
\r
9980 if (*name != '\\')
\r
9981 sprintf(fullname, "\\\\.\\%s", name);
\r
9983 strcpy(fullname, name);
\r
9985 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9986 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9987 if (h == (HANDLE) -1) {
\r
9988 return GetLastError();
\r
9992 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9994 /* Accumulate characters until a 100ms pause, then parse */
\r
9995 ct.ReadIntervalTimeout = 100;
\r
9996 ct.ReadTotalTimeoutMultiplier = 0;
\r
9997 ct.ReadTotalTimeoutConstant = 0;
\r
9998 ct.WriteTotalTimeoutMultiplier = 0;
\r
9999 ct.WriteTotalTimeoutConstant = 0;
\r
10000 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10002 /* Prepare return value */
\r
10003 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10004 cp->kind = CPComm;
\r
10007 *pr = (ProcRef *) cp;
\r
10013 OpenLoopback(ProcRef *pr)
\r
10015 DisplayFatalError("Not implemented", 0, 1);
\r
10021 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10025 SOCKET s, s2, s3;
\r
10026 struct sockaddr_in sa, mysa;
\r
10027 struct hostent FAR *hp;
\r
10028 unsigned short uport;
\r
10029 WORD wVersionRequested;
\r
10032 char stderrPortStr[MSG_SIZ];
\r
10034 /* Initialize socket DLL */
\r
10035 wVersionRequested = MAKEWORD(1, 1);
\r
10036 err = WSAStartup(wVersionRequested, &wsaData);
\r
10037 if (err != 0) return err;
\r
10039 /* Resolve remote host name */
\r
10040 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10041 if (!(hp = gethostbyname(host))) {
\r
10042 unsigned int b0, b1, b2, b3;
\r
10044 err = WSAGetLastError();
\r
10046 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10047 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10048 hp->h_addrtype = AF_INET;
\r
10049 hp->h_length = 4;
\r
10050 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10051 hp->h_addr_list[0] = (char *) malloc(4);
\r
10052 hp->h_addr_list[0][0] = (char) b0;
\r
10053 hp->h_addr_list[0][1] = (char) b1;
\r
10054 hp->h_addr_list[0][2] = (char) b2;
\r
10055 hp->h_addr_list[0][3] = (char) b3;
\r
10061 sa.sin_family = hp->h_addrtype;
\r
10062 uport = (unsigned short) 514;
\r
10063 sa.sin_port = htons(uport);
\r
10064 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10066 /* Bind local socket to unused "privileged" port address
\r
10068 s = INVALID_SOCKET;
\r
10069 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10070 mysa.sin_family = AF_INET;
\r
10071 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10072 for (fromPort = 1023;; fromPort--) {
\r
10073 if (fromPort < 0) {
\r
10075 return WSAEADDRINUSE;
\r
10077 if (s == INVALID_SOCKET) {
\r
10078 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10079 err = WSAGetLastError();
\r
10084 uport = (unsigned short) fromPort;
\r
10085 mysa.sin_port = htons(uport);
\r
10086 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10087 == SOCKET_ERROR) {
\r
10088 err = WSAGetLastError();
\r
10089 if (err == WSAEADDRINUSE) continue;
\r
10093 if (connect(s, (struct sockaddr *) &sa,
\r
10094 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10095 err = WSAGetLastError();
\r
10096 if (err == WSAEADDRINUSE) {
\r
10107 /* Bind stderr local socket to unused "privileged" port address
\r
10109 s2 = INVALID_SOCKET;
\r
10110 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10111 mysa.sin_family = AF_INET;
\r
10112 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10113 for (fromPort = 1023;; fromPort--) {
\r
10114 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10115 if (fromPort < 0) {
\r
10116 (void) closesocket(s);
\r
10118 return WSAEADDRINUSE;
\r
10120 if (s2 == INVALID_SOCKET) {
\r
10121 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10122 err = WSAGetLastError();
\r
10128 uport = (unsigned short) fromPort;
\r
10129 mysa.sin_port = htons(uport);
\r
10130 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10131 == SOCKET_ERROR) {
\r
10132 err = WSAGetLastError();
\r
10133 if (err == WSAEADDRINUSE) continue;
\r
10134 (void) closesocket(s);
\r
10138 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10139 err = WSAGetLastError();
\r
10140 if (err == WSAEADDRINUSE) {
\r
10142 s2 = INVALID_SOCKET;
\r
10145 (void) closesocket(s);
\r
10146 (void) closesocket(s2);
\r
10152 prevStderrPort = fromPort; // remember port used
\r
10153 sprintf(stderrPortStr, "%d", fromPort);
\r
10155 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10156 err = WSAGetLastError();
\r
10157 (void) closesocket(s);
\r
10158 (void) closesocket(s2);
\r
10163 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10164 err = WSAGetLastError();
\r
10165 (void) closesocket(s);
\r
10166 (void) closesocket(s2);
\r
10170 if (*user == NULLCHAR) user = UserName();
\r
10171 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10172 err = WSAGetLastError();
\r
10173 (void) closesocket(s);
\r
10174 (void) closesocket(s2);
\r
10178 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10179 err = WSAGetLastError();
\r
10180 (void) closesocket(s);
\r
10181 (void) closesocket(s2);
\r
10186 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10187 err = WSAGetLastError();
\r
10188 (void) closesocket(s);
\r
10189 (void) closesocket(s2);
\r
10193 (void) closesocket(s2); /* Stop listening */
\r
10195 /* Prepare return value */
\r
10196 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10197 cp->kind = CPRcmd;
\r
10200 *pr = (ProcRef *) cp;
\r
10207 AddInputSource(ProcRef pr, int lineByLine,
\r
10208 InputCallback func, VOIDSTAR closure)
\r
10210 InputSource *is, *is2 = NULL;
\r
10211 ChildProc *cp = (ChildProc *) pr;
\r
10213 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10214 is->lineByLine = lineByLine;
\r
10216 is->closure = closure;
\r
10217 is->second = NULL;
\r
10218 is->next = is->buf;
\r
10219 if (pr == NoProc) {
\r
10220 is->kind = CPReal;
\r
10221 consoleInputSource = is;
\r
10223 is->kind = cp->kind;
\r
10225 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10226 we create all threads suspended so that the is->hThread variable can be
\r
10227 safely assigned, then let the threads start with ResumeThread.
\r
10229 switch (cp->kind) {
\r
10231 is->hFile = cp->hFrom;
\r
10232 cp->hFrom = NULL; /* now owned by InputThread */
\r
10234 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10235 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10239 is->hFile = cp->hFrom;
\r
10240 cp->hFrom = NULL; /* now owned by InputThread */
\r
10242 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10243 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10247 is->sock = cp->sock;
\r
10249 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10250 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10254 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10256 is->sock = cp->sock;
\r
10257 is->second = is2;
\r
10258 is2->sock = cp->sock2;
\r
10259 is2->second = is2;
\r
10261 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10262 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10264 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10265 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10269 if( is->hThread != NULL ) {
\r
10270 ResumeThread( is->hThread );
\r
10273 if( is2 != NULL && is2->hThread != NULL ) {
\r
10274 ResumeThread( is2->hThread );
\r
10278 return (InputSourceRef) is;
\r
10282 RemoveInputSource(InputSourceRef isr)
\r
10286 is = (InputSource *) isr;
\r
10287 is->hThread = NULL; /* tell thread to stop */
\r
10288 CloseHandle(is->hThread);
\r
10289 if (is->second != NULL) {
\r
10290 is->second->hThread = NULL;
\r
10291 CloseHandle(is->second->hThread);
\r
10295 int no_wrap(char *message, int count)
\r
10297 ConsoleOutput(message, count, FALSE);
\r
10302 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10305 int outCount = SOCKET_ERROR;
\r
10306 ChildProc *cp = (ChildProc *) pr;
\r
10307 static OVERLAPPED ovl;
\r
10308 static int line = 0;
\r
10310 if (pr == NoProc)
\r
10312 if (appData.noJoin || !appData.useInternalWrap)
\r
10313 return no_wrap(message, count);
\r
10316 int width = get_term_width();
\r
10317 int len = wrap(NULL, message, count, width, &line);
\r
10318 char *msg = malloc(len);
\r
10322 return no_wrap(message, count);
\r
10325 dbgchk = wrap(msg, message, count, width, &line);
\r
10326 if (dbgchk != len && appData.debugMode)
\r
10327 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
10328 ConsoleOutput(msg, len, FALSE);
\r
10335 if (ovl.hEvent == NULL) {
\r
10336 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10338 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10340 switch (cp->kind) {
\r
10343 outCount = send(cp->sock, message, count, 0);
\r
10344 if (outCount == SOCKET_ERROR) {
\r
10345 *outError = WSAGetLastError();
\r
10347 *outError = NO_ERROR;
\r
10352 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10353 &dOutCount, NULL)) {
\r
10354 *outError = NO_ERROR;
\r
10355 outCount = (int) dOutCount;
\r
10357 *outError = GetLastError();
\r
10362 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10363 &dOutCount, &ovl);
\r
10364 if (*outError == NO_ERROR) {
\r
10365 outCount = (int) dOutCount;
\r
10373 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10376 /* Ignore delay, not implemented for WinBoard */
\r
10377 return OutputToProcess(pr, message, count, outError);
\r
10382 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10383 char *buf, int count, int error)
\r
10385 DisplayFatalError("Not implemented", 0, 1);
\r
10388 /* see wgamelist.c for Game List functions */
\r
10389 /* see wedittags.c for Edit Tags functions */
\r
10396 char buf[MSG_SIZ];
\r
10399 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10400 f = fopen(buf, "r");
\r
10402 ProcessICSInitScript(f);
\r
10410 StartAnalysisClock()
\r
10412 if (analysisTimerEvent) return;
\r
10413 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10414 (UINT) 2000, NULL);
\r
10418 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10420 highlightInfo.sq[0].x = fromX;
\r
10421 highlightInfo.sq[0].y = fromY;
\r
10422 highlightInfo.sq[1].x = toX;
\r
10423 highlightInfo.sq[1].y = toY;
\r
10427 ClearHighlights()
\r
10429 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10430 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10434 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10436 premoveHighlightInfo.sq[0].x = fromX;
\r
10437 premoveHighlightInfo.sq[0].y = fromY;
\r
10438 premoveHighlightInfo.sq[1].x = toX;
\r
10439 premoveHighlightInfo.sq[1].y = toY;
\r
10443 ClearPremoveHighlights()
\r
10445 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10446 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10450 ShutDownFrontEnd()
\r
10452 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10453 DeleteClipboardTempFiles();
\r
10459 if (IsIconic(hwndMain))
\r
10460 ShowWindow(hwndMain, SW_RESTORE);
\r
10462 SetActiveWindow(hwndMain);
\r
10466 * Prototypes for animation support routines
\r
10468 static void ScreenSquare(int column, int row, POINT * pt);
\r
10469 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10470 POINT frames[], int * nFrames);
\r
10474 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10475 { // [HGM] atomic: animate blast wave
\r
10477 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10478 explodeInfo.fromX = fromX;
\r
10479 explodeInfo.fromY = fromY;
\r
10480 explodeInfo.toX = toX;
\r
10481 explodeInfo.toY = toY;
\r
10482 for(i=1; i<nFrames; i++) {
\r
10483 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10484 DrawPosition(FALSE, NULL);
\r
10485 Sleep(appData.animSpeed);
\r
10487 explodeInfo.radius = 0;
\r
10488 DrawPosition(TRUE, NULL);
\r
10491 #define kFactor 4
\r
10494 AnimateMove(board, fromX, fromY, toX, toY)
\r
10501 ChessSquare piece;
\r
10502 POINT start, finish, mid;
\r
10503 POINT frames[kFactor * 2 + 1];
\r
10506 if (!appData.animate) return;
\r
10507 if (doingSizing) return;
\r
10508 if (fromY < 0 || fromX < 0) return;
\r
10509 piece = board[fromY][fromX];
\r
10510 if (piece >= EmptySquare) return;
\r
10512 ScreenSquare(fromX, fromY, &start);
\r
10513 ScreenSquare(toX, toY, &finish);
\r
10515 /* All pieces except knights move in straight line */
\r
10516 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10517 mid.x = start.x + (finish.x - start.x) / 2;
\r
10518 mid.y = start.y + (finish.y - start.y) / 2;
\r
10520 /* Knight: make diagonal movement then straight */
\r
10521 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10522 mid.x = start.x + (finish.x - start.x) / 2;
\r
10523 mid.y = finish.y;
\r
10525 mid.x = finish.x;
\r
10526 mid.y = start.y + (finish.y - start.y) / 2;
\r
10530 /* Don't use as many frames for very short moves */
\r
10531 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10532 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10534 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10536 animInfo.from.x = fromX;
\r
10537 animInfo.from.y = fromY;
\r
10538 animInfo.to.x = toX;
\r
10539 animInfo.to.y = toY;
\r
10540 animInfo.lastpos = start;
\r
10541 animInfo.piece = piece;
\r
10542 for (n = 0; n < nFrames; n++) {
\r
10543 animInfo.pos = frames[n];
\r
10544 DrawPosition(FALSE, NULL);
\r
10545 animInfo.lastpos = animInfo.pos;
\r
10546 Sleep(appData.animSpeed);
\r
10548 animInfo.pos = finish;
\r
10549 DrawPosition(FALSE, NULL);
\r
10550 animInfo.piece = EmptySquare;
\r
10551 if(gameInfo.variant == VariantAtomic &&
\r
10552 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10553 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10556 /* Convert board position to corner of screen rect and color */
\r
10559 ScreenSquare(column, row, pt)
\r
10560 int column; int row; POINT * pt;
\r
10563 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10564 pt->y = lineGap + row * (squareSize + lineGap);
\r
10566 pt->x = lineGap + column * (squareSize + lineGap);
\r
10567 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10571 /* Generate a series of frame coords from start->mid->finish.
\r
10572 The movement rate doubles until the half way point is
\r
10573 reached, then halves back down to the final destination,
\r
10574 which gives a nice slow in/out effect. The algorithmn
\r
10575 may seem to generate too many intermediates for short
\r
10576 moves, but remember that the purpose is to attract the
\r
10577 viewers attention to the piece about to be moved and
\r
10578 then to where it ends up. Too few frames would be less
\r
10582 Tween(start, mid, finish, factor, frames, nFrames)
\r
10583 POINT * start; POINT * mid;
\r
10584 POINT * finish; int factor;
\r
10585 POINT frames[]; int * nFrames;
\r
10587 int n, fraction = 1, count = 0;
\r
10589 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10590 for (n = 0; n < factor; n++)
\r
10592 for (n = 0; n < factor; n++) {
\r
10593 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10594 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10596 fraction = fraction / 2;
\r
10600 frames[count] = *mid;
\r
10603 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10605 for (n = 0; n < factor; n++) {
\r
10606 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10607 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10609 fraction = fraction * 2;
\r
10611 *nFrames = count;
\r
10615 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10617 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10619 EvalGraphSet( first, last, current, pvInfoList );
\r
10622 void SetProgramStats( FrontEndProgramStats * stats )
\r
10624 EngineOutputUpdate( stats );
\r