2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
83 #include "frontend.h"
\r
84 #include "backend.h"
\r
85 #include "winboard.h"
\r
87 #include "wclipbrd.h"
\r
88 #include "woptions.h"
\r
89 #include "wsockerr.h"
\r
90 #include "defaults.h"
\r
94 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
97 void mysrandom(unsigned int seed);
\r
99 extern int whiteFlag, blackFlag;
\r
100 Boolean flipClock = FALSE;
\r
101 extern HANDLE chatHandle[];
\r
102 extern int ics_type;
\r
104 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
105 VOID NewVariantPopup(HWND hwnd);
\r
106 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
107 /*char*/int promoChar));
\r
108 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
109 void DisplayMove P((int moveNumber));
\r
110 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
111 void ChatPopUp P(());
\r
113 ChessSquare piece;
\r
114 POINT pos; /* window coordinates of current pos */
\r
115 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
116 POINT from; /* board coordinates of the piece's orig pos */
\r
117 POINT to; /* board coordinates of the piece's new pos */
\r
120 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
123 POINT start; /* window coordinates of start pos */
\r
124 POINT pos; /* window coordinates of current pos */
\r
125 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
126 POINT from; /* board coordinates of the piece's orig pos */
\r
129 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
132 POINT sq[2]; /* board coordinates of from, to squares */
\r
135 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
136 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 typedef struct { // [HGM] atomic
\r
139 int fromX, fromY, toX, toY, radius;
\r
142 static ExplodeInfo explodeInfo;
\r
144 /* Window class names */
\r
145 char szAppName[] = "WinBoard";
\r
146 char szConsoleName[] = "WBConsole";
\r
148 /* Title bar text */
\r
149 char szTitle[] = "WinBoard";
\r
150 char szConsoleTitle[] = "I C S Interaction";
\r
153 char *settingsFileName;
\r
154 BOOLEAN saveSettingsOnExit;
\r
155 char installDir[MSG_SIZ];
\r
157 BoardSize boardSize;
\r
158 BOOLEAN chessProgram;
\r
159 //static int boardX, boardY;
\r
160 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
161 static int squareSize, lineGap, minorSize;
\r
162 static int winW, winH;
\r
163 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
164 static int logoHeight = 0;
\r
165 static char messageText[MESSAGE_TEXT_MAX];
\r
166 static int clockTimerEvent = 0;
\r
167 static int loadGameTimerEvent = 0;
\r
168 static int analysisTimerEvent = 0;
\r
169 static DelayedEventCallback delayedTimerCallback;
\r
170 static int delayedTimerEvent = 0;
\r
171 static int buttonCount = 2;
\r
172 char *icsTextMenuString;
\r
174 char *firstChessProgramNames;
\r
175 char *secondChessProgramNames;
\r
177 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
179 #define PALETTESIZE 256
\r
181 HINSTANCE hInst; /* current instance */
\r
182 BOOLEAN alwaysOnTop = FALSE;
\r
184 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
185 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
187 ColorClass currentColorClass;
\r
189 HWND hCommPort = NULL; /* currently open comm port */
\r
190 static HWND hwndPause; /* pause button */
\r
191 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
192 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
193 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
194 explodeBrush, /* [HGM] atomic */
\r
195 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
196 static POINT gridEndpoints[(BOARD_RANKS + BOARD_FILES + 2) * 2];
\r
197 static DWORD gridVertexCounts[BOARD_RANKS + BOARD_FILES + 2];
\r
198 static HPEN gridPen = NULL;
\r
199 static HPEN highlightPen = NULL;
\r
200 static HPEN premovePen = NULL;
\r
201 static NPLOGPALETTE pLogPal;
\r
202 static BOOL paletteChanged = FALSE;
\r
203 static HICON iconWhite, iconBlack, iconCurrent;
\r
204 static int doingSizing = FALSE;
\r
205 static int lastSizing = 0;
\r
206 static int prevStderrPort;
\r
207 static HBITMAP userLogo;
\r
209 /* [AS] Support for background textures */
\r
210 #define BACK_TEXTURE_MODE_DISABLED 0
\r
211 #define BACK_TEXTURE_MODE_PLAIN 1
\r
212 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
214 static HBITMAP liteBackTexture = NULL;
\r
215 static HBITMAP darkBackTexture = NULL;
\r
216 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
217 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
218 static int backTextureSquareSize = 0;
\r
219 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_RANKS][BOARD_FILES];
\r
221 #if __GNUC__ && !defined(_winmajor)
\r
222 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
224 #if defined(_winmajor)
\r
225 #define oldDialog (_winmajor < 4)
\r
227 #define oldDialog 0
\r
231 char *defaultTextAttribs[] =
\r
233 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
234 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
244 int cliWidth, cliHeight;
\r
247 SizeInfo sizeInfo[] =
\r
249 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
250 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
251 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
252 { "petite", 33, 1, 1, 1, 0, 0 },
\r
253 { "slim", 37, 2, 1, 0, 0, 0 },
\r
254 { "small", 40, 2, 1, 0, 0, 0 },
\r
255 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
256 { "middling", 49, 2, 0, 0, 0, 0 },
\r
257 { "average", 54, 2, 0, 0, 0, 0 },
\r
258 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
259 { "medium", 64, 3, 0, 0, 0, 0 },
\r
260 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
261 { "large", 80, 3, 0, 0, 0, 0 },
\r
262 { "big", 87, 3, 0, 0, 0, 0 },
\r
263 { "huge", 95, 3, 0, 0, 0, 0 },
\r
264 { "giant", 108, 3, 0, 0, 0, 0 },
\r
265 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
266 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
267 { NULL, 0, 0, 0, 0, 0, 0 }
\r
270 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
271 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
273 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
274 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
275 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
276 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
277 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
278 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
279 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
280 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
281 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
282 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
283 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
284 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
285 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
286 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
287 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
288 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
289 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
290 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
293 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
302 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
303 #define N_BUTTONS 5
\r
305 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
307 {"<<", IDM_ToStart, NULL, NULL},
\r
308 {"<", IDM_Backward, NULL, NULL},
\r
309 {"P", IDM_Pause, NULL, NULL},
\r
310 {">", IDM_Forward, NULL, NULL},
\r
311 {">>", IDM_ToEnd, NULL, NULL},
\r
314 int tinyLayout = 0, smallLayout = 0;
\r
315 #define MENU_BAR_ITEMS 7
\r
316 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
317 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
318 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
322 MySound sounds[(int)NSoundClasses];
\r
323 MyTextAttribs textAttribs[(int)NColorClasses];
\r
325 MyColorizeAttribs colorizeAttribs[] = {
\r
326 { (COLORREF)0, 0, "Shout Text" },
\r
327 { (COLORREF)0, 0, "SShout/CShout" },
\r
328 { (COLORREF)0, 0, "Channel 1 Text" },
\r
329 { (COLORREF)0, 0, "Channel Text" },
\r
330 { (COLORREF)0, 0, "Kibitz Text" },
\r
331 { (COLORREF)0, 0, "Tell Text" },
\r
332 { (COLORREF)0, 0, "Challenge Text" },
\r
333 { (COLORREF)0, 0, "Request Text" },
\r
334 { (COLORREF)0, 0, "Seek Text" },
\r
335 { (COLORREF)0, 0, "Normal Text" },
\r
336 { (COLORREF)0, 0, "None" }
\r
341 static char *commentTitle;
\r
342 static char *commentText;
\r
343 static int commentIndex;
\r
344 static Boolean editComment = FALSE;
\r
347 char errorTitle[MSG_SIZ];
\r
348 char errorMessage[2*MSG_SIZ];
\r
349 HWND errorDialog = NULL;
\r
350 BOOLEAN moveErrorMessageUp = FALSE;
\r
351 BOOLEAN consoleEcho = TRUE;
\r
352 CHARFORMAT consoleCF;
\r
353 COLORREF consoleBackgroundColor;
\r
355 char *programVersion;
\r
361 typedef int CPKind;
\r
370 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
373 #define INPUT_SOURCE_BUF_SIZE 4096
\r
375 typedef struct _InputSource {
\r
382 char buf[INPUT_SOURCE_BUF_SIZE];
\r
386 InputCallback func;
\r
387 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
391 InputSource *consoleInputSource;
\r
396 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
397 VOID ConsoleCreate();
\r
399 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
400 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
401 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
402 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
404 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
405 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
406 void ParseIcsTextMenu(char *icsTextMenuString);
\r
407 VOID PopUpMoveDialog(char firstchar);
\r
408 VOID PopUpNameDialog(char firstchar);
\r
409 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
413 int GameListOptions();
\r
415 int dummy; // [HGM] for obsolete args
\r
417 HWND hwndMain = NULL; /* root window*/
\r
418 HWND hwndConsole = NULL;
\r
419 HWND commentDialog = NULL;
\r
420 HWND moveHistoryDialog = NULL;
\r
421 HWND evalGraphDialog = NULL;
\r
422 HWND engineOutputDialog = NULL;
\r
423 HWND gameListDialog = NULL;
\r
424 HWND editTagsDialog = NULL;
\r
426 int commentUp = FALSE;
\r
428 WindowPlacement wpMain;
\r
429 WindowPlacement wpConsole;
\r
430 WindowPlacement wpComment;
\r
431 WindowPlacement wpMoveHistory;
\r
432 WindowPlacement wpEvalGraph;
\r
433 WindowPlacement wpEngineOutput;
\r
434 WindowPlacement wpGameList;
\r
435 WindowPlacement wpTags;
\r
437 VOID EngineOptionsPopup(); // [HGM] settings
\r
439 VOID GothicPopUp(char *title, VariantClass variant);
\r
441 * Setting "frozen" should disable all user input other than deleting
\r
442 * the window. We do this while engines are initializing themselves.
\r
444 static int frozen = 0;
\r
445 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
451 if (frozen) return;
\r
453 hmenu = GetMenu(hwndMain);
\r
454 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
455 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
457 DrawMenuBar(hwndMain);
\r
460 /* Undo a FreezeUI */
\r
466 if (!frozen) return;
\r
468 hmenu = GetMenu(hwndMain);
\r
469 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
470 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
472 DrawMenuBar(hwndMain);
\r
475 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
477 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
483 #define JAWS_ALT_INTERCEPT
\r
484 #define JAWS_KB_NAVIGATION
\r
485 #define JAWS_MENU_ITEMS
\r
486 #define JAWS_SILENCE
\r
487 #define JAWS_REPLAY
\r
489 #define JAWS_COPYRIGHT
\r
490 #define JAWS_DELETE(X) X
\r
491 #define SAYMACHINEMOVE()
\r
495 /*---------------------------------------------------------------------------*\
\r
499 \*---------------------------------------------------------------------------*/
\r
502 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
503 LPSTR lpCmdLine, int nCmdShow)
\r
506 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
507 // INITCOMMONCONTROLSEX ex;
\r
511 LoadLibrary("RICHED32.DLL");
\r
512 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
514 if (!InitApplication(hInstance)) {
\r
517 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
523 // InitCommonControlsEx(&ex);
\r
524 InitCommonControls();
\r
526 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
527 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
528 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
530 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
532 while (GetMessage(&msg, /* message structure */
\r
533 NULL, /* handle of window receiving the message */
\r
534 0, /* lowest message to examine */
\r
535 0)) /* highest message to examine */
\r
538 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
539 // [HGM] navigate: switch between all windows with tab
\r
540 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
541 int i, currentElement = 0;
\r
543 // first determine what element of the chain we come from (if any)
\r
544 if(appData.icsActive) {
\r
545 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
546 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
548 if(engineOutputDialog && EngineOutputIsUp()) {
\r
549 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
550 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
552 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
553 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
555 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
556 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
557 if(msg.hwnd == e1) currentElement = 2; else
\r
558 if(msg.hwnd == e2) currentElement = 3; else
\r
559 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
560 if(msg.hwnd == mh) currentElement = 4; else
\r
561 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
562 if(msg.hwnd == hText) currentElement = 5; else
\r
563 if(msg.hwnd == hInput) currentElement = 6; else
\r
564 for (i = 0; i < N_BUTTONS; i++) {
\r
565 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
568 // determine where to go to
\r
569 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
571 currentElement = (currentElement + direction) % 7;
\r
572 switch(currentElement) {
\r
574 h = hwndMain; break; // passing this case always makes the loop exit
\r
576 h = buttonDesc[0].hwnd; break; // could be NULL
\r
578 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
581 if(!EngineOutputIsUp()) continue;
\r
584 if(!MoveHistoryIsUp()) continue;
\r
586 // case 6: // input to eval graph does not seem to get here!
\r
587 // if(!EvalGraphIsUp()) continue;
\r
588 // h = evalGraphDialog; break;
\r
590 if(!appData.icsActive) continue;
\r
594 if(!appData.icsActive) continue;
\r
600 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
601 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
604 continue; // this message now has been processed
\r
608 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
609 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
610 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
611 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
612 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
613 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
614 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
615 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
616 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
617 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
618 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
619 for(i=0; i<MAX_CHAT; i++)
\r
620 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
623 if(done) continue; // [HGM] chat: end patch
\r
624 TranslateMessage(&msg); /* Translates virtual key codes */
\r
625 DispatchMessage(&msg); /* Dispatches message to window */
\r
630 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
633 /*---------------------------------------------------------------------------*\
\r
635 * Initialization functions
\r
637 \*---------------------------------------------------------------------------*/
\r
641 { // update user logo if necessary
\r
642 static char oldUserName[MSG_SIZ], *curName;
\r
644 if(appData.autoLogo) {
\r
645 curName = UserName();
\r
646 if(strcmp(curName, oldUserName)) {
\r
647 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
648 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
649 strcpy(oldUserName, curName);
\r
655 InitApplication(HINSTANCE hInstance)
\r
659 /* Fill in window class structure with parameters that describe the */
\r
662 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
663 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
664 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
665 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
666 wc.hInstance = hInstance; /* Owner of this class */
\r
667 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
668 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
669 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
670 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
671 wc.lpszClassName = szAppName; /* Name to register as */
\r
673 /* Register the window class and return success/failure code. */
\r
674 if (!RegisterClass(&wc)) return FALSE;
\r
676 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
677 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
679 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
680 wc.hInstance = hInstance;
\r
681 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
682 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
683 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
684 wc.lpszMenuName = NULL;
\r
685 wc.lpszClassName = szConsoleName;
\r
687 if (!RegisterClass(&wc)) return FALSE;
\r
692 /* Set by InitInstance, used by EnsureOnScreen */
\r
693 int screenHeight, screenWidth;
\r
696 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
698 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
699 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
700 if (*x > screenWidth - 32) *x = 0;
\r
701 if (*y > screenHeight - 32) *y = 0;
\r
702 if (*x < minX) *x = minX;
\r
703 if (*y < minY) *y = minY;
\r
707 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
709 HWND hwnd; /* Main window handle. */
\r
711 WINDOWPLACEMENT wp;
\r
714 hInst = hInstance; /* Store instance handle in our global variable */
\r
716 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
717 *filepart = NULLCHAR;
\r
719 GetCurrentDirectory(MSG_SIZ, installDir);
\r
721 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
722 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
723 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
724 if (appData.debugMode) {
\r
725 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
726 setbuf(debugFP, NULL);
\r
731 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
732 // InitEngineUCI( installDir, &second );
\r
734 /* Create a main window for this application instance. */
\r
735 hwnd = CreateWindow(szAppName, szTitle,
\r
736 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
737 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
738 NULL, NULL, hInstance, NULL);
\r
741 /* If window could not be created, return "failure" */
\r
746 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
747 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
748 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
750 if (first.programLogo == NULL && appData.debugMode) {
\r
751 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
753 } else if(appData.autoLogo) {
\r
754 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
756 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
757 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
761 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
762 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
764 if (second.programLogo == NULL && appData.debugMode) {
\r
765 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
767 } else if(appData.autoLogo) {
\r
769 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
770 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
771 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
773 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
774 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
775 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
781 iconWhite = LoadIcon(hInstance, "icon_white");
\r
782 iconBlack = LoadIcon(hInstance, "icon_black");
\r
783 iconCurrent = iconWhite;
\r
784 InitDrawingColors();
\r
785 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
786 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
787 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
788 /* Compute window size for each board size, and use the largest
\r
789 size that fits on this screen as the default. */
\r
790 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
791 if (boardSize == (BoardSize)-1 &&
\r
792 winH <= screenHeight
\r
793 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
794 && winW <= screenWidth) {
\r
795 boardSize = (BoardSize)ibs;
\r
799 InitDrawingSizes(boardSize, 0);
\r
801 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
803 /* [AS] Load textures if specified */
\r
804 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
806 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
807 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
808 liteBackTextureMode = appData.liteBackTextureMode;
\r
810 if (liteBackTexture == NULL && appData.debugMode) {
\r
811 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
815 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
816 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
817 darkBackTextureMode = appData.darkBackTextureMode;
\r
819 if (darkBackTexture == NULL && appData.debugMode) {
\r
820 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
824 mysrandom( (unsigned) time(NULL) );
\r
826 /* [AS] Restore layout */
\r
827 if( wpMoveHistory.visible ) {
\r
828 MoveHistoryPopUp();
\r
831 if( wpEvalGraph.visible ) {
\r
835 if( wpEngineOutput.visible ) {
\r
836 EngineOutputPopUp();
\r
841 /* Make the window visible; update its client area; and return "success" */
\r
842 EnsureOnScreen(&wpMain.x, &wpMain.y, minX, minY);
\r
843 wp.length = sizeof(WINDOWPLACEMENT);
\r
845 wp.showCmd = nCmdShow;
\r
846 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
847 wp.rcNormalPosition.left = wpMain.x;
\r
848 wp.rcNormalPosition.right = wpMain.x + wpMain.width;
\r
849 wp.rcNormalPosition.top = wpMain.y;
\r
850 wp.rcNormalPosition.bottom = wpMain.y + wpMain.height;
\r
851 SetWindowPlacement(hwndMain, &wp);
\r
853 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
854 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
858 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
859 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
861 ShowWindow(hwndConsole, nCmdShow);
\r
863 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
864 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
872 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
873 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
874 ArgSettingsFilename,
\r
875 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
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_FILES ||
\r
2171 appData.NrRanks > BOARD_RANKS )
\r
2172 DisplayFatalError("Recompile with BOARD_RANKS or BOARD_FILES, 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_FILES*BOARD_HEIGHT) {
\r
4162 backTextureBoardSize = BOARD_WIDTH+BOARD_FILES*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
7114 EndDialog(hDlg, TRUE);
\r
7118 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7119 gameMode != Training) {
\r
7120 DisplayMoveError("Displayed move is not current");
\r
7122 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7123 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7124 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7125 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7126 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7127 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7128 if (gameMode != Training)
\r
7129 forwardMostMove = currentMove;
\r
7130 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7132 DisplayMoveError("Could not parse move");
\r
7135 EndDialog(hDlg, TRUE);
\r
7138 EndDialog(hDlg, FALSE);
\r
7149 PopUpMoveDialog(char firstchar)
\r
7153 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7154 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7155 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7156 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7157 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7158 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7159 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7160 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7161 gameMode == Training) {
\r
7162 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7163 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7164 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7165 FreeProcInstance(lpProc);
\r
7169 /*---------------------------------------------------------------------------*\
\r
7171 * Type-in name dialog functions
\r
7173 \*---------------------------------------------------------------------------*/
\r
7176 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7178 char move[MSG_SIZ];
\r
7181 switch (message) {
\r
7182 case WM_INITDIALOG:
\r
7183 move[0] = (char) lParam;
\r
7184 move[1] = NULLCHAR;
\r
7185 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7186 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7187 SetWindowText(hInput, move);
\r
7189 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7193 switch (LOWORD(wParam)) {
\r
7195 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7196 appData.userName = strdup(move);
\r
7199 EndDialog(hDlg, TRUE);
\r
7202 EndDialog(hDlg, FALSE);
\r
7213 PopUpNameDialog(char firstchar)
\r
7217 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7218 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7219 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7220 FreeProcInstance(lpProc);
\r
7223 /*---------------------------------------------------------------------------*\
\r
7227 \*---------------------------------------------------------------------------*/
\r
7229 /* Nonmodal error box */
\r
7230 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7231 WPARAM wParam, LPARAM lParam);
\r
7234 ErrorPopUp(char *title, char *content)
\r
7238 BOOLEAN modal = hwndMain == NULL;
\r
7256 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7257 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7260 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7262 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7263 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7264 hwndMain, (DLGPROC)lpProc);
\r
7265 FreeProcInstance(lpProc);
\r
7272 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7273 if (errorDialog == NULL) return;
\r
7274 DestroyWindow(errorDialog);
\r
7275 errorDialog = NULL;
\r
7279 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7284 switch (message) {
\r
7285 case WM_INITDIALOG:
\r
7286 GetWindowRect(hDlg, &rChild);
\r
7289 SetWindowPos(hDlg, NULL, rChild.left,
\r
7290 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7291 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7295 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7296 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7297 and it doesn't work when you resize the dialog.
\r
7298 For now, just give it a default position.
\r
7300 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7302 errorDialog = hDlg;
\r
7303 SetWindowText(hDlg, errorTitle);
\r
7304 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7305 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7309 switch (LOWORD(wParam)) {
\r
7312 if (errorDialog == hDlg) errorDialog = NULL;
\r
7313 DestroyWindow(hDlg);
\r
7325 HWND gothicDialog = NULL;
\r
7328 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7332 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7334 switch (message) {
\r
7335 case WM_INITDIALOG:
\r
7336 GetWindowRect(hDlg, &rChild);
\r
7338 SetWindowPos(hDlg, NULL, wpMain.x, wpMain.y-height, wpMain.width, height,
\r
7342 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7343 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7344 and it doesn't work when you resize the dialog.
\r
7345 For now, just give it a default position.
\r
7347 gothicDialog = hDlg;
\r
7348 SetWindowText(hDlg, errorTitle);
\r
7349 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7350 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7354 switch (LOWORD(wParam)) {
\r
7357 if (errorDialog == hDlg) errorDialog = NULL;
\r
7358 DestroyWindow(hDlg);
\r
7370 GothicPopUp(char *title, VariantClass variant)
\r
7373 static char *lastTitle;
\r
7375 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7376 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7378 if(lastTitle != title && gothicDialog != NULL) {
\r
7379 DestroyWindow(gothicDialog);
\r
7380 gothicDialog = NULL;
\r
7382 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7383 title = lastTitle;
\r
7384 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7385 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7386 hwndMain, (DLGPROC)lpProc);
\r
7387 FreeProcInstance(lpProc);
\r
7392 /*---------------------------------------------------------------------------*\
\r
7394 * Ics Interaction console functions
\r
7396 \*---------------------------------------------------------------------------*/
\r
7398 #define HISTORY_SIZE 64
\r
7399 static char *history[HISTORY_SIZE];
\r
7400 int histIn = 0, histP = 0;
\r
7403 SaveInHistory(char *cmd)
\r
7405 if (history[histIn] != NULL) {
\r
7406 free(history[histIn]);
\r
7407 history[histIn] = NULL;
\r
7409 if (*cmd == NULLCHAR) return;
\r
7410 history[histIn] = StrSave(cmd);
\r
7411 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7412 if (history[histIn] != NULL) {
\r
7413 free(history[histIn]);
\r
7414 history[histIn] = NULL;
\r
7420 PrevInHistory(char *cmd)
\r
7423 if (histP == histIn) {
\r
7424 if (history[histIn] != NULL) free(history[histIn]);
\r
7425 history[histIn] = StrSave(cmd);
\r
7427 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7428 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7430 return history[histP];
\r
7436 if (histP == histIn) return NULL;
\r
7437 histP = (histP + 1) % HISTORY_SIZE;
\r
7438 return history[histP];
\r
7445 BOOLEAN immediate;
\r
7446 } IcsTextMenuEntry;
\r
7447 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7448 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7451 ParseIcsTextMenu(char *icsTextMenuString)
\r
7454 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7455 char *p = icsTextMenuString;
\r
7456 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7459 if (e->command != NULL) {
\r
7461 e->command = NULL;
\r
7465 e = icsTextMenuEntry;
\r
7466 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7467 if (*p == ';' || *p == '\n') {
\r
7468 e->item = strdup("-");
\r
7469 e->command = NULL;
\r
7471 } else if (*p == '-') {
\r
7472 e->item = strdup("-");
\r
7473 e->command = NULL;
\r
7477 char *q, *r, *s, *t;
\r
7479 q = strchr(p, ',');
\r
7480 if (q == NULL) break;
\r
7482 r = strchr(q + 1, ',');
\r
7483 if (r == NULL) break;
\r
7485 s = strchr(r + 1, ',');
\r
7486 if (s == NULL) break;
\r
7489 t = strchr(s + 1, c);
\r
7492 t = strchr(s + 1, c);
\r
7494 if (t != NULL) *t = NULLCHAR;
\r
7495 e->item = strdup(p);
\r
7496 e->command = strdup(q + 1);
\r
7497 e->getname = *(r + 1) != '0';
\r
7498 e->immediate = *(s + 1) != '0';
\r
7502 if (t == NULL) break;
\r
7511 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7515 hmenu = LoadMenu(hInst, "TextMenu");
\r
7516 h = GetSubMenu(hmenu, 0);
\r
7518 if (strcmp(e->item, "-") == 0) {
\r
7519 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7521 if (e->item[0] == '|') {
\r
7522 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7523 IDM_CommandX + i, &e->item[1]);
\r
7525 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7534 WNDPROC consoleTextWindowProc;
\r
7537 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7539 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7540 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7544 SetWindowText(hInput, command);
\r
7546 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7548 sel.cpMin = 999999;
\r
7549 sel.cpMax = 999999;
\r
7550 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7555 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7556 if (sel.cpMin == sel.cpMax) {
\r
7557 /* Expand to surrounding word */
\r
7560 tr.chrg.cpMax = sel.cpMin;
\r
7561 tr.chrg.cpMin = --sel.cpMin;
\r
7562 if (sel.cpMin < 0) break;
\r
7563 tr.lpstrText = name;
\r
7564 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7565 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7569 tr.chrg.cpMin = sel.cpMax;
\r
7570 tr.chrg.cpMax = ++sel.cpMax;
\r
7571 tr.lpstrText = name;
\r
7572 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7573 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7576 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7577 MessageBeep(MB_ICONEXCLAMATION);
\r
7581 tr.lpstrText = name;
\r
7582 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7584 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7585 MessageBeep(MB_ICONEXCLAMATION);
\r
7588 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7591 sprintf(buf, "%s %s", command, name);
\r
7592 SetWindowText(hInput, buf);
\r
7593 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7595 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7596 SetWindowText(hInput, buf);
\r
7597 sel.cpMin = 999999;
\r
7598 sel.cpMax = 999999;
\r
7599 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7605 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7610 switch (message) {
\r
7612 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7615 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7618 sel.cpMin = 999999;
\r
7619 sel.cpMax = 999999;
\r
7620 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7621 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7626 if(wParam != '\022') {
\r
7627 if (wParam == '\t') {
\r
7628 if (GetKeyState(VK_SHIFT) < 0) {
\r
7630 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7631 if (buttonDesc[0].hwnd) {
\r
7632 SetFocus(buttonDesc[0].hwnd);
\r
7634 SetFocus(hwndMain);
\r
7638 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7641 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7642 JAWS_DELETE( SetFocus(hInput); )
\r
7643 SendMessage(hInput, message, wParam, lParam);
\r
7646 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7647 case WM_RBUTTONUP:
\r
7648 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7649 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7650 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7653 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7654 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7655 if (sel.cpMin == sel.cpMax) {
\r
7656 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7657 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7659 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7660 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7662 pt.x = LOWORD(lParam);
\r
7663 pt.y = HIWORD(lParam);
\r
7664 MenuPopup(hwnd, pt, hmenu, -1);
\r
7668 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7670 return SendMessage(hInput, message, wParam, lParam);
\r
7671 case WM_MBUTTONDOWN:
\r
7672 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7673 case WM_RBUTTONDOWN:
\r
7674 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7675 /* Move selection here if it was empty */
\r
7677 pt.x = LOWORD(lParam);
\r
7678 pt.y = HIWORD(lParam);
\r
7679 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7680 if (sel.cpMin == sel.cpMax) {
\r
7681 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7682 sel.cpMax = sel.cpMin;
\r
7683 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7685 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7689 switch (LOWORD(wParam)) {
\r
7690 case IDM_QuickPaste:
\r
7692 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7693 if (sel.cpMin == sel.cpMax) {
\r
7694 MessageBeep(MB_ICONEXCLAMATION);
\r
7697 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7698 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7699 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7704 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7707 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7710 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7714 int i = LOWORD(wParam) - IDM_CommandX;
\r
7715 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7716 icsTextMenuEntry[i].command != NULL) {
\r
7717 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7718 icsTextMenuEntry[i].getname,
\r
7719 icsTextMenuEntry[i].immediate);
\r
7727 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7730 WNDPROC consoleInputWindowProc;
\r
7733 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7735 char buf[MSG_SIZ];
\r
7737 static BOOL sendNextChar = FALSE;
\r
7738 static BOOL quoteNextChar = FALSE;
\r
7739 InputSource *is = consoleInputSource;
\r
7743 switch (message) {
\r
7745 if (!appData.localLineEditing || sendNextChar) {
\r
7746 is->buf[0] = (CHAR) wParam;
\r
7748 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7749 sendNextChar = FALSE;
\r
7752 if (quoteNextChar) {
\r
7753 buf[0] = (char) wParam;
\r
7754 buf[1] = NULLCHAR;
\r
7755 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7756 quoteNextChar = FALSE;
\r
7760 case '\r': /* Enter key */
\r
7761 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7762 if (consoleEcho) SaveInHistory(is->buf);
\r
7763 is->buf[is->count++] = '\n';
\r
7764 is->buf[is->count] = NULLCHAR;
\r
7765 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7766 if (consoleEcho) {
\r
7767 ConsoleOutput(is->buf, is->count, TRUE);
\r
7768 } else if (appData.localLineEditing) {
\r
7769 ConsoleOutput("\n", 1, TRUE);
\r
7772 case '\033': /* Escape key */
\r
7773 SetWindowText(hwnd, "");
\r
7774 cf.cbSize = sizeof(CHARFORMAT);
\r
7775 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7776 if (consoleEcho) {
\r
7777 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7779 cf.crTextColor = COLOR_ECHOOFF;
\r
7781 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7782 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7784 case '\t': /* Tab key */
\r
7785 if (GetKeyState(VK_SHIFT) < 0) {
\r
7787 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7790 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7791 if (buttonDesc[0].hwnd) {
\r
7792 SetFocus(buttonDesc[0].hwnd);
\r
7794 SetFocus(hwndMain);
\r
7798 case '\023': /* Ctrl+S */
\r
7799 sendNextChar = TRUE;
\r
7801 case '\021': /* Ctrl+Q */
\r
7802 quoteNextChar = TRUE;
\r
7812 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7813 p = PrevInHistory(buf);
\r
7815 SetWindowText(hwnd, p);
\r
7816 sel.cpMin = 999999;
\r
7817 sel.cpMax = 999999;
\r
7818 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7823 p = NextInHistory();
\r
7825 SetWindowText(hwnd, p);
\r
7826 sel.cpMin = 999999;
\r
7827 sel.cpMax = 999999;
\r
7828 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7834 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7838 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7842 case WM_MBUTTONDOWN:
\r
7843 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7844 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7846 case WM_RBUTTONUP:
\r
7847 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7848 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7849 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7853 hmenu = LoadMenu(hInst, "InputMenu");
\r
7854 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7855 if (sel.cpMin == sel.cpMax) {
\r
7856 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7857 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7859 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7860 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7862 pt.x = LOWORD(lParam);
\r
7863 pt.y = HIWORD(lParam);
\r
7864 MenuPopup(hwnd, pt, hmenu, -1);
\r
7868 switch (LOWORD(wParam)) {
\r
7870 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7872 case IDM_SelectAll:
\r
7874 sel.cpMax = -1; /*999999?*/
\r
7875 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7878 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7881 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7884 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7889 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7892 #define CO_MAX 100000
\r
7893 #define CO_TRIM 1000
\r
7896 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7898 static SnapData sd;
\r
7899 HWND hText, hInput;
\r
7901 static int sizeX, sizeY;
\r
7902 int newSizeX, newSizeY;
\r
7906 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7907 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7909 switch (message) {
\r
7911 if (((NMHDR*)lParam)->code == EN_LINK)
\r
7913 ENLINK *pLink = (ENLINK*)lParam;
\r
7914 if (pLink->msg == WM_LBUTTONUP)
\r
7918 tr.chrg = pLink->chrg;
\r
7919 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
7920 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
7921 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
7922 free(tr.lpstrText);
\r
7926 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7927 hwndConsole = hDlg;
\r
7929 consoleTextWindowProc = (WNDPROC)
\r
7930 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7931 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7932 consoleInputWindowProc = (WNDPROC)
\r
7933 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7934 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7935 Colorize(ColorNormal, TRUE);
\r
7936 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7937 ChangedConsoleFont();
\r
7938 GetClientRect(hDlg, &rect);
\r
7939 sizeX = rect.right;
\r
7940 sizeY = rect.bottom;
\r
7941 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
7942 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
7943 WINDOWPLACEMENT wp;
\r
7944 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7945 wp.length = sizeof(WINDOWPLACEMENT);
\r
7947 wp.showCmd = SW_SHOW;
\r
7948 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7949 wp.rcNormalPosition.left = wpConsole.x;
\r
7950 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7951 wp.rcNormalPosition.top = wpConsole.y;
\r
7952 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7953 SetWindowPlacement(hDlg, &wp);
\r
7956 // [HGM] Chessknight's change 2004-07-13
\r
7957 else { /* Determine Defaults */
\r
7958 WINDOWPLACEMENT wp;
\r
7959 wpConsole.x = wpMain.width + 1;
\r
7960 wpConsole.y = wpMain.y;
\r
7961 wpConsole.width = screenWidth - wpMain.width;
\r
7962 wpConsole.height = wpMain.height;
\r
7963 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
7964 wp.length = sizeof(WINDOWPLACEMENT);
\r
7966 wp.showCmd = SW_SHOW;
\r
7967 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7968 wp.rcNormalPosition.left = wpConsole.x;
\r
7969 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
7970 wp.rcNormalPosition.top = wpConsole.y;
\r
7971 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
7972 SetWindowPlacement(hDlg, &wp);
\r
7975 // Allow hText to highlight URLs and send notifications on them
\r
7976 wMask = (WORD) SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
7977 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
7978 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
7979 SetWindowLong(hText, GWL_USERDATA, 79); // initialize the text window's width
\r
7993 if (IsIconic(hDlg)) break;
\r
7994 newSizeX = LOWORD(lParam);
\r
7995 newSizeY = HIWORD(lParam);
\r
7996 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7997 RECT rectText, rectInput;
\r
7999 int newTextHeight, newTextWidth;
\r
8000 GetWindowRect(hText, &rectText);
\r
8001 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8002 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8003 if (newTextHeight < 0) {
\r
8004 newSizeY += -newTextHeight;
\r
8005 newTextHeight = 0;
\r
8007 SetWindowPos(hText, NULL, 0, 0,
\r
8008 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8009 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8010 pt.x = rectInput.left;
\r
8011 pt.y = rectInput.top + newSizeY - sizeY;
\r
8012 ScreenToClient(hDlg, &pt);
\r
8013 SetWindowPos(hInput, NULL,
\r
8014 pt.x, pt.y, /* needs client coords */
\r
8015 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8016 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8022 case WM_GETMINMAXINFO:
\r
8023 /* Prevent resizing window too small */
\r
8024 mmi = (MINMAXINFO *) lParam;
\r
8025 mmi->ptMinTrackSize.x = 100;
\r
8026 mmi->ptMinTrackSize.y = 100;
\r
8029 /* [AS] Snapping */
\r
8030 case WM_ENTERSIZEMOVE:
\r
8031 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8034 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8037 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8039 case WM_EXITSIZEMOVE:
\r
8040 UpdateICSWidth(hText);
\r
8041 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8044 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8052 if (hwndConsole) return;
\r
8053 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8054 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8059 ConsoleOutput(char* data, int length, int forceVisible)
\r
8064 char buf[CO_MAX+1];
\r
8067 static int delayLF = 0;
\r
8068 CHARRANGE savesel, sel;
\r
8070 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8078 while (length--) {
\r
8086 } else if (*p == '\007') {
\r
8087 MyPlaySound(&sounds[(int)SoundBell]);
\r
8094 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8095 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8096 /* Save current selection */
\r
8097 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8098 exlen = GetWindowTextLength(hText);
\r
8099 /* Find out whether current end of text is visible */
\r
8100 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8101 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8102 /* Trim existing text if it's too long */
\r
8103 if (exlen + (q - buf) > CO_MAX) {
\r
8104 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8107 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8108 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8110 savesel.cpMin -= trim;
\r
8111 savesel.cpMax -= trim;
\r
8112 if (exlen < 0) exlen = 0;
\r
8113 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8114 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8116 /* Append the new text */
\r
8117 sel.cpMin = exlen;
\r
8118 sel.cpMax = exlen;
\r
8119 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8120 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8121 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8122 if (forceVisible || exlen == 0 ||
\r
8123 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8124 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8125 /* Scroll to make new end of text visible if old end of text
\r
8126 was visible or new text is an echo of user typein */
\r
8127 sel.cpMin = 9999999;
\r
8128 sel.cpMax = 9999999;
\r
8129 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8130 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8131 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8132 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8134 if (savesel.cpMax == exlen || forceVisible) {
\r
8135 /* Move insert point to new end of text if it was at the old
\r
8136 end of text or if the new text is an echo of user typein */
\r
8137 sel.cpMin = 9999999;
\r
8138 sel.cpMax = 9999999;
\r
8139 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8141 /* Restore previous selection */
\r
8142 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8144 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8151 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8155 COLORREF oldFg, oldBg;
\r
8159 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8161 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8162 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8163 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8166 rect.right = x + squareSize;
\r
8168 rect.bottom = y + squareSize;
\r
8171 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8172 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8173 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8174 &rect, str, strlen(str), NULL);
\r
8176 (void) SetTextColor(hdc, oldFg);
\r
8177 (void) SetBkColor(hdc, oldBg);
\r
8178 (void) SelectObject(hdc, oldFont);
\r
8182 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8183 RECT *rect, char *color, char *flagFell)
\r
8187 COLORREF oldFg, oldBg;
\r
8190 if (appData.clockMode) {
\r
8192 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8194 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8201 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8202 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8204 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8205 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8207 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8211 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8212 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8213 rect, str, strlen(str), NULL);
\r
8214 if(logoHeight > 0 && appData.clockMode) {
\r
8216 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8217 r.top = rect->top + logoHeight/2;
\r
8218 r.left = rect->left;
\r
8219 r.right = rect->right;
\r
8220 r.bottom = rect->bottom;
\r
8221 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8222 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8223 &r, str, strlen(str), NULL);
\r
8225 (void) SetTextColor(hdc, oldFg);
\r
8226 (void) SetBkColor(hdc, oldBg);
\r
8227 (void) SelectObject(hdc, oldFont);
\r
8232 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8238 if( count <= 0 ) {
\r
8239 if (appData.debugMode) {
\r
8240 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8243 return ERROR_INVALID_USER_BUFFER;
\r
8246 ResetEvent(ovl->hEvent);
\r
8247 ovl->Offset = ovl->OffsetHigh = 0;
\r
8248 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8252 err = GetLastError();
\r
8253 if (err == ERROR_IO_PENDING) {
\r
8254 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8258 err = GetLastError();
\r
8265 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8270 ResetEvent(ovl->hEvent);
\r
8271 ovl->Offset = ovl->OffsetHigh = 0;
\r
8272 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8276 err = GetLastError();
\r
8277 if (err == ERROR_IO_PENDING) {
\r
8278 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8282 err = GetLastError();
\r
8288 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8289 void CheckForInputBufferFull( InputSource * is )
\r
8291 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8292 /* Look for end of line */
\r
8293 char * p = is->buf;
\r
8295 while( p < is->next && *p != '\n' ) {
\r
8299 if( p >= is->next ) {
\r
8300 if (appData.debugMode) {
\r
8301 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8304 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8305 is->count = (DWORD) -1;
\r
8306 is->next = is->buf;
\r
8312 InputThread(LPVOID arg)
\r
8317 is = (InputSource *) arg;
\r
8318 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8319 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8320 while (is->hThread != NULL) {
\r
8321 is->error = DoReadFile(is->hFile, is->next,
\r
8322 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8323 &is->count, &ovl);
\r
8324 if (is->error == NO_ERROR) {
\r
8325 is->next += is->count;
\r
8327 if (is->error == ERROR_BROKEN_PIPE) {
\r
8328 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8331 is->count = (DWORD) -1;
\r
8332 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8337 CheckForInputBufferFull( is );
\r
8339 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8341 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8343 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8346 CloseHandle(ovl.hEvent);
\r
8347 CloseHandle(is->hFile);
\r
8349 if (appData.debugMode) {
\r
8350 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8357 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8359 NonOvlInputThread(LPVOID arg)
\r
8366 is = (InputSource *) arg;
\r
8367 while (is->hThread != NULL) {
\r
8368 is->error = ReadFile(is->hFile, is->next,
\r
8369 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8370 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8371 if (is->error == NO_ERROR) {
\r
8372 /* Change CRLF to LF */
\r
8373 if (is->next > is->buf) {
\r
8375 i = is->count + 1;
\r
8383 if (prev == '\r' && *p == '\n') {
\r
8395 if (is->error == ERROR_BROKEN_PIPE) {
\r
8396 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8399 is->count = (DWORD) -1;
\r
8403 CheckForInputBufferFull( is );
\r
8405 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8407 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8409 if (is->count < 0) break; /* Quit on error */
\r
8411 CloseHandle(is->hFile);
\r
8416 SocketInputThread(LPVOID arg)
\r
8420 is = (InputSource *) arg;
\r
8421 while (is->hThread != NULL) {
\r
8422 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8423 if ((int)is->count == SOCKET_ERROR) {
\r
8424 is->count = (DWORD) -1;
\r
8425 is->error = WSAGetLastError();
\r
8427 is->error = NO_ERROR;
\r
8428 is->next += is->count;
\r
8429 if (is->count == 0 && is->second == is) {
\r
8430 /* End of file on stderr; quit with no message */
\r
8434 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8436 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8438 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8444 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8448 is = (InputSource *) lParam;
\r
8449 if (is->lineByLine) {
\r
8450 /* Feed in lines one by one */
\r
8451 char *p = is->buf;
\r
8453 while (q < is->next) {
\r
8454 if (*q++ == '\n') {
\r
8455 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8460 /* Move any partial line to the start of the buffer */
\r
8462 while (p < is->next) {
\r
8467 if (is->error != NO_ERROR || is->count == 0) {
\r
8468 /* Notify backend of the error. Note: If there was a partial
\r
8469 line at the end, it is not flushed through. */
\r
8470 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8473 /* Feed in the whole chunk of input at once */
\r
8474 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8475 is->next = is->buf;
\r
8479 /*---------------------------------------------------------------------------*\
\r
8481 * Menu enables. Used when setting various modes.
\r
8483 \*---------------------------------------------------------------------------*/
\r
8491 GreyRevert(Boolean grey)
\r
8492 { // [HGM] vari: for retracting variations in local mode
\r
8493 HMENU hmenu = GetMenu(hwndMain);
\r
8494 EnableMenuItem(hmenu, IDM_Revert, MF_BYCOMMAND|(grey ? MF_GRAYED : MF_ENABLED));
\r
8498 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8500 while (enab->item > 0) {
\r
8501 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8506 Enables gnuEnables[] = {
\r
8507 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8508 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8509 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8510 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8511 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8512 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8513 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8514 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8515 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8516 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8517 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8521 Enables icsEnables[] = {
\r
8522 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8523 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8524 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8525 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8526 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8527 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8528 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8529 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8530 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8531 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8532 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8533 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8534 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8535 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8536 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8541 Enables zippyEnables[] = {
\r
8542 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8543 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8544 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8545 { IDM_Engine1Options, MF_BYCOMMAND|MF_ENABLED },
\r
8550 Enables ncpEnables[] = {
\r
8551 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8552 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8553 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8554 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8555 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8556 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8557 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8558 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8559 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8560 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8561 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8562 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8563 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8564 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8565 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8566 { IDM_MachineBoth, MF_BYCOMMAND|MF_GRAYED },
\r
8567 { IDM_NewChat, MF_BYCOMMAND|MF_GRAYED },
\r
8568 { IDM_Engine1Options, MF_BYCOMMAND|MF_GRAYED },
\r
8569 { IDM_Engine2Options, MF_BYCOMMAND|MF_GRAYED },
\r
8573 Enables trainingOnEnables[] = {
\r
8574 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8575 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8576 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8577 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8578 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8579 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8580 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8581 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8585 Enables trainingOffEnables[] = {
\r
8586 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8587 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8588 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8589 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8590 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8591 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8592 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8593 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8597 /* These modify either ncpEnables or gnuEnables */
\r
8598 Enables cmailEnables[] = {
\r
8599 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8600 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8601 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8602 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8603 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8604 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8605 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8609 Enables machineThinkingEnables[] = {
\r
8610 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8611 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8612 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8613 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8614 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8615 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8616 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8617 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8618 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8619 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8620 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8621 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8622 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8623 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8624 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8628 Enables userThinkingEnables[] = {
\r
8629 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8630 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8631 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8632 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8633 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8634 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8635 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8636 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8637 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8638 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8639 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8640 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8641 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8642 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8643 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8647 /*---------------------------------------------------------------------------*\
\r
8649 * Front-end interface functions exported by XBoard.
\r
8650 * Functions appear in same order as prototypes in frontend.h.
\r
8652 \*---------------------------------------------------------------------------*/
\r
8656 static UINT prevChecked = 0;
\r
8657 static int prevPausing = 0;
\r
8660 if (pausing != prevPausing) {
\r
8661 prevPausing = pausing;
\r
8662 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8663 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8664 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8667 switch (gameMode) {
\r
8668 case BeginningOfGame:
\r
8669 if (appData.icsActive)
\r
8670 nowChecked = IDM_IcsClient;
\r
8671 else if (appData.noChessProgram)
\r
8672 nowChecked = IDM_EditGame;
\r
8674 nowChecked = IDM_MachineBlack;
\r
8676 case MachinePlaysBlack:
\r
8677 nowChecked = IDM_MachineBlack;
\r
8679 case MachinePlaysWhite:
\r
8680 nowChecked = IDM_MachineWhite;
\r
8682 case TwoMachinesPlay:
\r
8683 nowChecked = IDM_TwoMachines;
\r
8686 nowChecked = IDM_AnalysisMode;
\r
8689 nowChecked = IDM_AnalyzeFile;
\r
8692 nowChecked = IDM_EditGame;
\r
8694 case PlayFromGameFile:
\r
8695 nowChecked = IDM_LoadGame;
\r
8697 case EditPosition:
\r
8698 nowChecked = IDM_EditPosition;
\r
8701 nowChecked = IDM_Training;
\r
8703 case IcsPlayingWhite:
\r
8704 case IcsPlayingBlack:
\r
8705 case IcsObserving:
\r
8707 nowChecked = IDM_IcsClient;
\r
8714 if (prevChecked != 0)
\r
8715 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8716 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8717 if (nowChecked != 0)
\r
8718 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8719 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8721 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8722 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8723 MF_BYCOMMAND|MF_ENABLED);
\r
8725 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8726 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8729 prevChecked = nowChecked;
\r
8731 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8732 if (appData.icsActive) {
\r
8733 if (appData.icsEngineAnalyze) {
\r
8734 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8735 MF_BYCOMMAND|MF_CHECKED);
\r
8737 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8738 MF_BYCOMMAND|MF_UNCHECKED);
\r
8746 HMENU hmenu = GetMenu(hwndMain);
\r
8747 SetMenuEnables(hmenu, icsEnables);
\r
8748 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8749 MF_BYPOSITION|MF_ENABLED);
\r
8751 if (appData.zippyPlay) {
\r
8752 SetMenuEnables(hmenu, zippyEnables);
\r
8753 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8754 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8755 MF_BYCOMMAND|MF_ENABLED);
\r
8763 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8769 HMENU hmenu = GetMenu(hwndMain);
\r
8770 SetMenuEnables(hmenu, ncpEnables);
\r
8771 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8772 MF_BYPOSITION|MF_GRAYED);
\r
8773 DrawMenuBar(hwndMain);
\r
8779 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8783 SetTrainingModeOn()
\r
8786 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8787 for (i = 0; i < N_BUTTONS; i++) {
\r
8788 if (buttonDesc[i].hwnd != NULL)
\r
8789 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8794 VOID SetTrainingModeOff()
\r
8797 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8798 for (i = 0; i < N_BUTTONS; i++) {
\r
8799 if (buttonDesc[i].hwnd != NULL)
\r
8800 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8806 SetUserThinkingEnables()
\r
8808 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8812 SetMachineThinkingEnables()
\r
8814 HMENU hMenu = GetMenu(hwndMain);
\r
8815 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8817 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8819 if (gameMode == MachinePlaysBlack) {
\r
8820 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8821 } else if (gameMode == MachinePlaysWhite) {
\r
8822 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8823 } else if (gameMode == TwoMachinesPlay) {
\r
8824 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8830 DisplayTitle(char *str)
\r
8832 char title[MSG_SIZ], *host;
\r
8833 if (str[0] != NULLCHAR) {
\r
8834 strcpy(title, str);
\r
8835 } else if (appData.icsActive) {
\r
8836 if (appData.icsCommPort[0] != NULLCHAR)
\r
8839 host = appData.icsHost;
\r
8840 sprintf(title, "%s: %s", szTitle, host);
\r
8841 } else if (appData.noChessProgram) {
\r
8842 strcpy(title, szTitle);
\r
8844 strcpy(title, szTitle);
\r
8845 strcat(title, ": ");
\r
8846 strcat(title, first.tidy);
\r
8848 SetWindowText(hwndMain, title);
\r
8853 DisplayMessage(char *str1, char *str2)
\r
8857 int remain = MESSAGE_TEXT_MAX - 1;
\r
8860 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8861 messageText[0] = NULLCHAR;
\r
8863 len = strlen(str1);
\r
8864 if (len > remain) len = remain;
\r
8865 strncpy(messageText, str1, len);
\r
8866 messageText[len] = NULLCHAR;
\r
8869 if (*str2 && remain >= 2) {
\r
8871 strcat(messageText, " ");
\r
8874 len = strlen(str2);
\r
8875 if (len > remain) len = remain;
\r
8876 strncat(messageText, str2, len);
\r
8878 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8880 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8884 hdc = GetDC(hwndMain);
\r
8885 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8886 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8887 &messageRect, messageText, strlen(messageText), NULL);
\r
8888 (void) SelectObject(hdc, oldFont);
\r
8889 (void) ReleaseDC(hwndMain, hdc);
\r
8893 DisplayError(char *str, int error)
\r
8895 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8901 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8902 NULL, error, LANG_NEUTRAL,
\r
8903 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8905 sprintf(buf, "%s:\n%s", str, buf2);
\r
8907 ErrorMap *em = errmap;
\r
8908 while (em->err != 0 && em->err != error) em++;
\r
8909 if (em->err != 0) {
\r
8910 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8912 sprintf(buf, "%s:\nError code %d", str, error);
\r
8917 ErrorPopUp("Error", buf);
\r
8922 DisplayMoveError(char *str)
\r
8924 fromX = fromY = -1;
\r
8925 ClearHighlights();
\r
8926 DrawPosition(FALSE, NULL);
\r
8927 if (appData.popupMoveErrors) {
\r
8928 ErrorPopUp("Error", str);
\r
8930 DisplayMessage(str, "");
\r
8931 moveErrorMessageUp = TRUE;
\r
8936 DisplayFatalError(char *str, int error, int exitStatus)
\r
8938 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8940 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8943 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8944 NULL, error, LANG_NEUTRAL,
\r
8945 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8947 sprintf(buf, "%s:\n%s", str, buf2);
\r
8949 ErrorMap *em = errmap;
\r
8950 while (em->err != 0 && em->err != error) em++;
\r
8951 if (em->err != 0) {
\r
8952 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8954 sprintf(buf, "%s:\nError code %d", str, error);
\r
8959 if (appData.debugMode) {
\r
8960 fprintf(debugFP, "%s: %s\n", label, str);
\r
8962 if (appData.popupExitMessage) {
\r
8963 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8964 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8966 ExitEvent(exitStatus);
\r
8971 DisplayInformation(char *str)
\r
8973 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8978 DisplayNote(char *str)
\r
8980 ErrorPopUp("Note", str);
\r
8985 char *title, *question, *replyPrefix;
\r
8990 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8992 static QuestionParams *qp;
\r
8993 char reply[MSG_SIZ];
\r
8996 switch (message) {
\r
8997 case WM_INITDIALOG:
\r
8998 qp = (QuestionParams *) lParam;
\r
8999 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9000 SetWindowText(hDlg, qp->title);
\r
9001 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9002 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9006 switch (LOWORD(wParam)) {
\r
9008 strcpy(reply, qp->replyPrefix);
\r
9009 if (*reply) strcat(reply, " ");
\r
9010 len = strlen(reply);
\r
9011 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9012 strcat(reply, "\n");
\r
9013 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9014 EndDialog(hDlg, TRUE);
\r
9015 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9018 EndDialog(hDlg, FALSE);
\r
9029 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9031 QuestionParams qp;
\r
9035 qp.question = question;
\r
9036 qp.replyPrefix = replyPrefix;
\r
9038 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9039 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9040 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9041 FreeProcInstance(lpProc);
\r
9044 /* [AS] Pick FRC position */
\r
9045 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9047 static int * lpIndexFRC;
\r
9053 case WM_INITDIALOG:
\r
9054 lpIndexFRC = (int *) lParam;
\r
9056 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9058 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9059 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9060 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9061 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9066 switch( LOWORD(wParam) ) {
\r
9068 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9069 EndDialog( hDlg, 0 );
\r
9070 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9073 EndDialog( hDlg, 1 );
\r
9075 case IDC_NFG_Edit:
\r
9076 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9077 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9079 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9082 case IDC_NFG_Random:
\r
9083 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9084 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9097 int index = appData.defaultFrcPosition;
\r
9098 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9100 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9102 if( result == 0 ) {
\r
9103 appData.defaultFrcPosition = index;
\r
9109 /* [AS] Game list options */
\r
9115 static GLT_Item GLT_ItemInfo[] = {
\r
9116 { GLT_EVENT, "Event" },
\r
9117 { GLT_SITE, "Site" },
\r
9118 { GLT_DATE, "Date" },
\r
9119 { GLT_ROUND, "Round" },
\r
9120 { GLT_PLAYERS, "Players" },
\r
9121 { GLT_RESULT, "Result" },
\r
9122 { GLT_WHITE_ELO, "White Rating" },
\r
9123 { GLT_BLACK_ELO, "Black Rating" },
\r
9124 { GLT_TIME_CONTROL,"Time Control" },
\r
9125 { GLT_VARIANT, "Variant" },
\r
9126 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9127 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9131 const char * GLT_FindItem( char id )
\r
9133 const char * result = 0;
\r
9135 GLT_Item * list = GLT_ItemInfo;
\r
9137 while( list->id != 0 ) {
\r
9138 if( list->id == id ) {
\r
9139 result = list->name;
\r
9149 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9151 const char * name = GLT_FindItem( id );
\r
9154 if( index >= 0 ) {
\r
9155 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9158 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9163 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9167 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9170 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9174 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9176 pc = GLT_ALL_TAGS;
\r
9179 if( strchr( tags, *pc ) == 0 ) {
\r
9180 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9185 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9188 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9190 char result = '\0';
\r
9193 GLT_Item * list = GLT_ItemInfo;
\r
9195 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9196 while( list->id != 0 ) {
\r
9197 if( strcmp( list->name, name ) == 0 ) {
\r
9198 result = list->id;
\r
9209 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9211 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9212 int idx2 = idx1 + delta;
\r
9213 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9215 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9218 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9219 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9220 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9221 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9225 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9227 static char glt[64];
\r
9228 static char * lpUserGLT;
\r
9232 case WM_INITDIALOG:
\r
9233 lpUserGLT = (char *) lParam;
\r
9235 strcpy( glt, lpUserGLT );
\r
9237 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9239 /* Initialize list */
\r
9240 GLT_TagsToList( hDlg, glt );
\r
9242 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9247 switch( LOWORD(wParam) ) {
\r
9250 char * pc = lpUserGLT;
\r
9252 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9256 id = GLT_ListItemToTag( hDlg, idx );
\r
9260 } while( id != '\0' );
\r
9262 EndDialog( hDlg, 0 );
\r
9265 EndDialog( hDlg, 1 );
\r
9268 case IDC_GLT_Default:
\r
9269 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9270 GLT_TagsToList( hDlg, glt );
\r
9273 case IDC_GLT_Restore:
\r
9274 strcpy( glt, lpUserGLT );
\r
9275 GLT_TagsToList( hDlg, glt );
\r
9279 GLT_MoveSelection( hDlg, -1 );
\r
9282 case IDC_GLT_Down:
\r
9283 GLT_MoveSelection( hDlg, +1 );
\r
9293 int GameListOptions()
\r
9297 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9299 strcpy( glt, appData.gameListTags );
\r
9301 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9303 if( result == 0 ) {
\r
9304 /* [AS] Memory leak here! */
\r
9305 appData.gameListTags = strdup( glt );
\r
9313 DisplayIcsInteractionTitle(char *str)
\r
9315 char consoleTitle[MSG_SIZ];
\r
9317 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9318 SetWindowText(hwndConsole, consoleTitle);
\r
9322 DrawPosition(int fullRedraw, Board board)
\r
9324 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9327 void NotifyFrontendLogin()
\r
9330 UpdateICSWidth(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
9336 fromX = fromY = -1;
\r
9337 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9338 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9339 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9340 dragInfo.lastpos = dragInfo.pos;
\r
9341 dragInfo.start.x = dragInfo.start.y = -1;
\r
9342 dragInfo.from = dragInfo.start;
\r
9344 DrawPosition(TRUE, NULL);
\r
9350 CommentPopUp(char *title, char *str)
\r
9352 HWND hwnd = GetActiveWindow();
\r
9353 EitherCommentPopUp(0, title, str, FALSE);
\r
9355 SetActiveWindow(hwnd);
\r
9359 CommentPopDown(void)
\r
9361 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9362 if (commentDialog) {
\r
9363 ShowWindow(commentDialog, SW_HIDE);
\r
9365 commentUp = FALSE;
\r
9369 EditCommentPopUp(int index, char *title, char *str)
\r
9371 EitherCommentPopUp(index, title, str, TRUE);
\r
9378 MyPlaySound(&sounds[(int)SoundMove]);
\r
9381 VOID PlayIcsWinSound()
\r
9383 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9386 VOID PlayIcsLossSound()
\r
9388 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9391 VOID PlayIcsDrawSound()
\r
9393 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9396 VOID PlayIcsUnfinishedSound()
\r
9398 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9404 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9412 consoleEcho = TRUE;
\r
9413 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9414 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9415 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9424 consoleEcho = FALSE;
\r
9425 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9426 /* This works OK: set text and background both to the same color */
\r
9428 cf.crTextColor = COLOR_ECHOOFF;
\r
9429 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9430 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9433 /* No Raw()...? */
\r
9435 void Colorize(ColorClass cc, int continuation)
\r
9437 currentColorClass = cc;
\r
9438 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9439 consoleCF.crTextColor = textAttribs[cc].color;
\r
9440 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9441 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9447 static char buf[MSG_SIZ];
\r
9448 DWORD bufsiz = MSG_SIZ;
\r
9450 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9451 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9453 if (!GetUserName(buf, &bufsiz)) {
\r
9454 /*DisplayError("Error getting user name", GetLastError());*/
\r
9455 strcpy(buf, "User");
\r
9463 static char buf[MSG_SIZ];
\r
9464 DWORD bufsiz = MSG_SIZ;
\r
9466 if (!GetComputerName(buf, &bufsiz)) {
\r
9467 /*DisplayError("Error getting host name", GetLastError());*/
\r
9468 strcpy(buf, "Unknown");
\r
9475 ClockTimerRunning()
\r
9477 return clockTimerEvent != 0;
\r
9483 if (clockTimerEvent == 0) return FALSE;
\r
9484 KillTimer(hwndMain, clockTimerEvent);
\r
9485 clockTimerEvent = 0;
\r
9490 StartClockTimer(long millisec)
\r
9492 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9493 (UINT) millisec, NULL);
\r
9497 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9500 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9502 if(appData.noGUI) return;
\r
9503 hdc = GetDC(hwndMain);
\r
9504 if (!IsIconic(hwndMain)) {
\r
9505 DisplayAClock(hdc, timeRemaining, highlight,
\r
9506 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9508 if (highlight && iconCurrent == iconBlack) {
\r
9509 iconCurrent = iconWhite;
\r
9510 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9511 if (IsIconic(hwndMain)) {
\r
9512 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9515 (void) ReleaseDC(hwndMain, hdc);
\r
9517 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9521 DisplayBlackClock(long timeRemaining, int highlight)
\r
9524 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9526 if(appData.noGUI) return;
\r
9527 hdc = GetDC(hwndMain);
\r
9528 if (!IsIconic(hwndMain)) {
\r
9529 DisplayAClock(hdc, timeRemaining, highlight,
\r
9530 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9532 if (highlight && iconCurrent == iconWhite) {
\r
9533 iconCurrent = iconBlack;
\r
9534 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9535 if (IsIconic(hwndMain)) {
\r
9536 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9539 (void) ReleaseDC(hwndMain, hdc);
\r
9541 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9546 LoadGameTimerRunning()
\r
9548 return loadGameTimerEvent != 0;
\r
9552 StopLoadGameTimer()
\r
9554 if (loadGameTimerEvent == 0) return FALSE;
\r
9555 KillTimer(hwndMain, loadGameTimerEvent);
\r
9556 loadGameTimerEvent = 0;
\r
9561 StartLoadGameTimer(long millisec)
\r
9563 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9564 (UINT) millisec, NULL);
\r
9572 char fileTitle[MSG_SIZ];
\r
9574 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9575 f = OpenFileDialog(hwndMain, "a", defName,
\r
9576 appData.oldSaveStyle ? "gam" : "pgn",
\r
9578 "Save Game to File", NULL, fileTitle, NULL);
\r
9580 SaveGame(f, 0, "");
\r
9587 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9589 if (delayedTimerEvent != 0) {
\r
9590 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9591 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9593 KillTimer(hwndMain, delayedTimerEvent);
\r
9594 delayedTimerEvent = 0;
\r
9595 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9596 delayedTimerCallback();
\r
9598 delayedTimerCallback = cb;
\r
9599 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9600 (UINT) millisec, NULL);
\r
9603 DelayedEventCallback
\r
9606 if (delayedTimerEvent) {
\r
9607 return delayedTimerCallback;
\r
9614 CancelDelayedEvent()
\r
9616 if (delayedTimerEvent) {
\r
9617 KillTimer(hwndMain, delayedTimerEvent);
\r
9618 delayedTimerEvent = 0;
\r
9622 DWORD GetWin32Priority(int nice)
\r
9623 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9625 REALTIME_PRIORITY_CLASS 0x00000100
\r
9626 HIGH_PRIORITY_CLASS 0x00000080
\r
9627 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9628 NORMAL_PRIORITY_CLASS 0x00000020
\r
9629 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9630 IDLE_PRIORITY_CLASS 0x00000040
\r
9632 if (nice < -15) return 0x00000080;
\r
9633 if (nice < 0) return 0x00008000;
\r
9634 if (nice == 0) return 0x00000020;
\r
9635 if (nice < 15) return 0x00004000;
\r
9636 return 0x00000040;
\r
9639 /* Start a child process running the given program.
\r
9640 The process's standard output can be read from "from", and its
\r
9641 standard input can be written to "to".
\r
9642 Exit with fatal error if anything goes wrong.
\r
9643 Returns an opaque pointer that can be used to destroy the process
\r
9647 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9649 #define BUFSIZE 4096
\r
9651 HANDLE hChildStdinRd, hChildStdinWr,
\r
9652 hChildStdoutRd, hChildStdoutWr;
\r
9653 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9654 SECURITY_ATTRIBUTES saAttr;
\r
9656 PROCESS_INFORMATION piProcInfo;
\r
9657 STARTUPINFO siStartInfo;
\r
9659 char buf[MSG_SIZ];
\r
9662 if (appData.debugMode) {
\r
9663 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9668 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9669 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9670 saAttr.bInheritHandle = TRUE;
\r
9671 saAttr.lpSecurityDescriptor = NULL;
\r
9674 * The steps for redirecting child's STDOUT:
\r
9675 * 1. Create anonymous pipe to be STDOUT for child.
\r
9676 * 2. Create a noninheritable duplicate of read handle,
\r
9677 * and close the inheritable read handle.
\r
9680 /* Create a pipe for the child's STDOUT. */
\r
9681 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9682 return GetLastError();
\r
9685 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9686 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9687 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9688 FALSE, /* not inherited */
\r
9689 DUPLICATE_SAME_ACCESS);
\r
9691 return GetLastError();
\r
9693 CloseHandle(hChildStdoutRd);
\r
9696 * The steps for redirecting child's STDIN:
\r
9697 * 1. Create anonymous pipe to be STDIN for child.
\r
9698 * 2. Create a noninheritable duplicate of write handle,
\r
9699 * and close the inheritable write handle.
\r
9702 /* Create a pipe for the child's STDIN. */
\r
9703 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9704 return GetLastError();
\r
9707 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9708 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9709 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9710 FALSE, /* not inherited */
\r
9711 DUPLICATE_SAME_ACCESS);
\r
9713 return GetLastError();
\r
9715 CloseHandle(hChildStdinWr);
\r
9717 /* Arrange to (1) look in dir for the child .exe file, and
\r
9718 * (2) have dir be the child's working directory. Interpret
\r
9719 * dir relative to the directory WinBoard loaded from. */
\r
9720 GetCurrentDirectory(MSG_SIZ, buf);
\r
9721 SetCurrentDirectory(installDir);
\r
9722 SetCurrentDirectory(dir);
\r
9724 /* Now create the child process. */
\r
9726 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9727 siStartInfo.lpReserved = NULL;
\r
9728 siStartInfo.lpDesktop = NULL;
\r
9729 siStartInfo.lpTitle = NULL;
\r
9730 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9731 siStartInfo.cbReserved2 = 0;
\r
9732 siStartInfo.lpReserved2 = NULL;
\r
9733 siStartInfo.hStdInput = hChildStdinRd;
\r
9734 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9735 siStartInfo.hStdError = hChildStdoutWr;
\r
9737 fSuccess = CreateProcess(NULL,
\r
9738 cmdLine, /* command line */
\r
9739 NULL, /* process security attributes */
\r
9740 NULL, /* primary thread security attrs */
\r
9741 TRUE, /* handles are inherited */
\r
9742 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9743 NULL, /* use parent's environment */
\r
9745 &siStartInfo, /* STARTUPINFO pointer */
\r
9746 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9748 err = GetLastError();
\r
9749 SetCurrentDirectory(buf); /* return to prev directory */
\r
9754 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9755 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9756 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9759 /* Close the handles we don't need in the parent */
\r
9760 CloseHandle(piProcInfo.hThread);
\r
9761 CloseHandle(hChildStdinRd);
\r
9762 CloseHandle(hChildStdoutWr);
\r
9764 /* Prepare return value */
\r
9765 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9766 cp->kind = CPReal;
\r
9767 cp->hProcess = piProcInfo.hProcess;
\r
9768 cp->pid = piProcInfo.dwProcessId;
\r
9769 cp->hFrom = hChildStdoutRdDup;
\r
9770 cp->hTo = hChildStdinWrDup;
\r
9772 *pr = (void *) cp;
\r
9774 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9775 2000 where engines sometimes don't see the initial command(s)
\r
9776 from WinBoard and hang. I don't understand how that can happen,
\r
9777 but the Sleep is harmless, so I've put it in. Others have also
\r
9778 reported what may be the same problem, so hopefully this will fix
\r
9779 it for them too. */
\r
9787 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9789 ChildProc *cp; int result;
\r
9791 cp = (ChildProc *) pr;
\r
9792 if (cp == NULL) return;
\r
9794 switch (cp->kind) {
\r
9796 /* TerminateProcess is considered harmful, so... */
\r
9797 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9798 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9799 /* The following doesn't work because the chess program
\r
9800 doesn't "have the same console" as WinBoard. Maybe
\r
9801 we could arrange for this even though neither WinBoard
\r
9802 nor the chess program uses a console for stdio? */
\r
9803 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9805 /* [AS] Special termination modes for misbehaving programs... */
\r
9806 if( signal == 9 ) {
\r
9807 result = TerminateProcess( cp->hProcess, 0 );
\r
9809 if ( appData.debugMode) {
\r
9810 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9813 else if( signal == 10 ) {
\r
9814 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9816 if( dw != WAIT_OBJECT_0 ) {
\r
9817 result = TerminateProcess( cp->hProcess, 0 );
\r
9819 if ( appData.debugMode) {
\r
9820 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9826 CloseHandle(cp->hProcess);
\r
9830 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9834 closesocket(cp->sock);
\r
9839 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9840 closesocket(cp->sock);
\r
9841 closesocket(cp->sock2);
\r
9849 InterruptChildProcess(ProcRef pr)
\r
9853 cp = (ChildProc *) pr;
\r
9854 if (cp == NULL) return;
\r
9855 switch (cp->kind) {
\r
9857 /* The following doesn't work because the chess program
\r
9858 doesn't "have the same console" as WinBoard. Maybe
\r
9859 we could arrange for this even though neither WinBoard
\r
9860 nor the chess program uses a console for stdio */
\r
9861 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9866 /* Can't interrupt */
\r
9870 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9877 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9879 char cmdLine[MSG_SIZ];
\r
9881 if (port[0] == NULLCHAR) {
\r
9882 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9884 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9886 return StartChildProcess(cmdLine, "", pr);
\r
9890 /* Code to open TCP sockets */
\r
9893 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9898 struct sockaddr_in sa, mysa;
\r
9899 struct hostent FAR *hp;
\r
9900 unsigned short uport;
\r
9901 WORD wVersionRequested;
\r
9904 /* Initialize socket DLL */
\r
9905 wVersionRequested = MAKEWORD(1, 1);
\r
9906 err = WSAStartup(wVersionRequested, &wsaData);
\r
9907 if (err != 0) return err;
\r
9910 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9911 err = WSAGetLastError();
\r
9916 /* Bind local address using (mostly) don't-care values.
\r
9918 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9919 mysa.sin_family = AF_INET;
\r
9920 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9921 uport = (unsigned short) 0;
\r
9922 mysa.sin_port = htons(uport);
\r
9923 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9924 == SOCKET_ERROR) {
\r
9925 err = WSAGetLastError();
\r
9930 /* Resolve remote host name */
\r
9931 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9932 if (!(hp = gethostbyname(host))) {
\r
9933 unsigned int b0, b1, b2, b3;
\r
9935 err = WSAGetLastError();
\r
9937 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9938 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9939 hp->h_addrtype = AF_INET;
\r
9941 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9942 hp->h_addr_list[0] = (char *) malloc(4);
\r
9943 hp->h_addr_list[0][0] = (char) b0;
\r
9944 hp->h_addr_list[0][1] = (char) b1;
\r
9945 hp->h_addr_list[0][2] = (char) b2;
\r
9946 hp->h_addr_list[0][3] = (char) b3;
\r
9952 sa.sin_family = hp->h_addrtype;
\r
9953 uport = (unsigned short) atoi(port);
\r
9954 sa.sin_port = htons(uport);
\r
9955 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9957 /* Make connection */
\r
9958 if (connect(s, (struct sockaddr *) &sa,
\r
9959 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9960 err = WSAGetLastError();
\r
9965 /* Prepare return value */
\r
9966 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9967 cp->kind = CPSock;
\r
9969 *pr = (ProcRef *) cp;
\r
9975 OpenCommPort(char *name, ProcRef *pr)
\r
9980 char fullname[MSG_SIZ];
\r
9982 if (*name != '\\')
\r
9983 sprintf(fullname, "\\\\.\\%s", name);
\r
9985 strcpy(fullname, name);
\r
9987 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9988 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9989 if (h == (HANDLE) -1) {
\r
9990 return GetLastError();
\r
9994 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9996 /* Accumulate characters until a 100ms pause, then parse */
\r
9997 ct.ReadIntervalTimeout = 100;
\r
9998 ct.ReadTotalTimeoutMultiplier = 0;
\r
9999 ct.ReadTotalTimeoutConstant = 0;
\r
10000 ct.WriteTotalTimeoutMultiplier = 0;
\r
10001 ct.WriteTotalTimeoutConstant = 0;
\r
10002 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10004 /* Prepare return value */
\r
10005 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10006 cp->kind = CPComm;
\r
10009 *pr = (ProcRef *) cp;
\r
10015 OpenLoopback(ProcRef *pr)
\r
10017 DisplayFatalError("Not implemented", 0, 1);
\r
10023 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10027 SOCKET s, s2, s3;
\r
10028 struct sockaddr_in sa, mysa;
\r
10029 struct hostent FAR *hp;
\r
10030 unsigned short uport;
\r
10031 WORD wVersionRequested;
\r
10034 char stderrPortStr[MSG_SIZ];
\r
10036 /* Initialize socket DLL */
\r
10037 wVersionRequested = MAKEWORD(1, 1);
\r
10038 err = WSAStartup(wVersionRequested, &wsaData);
\r
10039 if (err != 0) return err;
\r
10041 /* Resolve remote host name */
\r
10042 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10043 if (!(hp = gethostbyname(host))) {
\r
10044 unsigned int b0, b1, b2, b3;
\r
10046 err = WSAGetLastError();
\r
10048 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10049 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10050 hp->h_addrtype = AF_INET;
\r
10051 hp->h_length = 4;
\r
10052 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10053 hp->h_addr_list[0] = (char *) malloc(4);
\r
10054 hp->h_addr_list[0][0] = (char) b0;
\r
10055 hp->h_addr_list[0][1] = (char) b1;
\r
10056 hp->h_addr_list[0][2] = (char) b2;
\r
10057 hp->h_addr_list[0][3] = (char) b3;
\r
10063 sa.sin_family = hp->h_addrtype;
\r
10064 uport = (unsigned short) 514;
\r
10065 sa.sin_port = htons(uport);
\r
10066 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10068 /* Bind local socket to unused "privileged" port address
\r
10070 s = INVALID_SOCKET;
\r
10071 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10072 mysa.sin_family = AF_INET;
\r
10073 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10074 for (fromPort = 1023;; fromPort--) {
\r
10075 if (fromPort < 0) {
\r
10077 return WSAEADDRINUSE;
\r
10079 if (s == INVALID_SOCKET) {
\r
10080 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10081 err = WSAGetLastError();
\r
10086 uport = (unsigned short) fromPort;
\r
10087 mysa.sin_port = htons(uport);
\r
10088 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10089 == SOCKET_ERROR) {
\r
10090 err = WSAGetLastError();
\r
10091 if (err == WSAEADDRINUSE) continue;
\r
10095 if (connect(s, (struct sockaddr *) &sa,
\r
10096 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10097 err = WSAGetLastError();
\r
10098 if (err == WSAEADDRINUSE) {
\r
10109 /* Bind stderr local socket to unused "privileged" port address
\r
10111 s2 = INVALID_SOCKET;
\r
10112 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10113 mysa.sin_family = AF_INET;
\r
10114 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10115 for (fromPort = 1023;; fromPort--) {
\r
10116 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10117 if (fromPort < 0) {
\r
10118 (void) closesocket(s);
\r
10120 return WSAEADDRINUSE;
\r
10122 if (s2 == INVALID_SOCKET) {
\r
10123 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10124 err = WSAGetLastError();
\r
10130 uport = (unsigned short) fromPort;
\r
10131 mysa.sin_port = htons(uport);
\r
10132 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10133 == SOCKET_ERROR) {
\r
10134 err = WSAGetLastError();
\r
10135 if (err == WSAEADDRINUSE) continue;
\r
10136 (void) closesocket(s);
\r
10140 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10141 err = WSAGetLastError();
\r
10142 if (err == WSAEADDRINUSE) {
\r
10144 s2 = INVALID_SOCKET;
\r
10147 (void) closesocket(s);
\r
10148 (void) closesocket(s2);
\r
10154 prevStderrPort = fromPort; // remember port used
\r
10155 sprintf(stderrPortStr, "%d", fromPort);
\r
10157 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10158 err = WSAGetLastError();
\r
10159 (void) closesocket(s);
\r
10160 (void) closesocket(s2);
\r
10165 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10166 err = WSAGetLastError();
\r
10167 (void) closesocket(s);
\r
10168 (void) closesocket(s2);
\r
10172 if (*user == NULLCHAR) user = UserName();
\r
10173 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10174 err = WSAGetLastError();
\r
10175 (void) closesocket(s);
\r
10176 (void) closesocket(s2);
\r
10180 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10181 err = WSAGetLastError();
\r
10182 (void) closesocket(s);
\r
10183 (void) closesocket(s2);
\r
10188 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10189 err = WSAGetLastError();
\r
10190 (void) closesocket(s);
\r
10191 (void) closesocket(s2);
\r
10195 (void) closesocket(s2); /* Stop listening */
\r
10197 /* Prepare return value */
\r
10198 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10199 cp->kind = CPRcmd;
\r
10202 *pr = (ProcRef *) cp;
\r
10209 AddInputSource(ProcRef pr, int lineByLine,
\r
10210 InputCallback func, VOIDSTAR closure)
\r
10212 InputSource *is, *is2 = NULL;
\r
10213 ChildProc *cp = (ChildProc *) pr;
\r
10215 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10216 is->lineByLine = lineByLine;
\r
10218 is->closure = closure;
\r
10219 is->second = NULL;
\r
10220 is->next = is->buf;
\r
10221 if (pr == NoProc) {
\r
10222 is->kind = CPReal;
\r
10223 consoleInputSource = is;
\r
10225 is->kind = cp->kind;
\r
10227 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10228 we create all threads suspended so that the is->hThread variable can be
\r
10229 safely assigned, then let the threads start with ResumeThread.
\r
10231 switch (cp->kind) {
\r
10233 is->hFile = cp->hFrom;
\r
10234 cp->hFrom = NULL; /* now owned by InputThread */
\r
10236 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10237 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10241 is->hFile = cp->hFrom;
\r
10242 cp->hFrom = NULL; /* now owned by InputThread */
\r
10244 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10245 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10249 is->sock = cp->sock;
\r
10251 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10252 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10256 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10258 is->sock = cp->sock;
\r
10259 is->second = is2;
\r
10260 is2->sock = cp->sock2;
\r
10261 is2->second = is2;
\r
10263 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10264 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10266 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10267 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10271 if( is->hThread != NULL ) {
\r
10272 ResumeThread( is->hThread );
\r
10275 if( is2 != NULL && is2->hThread != NULL ) {
\r
10276 ResumeThread( is2->hThread );
\r
10280 return (InputSourceRef) is;
\r
10284 RemoveInputSource(InputSourceRef isr)
\r
10288 is = (InputSource *) isr;
\r
10289 is->hThread = NULL; /* tell thread to stop */
\r
10290 CloseHandle(is->hThread);
\r
10291 if (is->second != NULL) {
\r
10292 is->second->hThread = NULL;
\r
10293 CloseHandle(is->second->hThread);
\r
10297 int no_wrap(char *message, int count)
\r
10299 ConsoleOutput(message, count, FALSE);
\r
10304 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10307 int outCount = SOCKET_ERROR;
\r
10308 ChildProc *cp = (ChildProc *) pr;
\r
10309 static OVERLAPPED ovl;
\r
10310 static int line = 0;
\r
10312 if (pr == NoProc)
\r
10314 if (appData.noJoin || !appData.useInternalWrap)
\r
10315 return no_wrap(message, count);
\r
10318 int width = get_term_width();
\r
10319 int len = wrap(NULL, message, count, width, &line);
\r
10320 char *msg = malloc(len);
\r
10324 return no_wrap(message, count);
\r
10327 dbgchk = wrap(msg, message, count, width, &line);
\r
10328 if (dbgchk != len && appData.debugMode)
\r
10329 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
\r
10330 ConsoleOutput(msg, len, FALSE);
\r
10337 if (ovl.hEvent == NULL) {
\r
10338 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10340 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10342 switch (cp->kind) {
\r
10345 outCount = send(cp->sock, message, count, 0);
\r
10346 if (outCount == SOCKET_ERROR) {
\r
10347 *outError = WSAGetLastError();
\r
10349 *outError = NO_ERROR;
\r
10354 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10355 &dOutCount, NULL)) {
\r
10356 *outError = NO_ERROR;
\r
10357 outCount = (int) dOutCount;
\r
10359 *outError = GetLastError();
\r
10364 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10365 &dOutCount, &ovl);
\r
10366 if (*outError == NO_ERROR) {
\r
10367 outCount = (int) dOutCount;
\r
10375 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10378 /* Ignore delay, not implemented for WinBoard */
\r
10379 return OutputToProcess(pr, message, count, outError);
\r
10384 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10385 char *buf, int count, int error)
\r
10387 DisplayFatalError("Not implemented", 0, 1);
\r
10390 /* see wgamelist.c for Game List functions */
\r
10391 /* see wedittags.c for Edit Tags functions */
\r
10398 char buf[MSG_SIZ];
\r
10401 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10402 f = fopen(buf, "r");
\r
10404 ProcessICSInitScript(f);
\r
10412 StartAnalysisClock()
\r
10414 if (analysisTimerEvent) return;
\r
10415 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10416 (UINT) 2000, NULL);
\r
10420 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10422 highlightInfo.sq[0].x = fromX;
\r
10423 highlightInfo.sq[0].y = fromY;
\r
10424 highlightInfo.sq[1].x = toX;
\r
10425 highlightInfo.sq[1].y = toY;
\r
10429 ClearHighlights()
\r
10431 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10432 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10436 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10438 premoveHighlightInfo.sq[0].x = fromX;
\r
10439 premoveHighlightInfo.sq[0].y = fromY;
\r
10440 premoveHighlightInfo.sq[1].x = toX;
\r
10441 premoveHighlightInfo.sq[1].y = toY;
\r
10445 ClearPremoveHighlights()
\r
10447 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10448 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10452 ShutDownFrontEnd()
\r
10454 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10455 DeleteClipboardTempFiles();
\r
10461 if (IsIconic(hwndMain))
\r
10462 ShowWindow(hwndMain, SW_RESTORE);
\r
10464 SetActiveWindow(hwndMain);
\r
10468 * Prototypes for animation support routines
\r
10470 static void ScreenSquare(int column, int row, POINT * pt);
\r
10471 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10472 POINT frames[], int * nFrames);
\r
10476 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10477 { // [HGM] atomic: animate blast wave
\r
10479 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10480 explodeInfo.fromX = fromX;
\r
10481 explodeInfo.fromY = fromY;
\r
10482 explodeInfo.toX = toX;
\r
10483 explodeInfo.toY = toY;
\r
10484 for(i=1; i<nFrames; i++) {
\r
10485 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10486 DrawPosition(FALSE, NULL);
\r
10487 Sleep(appData.animSpeed);
\r
10489 explodeInfo.radius = 0;
\r
10490 DrawPosition(TRUE, NULL);
\r
10493 #define kFactor 4
\r
10496 AnimateMove(board, fromX, fromY, toX, toY)
\r
10503 ChessSquare piece;
\r
10504 POINT start, finish, mid;
\r
10505 POINT frames[kFactor * 2 + 1];
\r
10508 if (!appData.animate) return;
\r
10509 if (doingSizing) return;
\r
10510 if (fromY < 0 || fromX < 0) return;
\r
10511 piece = board[fromY][fromX];
\r
10512 if (piece >= EmptySquare) return;
\r
10514 ScreenSquare(fromX, fromY, &start);
\r
10515 ScreenSquare(toX, toY, &finish);
\r
10517 /* All pieces except knights move in straight line */
\r
10518 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10519 mid.x = start.x + (finish.x - start.x) / 2;
\r
10520 mid.y = start.y + (finish.y - start.y) / 2;
\r
10522 /* Knight: make diagonal movement then straight */
\r
10523 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10524 mid.x = start.x + (finish.x - start.x) / 2;
\r
10525 mid.y = finish.y;
\r
10527 mid.x = finish.x;
\r
10528 mid.y = start.y + (finish.y - start.y) / 2;
\r
10532 /* Don't use as many frames for very short moves */
\r
10533 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10534 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10536 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10538 animInfo.from.x = fromX;
\r
10539 animInfo.from.y = fromY;
\r
10540 animInfo.to.x = toX;
\r
10541 animInfo.to.y = toY;
\r
10542 animInfo.lastpos = start;
\r
10543 animInfo.piece = piece;
\r
10544 for (n = 0; n < nFrames; n++) {
\r
10545 animInfo.pos = frames[n];
\r
10546 DrawPosition(FALSE, NULL);
\r
10547 animInfo.lastpos = animInfo.pos;
\r
10548 Sleep(appData.animSpeed);
\r
10550 animInfo.pos = finish;
\r
10551 DrawPosition(FALSE, NULL);
\r
10552 animInfo.piece = EmptySquare;
\r
10553 if(gameInfo.variant == VariantAtomic &&
\r
10554 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10555 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10558 /* Convert board position to corner of screen rect and color */
\r
10561 ScreenSquare(column, row, pt)
\r
10562 int column; int row; POINT * pt;
\r
10565 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10566 pt->y = lineGap + row * (squareSize + lineGap);
\r
10568 pt->x = lineGap + column * (squareSize + lineGap);
\r
10569 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10573 /* Generate a series of frame coords from start->mid->finish.
\r
10574 The movement rate doubles until the half way point is
\r
10575 reached, then halves back down to the final destination,
\r
10576 which gives a nice slow in/out effect. The algorithmn
\r
10577 may seem to generate too many intermediates for short
\r
10578 moves, but remember that the purpose is to attract the
\r
10579 viewers attention to the piece about to be moved and
\r
10580 then to where it ends up. Too few frames would be less
\r
10584 Tween(start, mid, finish, factor, frames, nFrames)
\r
10585 POINT * start; POINT * mid;
\r
10586 POINT * finish; int factor;
\r
10587 POINT frames[]; int * nFrames;
\r
10589 int n, fraction = 1, count = 0;
\r
10591 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10592 for (n = 0; n < factor; n++)
\r
10594 for (n = 0; n < factor; n++) {
\r
10595 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10596 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10598 fraction = fraction / 2;
\r
10602 frames[count] = *mid;
\r
10605 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10607 for (n = 0; n < factor; n++) {
\r
10608 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10609 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10611 fraction = fraction * 2;
\r
10613 *nFrames = count;
\r
10617 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10619 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10621 EvalGraphSet( first, last, current, pvInfoList );
\r
10624 void SetProgramStats( FrontEndProgramStats * stats )
\r
10626 EngineOutputUpdate( stats );
\r