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 "winboard.h"
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
87 #include "wclipbrd.h"
\r
88 #include "wgamelist.h"
\r
89 #include "wedittags.h"
\r
90 #include "woptions.h"
\r
91 #include "wsockerr.h"
\r
92 #include "defaults.h"
\r
96 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
99 void mysrandom(unsigned int seed);
\r
101 extern int whiteFlag, blackFlag;
\r
102 Boolean flipClock = FALSE;
\r
103 extern HANDLE chatHandle[];
\r
104 extern int ics_type;
\r
106 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
107 VOID NewVariantPopup(HWND hwnd);
\r
108 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
109 /*char*/int promoChar));
\r
110 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
111 void DisplayMove P((int moveNumber));
\r
112 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
113 void ChatPopUp P(());
\r
115 ChessSquare piece;
\r
116 POINT pos; /* window coordinates of current pos */
\r
117 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
118 POINT from; /* board coordinates of the piece's orig pos */
\r
119 POINT to; /* board coordinates of the piece's new pos */
\r
122 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
125 POINT start; /* window coordinates of start pos */
\r
126 POINT pos; /* window coordinates of current pos */
\r
127 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
128 POINT from; /* board coordinates of the piece's orig pos */
\r
131 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
134 POINT sq[2]; /* board coordinates of from, to squares */
\r
137 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
140 typedef struct { // [HGM] atomic
\r
141 int fromX, fromY, toX, toY, radius;
\r
144 static ExplodeInfo explodeInfo;
\r
146 /* Window class names */
\r
147 char szAppName[] = "WinBoard";
\r
148 char szConsoleName[] = "WBConsole";
\r
150 /* Title bar text */
\r
151 char szTitle[] = "WinBoard";
\r
152 char szConsoleTitle[] = "I C S Interaction";
\r
155 char *settingsFileName;
\r
156 BOOLEAN saveSettingsOnExit;
\r
157 char installDir[MSG_SIZ];
\r
159 BoardSize boardSize;
\r
160 BOOLEAN chessProgram;
\r
161 static int boardX, boardY;
\r
162 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
163 static int squareSize, lineGap, minorSize;
\r
164 static int winWidth, winHeight, winW, winH;
\r
165 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
166 static int logoHeight = 0;
\r
167 static char messageText[MESSAGE_TEXT_MAX];
\r
168 static int clockTimerEvent = 0;
\r
169 static int loadGameTimerEvent = 0;
\r
170 static int analysisTimerEvent = 0;
\r
171 static DelayedEventCallback delayedTimerCallback;
\r
172 static int delayedTimerEvent = 0;
\r
173 static int buttonCount = 2;
\r
174 char *icsTextMenuString;
\r
176 char *firstChessProgramNames;
\r
177 char *secondChessProgramNames;
\r
179 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
181 #define PALETTESIZE 256
\r
183 HINSTANCE hInst; /* current instance */
\r
184 HWND hwndMain = NULL; /* root window*/
\r
185 HWND hwndConsole = NULL;
\r
186 BOOLEAN alwaysOnTop = FALSE;
\r
188 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
189 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
191 ColorClass currentColorClass;
\r
193 HWND hCommPort = NULL; /* currently open comm port */
\r
194 static HWND hwndPause; /* pause button */
\r
195 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
196 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
197 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
198 explodeBrush, /* [HGM] atomic */
\r
199 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
200 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
201 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
202 static HPEN gridPen = NULL;
\r
203 static HPEN highlightPen = NULL;
\r
204 static HPEN premovePen = NULL;
\r
205 static NPLOGPALETTE pLogPal;
\r
206 static BOOL paletteChanged = FALSE;
\r
207 static HICON iconWhite, iconBlack, iconCurrent;
\r
208 static int doingSizing = FALSE;
\r
209 static int lastSizing = 0;
\r
210 static int prevStderrPort;
\r
211 static HBITMAP userLogo;
\r
213 /* [AS] Support for background textures */
\r
214 #define BACK_TEXTURE_MODE_DISABLED 0
\r
215 #define BACK_TEXTURE_MODE_PLAIN 1
\r
216 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
218 static HBITMAP liteBackTexture = NULL;
\r
219 static HBITMAP darkBackTexture = NULL;
\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int backTextureSquareSize = 0;
\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
225 #if __GNUC__ && !defined(_winmajor)
\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
228 #if defined(_winmajor)
\r
229 #define oldDialog (_winmajor < 4)
\r
231 #define oldDialog 0
\r
235 char *defaultTextAttribs[] =
\r
237 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
238 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
248 int cliWidth, cliHeight;
\r
251 SizeInfo sizeInfo[] =
\r
253 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
254 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
255 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
256 { "petite", 33, 1, 1, 1, 0, 0 },
\r
257 { "slim", 37, 2, 1, 0, 0, 0 },
\r
258 { "small", 40, 2, 1, 0, 0, 0 },
\r
259 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
260 { "middling", 49, 2, 0, 0, 0, 0 },
\r
261 { "average", 54, 2, 0, 0, 0, 0 },
\r
262 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
263 { "medium", 64, 3, 0, 0, 0, 0 },
\r
264 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
265 { "large", 80, 3, 0, 0, 0, 0 },
\r
266 { "big", 87, 3, 0, 0, 0, 0 },
\r
267 { "huge", 95, 3, 0, 0, 0, 0 },
\r
268 { "giant", 108, 3, 0, 0, 0, 0 },
\r
269 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
270 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
271 { NULL, 0, 0, 0, 0, 0, 0 }
\r
274 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
275 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
277 { 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
278 { 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
279 { 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
280 { 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
281 { 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
282 { 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
283 { 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
284 { 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
285 { 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
286 { 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
287 { 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
288 { 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
289 { 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
290 { 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
291 { 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
292 { 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
293 { 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
294 { 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
297 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
306 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
307 #define N_BUTTONS 5
\r
309 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
311 {"<<", IDM_ToStart, NULL, NULL},
\r
312 {"<", IDM_Backward, NULL, NULL},
\r
313 {"P", IDM_Pause, NULL, NULL},
\r
314 {">", IDM_Forward, NULL, NULL},
\r
315 {">>", IDM_ToEnd, NULL, NULL},
\r
318 int tinyLayout = 0, smallLayout = 0;
\r
319 #define MENU_BAR_ITEMS 7
\r
320 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
321 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
322 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
326 MySound sounds[(int)NSoundClasses];
\r
327 MyTextAttribs textAttribs[(int)NColorClasses];
\r
329 MyColorizeAttribs colorizeAttribs[] = {
\r
330 { (COLORREF)0, 0, "Shout Text" },
\r
331 { (COLORREF)0, 0, "SShout/CShout" },
\r
332 { (COLORREF)0, 0, "Channel 1 Text" },
\r
333 { (COLORREF)0, 0, "Channel Text" },
\r
334 { (COLORREF)0, 0, "Kibitz Text" },
\r
335 { (COLORREF)0, 0, "Tell Text" },
\r
336 { (COLORREF)0, 0, "Challenge Text" },
\r
337 { (COLORREF)0, 0, "Request Text" },
\r
338 { (COLORREF)0, 0, "Seek Text" },
\r
339 { (COLORREF)0, 0, "Normal Text" },
\r
340 { (COLORREF)0, 0, "None" }
\r
345 static char *commentTitle;
\r
346 static char *commentText;
\r
347 static int commentIndex;
\r
348 static Boolean editComment = FALSE;
\r
349 HWND commentDialog = NULL;
\r
350 BOOLEAN commentDialogUp = FALSE;
\r
351 static int commentX, commentY, commentH, commentW;
\r
353 static char *analysisTitle;
\r
354 static char *analysisText;
\r
355 HWND analysisDialog = NULL;
\r
356 BOOLEAN analysisDialogUp = FALSE;
\r
357 static int analysisX, analysisY, analysisH, analysisW;
\r
359 char errorTitle[MSG_SIZ];
\r
360 char errorMessage[2*MSG_SIZ];
\r
361 HWND errorDialog = NULL;
\r
362 BOOLEAN moveErrorMessageUp = FALSE;
\r
363 BOOLEAN consoleEcho = TRUE;
\r
364 CHARFORMAT consoleCF;
\r
365 COLORREF consoleBackgroundColor;
\r
367 char *programVersion;
\r
373 typedef int CPKind;
\r
382 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
385 #define INPUT_SOURCE_BUF_SIZE 4096
\r
387 typedef struct _InputSource {
\r
394 char buf[INPUT_SOURCE_BUF_SIZE];
\r
398 InputCallback func;
\r
399 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
403 InputSource *consoleInputSource;
\r
408 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
409 VOID ConsoleCreate();
\r
411 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
412 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
413 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
414 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
416 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
417 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
418 void ParseIcsTextMenu(char *icsTextMenuString);
\r
419 VOID PopUpMoveDialog(char firstchar);
\r
420 VOID PopUpNameDialog(char firstchar);
\r
421 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
425 int GameListOptions();
\r
427 HWND moveHistoryDialog = NULL;
\r
428 BOOLEAN moveHistoryDialogUp = FALSE;
\r
430 WindowPlacement wpMoveHistory;
\r
432 HWND evalGraphDialog = NULL;
\r
433 BOOLEAN evalGraphDialogUp = FALSE;
\r
435 WindowPlacement wpEvalGraph;
\r
437 HWND engineOutputDialog = NULL;
\r
438 BOOLEAN engineOutputDialogUp = FALSE;
\r
440 WindowPlacement wpEngineOutput;
\r
441 WindowPlacement wpGameList;
\r
442 WindowPlacement wpConsole;
\r
444 VOID MoveHistoryPopUp();
\r
445 VOID MoveHistoryPopDown();
\r
446 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
447 BOOL MoveHistoryIsUp();
\r
449 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
450 VOID EvalGraphPopUp();
\r
451 VOID EvalGraphPopDown();
\r
452 BOOL EvalGraphIsUp();
\r
454 VOID EngineOutputPopUp();
\r
455 VOID EngineOutputPopDown();
\r
456 BOOL EngineOutputIsUp();
\r
457 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
459 VOID EngineOptionsPopup(); // [HGM] settings
\r
461 VOID GothicPopUp(char *title, VariantClass variant);
\r
463 * Setting "frozen" should disable all user input other than deleting
\r
464 * the window. We do this while engines are initializing themselves.
\r
466 static int frozen = 0;
\r
467 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
473 if (frozen) return;
\r
475 hmenu = GetMenu(hwndMain);
\r
476 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
477 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
479 DrawMenuBar(hwndMain);
\r
482 /* Undo a FreezeUI */
\r
488 if (!frozen) return;
\r
490 hmenu = GetMenu(hwndMain);
\r
491 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
492 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
494 DrawMenuBar(hwndMain);
\r
497 /*static*/ int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
499 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
505 #define JAWS_ALT_INTERCEPT
\r
506 #define JAWS_KB_NAVIGATION
\r
507 #define JAWS_MENU_ITEMS
\r
508 #define JAWS_SILENCE
\r
509 #define JAWS_REPLAY
\r
511 #define JAWS_COPYRIGHT
\r
512 #define JAWS_DELETE(X) X
\r
513 #define SAYMACHINEMOVE()
\r
517 /*---------------------------------------------------------------------------*\
\r
521 \*---------------------------------------------------------------------------*/
\r
524 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
525 LPSTR lpCmdLine, int nCmdShow)
\r
528 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
529 // INITCOMMONCONTROLSEX ex;
\r
533 LoadLibrary("RICHED32.DLL");
\r
534 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
536 if (!InitApplication(hInstance)) {
\r
539 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
545 // InitCommonControlsEx(&ex);
\r
546 InitCommonControls();
\r
548 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
549 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
550 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
552 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
554 while (GetMessage(&msg, /* message structure */
\r
555 NULL, /* handle of window receiving the message */
\r
556 0, /* lowest message to examine */
\r
557 0)) /* highest message to examine */
\r
560 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
561 // [HGM] navigate: switch between all windows with tab
\r
562 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
563 int i, currentElement = 0;
\r
565 // first determine what element of the chain we come from (if any)
\r
566 if(appData.icsActive) {
\r
567 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
568 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
570 if(engineOutputDialog && EngineOutputIsUp()) {
\r
571 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
572 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
574 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
575 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
577 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
578 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
579 if(msg.hwnd == e1) currentElement = 2; else
\r
580 if(msg.hwnd == e2) currentElement = 3; else
\r
581 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
582 if(msg.hwnd == mh) currentElement = 4; else
\r
583 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
584 if(msg.hwnd == hText) currentElement = 5; else
\r
585 if(msg.hwnd == hInput) currentElement = 6; else
\r
586 for (i = 0; i < N_BUTTONS; i++) {
\r
587 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
590 // determine where to go to
\r
591 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
593 currentElement = (currentElement + direction) % 7;
\r
594 switch(currentElement) {
\r
596 h = hwndMain; break; // passing this case always makes the loop exit
\r
598 h = buttonDesc[0].hwnd; break; // could be NULL
\r
600 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
603 if(!EngineOutputIsUp()) continue;
\r
606 if(!MoveHistoryIsUp()) continue;
\r
608 // case 6: // input to eval graph does not seem to get here!
\r
609 // if(!EvalGraphIsUp()) continue;
\r
610 // h = evalGraphDialog; break;
\r
612 if(!appData.icsActive) continue;
\r
616 if(!appData.icsActive) continue;
\r
622 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
623 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
626 continue; // this message now has been processed
\r
630 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
631 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
632 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
633 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
634 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
635 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
636 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
637 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
638 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
639 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
640 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
641 for(i=0; i<MAX_CHAT; i++)
\r
642 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
645 if(done) continue; // [HGM] chat: end patch
\r
646 TranslateMessage(&msg); /* Translates virtual key codes */
\r
647 DispatchMessage(&msg); /* Dispatches message to window */
\r
652 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
655 /*---------------------------------------------------------------------------*\
\r
657 * Initialization functions
\r
659 \*---------------------------------------------------------------------------*/
\r
663 { // update user logo if necessary
\r
664 static char oldUserName[MSG_SIZ], *curName;
\r
666 if(appData.autoLogo) {
\r
667 curName = UserName();
\r
668 if(strcmp(curName, oldUserName)) {
\r
669 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
670 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
671 strcpy(oldUserName, curName);
\r
677 InitApplication(HINSTANCE hInstance)
\r
681 /* Fill in window class structure with parameters that describe the */
\r
684 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
685 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
686 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
687 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
688 wc.hInstance = hInstance; /* Owner of this class */
\r
689 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
690 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
691 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
692 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
693 wc.lpszClassName = szAppName; /* Name to register as */
\r
695 /* Register the window class and return success/failure code. */
\r
696 if (!RegisterClass(&wc)) return FALSE;
\r
698 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
699 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
701 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
702 wc.hInstance = hInstance;
\r
703 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
704 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
705 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
706 wc.lpszMenuName = NULL;
\r
707 wc.lpszClassName = szConsoleName;
\r
709 if (!RegisterClass(&wc)) return FALSE;
\r
714 /* Set by InitInstance, used by EnsureOnScreen */
\r
715 int screenHeight, screenWidth;
\r
718 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
720 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
721 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
722 if (*x > screenWidth - 32) *x = 0;
\r
723 if (*y > screenHeight - 32) *y = 0;
\r
724 if (*x < minX) *x = minX;
\r
725 if (*y < minY) *y = minY;
\r
729 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
731 HWND hwnd; /* Main window handle. */
\r
733 WINDOWPLACEMENT wp;
\r
736 hInst = hInstance; /* Store instance handle in our global variable */
\r
738 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
739 *filepart = NULLCHAR;
\r
741 GetCurrentDirectory(MSG_SIZ, installDir);
\r
743 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
744 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
745 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
746 if (appData.debugMode) {
\r
747 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
748 setbuf(debugFP, NULL);
\r
753 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
754 // InitEngineUCI( installDir, &second );
\r
756 /* Create a main window for this application instance. */
\r
757 hwnd = CreateWindow(szAppName, szTitle,
\r
758 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
759 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
760 NULL, NULL, hInstance, NULL);
\r
763 /* If window could not be created, return "failure" */
\r
768 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
769 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
770 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
772 if (first.programLogo == NULL && appData.debugMode) {
\r
773 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
775 } else if(appData.autoLogo) {
\r
776 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
778 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
779 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
783 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
784 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
786 if (second.programLogo == NULL && appData.debugMode) {
\r
787 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
789 } else if(appData.autoLogo) {
\r
791 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
792 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
793 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
795 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
796 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
797 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
803 iconWhite = LoadIcon(hInstance, "icon_white");
\r
804 iconBlack = LoadIcon(hInstance, "icon_black");
\r
805 iconCurrent = iconWhite;
\r
806 InitDrawingColors();
\r
807 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
808 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
809 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
810 /* Compute window size for each board size, and use the largest
\r
811 size that fits on this screen as the default. */
\r
812 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
813 if (boardSize == (BoardSize)-1 &&
\r
814 winH <= screenHeight
\r
815 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
816 && winW <= screenWidth) {
\r
817 boardSize = (BoardSize)ibs;
\r
821 InitDrawingSizes(boardSize, 0);
\r
823 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
825 /* [AS] Load textures if specified */
\r
826 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
828 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
829 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
830 liteBackTextureMode = appData.liteBackTextureMode;
\r
832 if (liteBackTexture == NULL && appData.debugMode) {
\r
833 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
837 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
838 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
839 darkBackTextureMode = appData.darkBackTextureMode;
\r
841 if (darkBackTexture == NULL && appData.debugMode) {
\r
842 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
846 mysrandom( (unsigned) time(NULL) );
\r
848 /* [AS] Restore layout */
\r
849 if( wpMoveHistory.visible ) {
\r
850 MoveHistoryPopUp();
\r
853 if( wpEvalGraph.visible ) {
\r
857 if( wpEngineOutput.visible ) {
\r
858 EngineOutputPopUp();
\r
863 /* Make the window visible; update its client area; and return "success" */
\r
864 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
865 wp.length = sizeof(WINDOWPLACEMENT);
\r
867 wp.showCmd = nCmdShow;
\r
868 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
869 wp.rcNormalPosition.left = boardX;
\r
870 wp.rcNormalPosition.right = boardX + winWidth;
\r
871 wp.rcNormalPosition.top = boardY;
\r
872 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
873 SetWindowPlacement(hwndMain, &wp);
\r
875 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
876 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
880 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
881 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
883 ShowWindow(hwndConsole, nCmdShow);
\r
885 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
886 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
894 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
895 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
896 ArgSettingsFilename,
\r
897 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
905 String *pString; // ArgString
\r
906 int *pInt; // ArgInt
\r
907 float *pFloat; // ArgFloat
\r
908 Boolean *pBoolean; // ArgBoolean
\r
909 COLORREF *pColor; // ArgColor
\r
910 ColorClass cc; // ArgAttribs
\r
911 String *pFilename; // ArgFilename
\r
912 BoardSize *pBoardSize; // ArgBoardSize
\r
913 int whichFont; // ArgFont
\r
914 DCB *pDCB; // ArgCommSettings
\r
915 String *pFilename; // ArgSettingsFilename
\r
923 ArgDescriptor argDescriptors[] = {
\r
924 /* positional arguments */
\r
925 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
926 { "", ArgNone, NULL },
\r
927 /* keyword arguments */
\r
929 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
930 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
931 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
932 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
933 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
934 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
935 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
936 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
937 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
938 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
939 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
940 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
941 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
942 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
943 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
944 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
945 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
946 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
948 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
950 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
952 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
953 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
955 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
956 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
957 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
958 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
959 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
960 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
961 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
962 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
963 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
964 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
965 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
966 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
967 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
968 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
969 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
970 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
971 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
972 /*!!bitmapDirectory?*/
\r
973 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
974 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
975 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
976 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
977 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
978 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
979 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
980 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
981 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
982 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
983 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
984 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
985 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
986 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
987 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
988 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
989 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
990 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
991 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
992 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
993 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
994 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
995 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
996 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
997 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
998 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
999 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
1000 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
1001 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
1002 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
1003 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
1004 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1005 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1006 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1007 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1008 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
1009 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
1010 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
1011 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1012 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1013 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1014 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1015 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1016 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1017 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1018 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1019 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1020 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1021 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1022 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1023 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1024 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1025 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1026 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1027 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1028 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1029 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1030 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1031 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1032 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1033 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1034 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1035 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1036 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1037 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1038 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1039 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1040 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1041 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1042 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1043 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1044 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1045 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1046 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1047 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1048 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1049 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1050 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1051 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1052 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1053 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1054 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1055 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1056 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1057 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1058 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1059 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1060 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1061 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1062 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1063 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1064 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1065 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1066 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1067 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1068 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1069 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1070 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1071 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1072 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1073 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1074 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1075 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1076 TRUE }, /* must come after all fonts */
\r
1077 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1078 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1079 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1080 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1081 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1082 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1083 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1084 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1085 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1086 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1087 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1088 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1089 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1090 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1091 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1092 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1093 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1094 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1095 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1096 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1097 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1098 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1099 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1100 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1101 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1102 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1103 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1104 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1105 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1106 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1107 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1108 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1109 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1110 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1111 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1112 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1113 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1114 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1115 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1116 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1117 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1118 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1119 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1120 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1121 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1122 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1123 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1124 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1125 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1126 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1127 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1128 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1129 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1130 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1131 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1132 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1133 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1134 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1135 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1136 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1137 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1138 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1139 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1140 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1141 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1142 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1143 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1144 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1145 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1146 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1147 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1148 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1149 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1150 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1151 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1152 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1153 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1154 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1155 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1156 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1157 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1158 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1159 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1160 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1161 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1162 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1163 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1164 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1165 { "highlightLastMove", ArgBoolean,
\r
1166 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1167 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1168 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1169 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1170 { "highlightDragging", ArgBoolean,
\r
1171 (LPVOID) &appData.highlightDragging, TRUE },
\r
1172 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1173 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1174 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1175 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1176 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1177 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1178 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1179 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1180 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1181 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1182 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1183 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1184 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1185 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1186 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1187 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1188 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1189 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1190 { "soundShout", ArgFilename,
\r
1191 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1192 { "soundSShout", ArgFilename,
\r
1193 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1194 { "soundChannel1", ArgFilename,
\r
1195 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1196 { "soundChannel", ArgFilename,
\r
1197 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1198 { "soundKibitz", ArgFilename,
\r
1199 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1200 { "soundTell", ArgFilename,
\r
1201 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1202 { "soundChallenge", ArgFilename,
\r
1203 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1204 { "soundRequest", ArgFilename,
\r
1205 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1206 { "soundSeek", ArgFilename,
\r
1207 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1208 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1209 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1210 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1211 { "soundIcsLoss", ArgFilename,
\r
1212 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1213 { "soundIcsDraw", ArgFilename,
\r
1214 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1215 { "soundIcsUnfinished", ArgFilename,
\r
1216 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1217 { "soundIcsAlarm", ArgFilename,
\r
1218 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1219 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1220 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1221 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1222 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1223 { "reuseChessPrograms", ArgBoolean,
\r
1224 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1225 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1226 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1227 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1228 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1229 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1230 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1231 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1232 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1233 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1234 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1235 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1236 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1237 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1238 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1239 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1241 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1243 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1244 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1245 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1246 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1247 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1248 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1249 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1250 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1251 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1252 /* [AS] New features */
\r
1253 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1254 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1255 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1256 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1257 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1258 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1259 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1260 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1261 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1262 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1263 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1264 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1265 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1266 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1267 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1268 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1269 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1270 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1271 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1272 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1273 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1274 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1275 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1276 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1277 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1278 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1279 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1280 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1281 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1282 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1283 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1284 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1285 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1286 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1287 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1288 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1289 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1290 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1291 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1292 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1293 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1294 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1295 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1296 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1297 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1298 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1299 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1300 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1301 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1302 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1304 /* [HGM] board-size, adjudication and misc. options */
\r
1305 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1306 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1307 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1308 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1309 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1310 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1311 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1312 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1313 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1314 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1315 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1316 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1317 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1318 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1319 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1320 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1321 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1322 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1323 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1324 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1325 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1326 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1327 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1328 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1329 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1330 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1331 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1332 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1333 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1334 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1335 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1336 { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },
\r
1337 { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },
\r
1338 { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE },
\r
1341 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1342 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1343 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1344 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1345 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1346 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1347 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1348 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1349 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1350 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1351 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1352 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1353 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1355 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1356 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1357 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1358 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1359 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1360 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1361 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1363 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1364 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1365 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1366 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1367 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1368 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1369 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1370 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1371 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1372 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1373 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1374 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1375 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1376 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1377 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1378 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1379 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1380 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1381 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1383 /* [HGM] options for broadcasting and time odds */
\r
1384 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1385 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1386 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1387 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1388 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1389 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1390 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1391 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1392 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1393 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1394 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1396 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1397 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1398 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1399 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1400 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1401 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1402 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1403 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1404 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1405 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1406 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1407 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1408 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1409 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1410 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1411 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1412 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1413 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1414 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1415 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1416 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1417 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1418 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1419 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1420 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1421 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1422 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1423 /* [AS] Layout stuff */
\r
1424 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1425 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1426 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1427 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1428 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1430 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1431 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1432 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1433 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1434 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1436 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1437 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1438 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1439 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1440 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1442 { NULL, ArgNone, NULL, FALSE }
\r
1446 /* Kludge for indirection files on command line */
\r
1447 char* lastIndirectionFilename;
\r
1448 ArgDescriptor argDescriptorIndirection =
\r
1449 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1453 ExitArgError(char *msg, char *badArg)
\r
1455 char buf[MSG_SIZ];
\r
1457 sprintf(buf, "%s %s", msg, badArg);
\r
1458 DisplayFatalError(buf, 0, 2);
\r
1462 /* Command line font name parser. NULL name means do nothing.
\r
1463 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1464 For backward compatibility, syntax without the colon is also
\r
1465 accepted, but font names with digits in them won't work in that case.
\r
1468 ParseFontName(char *name, MyFontParams *mfp)
\r
1471 if (name == NULL) return;
\r
1473 q = strchr(p, ':');
\r
1475 if (q - p >= sizeof(mfp->faceName))
\r
1476 ExitArgError("Font name too long:", name);
\r
1477 memcpy(mfp->faceName, p, q - p);
\r
1478 mfp->faceName[q - p] = NULLCHAR;
\r
1481 q = mfp->faceName;
\r
1482 while (*p && !isdigit(*p)) {
\r
1484 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1485 ExitArgError("Font name too long:", name);
\r
1487 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1490 if (!*p) ExitArgError("Font point size missing:", name);
\r
1491 mfp->pointSize = (float) atof(p);
\r
1492 mfp->bold = (strchr(p, 'b') != NULL);
\r
1493 mfp->italic = (strchr(p, 'i') != NULL);
\r
1494 mfp->underline = (strchr(p, 'u') != NULL);
\r
1495 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1498 /* Color name parser.
\r
1499 X version accepts X color names, but this one
\r
1500 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1502 ParseColorName(char *name)
\r
1504 int red, green, blue, count;
\r
1505 char buf[MSG_SIZ];
\r
1507 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1509 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1510 &red, &green, &blue);
\r
1513 sprintf(buf, "Can't parse color name %s", name);
\r
1514 DisplayError(buf, 0);
\r
1515 return RGB(0, 0, 0);
\r
1517 return PALETTERGB(red, green, blue);
\r
1521 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1523 char *e = argValue;
\r
1527 if (*e == 'b') eff |= CFE_BOLD;
\r
1528 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1529 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1530 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1531 else if (*e == '#' || isdigit(*e)) break;
\r
1535 *color = ParseColorName(e);
\r
1540 ParseBoardSize(char *name)
\r
1542 BoardSize bs = SizeTiny;
\r
1543 while (sizeInfo[bs].name != NULL) {
\r
1544 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1547 ExitArgError("Unrecognized board size value", name);
\r
1548 return bs; /* not reached */
\r
1553 StringGet(void *getClosure)
\r
1555 char **p = (char **) getClosure;
\r
1560 FileGet(void *getClosure)
\r
1563 FILE* f = (FILE*) getClosure;
\r
1566 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1573 /* Parse settings file named "name". If file found, return the
\r
1574 full name in fullname and return TRUE; else return FALSE */
\r
1576 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1580 int ok; char buf[MSG_SIZ];
\r
1582 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1583 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1584 sprintf(buf, "%s.ini", name);
\r
1585 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1588 f = fopen(fullname, "r");
\r
1590 ParseArgs(FileGet, f);
\r
1599 ParseArgs(GetFunc get, void *cl)
\r
1601 char argName[ARG_MAX];
\r
1602 char argValue[ARG_MAX];
\r
1603 ArgDescriptor *ad;
\r
1612 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1613 if (ch == NULLCHAR) break;
\r
1615 /* Comment to end of line */
\r
1617 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1619 } else if (ch == '/' || ch == '-') {
\r
1622 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1623 ch != '\n' && ch != '\t') {
\r
1629 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1630 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1632 if (ad->argName == NULL)
\r
1633 ExitArgError("Unrecognized argument", argName);
\r
1635 } else if (ch == '@') {
\r
1636 /* Indirection file */
\r
1637 ad = &argDescriptorIndirection;
\r
1640 /* Positional argument */
\r
1641 ad = &argDescriptors[posarg++];
\r
1642 strcpy(argName, ad->argName);
\r
1645 if (ad->argType == ArgTrue) {
\r
1646 *(Boolean *) ad->argLoc = TRUE;
\r
1649 if (ad->argType == ArgFalse) {
\r
1650 *(Boolean *) ad->argLoc = FALSE;
\r
1654 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1655 if (ch == NULLCHAR || ch == '\n') {
\r
1656 ExitArgError("No value provided for argument", argName);
\r
1660 // Quoting with { }. No characters have to (or can) be escaped.
\r
1661 // Thus the string cannot contain a '}' character.
\r
1681 } else if (ch == '\'' || ch == '"') {
\r
1682 // Quoting with ' ' or " ", with \ as escape character.
\r
1683 // Inconvenient for long strings that may contain Windows filenames.
\r
1700 if (ch == start) {
\r
1709 if (ad->argType == ArgFilename
\r
1710 || ad->argType == ArgSettingsFilename) {
\r
1716 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1740 for (i = 0; i < 3; i++) {
\r
1741 if (ch >= '0' && ch <= '7') {
\r
1742 octval = octval*8 + (ch - '0');
\r
1749 *q++ = (char) octval;
\r
1760 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1767 switch (ad->argType) {
\r
1769 *(int *) ad->argLoc = atoi(argValue);
\r
1773 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1777 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1781 *(int *) ad->argLoc = atoi(argValue);
\r
1782 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1786 *(float *) ad->argLoc = (float) atof(argValue);
\r
1791 *(char **) ad->argLoc = strdup(argValue);
\r
1794 case ArgSettingsFilename:
\r
1796 char fullname[MSG_SIZ];
\r
1797 if (ParseSettingsFile(argValue, fullname)) {
\r
1798 if (ad->argLoc != NULL) {
\r
1799 *(char **) ad->argLoc = strdup(fullname);
\r
1802 if (ad->argLoc != NULL) {
\r
1804 ExitArgError("Failed to open indirection file", argValue);
\r
1811 switch (argValue[0]) {
\r
1814 *(Boolean *) ad->argLoc = TRUE;
\r
1818 *(Boolean *) ad->argLoc = FALSE;
\r
1821 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1827 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1830 case ArgAttribs: {
\r
1831 ColorClass cc = (ColorClass)ad->argLoc;
\r
1832 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1836 case ArgBoardSize:
\r
1837 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1841 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1844 case ArgCommSettings:
\r
1845 ParseCommSettings(argValue, &dcb);
\r
1849 ExitArgError("Unrecognized argument", argValue);
\r
1858 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1860 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1861 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1864 lf->lfEscapement = 0;
\r
1865 lf->lfOrientation = 0;
\r
1866 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1867 lf->lfItalic = mfp->italic;
\r
1868 lf->lfUnderline = mfp->underline;
\r
1869 lf->lfStrikeOut = mfp->strikeout;
\r
1870 lf->lfCharSet = DEFAULT_CHARSET;
\r
1871 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1872 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1873 lf->lfQuality = DEFAULT_QUALITY;
\r
1874 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1875 strcpy(lf->lfFaceName, mfp->faceName);
\r
1879 CreateFontInMF(MyFont *mf)
\r
1881 LFfromMFP(&mf->lf, &mf->mfp);
\r
1882 if (mf->hf) DeleteObject(mf->hf);
\r
1883 mf->hf = CreateFontIndirect(&mf->lf);
\r
1887 SetDefaultTextAttribs()
\r
1890 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1891 ParseAttribs(&textAttribs[cc].color,
\r
1892 &textAttribs[cc].effects,
\r
1893 defaultTextAttribs[cc]);
\r
1898 SetDefaultSounds()
\r
1902 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1903 textAttribs[cc].sound.name = strdup("");
\r
1904 textAttribs[cc].sound.data = NULL;
\r
1906 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1907 sounds[sc].name = strdup("");
\r
1908 sounds[sc].data = NULL;
\r
1910 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1918 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1919 MyLoadSound(&textAttribs[cc].sound);
\r
1921 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1922 MyLoadSound(&sounds[sc]);
\r
1927 InitAppData(LPSTR lpCmdLine)
\r
1930 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1933 programName = szAppName;
\r
1935 /* Initialize to defaults */
\r
1936 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1937 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1938 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1939 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1940 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1941 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1942 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1943 SetDefaultTextAttribs();
\r
1944 SetDefaultSounds();
\r
1945 appData.movesPerSession = MOVES_PER_SESSION;
\r
1946 appData.initString = INIT_STRING;
\r
1947 appData.secondInitString = INIT_STRING;
\r
1948 appData.firstComputerString = COMPUTER_STRING;
\r
1949 appData.secondComputerString = COMPUTER_STRING;
\r
1950 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1951 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1952 appData.firstPlaysBlack = FALSE;
\r
1953 appData.noChessProgram = FALSE;
\r
1954 chessProgram = FALSE;
\r
1955 appData.firstHost = FIRST_HOST;
\r
1956 appData.secondHost = SECOND_HOST;
\r
1957 appData.firstDirectory = FIRST_DIRECTORY;
\r
1958 appData.secondDirectory = SECOND_DIRECTORY;
\r
1959 appData.bitmapDirectory = "";
\r
1960 appData.remoteShell = REMOTE_SHELL;
\r
1961 appData.remoteUser = "";
\r
1962 appData.timeDelay = TIME_DELAY;
\r
1963 appData.timeControl = TIME_CONTROL;
\r
1964 appData.timeIncrement = TIME_INCREMENT;
\r
1965 appData.icsActive = FALSE;
\r
1966 appData.icsHost = "";
\r
1967 appData.icsPort = ICS_PORT;
\r
1968 appData.icsCommPort = ICS_COMM_PORT;
\r
1969 appData.icsLogon = ICS_LOGON;
\r
1970 appData.icsHelper = "";
\r
1971 appData.useTelnet = FALSE;
\r
1972 appData.telnetProgram = TELNET_PROGRAM;
\r
1973 appData.gateway = "";
\r
1974 appData.loadGameFile = "";
\r
1975 appData.loadGameIndex = 0;
\r
1976 appData.saveGameFile = "";
\r
1977 appData.autoSaveGames = FALSE;
\r
1978 appData.loadPositionFile = "";
\r
1979 appData.loadPositionIndex = 1;
\r
1980 appData.savePositionFile = "";
\r
1981 appData.matchMode = FALSE;
\r
1982 appData.matchGames = 0;
\r
1983 appData.monoMode = FALSE;
\r
1984 appData.debugMode = FALSE;
\r
1985 appData.clockMode = TRUE;
\r
1986 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1987 appData.Iconic = FALSE; /*unused*/
\r
1988 appData.searchTime = "";
\r
1989 appData.searchDepth = 0;
\r
1990 appData.showCoords = FALSE;
\r
1991 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1992 appData.autoCallFlag = FALSE;
\r
1993 appData.flipView = FALSE;
\r
1994 appData.autoFlipView = TRUE;
\r
1995 appData.cmailGameName = "";
\r
1996 appData.alwaysPromoteToQueen = FALSE;
\r
1997 appData.oldSaveStyle = FALSE;
\r
1998 appData.quietPlay = FALSE;
\r
1999 appData.showThinking = FALSE;
\r
2000 appData.ponderNextMove = TRUE;
\r
2001 appData.periodicUpdates = TRUE;
\r
2002 appData.popupExitMessage = TRUE;
\r
2003 appData.popupMoveErrors = FALSE;
\r
2004 appData.autoObserve = FALSE;
\r
2005 appData.autoComment = FALSE;
\r
2006 appData.animate = TRUE;
\r
2007 appData.animSpeed = 10;
\r
2008 appData.animateDragging = TRUE;
\r
2009 appData.highlightLastMove = TRUE;
\r
2010 appData.getMoveList = TRUE;
\r
2011 appData.testLegality = TRUE;
\r
2012 appData.premove = TRUE;
\r
2013 appData.premoveWhite = FALSE;
\r
2014 appData.premoveWhiteText = "";
\r
2015 appData.premoveBlack = FALSE;
\r
2016 appData.premoveBlackText = "";
\r
2017 appData.icsAlarm = TRUE;
\r
2018 appData.icsAlarmTime = 5000;
\r
2019 appData.autoRaiseBoard = TRUE;
\r
2020 appData.localLineEditing = TRUE;
\r
2021 appData.colorize = TRUE;
\r
2022 appData.reuseFirst = TRUE;
\r
2023 appData.reuseSecond = TRUE;
\r
2024 appData.blindfold = FALSE;
\r
2025 appData.icsEngineAnalyze = FALSE;
\r
2026 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2027 dcb.DCBlength = sizeof(DCB);
\r
2028 dcb.BaudRate = 9600;
\r
2029 dcb.fBinary = TRUE;
\r
2030 dcb.fParity = FALSE;
\r
2031 dcb.fOutxCtsFlow = FALSE;
\r
2032 dcb.fOutxDsrFlow = FALSE;
\r
2033 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2034 dcb.fDsrSensitivity = FALSE;
\r
2035 dcb.fTXContinueOnXoff = TRUE;
\r
2036 dcb.fOutX = FALSE;
\r
2038 dcb.fNull = FALSE;
\r
2039 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2040 dcb.fAbortOnError = FALSE;
\r
2042 dcb.Parity = SPACEPARITY;
\r
2043 dcb.StopBits = ONESTOPBIT;
\r
2044 settingsFileName = SETTINGS_FILE;
\r
2045 saveSettingsOnExit = TRUE;
\r
2046 boardX = CW_USEDEFAULT;
\r
2047 boardY = CW_USEDEFAULT;
\r
2048 analysisX = CW_USEDEFAULT;
\r
2049 analysisY = CW_USEDEFAULT;
\r
2050 analysisW = CW_USEDEFAULT;
\r
2051 analysisH = CW_USEDEFAULT;
\r
2052 commentX = CW_USEDEFAULT;
\r
2053 commentY = CW_USEDEFAULT;
\r
2054 commentW = CW_USEDEFAULT;
\r
2055 commentH = CW_USEDEFAULT;
\r
2056 editTagsX = CW_USEDEFAULT;
\r
2057 editTagsY = CW_USEDEFAULT;
\r
2058 editTagsW = CW_USEDEFAULT;
\r
2059 editTagsH = CW_USEDEFAULT;
\r
2060 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2061 icsNames = ICS_NAMES;
\r
2062 firstChessProgramNames = FCP_NAMES;
\r
2063 secondChessProgramNames = SCP_NAMES;
\r
2064 appData.initialMode = "";
\r
2065 appData.variant = "normal";
\r
2066 appData.firstProtocolVersion = PROTOVER;
\r
2067 appData.secondProtocolVersion = PROTOVER;
\r
2068 appData.showButtonBar = TRUE;
\r
2070 /* [AS] New properties (see comments in header file) */
\r
2071 appData.firstScoreIsAbsolute = FALSE;
\r
2072 appData.secondScoreIsAbsolute = FALSE;
\r
2073 appData.saveExtendedInfoInPGN = FALSE;
\r
2074 appData.hideThinkingFromHuman = FALSE;
\r
2075 appData.liteBackTextureFile = "";
\r
2076 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2077 appData.darkBackTextureFile = "";
\r
2078 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2079 appData.renderPiecesWithFont = "";
\r
2080 appData.fontToPieceTable = "";
\r
2081 appData.fontBackColorWhite = 0;
\r
2082 appData.fontForeColorWhite = 0;
\r
2083 appData.fontBackColorBlack = 0;
\r
2084 appData.fontForeColorBlack = 0;
\r
2085 appData.fontPieceSize = 80;
\r
2086 appData.overrideLineGap = 1;
\r
2087 appData.adjudicateLossThreshold = 0;
\r
2088 appData.delayBeforeQuit = 0;
\r
2089 appData.delayAfterQuit = 0;
\r
2090 appData.nameOfDebugFile = "winboard.debug";
\r
2091 appData.pgnEventHeader = "Computer Chess Game";
\r
2092 appData.defaultFrcPosition = -1;
\r
2093 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2094 appData.saveOutOfBookInfo = TRUE;
\r
2095 appData.showEvalInMoveHistory = TRUE;
\r
2096 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2097 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2098 appData.highlightMoveWithArrow = FALSE;
\r
2099 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2100 appData.useStickyWindows = TRUE;
\r
2101 appData.adjudicateDrawMoves = 0;
\r
2102 appData.autoDisplayComment = TRUE;
\r
2103 appData.autoDisplayTags = TRUE;
\r
2104 appData.firstIsUCI = FALSE;
\r
2105 appData.secondIsUCI = FALSE;
\r
2106 appData.firstHasOwnBookUCI = TRUE;
\r
2107 appData.secondHasOwnBookUCI = TRUE;
\r
2108 appData.polyglotDir = "";
\r
2109 appData.usePolyglotBook = FALSE;
\r
2110 appData.polyglotBook = "";
\r
2111 appData.defaultHashSize = 64;
\r
2112 appData.defaultCacheSizeEGTB = 4;
\r
2113 appData.defaultPathEGTB = "c:\\egtb";
\r
2114 appData.firstOptions = "";
\r
2115 appData.secondOptions = "";
\r
2117 InitWindowPlacement( &wpGameList );
\r
2118 InitWindowPlacement( &wpMoveHistory );
\r
2119 InitWindowPlacement( &wpEvalGraph );
\r
2120 InitWindowPlacement( &wpEngineOutput );
\r
2121 InitWindowPlacement( &wpConsole );
\r
2123 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2124 appData.NrFiles = -1;
\r
2125 appData.NrRanks = -1;
\r
2126 appData.holdingsSize = -1;
\r
2127 appData.testClaims = FALSE;
\r
2128 appData.checkMates = FALSE;
\r
2129 appData.materialDraws= FALSE;
\r
2130 appData.trivialDraws = FALSE;
\r
2131 appData.ruleMoves = 51;
\r
2132 appData.drawRepeats = 6;
\r
2133 appData.matchPause = 10000;
\r
2134 appData.alphaRank = FALSE;
\r
2135 appData.allWhite = FALSE;
\r
2136 appData.upsideDown = FALSE;
\r
2137 appData.serverPause = 15;
\r
2138 appData.serverMovesName = NULL;
\r
2139 appData.suppressLoadMoves = FALSE;
\r
2140 appData.firstTimeOdds = 1;
\r
2141 appData.secondTimeOdds = 1;
\r
2142 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2143 appData.secondAccumulateTC = 1;
\r
2144 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2145 appData.secondNPS = -1;
\r
2146 appData.engineComments = 1;
\r
2147 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2148 appData.egtFormats = "";
\r
2151 appData.zippyTalk = ZIPPY_TALK;
\r
2152 appData.zippyPlay = ZIPPY_PLAY;
\r
2153 appData.zippyLines = ZIPPY_LINES;
\r
2154 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2155 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2156 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2157 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2158 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2159 appData.zippyUseI = ZIPPY_USE_I;
\r
2160 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2161 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2162 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2163 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2164 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2165 appData.zippyAbort = ZIPPY_ABORT;
\r
2166 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2167 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2168 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2171 /* Point font array elements to structures and
\r
2172 parse default font names */
\r
2173 for (i=0; i<NUM_FONTS; i++) {
\r
2174 for (j=0; j<NUM_SIZES; j++) {
\r
2175 font[j][i] = &fontRec[j][i];
\r
2176 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2180 /* Parse default settings file if any */
\r
2181 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2182 settingsFileName = strdup(buf);
\r
2185 /* Parse command line */
\r
2186 ParseArgs(StringGet, &lpCmdLine);
\r
2188 /* [HGM] make sure board size is acceptable */
\r
2189 if(appData.NrFiles > BOARD_SIZE ||
\r
2190 appData.NrRanks > BOARD_SIZE )
\r
2191 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2193 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2194 * with options from the command line, we now make an even higher priority
\r
2195 * overrule by WB options attached to the engine command line. This so that
\r
2196 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2199 if(appData.firstChessProgram != NULL) {
\r
2200 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2201 static char *f = "first";
\r
2202 char buf[MSG_SIZ], *q = buf;
\r
2203 if(p != NULL) { // engine command line contains WinBoard options
\r
2204 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2205 ParseArgs(StringGet, &q);
\r
2206 p[-1] = 0; // cut them offengine command line
\r
2209 // now do same for second chess program
\r
2210 if(appData.secondChessProgram != NULL) {
\r
2211 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2212 static char *s = "second";
\r
2213 char buf[MSG_SIZ], *q = buf;
\r
2214 if(p != NULL) { // engine command line contains WinBoard options
\r
2215 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2216 ParseArgs(StringGet, &q);
\r
2217 p[-1] = 0; // cut them offengine command line
\r
2222 /* Propagate options that affect others */
\r
2223 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2224 if (appData.icsActive || appData.noChessProgram) {
\r
2225 chessProgram = FALSE; /* not local chess program mode */
\r
2228 /* Open startup dialog if needed */
\r
2229 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2230 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2231 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2232 *appData.secondChessProgram == NULLCHAR))) {
\r
2235 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2236 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2237 FreeProcInstance(lpProc);
\r
2240 /* Make sure save files land in the right (?) directory */
\r
2241 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2242 appData.saveGameFile = strdup(buf);
\r
2244 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2245 appData.savePositionFile = strdup(buf);
\r
2248 /* Finish initialization for fonts and sounds */
\r
2249 for (i=0; i<NUM_FONTS; i++) {
\r
2250 for (j=0; j<NUM_SIZES; j++) {
\r
2251 CreateFontInMF(font[j][i]);
\r
2254 /* xboard, and older WinBoards, controlled the move sound with the
\r
2255 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2256 always turn the option on (so that the backend will call us),
\r
2257 then let the user turn the sound off by setting it to silence if
\r
2258 desired. To accommodate old winboard.ini files saved by old
\r
2259 versions of WinBoard, we also turn off the sound if the option
\r
2260 was initially set to false. */
\r
2261 if (!appData.ringBellAfterMoves) {
\r
2262 sounds[(int)SoundMove].name = strdup("");
\r
2263 appData.ringBellAfterMoves = TRUE;
\r
2265 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2266 SetCurrentDirectory(installDir);
\r
2268 SetCurrentDirectory(currDir);
\r
2270 p = icsTextMenuString;
\r
2271 if (p[0] == '@') {
\r
2272 FILE* f = fopen(p + 1, "r");
\r
2274 DisplayFatalError(p + 1, errno, 2);
\r
2277 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2279 buf[i] = NULLCHAR;
\r
2282 ParseIcsTextMenu(strdup(p));
\r
2289 HMENU hmenu = GetMenu(hwndMain);
\r
2291 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2292 MF_BYCOMMAND|((appData.icsActive &&
\r
2293 *appData.icsCommPort != NULLCHAR) ?
\r
2294 MF_ENABLED : MF_GRAYED));
\r
2295 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2296 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2297 MF_CHECKED : MF_UNCHECKED));
\r
2302 SaveSettings(char* name)
\r
2305 ArgDescriptor *ad;
\r
2306 WINDOWPLACEMENT wp;
\r
2307 char dir[MSG_SIZ];
\r
2309 if (!hwndMain) return;
\r
2311 GetCurrentDirectory(MSG_SIZ, dir);
\r
2312 SetCurrentDirectory(installDir);
\r
2313 f = fopen(name, "w");
\r
2314 SetCurrentDirectory(dir);
\r
2316 DisplayError(name, errno);
\r
2319 fprintf(f, ";\n");
\r
2320 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2321 fprintf(f, ";\n");
\r
2322 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2323 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2324 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2325 fprintf(f, ";\n");
\r
2327 wp.length = sizeof(WINDOWPLACEMENT);
\r
2328 GetWindowPlacement(hwndMain, &wp);
\r
2329 boardX = wp.rcNormalPosition.left;
\r
2330 boardY = wp.rcNormalPosition.top;
\r
2332 if (hwndConsole) {
\r
2333 GetWindowPlacement(hwndConsole, &wp);
\r
2334 wpConsole.x = wp.rcNormalPosition.left;
\r
2335 wpConsole.y = wp.rcNormalPosition.top;
\r
2336 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2337 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2340 if (analysisDialog) {
\r
2341 GetWindowPlacement(analysisDialog, &wp);
\r
2342 analysisX = wp.rcNormalPosition.left;
\r
2343 analysisY = wp.rcNormalPosition.top;
\r
2344 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2345 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2348 if (commentDialog) {
\r
2349 GetWindowPlacement(commentDialog, &wp);
\r
2350 commentX = wp.rcNormalPosition.left;
\r
2351 commentY = wp.rcNormalPosition.top;
\r
2352 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2353 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2356 if (editTagsDialog) {
\r
2357 GetWindowPlacement(editTagsDialog, &wp);
\r
2358 editTagsX = wp.rcNormalPosition.left;
\r
2359 editTagsY = wp.rcNormalPosition.top;
\r
2360 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2361 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2364 if (gameListDialog) {
\r
2365 GetWindowPlacement(gameListDialog, &wp);
\r
2366 wpGameList.x = wp.rcNormalPosition.left;
\r
2367 wpGameList.y = wp.rcNormalPosition.top;
\r
2368 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2369 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2372 /* [AS] Move history */
\r
2373 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2375 if( moveHistoryDialog ) {
\r
2376 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2377 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2378 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2379 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2380 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2383 /* [AS] Eval graph */
\r
2384 wpEvalGraph.visible = EvalGraphIsUp();
\r
2386 if( evalGraphDialog ) {
\r
2387 GetWindowPlacement(evalGraphDialog, &wp);
\r
2388 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2389 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2390 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2391 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2394 /* [AS] Engine output */
\r
2395 wpEngineOutput.visible = EngineOutputIsUp();
\r
2397 if( engineOutputDialog ) {
\r
2398 GetWindowPlacement(engineOutputDialog, &wp);
\r
2399 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2400 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2401 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2402 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2405 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2406 if (!ad->save) continue;
\r
2407 switch (ad->argType) {
\r
2410 char *p = *(char **)ad->argLoc;
\r
2411 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2412 /* Quote multiline values or \-containing values
\r
2413 with { } if possible */
\r
2414 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2416 /* Else quote with " " */
\r
2417 fprintf(f, "/%s=\"", ad->argName);
\r
2419 if (*p == '\n') fprintf(f, "\n");
\r
2420 else if (*p == '\r') fprintf(f, "\\r");
\r
2421 else if (*p == '\t') fprintf(f, "\\t");
\r
2422 else if (*p == '\b') fprintf(f, "\\b");
\r
2423 else if (*p == '\f') fprintf(f, "\\f");
\r
2424 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2425 else if (*p == '\"') fprintf(f, "\\\"");
\r
2426 else if (*p == '\\') fprintf(f, "\\\\");
\r
2430 fprintf(f, "\"\n");
\r
2436 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2439 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2442 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2445 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2448 fprintf(f, "/%s=%s\n", ad->argName,
\r
2449 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2452 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2455 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2459 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2460 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2461 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2466 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2467 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2468 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2469 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2470 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2471 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2472 (ta->effects) ? " " : "",
\r
2473 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2477 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2478 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2480 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2483 case ArgBoardSize:
\r
2484 fprintf(f, "/%s=%s\n", ad->argName,
\r
2485 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2490 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2491 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2492 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2493 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2494 ad->argName, mfp->faceName, mfp->pointSize,
\r
2495 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2496 mfp->bold ? "b" : "",
\r
2497 mfp->italic ? "i" : "",
\r
2498 mfp->underline ? "u" : "",
\r
2499 mfp->strikeout ? "s" : "");
\r
2503 case ArgCommSettings:
\r
2504 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2506 case ArgSettingsFilename: ;
\r
2514 /*---------------------------------------------------------------------------*\
\r
2516 * GDI board drawing routines
\r
2518 \*---------------------------------------------------------------------------*/
\r
2520 /* [AS] Draw square using background texture */
\r
2521 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2526 return; /* Should never happen! */
\r
2529 SetGraphicsMode( dst, GM_ADVANCED );
\r
2536 /* X reflection */
\r
2541 x.eDx = (FLOAT) dw + dx - 1;
\r
2544 SetWorldTransform( dst, &x );
\r
2547 /* Y reflection */
\r
2553 x.eDy = (FLOAT) dh + dy - 1;
\r
2555 SetWorldTransform( dst, &x );
\r
2563 x.eDx = (FLOAT) dx;
\r
2564 x.eDy = (FLOAT) dy;
\r
2567 SetWorldTransform( dst, &x );
\r
2571 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2579 SetWorldTransform( dst, &x );
\r
2581 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2584 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2586 PM_WP = (int) WhitePawn,
\r
2587 PM_WN = (int) WhiteKnight,
\r
2588 PM_WB = (int) WhiteBishop,
\r
2589 PM_WR = (int) WhiteRook,
\r
2590 PM_WQ = (int) WhiteQueen,
\r
2591 PM_WF = (int) WhiteFerz,
\r
2592 PM_WW = (int) WhiteWazir,
\r
2593 PM_WE = (int) WhiteAlfil,
\r
2594 PM_WM = (int) WhiteMan,
\r
2595 PM_WO = (int) WhiteCannon,
\r
2596 PM_WU = (int) WhiteUnicorn,
\r
2597 PM_WH = (int) WhiteNightrider,
\r
2598 PM_WA = (int) WhiteAngel,
\r
2599 PM_WC = (int) WhiteMarshall,
\r
2600 PM_WAB = (int) WhiteCardinal,
\r
2601 PM_WD = (int) WhiteDragon,
\r
2602 PM_WL = (int) WhiteLance,
\r
2603 PM_WS = (int) WhiteCobra,
\r
2604 PM_WV = (int) WhiteFalcon,
\r
2605 PM_WSG = (int) WhiteSilver,
\r
2606 PM_WG = (int) WhiteGrasshopper,
\r
2607 PM_WK = (int) WhiteKing,
\r
2608 PM_BP = (int) BlackPawn,
\r
2609 PM_BN = (int) BlackKnight,
\r
2610 PM_BB = (int) BlackBishop,
\r
2611 PM_BR = (int) BlackRook,
\r
2612 PM_BQ = (int) BlackQueen,
\r
2613 PM_BF = (int) BlackFerz,
\r
2614 PM_BW = (int) BlackWazir,
\r
2615 PM_BE = (int) BlackAlfil,
\r
2616 PM_BM = (int) BlackMan,
\r
2617 PM_BO = (int) BlackCannon,
\r
2618 PM_BU = (int) BlackUnicorn,
\r
2619 PM_BH = (int) BlackNightrider,
\r
2620 PM_BA = (int) BlackAngel,
\r
2621 PM_BC = (int) BlackMarshall,
\r
2622 PM_BG = (int) BlackGrasshopper,
\r
2623 PM_BAB = (int) BlackCardinal,
\r
2624 PM_BD = (int) BlackDragon,
\r
2625 PM_BL = (int) BlackLance,
\r
2626 PM_BS = (int) BlackCobra,
\r
2627 PM_BV = (int) BlackFalcon,
\r
2628 PM_BSG = (int) BlackSilver,
\r
2629 PM_BK = (int) BlackKing
\r
2632 static HFONT hPieceFont = NULL;
\r
2633 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2634 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2635 static int fontBitmapSquareSize = 0;
\r
2636 static char pieceToFontChar[(int) EmptySquare] =
\r
2637 { 'p', 'n', 'b', 'r', 'q',
\r
2638 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2639 'k', 'o', 'm', 'v', 't', 'w',
\r
2640 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2643 extern BOOL SetCharTable( char *table, const char * map );
\r
2644 /* [HGM] moved to backend.c */
\r
2646 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2649 BYTE r1 = GetRValue( color );
\r
2650 BYTE g1 = GetGValue( color );
\r
2651 BYTE b1 = GetBValue( color );
\r
2657 /* Create a uniform background first */
\r
2658 hbrush = CreateSolidBrush( color );
\r
2659 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2660 FillRect( hdc, &rc, hbrush );
\r
2661 DeleteObject( hbrush );
\r
2664 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2665 int steps = squareSize / 2;
\r
2668 for( i=0; i<steps; i++ ) {
\r
2669 BYTE r = r1 - (r1-r2) * i / steps;
\r
2670 BYTE g = g1 - (g1-g2) * i / steps;
\r
2671 BYTE b = b1 - (b1-b2) * i / steps;
\r
2673 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2674 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2675 FillRect( hdc, &rc, hbrush );
\r
2676 DeleteObject(hbrush);
\r
2679 else if( mode == 2 ) {
\r
2680 /* Diagonal gradient, good more or less for every piece */
\r
2681 POINT triangle[3];
\r
2682 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2683 HBRUSH hbrush_old;
\r
2684 int steps = squareSize;
\r
2687 triangle[0].x = squareSize - steps;
\r
2688 triangle[0].y = squareSize;
\r
2689 triangle[1].x = squareSize;
\r
2690 triangle[1].y = squareSize;
\r
2691 triangle[2].x = squareSize;
\r
2692 triangle[2].y = squareSize - steps;
\r
2694 for( i=0; i<steps; i++ ) {
\r
2695 BYTE r = r1 - (r1-r2) * i / steps;
\r
2696 BYTE g = g1 - (g1-g2) * i / steps;
\r
2697 BYTE b = b1 - (b1-b2) * i / steps;
\r
2699 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2700 hbrush_old = SelectObject( hdc, hbrush );
\r
2701 Polygon( hdc, triangle, 3 );
\r
2702 SelectObject( hdc, hbrush_old );
\r
2703 DeleteObject(hbrush);
\r
2708 SelectObject( hdc, hpen );
\r
2713 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2714 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2715 piece: follow the steps as explained below.
\r
2717 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2721 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2725 int backColor = whitePieceColor;
\r
2726 int foreColor = blackPieceColor;
\r
2728 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2729 backColor = appData.fontBackColorWhite;
\r
2730 foreColor = appData.fontForeColorWhite;
\r
2732 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2733 backColor = appData.fontBackColorBlack;
\r
2734 foreColor = appData.fontForeColorBlack;
\r
2738 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2740 hbm_old = SelectObject( hdc, hbm );
\r
2744 rc.right = squareSize;
\r
2745 rc.bottom = squareSize;
\r
2747 /* Step 1: background is now black */
\r
2748 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2750 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2752 pt.x = (squareSize - sz.cx) / 2;
\r
2753 pt.y = (squareSize - sz.cy) / 2;
\r
2755 SetBkMode( hdc, TRANSPARENT );
\r
2756 SetTextColor( hdc, chroma );
\r
2757 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2758 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2760 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2761 /* Step 3: the area outside the piece is filled with white */
\r
2762 // FloodFill( hdc, 0, 0, chroma );
\r
2763 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2764 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2765 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2766 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2767 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2769 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2770 but if the start point is not inside the piece we're lost!
\r
2771 There should be a better way to do this... if we could create a region or path
\r
2772 from the fill operation we would be fine for example.
\r
2774 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2775 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2777 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2778 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2779 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2781 SelectObject( dc2, bm2 );
\r
2782 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2783 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2784 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2785 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2786 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2789 DeleteObject( bm2 );
\r
2792 SetTextColor( hdc, 0 );
\r
2794 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2795 draw the piece again in black for safety.
\r
2797 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2799 SelectObject( hdc, hbm_old );
\r
2801 if( hPieceMask[index] != NULL ) {
\r
2802 DeleteObject( hPieceMask[index] );
\r
2805 hPieceMask[index] = hbm;
\r
2808 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2810 SelectObject( hdc, hbm );
\r
2813 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2814 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2815 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2817 SelectObject( dc1, hPieceMask[index] );
\r
2818 SelectObject( dc2, bm2 );
\r
2819 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2820 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2823 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2824 the piece background and deletes (makes transparent) the rest.
\r
2825 Thanks to that mask, we are free to paint the background with the greates
\r
2826 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2827 We use this, to make gradients and give the pieces a "roundish" look.
\r
2829 SetPieceBackground( hdc, backColor, 2 );
\r
2830 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2834 DeleteObject( bm2 );
\r
2837 SetTextColor( hdc, foreColor );
\r
2838 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2840 SelectObject( hdc, hbm_old );
\r
2842 if( hPieceFace[index] != NULL ) {
\r
2843 DeleteObject( hPieceFace[index] );
\r
2846 hPieceFace[index] = hbm;
\r
2849 static int TranslatePieceToFontPiece( int piece )
\r
2879 case BlackMarshall:
\r
2883 case BlackNightrider:
\r
2889 case BlackUnicorn:
\r
2893 case BlackGrasshopper:
\r
2905 case BlackCardinal:
\r
2912 case WhiteMarshall:
\r
2916 case WhiteNightrider:
\r
2922 case WhiteUnicorn:
\r
2926 case WhiteGrasshopper:
\r
2938 case WhiteCardinal:
\r
2947 void CreatePiecesFromFont()
\r
2950 HDC hdc_window = NULL;
\r
2956 if( fontBitmapSquareSize < 0 ) {
\r
2957 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2961 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2962 fontBitmapSquareSize = -1;
\r
2966 if( fontBitmapSquareSize != squareSize ) {
\r
2967 hdc_window = GetDC( hwndMain );
\r
2968 hdc = CreateCompatibleDC( hdc_window );
\r
2970 if( hPieceFont != NULL ) {
\r
2971 DeleteObject( hPieceFont );
\r
2974 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2975 hPieceMask[i] = NULL;
\r
2976 hPieceFace[i] = NULL;
\r
2982 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2983 fontHeight = appData.fontPieceSize;
\r
2986 fontHeight = (fontHeight * squareSize) / 100;
\r
2988 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2990 lf.lfEscapement = 0;
\r
2991 lf.lfOrientation = 0;
\r
2992 lf.lfWeight = FW_NORMAL;
\r
2994 lf.lfUnderline = 0;
\r
2995 lf.lfStrikeOut = 0;
\r
2996 lf.lfCharSet = DEFAULT_CHARSET;
\r
2997 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2998 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2999 lf.lfQuality = PROOF_QUALITY;
\r
3000 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
3001 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3002 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3004 hPieceFont = CreateFontIndirect( &lf );
\r
3006 if( hPieceFont == NULL ) {
\r
3007 fontBitmapSquareSize = -2;
\r
3010 /* Setup font-to-piece character table */
\r
3011 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3012 /* No (or wrong) global settings, try to detect the font */
\r
3013 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3015 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3017 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3018 /* DiagramTT* family */
\r
3019 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3021 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3022 /* Fairy symbols */
\r
3023 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3025 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3026 /* Good Companion (Some characters get warped as literal :-( */
\r
3027 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3028 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3029 SetCharTable(pieceToFontChar, s);
\r
3032 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3033 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3037 /* Create bitmaps */
\r
3038 hfont_old = SelectObject( hdc, hPieceFont );
\r
3039 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3040 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3043 SelectObject( hdc, hfont_old );
\r
3045 fontBitmapSquareSize = squareSize;
\r
3049 if( hdc != NULL ) {
\r
3053 if( hdc_window != NULL ) {
\r
3054 ReleaseDC( hwndMain, hdc_window );
\r
3059 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3063 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3064 if (gameInfo.event &&
\r
3065 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3066 strcmp(name, "k80s") == 0) {
\r
3067 strcpy(name, "tim");
\r
3069 return LoadBitmap(hinst, name);
\r
3073 /* Insert a color into the program's logical palette
\r
3074 structure. This code assumes the given color is
\r
3075 the result of the RGB or PALETTERGB macro, and it
\r
3076 knows how those macros work (which is documented).
\r
3079 InsertInPalette(COLORREF color)
\r
3081 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3083 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3084 DisplayFatalError("Too many colors", 0, 1);
\r
3085 pLogPal->palNumEntries--;
\r
3089 pe->peFlags = (char) 0;
\r
3090 pe->peRed = (char) (0xFF & color);
\r
3091 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3092 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3098 InitDrawingColors()
\r
3100 if (pLogPal == NULL) {
\r
3101 /* Allocate enough memory for a logical palette with
\r
3102 * PALETTESIZE entries and set the size and version fields
\r
3103 * of the logical palette structure.
\r
3105 pLogPal = (NPLOGPALETTE)
\r
3106 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3107 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3108 pLogPal->palVersion = 0x300;
\r
3110 pLogPal->palNumEntries = 0;
\r
3112 InsertInPalette(lightSquareColor);
\r
3113 InsertInPalette(darkSquareColor);
\r
3114 InsertInPalette(whitePieceColor);
\r
3115 InsertInPalette(blackPieceColor);
\r
3116 InsertInPalette(highlightSquareColor);
\r
3117 InsertInPalette(premoveHighlightColor);
\r
3119 /* create a logical color palette according the information
\r
3120 * in the LOGPALETTE structure.
\r
3122 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3124 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3125 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3126 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3127 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3128 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3129 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3130 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3131 /* [AS] Force rendering of the font-based pieces */
\r
3132 if( fontBitmapSquareSize > 0 ) {
\r
3133 fontBitmapSquareSize = 0;
\r
3139 BoardWidth(int boardSize, int n)
\r
3140 { /* [HGM] argument n added to allow different width and height */
\r
3141 int lineGap = sizeInfo[boardSize].lineGap;
\r
3143 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3144 lineGap = appData.overrideLineGap;
\r
3147 return (n + 1) * lineGap +
\r
3148 n * sizeInfo[boardSize].squareSize;
\r
3151 /* Respond to board resize by dragging edge */
\r
3153 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3155 BoardSize newSize = NUM_SIZES - 1;
\r
3156 static int recurse = 0;
\r
3157 if (IsIconic(hwndMain)) return;
\r
3158 if (recurse > 0) return;
\r
3160 while (newSize > 0) {
\r
3161 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3162 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3163 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3166 boardSize = newSize;
\r
3167 InitDrawingSizes(boardSize, flags);
\r
3174 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3176 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3177 ChessSquare piece;
\r
3178 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3180 SIZE clockSize, messageSize;
\r
3182 char buf[MSG_SIZ];
\r
3184 HMENU hmenu = GetMenu(hwndMain);
\r
3185 RECT crect, wrect, oldRect;
\r
3187 LOGBRUSH logbrush;
\r
3189 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3190 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3192 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3193 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3195 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3196 oldRect.top = boardY;
\r
3197 oldRect.right = boardX + winWidth;
\r
3198 oldRect.bottom = boardY + winHeight;
\r
3200 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3201 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3202 squareSize = sizeInfo[boardSize].squareSize;
\r
3203 lineGap = sizeInfo[boardSize].lineGap;
\r
3204 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3206 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3207 lineGap = appData.overrideLineGap;
\r
3210 if (tinyLayout != oldTinyLayout) {
\r
3211 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3213 style &= ~WS_SYSMENU;
\r
3214 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3215 "&Minimize\tCtrl+F4");
\r
3217 style |= WS_SYSMENU;
\r
3218 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3220 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3222 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3223 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3224 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3226 DrawMenuBar(hwndMain);
\r
3229 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3230 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3232 /* Get text area sizes */
\r
3233 hdc = GetDC(hwndMain);
\r
3234 if (appData.clockMode) {
\r
3235 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3237 sprintf(buf, "White");
\r
3239 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3240 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3241 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3242 str = "We only care about the height here";
\r
3243 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3244 SelectObject(hdc, oldFont);
\r
3245 ReleaseDC(hwndMain, hdc);
\r
3247 /* Compute where everything goes */
\r
3248 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3249 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3250 logoHeight = 2*clockSize.cy;
\r
3251 leftLogoRect.left = OUTER_MARGIN;
\r
3252 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3253 leftLogoRect.top = OUTER_MARGIN;
\r
3254 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3256 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3257 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3258 rightLogoRect.top = OUTER_MARGIN;
\r
3259 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3262 whiteRect.left = leftLogoRect.right;
\r
3263 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3264 whiteRect.top = OUTER_MARGIN;
\r
3265 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3267 blackRect.right = rightLogoRect.left;
\r
3268 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3269 blackRect.top = whiteRect.top;
\r
3270 blackRect.bottom = whiteRect.bottom;
\r
3272 whiteRect.left = OUTER_MARGIN;
\r
3273 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3274 whiteRect.top = OUTER_MARGIN;
\r
3275 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3277 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3278 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3279 blackRect.top = whiteRect.top;
\r
3280 blackRect.bottom = whiteRect.bottom;
\r
3283 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3284 if (appData.showButtonBar) {
\r
3285 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3286 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3288 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3290 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3291 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3293 boardRect.left = OUTER_MARGIN;
\r
3294 boardRect.right = boardRect.left + boardWidth;
\r
3295 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3296 boardRect.bottom = boardRect.top + boardHeight;
\r
3298 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3299 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3300 oldBoardSize = boardSize;
\r
3301 oldTinyLayout = tinyLayout;
\r
3302 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3303 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3304 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3305 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3306 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3307 winHeight = winH; // without disturbing window attachments
\r
3308 GetWindowRect(hwndMain, &wrect);
\r
3309 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3310 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3312 // [HGM] placement: let attached windows follow size change.
\r
3313 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3314 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3315 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3316 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3317 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3319 /* compensate if menu bar wrapped */
\r
3320 GetClientRect(hwndMain, &crect);
\r
3321 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3322 winHeight += offby;
\r
3324 case WMSZ_TOPLEFT:
\r
3325 SetWindowPos(hwndMain, NULL,
\r
3326 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3327 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3330 case WMSZ_TOPRIGHT:
\r
3332 SetWindowPos(hwndMain, NULL,
\r
3333 wrect.left, wrect.bottom - winHeight,
\r
3334 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3337 case WMSZ_BOTTOMLEFT:
\r
3339 SetWindowPos(hwndMain, NULL,
\r
3340 wrect.right - winWidth, wrect.top,
\r
3341 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3344 case WMSZ_BOTTOMRIGHT:
\r
3348 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3349 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3354 for (i = 0; i < N_BUTTONS; i++) {
\r
3355 if (buttonDesc[i].hwnd != NULL) {
\r
3356 DestroyWindow(buttonDesc[i].hwnd);
\r
3357 buttonDesc[i].hwnd = NULL;
\r
3359 if (appData.showButtonBar) {
\r
3360 buttonDesc[i].hwnd =
\r
3361 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3362 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3363 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3364 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3365 (HMENU) buttonDesc[i].id,
\r
3366 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3368 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3369 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3370 MAKELPARAM(FALSE, 0));
\r
3372 if (buttonDesc[i].id == IDM_Pause)
\r
3373 hwndPause = buttonDesc[i].hwnd;
\r
3374 buttonDesc[i].wndproc = (WNDPROC)
\r
3375 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3378 if (gridPen != NULL) DeleteObject(gridPen);
\r
3379 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3380 if (premovePen != NULL) DeleteObject(premovePen);
\r
3381 if (lineGap != 0) {
\r
3382 logbrush.lbStyle = BS_SOLID;
\r
3383 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3385 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3386 lineGap, &logbrush, 0, NULL);
\r
3387 logbrush.lbColor = highlightSquareColor;
\r
3389 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3390 lineGap, &logbrush, 0, NULL);
\r
3392 logbrush.lbColor = premoveHighlightColor;
\r
3394 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3395 lineGap, &logbrush, 0, NULL);
\r
3397 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3398 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3399 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3400 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3401 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3402 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3403 BOARD_WIDTH * (squareSize + lineGap);
\r
3404 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3406 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3407 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3408 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3409 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3410 lineGap / 2 + (i * (squareSize + lineGap));
\r
3411 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3412 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3413 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3417 /* [HGM] Licensing requirement */
\r
3419 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3422 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3424 GothicPopUp( "", VariantNormal);
\r
3427 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3429 /* Load piece bitmaps for this board size */
\r
3430 for (i=0; i<=2; i++) {
\r
3431 for (piece = WhitePawn;
\r
3432 (int) piece < (int) BlackPawn;
\r
3433 piece = (ChessSquare) ((int) piece + 1)) {
\r
3434 if (pieceBitmap[i][piece] != NULL)
\r
3435 DeleteObject(pieceBitmap[i][piece]);
\r
3439 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3440 // Orthodox Chess pieces
\r
3441 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3442 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3443 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3444 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3445 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3446 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3447 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3448 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3449 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3450 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3451 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3452 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3453 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3454 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3455 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3456 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3457 // in Shogi, Hijack the unused Queen for Lance
\r
3458 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3459 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3460 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3462 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3463 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3464 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3467 if(squareSize <= 72 && squareSize >= 33) {
\r
3468 /* A & C are available in most sizes now */
\r
3469 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3470 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3471 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3472 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3473 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3474 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3475 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3476 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3477 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3478 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3479 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3480 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3481 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3482 } else { // Smirf-like
\r
3483 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3484 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3485 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3487 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3488 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3489 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3490 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3491 } else { // WinBoard standard
\r
3492 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3493 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3494 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3499 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3500 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3501 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3502 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3503 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3504 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3505 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3506 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3507 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3508 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3509 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3510 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3511 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3512 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3513 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3514 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3515 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3516 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3517 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3518 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3519 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3520 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3521 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3522 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3523 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3524 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3525 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3526 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3527 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3528 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3529 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3531 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3532 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3533 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3534 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3535 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3536 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3537 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3538 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3539 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3540 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3541 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3542 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3543 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3545 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3546 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3547 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3548 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3549 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3550 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3551 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3552 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3553 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3554 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3555 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3556 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3559 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3560 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3561 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3562 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3563 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3564 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3565 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3566 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3567 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3568 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3569 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3570 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3571 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3572 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3573 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3577 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3578 /* special Shogi support in this size */
\r
3579 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3580 for (piece = WhitePawn;
\r
3581 (int) piece < (int) BlackPawn;
\r
3582 piece = (ChessSquare) ((int) piece + 1)) {
\r
3583 if (pieceBitmap[i][piece] != NULL)
\r
3584 DeleteObject(pieceBitmap[i][piece]);
\r
3587 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3588 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3589 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3590 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3591 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3592 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3593 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3594 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3595 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3596 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3597 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3598 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3599 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3600 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3601 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3602 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3603 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3604 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3605 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3606 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3607 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3608 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3609 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3610 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3611 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3612 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3613 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3614 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3615 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3616 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3617 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3618 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3619 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3620 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3621 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3622 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3623 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3624 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3625 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3626 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3627 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3628 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3634 PieceBitmap(ChessSquare p, int kind)
\r
3636 if ((int) p >= (int) BlackPawn)
\r
3637 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3639 return pieceBitmap[kind][(int) p];
\r
3642 /***************************************************************/
\r
3644 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3645 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3647 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3648 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3652 SquareToPos(int row, int column, int * x, int * y)
\r
3655 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3656 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3658 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3659 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3664 DrawCoordsOnDC(HDC hdc)
\r
3666 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
3667 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
3668 char str[2] = { NULLCHAR, NULLCHAR };
\r
3669 int oldMode, oldAlign, x, y, start, i;
\r
3673 if (!appData.showCoords)
\r
3676 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3678 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3679 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3680 oldAlign = GetTextAlign(hdc);
\r
3681 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3683 y = boardRect.top + lineGap;
\r
3684 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3686 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3687 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3688 str[0] = files[start + i];
\r
3689 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3690 y += squareSize + lineGap;
\r
3693 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3695 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3696 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3697 str[0] = ranks[start + i];
\r
3698 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3699 x += squareSize + lineGap;
\r
3702 SelectObject(hdc, oldBrush);
\r
3703 SetBkMode(hdc, oldMode);
\r
3704 SetTextAlign(hdc, oldAlign);
\r
3705 SelectObject(hdc, oldFont);
\r
3709 DrawGridOnDC(HDC hdc)
\r
3713 if (lineGap != 0) {
\r
3714 oldPen = SelectObject(hdc, gridPen);
\r
3715 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3716 SelectObject(hdc, oldPen);
\r
3720 #define HIGHLIGHT_PEN 0
\r
3721 #define PREMOVE_PEN 1
\r
3724 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3727 HPEN oldPen, hPen;
\r
3728 if (lineGap == 0) return;
\r
3730 x1 = boardRect.left +
\r
3731 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3732 y1 = boardRect.top +
\r
3733 lineGap/2 + y * (squareSize + lineGap);
\r
3735 x1 = boardRect.left +
\r
3736 lineGap/2 + x * (squareSize + lineGap);
\r
3737 y1 = boardRect.top +
\r
3738 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3740 hPen = pen ? premovePen : highlightPen;
\r
3741 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3742 MoveToEx(hdc, x1, y1, NULL);
\r
3743 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3744 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3745 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3746 LineTo(hdc, x1, y1);
\r
3747 SelectObject(hdc, oldPen);
\r
3751 DrawHighlightsOnDC(HDC hdc)
\r
3754 for (i=0; i<2; i++) {
\r
3755 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3756 DrawHighlightOnDC(hdc, TRUE,
\r
3757 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3760 for (i=0; i<2; i++) {
\r
3761 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3762 premoveHighlightInfo.sq[i].y >= 0) {
\r
3763 DrawHighlightOnDC(hdc, TRUE,
\r
3764 premoveHighlightInfo.sq[i].x,
\r
3765 premoveHighlightInfo.sq[i].y,
\r
3771 /* Note: sqcolor is used only in monoMode */
\r
3772 /* Note that this code is largely duplicated in woptions.c,
\r
3773 function DrawSampleSquare, so that needs to be updated too */
\r
3775 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3777 HBITMAP oldBitmap;
\r
3781 if (appData.blindfold) return;
\r
3783 /* [AS] Use font-based pieces if needed */
\r
3784 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3785 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3786 CreatePiecesFromFont();
\r
3788 if( fontBitmapSquareSize == squareSize ) {
\r
3789 int index = TranslatePieceToFontPiece(piece);
\r
3791 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3795 squareSize, squareSize,
\r
3800 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3804 squareSize, squareSize,
\r
3813 if (appData.monoMode) {
\r
3814 SelectObject(tmphdc, PieceBitmap(piece,
\r
3815 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3816 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3817 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3819 tmpSize = squareSize;
\r
3821 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3822 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3823 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3824 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3825 x += (squareSize - minorSize)>>1;
\r
3826 y += squareSize - minorSize - 2;
\r
3827 tmpSize = minorSize;
\r
3829 if (color || appData.allWhite ) {
\r
3830 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3832 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3833 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3834 if(appData.upsideDown && color==flipView)
\r
3835 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3837 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3838 /* Use black for outline of white pieces */
\r
3839 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3840 if(appData.upsideDown && color==flipView)
\r
3841 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3843 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3845 /* Use square color for details of black pieces */
\r
3846 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3847 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3848 if(appData.upsideDown && !flipView)
\r
3849 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3851 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3853 SelectObject(hdc, oldBrush);
\r
3854 SelectObject(tmphdc, oldBitmap);
\r
3858 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3859 int GetBackTextureMode( int algo )
\r
3861 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3865 case BACK_TEXTURE_MODE_PLAIN:
\r
3866 result = 1; /* Always use identity map */
\r
3868 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3869 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3877 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3878 to handle redraws cleanly (as random numbers would always be different).
\r
3880 VOID RebuildTextureSquareInfo()
\r
3890 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3892 if( liteBackTexture != NULL ) {
\r
3893 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3894 lite_w = bi.bmWidth;
\r
3895 lite_h = bi.bmHeight;
\r
3899 if( darkBackTexture != NULL ) {
\r
3900 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3901 dark_w = bi.bmWidth;
\r
3902 dark_h = bi.bmHeight;
\r
3906 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3907 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3908 if( (col + row) & 1 ) {
\r
3910 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3911 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3912 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3913 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3918 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3919 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3920 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3921 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3928 /* [AS] Arrow highlighting support */
\r
3930 static int A_WIDTH = 5; /* Width of arrow body */
\r
3932 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3933 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3935 static double Sqr( double x )
\r
3940 static int Round( double x )
\r
3942 return (int) (x + 0.5);
\r
3945 /* Draw an arrow between two points using current settings */
\r
3946 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3949 double dx, dy, j, k, x, y;
\r
3951 if( d_x == s_x ) {
\r
3952 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3954 arrow[0].x = s_x + A_WIDTH;
\r
3957 arrow[1].x = s_x + A_WIDTH;
\r
3958 arrow[1].y = d_y - h;
\r
3960 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3961 arrow[2].y = d_y - h;
\r
3966 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3967 arrow[4].y = d_y - h;
\r
3969 arrow[5].x = s_x - A_WIDTH;
\r
3970 arrow[5].y = d_y - h;
\r
3972 arrow[6].x = s_x - A_WIDTH;
\r
3975 else if( d_y == s_y ) {
\r
3976 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3979 arrow[0].y = s_y + A_WIDTH;
\r
3981 arrow[1].x = d_x - w;
\r
3982 arrow[1].y = s_y + A_WIDTH;
\r
3984 arrow[2].x = d_x - w;
\r
3985 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3990 arrow[4].x = d_x - w;
\r
3991 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3993 arrow[5].x = d_x - w;
\r
3994 arrow[5].y = s_y - A_WIDTH;
\r
3997 arrow[6].y = s_y - A_WIDTH;
\r
4000 /* [AS] Needed a lot of paper for this! :-) */
\r
4001 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4002 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4004 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4006 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4011 arrow[0].x = Round(x - j);
\r
4012 arrow[0].y = Round(y + j*dx);
\r
4014 arrow[1].x = Round(x + j);
\r
4015 arrow[1].y = Round(y - j*dx);
\r
4018 x = (double) d_x - k;
\r
4019 y = (double) d_y - k*dy;
\r
4022 x = (double) d_x + k;
\r
4023 y = (double) d_y + k*dy;
\r
4026 arrow[2].x = Round(x + j);
\r
4027 arrow[2].y = Round(y - j*dx);
\r
4029 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4030 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4035 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4036 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4038 arrow[6].x = Round(x - j);
\r
4039 arrow[6].y = Round(y + j*dx);
\r
4042 Polygon( hdc, arrow, 7 );
\r
4045 /* [AS] Draw an arrow between two squares */
\r
4046 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4048 int s_x, s_y, d_x, d_y;
\r
4055 if( s_col == d_col && s_row == d_row ) {
\r
4059 /* Get source and destination points */
\r
4060 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4061 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4064 d_y += squareSize / 4;
\r
4066 else if( d_y < s_y ) {
\r
4067 d_y += 3 * squareSize / 4;
\r
4070 d_y += squareSize / 2;
\r
4074 d_x += squareSize / 4;
\r
4076 else if( d_x < s_x ) {
\r
4077 d_x += 3 * squareSize / 4;
\r
4080 d_x += squareSize / 2;
\r
4083 s_x += squareSize / 2;
\r
4084 s_y += squareSize / 2;
\r
4086 /* Adjust width */
\r
4087 A_WIDTH = squareSize / 14;
\r
4090 stLB.lbStyle = BS_SOLID;
\r
4091 stLB.lbColor = appData.highlightArrowColor;
\r
4094 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4095 holdpen = SelectObject( hdc, hpen );
\r
4096 hbrush = CreateBrushIndirect( &stLB );
\r
4097 holdbrush = SelectObject( hdc, hbrush );
\r
4099 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4101 SelectObject( hdc, holdpen );
\r
4102 SelectObject( hdc, holdbrush );
\r
4103 DeleteObject( hpen );
\r
4104 DeleteObject( hbrush );
\r
4107 BOOL HasHighlightInfo()
\r
4109 BOOL result = FALSE;
\r
4111 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4112 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4120 BOOL IsDrawArrowEnabled()
\r
4122 BOOL result = FALSE;
\r
4124 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4131 VOID DrawArrowHighlight( HDC hdc )
\r
4133 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4134 DrawArrowBetweenSquares( hdc,
\r
4135 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4136 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4140 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4142 HRGN result = NULL;
\r
4144 if( HasHighlightInfo() ) {
\r
4145 int x1, y1, x2, y2;
\r
4146 int sx, sy, dx, dy;
\r
4148 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4149 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4151 sx = MIN( x1, x2 );
\r
4152 sy = MIN( y1, y2 );
\r
4153 dx = MAX( x1, x2 ) + squareSize;
\r
4154 dy = MAX( y1, y2 ) + squareSize;
\r
4156 result = CreateRectRgn( sx, sy, dx, dy );
\r
4163 Warning: this function modifies the behavior of several other functions.
\r
4165 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4166 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4167 repaint is scattered all over the place, which is not good for features such as
\r
4168 "arrow highlighting" that require a full repaint of the board.
\r
4170 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4171 user interaction, when speed is not so important) but especially to avoid errors
\r
4172 in the displayed graphics.
\r
4174 In such patched places, I always try refer to this function so there is a single
\r
4175 place to maintain knowledge.
\r
4177 To restore the original behavior, just return FALSE unconditionally.
\r
4179 BOOL IsFullRepaintPreferrable()
\r
4181 BOOL result = FALSE;
\r
4183 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4184 /* Arrow may appear on the board */
\r
4192 This function is called by DrawPosition to know whether a full repaint must
\r
4195 Only DrawPosition may directly call this function, which makes use of
\r
4196 some state information. Other function should call DrawPosition specifying
\r
4197 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4199 BOOL DrawPositionNeedsFullRepaint()
\r
4201 BOOL result = FALSE;
\r
4204 Probably a slightly better policy would be to trigger a full repaint
\r
4205 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4206 but animation is fast enough that it's difficult to notice.
\r
4208 if( animInfo.piece == EmptySquare ) {
\r
4209 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4218 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4220 int row, column, x, y, square_color, piece_color;
\r
4221 ChessSquare piece;
\r
4223 HDC texture_hdc = NULL;
\r
4225 /* [AS] Initialize background textures if needed */
\r
4226 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4227 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4228 if( backTextureSquareSize != squareSize
\r
4229 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4230 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4231 backTextureSquareSize = squareSize;
\r
4232 RebuildTextureSquareInfo();
\r
4235 texture_hdc = CreateCompatibleDC( hdc );
\r
4238 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4239 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4241 SquareToPos(row, column, &x, &y);
\r
4243 piece = board[row][column];
\r
4245 square_color = ((column + row) % 2) == 1;
\r
4246 if( gameInfo.variant == VariantXiangqi ) {
\r
4247 square_color = !InPalace(row, column);
\r
4248 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4249 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4251 piece_color = (int) piece < (int) BlackPawn;
\r
4254 /* [HGM] holdings file: light square or black */
\r
4255 if(column == BOARD_LEFT-2) {
\r
4256 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4259 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4263 if(column == BOARD_RGHT + 1 ) {
\r
4264 if( row < gameInfo.holdingsSize )
\r
4267 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4271 if(column == BOARD_LEFT-1 ) /* left align */
\r
4272 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4273 else if( column == BOARD_RGHT) /* right align */
\r
4274 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4276 if (appData.monoMode) {
\r
4277 if (piece == EmptySquare) {
\r
4278 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4279 square_color ? WHITENESS : BLACKNESS);
\r
4281 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4284 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4285 /* [AS] Draw the square using a texture bitmap */
\r
4286 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4287 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4288 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4291 squareSize, squareSize,
\r
4294 backTextureSquareInfo[r][c].mode,
\r
4295 backTextureSquareInfo[r][c].x,
\r
4296 backTextureSquareInfo[r][c].y );
\r
4298 SelectObject( texture_hdc, hbm );
\r
4300 if (piece != EmptySquare) {
\r
4301 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4305 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4307 oldBrush = SelectObject(hdc, brush );
\r
4308 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4309 SelectObject(hdc, oldBrush);
\r
4310 if (piece != EmptySquare)
\r
4311 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4316 if( texture_hdc != NULL ) {
\r
4317 DeleteDC( texture_hdc );
\r
4321 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4322 void fputDW(FILE *f, int x)
\r
4324 fputc(x & 255, f);
\r
4325 fputc(x>>8 & 255, f);
\r
4326 fputc(x>>16 & 255, f);
\r
4327 fputc(x>>24 & 255, f);
\r
4330 #define MAX_CLIPS 200 /* more than enough */
\r
4333 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4335 // HBITMAP bufferBitmap;
\r
4340 int w = 100, h = 50;
\r
4342 if(logo == NULL) return;
\r
4343 // GetClientRect(hwndMain, &Rect);
\r
4344 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4345 // Rect.bottom-Rect.top+1);
\r
4346 tmphdc = CreateCompatibleDC(hdc);
\r
4347 hbm = SelectObject(tmphdc, logo);
\r
4348 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4352 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4353 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4354 SelectObject(tmphdc, hbm);
\r
4359 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4361 static Board lastReq, lastDrawn;
\r
4362 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4363 static int lastDrawnFlipView = 0;
\r
4364 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4365 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4368 HBITMAP bufferBitmap;
\r
4369 HBITMAP oldBitmap;
\r
4371 HRGN clips[MAX_CLIPS];
\r
4372 ChessSquare dragged_piece = EmptySquare;
\r
4374 /* I'm undecided on this - this function figures out whether a full
\r
4375 * repaint is necessary on its own, so there's no real reason to have the
\r
4376 * caller tell it that. I think this can safely be set to FALSE - but
\r
4377 * if we trust the callers not to request full repaints unnessesarily, then
\r
4378 * we could skip some clipping work. In other words, only request a full
\r
4379 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4380 * gamestart and similar) --Hawk
\r
4382 Boolean fullrepaint = repaint;
\r
4384 if( DrawPositionNeedsFullRepaint() ) {
\r
4385 fullrepaint = TRUE;
\r
4388 if (board == NULL) {
\r
4389 if (!lastReqValid) {
\r
4394 CopyBoard(lastReq, board);
\r
4398 if (doingSizing) {
\r
4402 if (IsIconic(hwndMain)) {
\r
4406 if (hdc == NULL) {
\r
4407 hdc = GetDC(hwndMain);
\r
4408 if (!appData.monoMode) {
\r
4409 SelectPalette(hdc, hPal, FALSE);
\r
4410 RealizePalette(hdc);
\r
4414 releaseDC = FALSE;
\r
4417 /* Create some work-DCs */
\r
4418 hdcmem = CreateCompatibleDC(hdc);
\r
4419 tmphdc = CreateCompatibleDC(hdc);
\r
4421 /* If dragging is in progress, we temporarely remove the piece */
\r
4422 /* [HGM] or temporarily decrease count if stacked */
\r
4423 /* !! Moved to before board compare !! */
\r
4424 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4425 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4426 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4427 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4428 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4430 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4431 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4432 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4434 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4437 /* Figure out which squares need updating by comparing the
\r
4438 * newest board with the last drawn board and checking if
\r
4439 * flipping has changed.
\r
4441 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4442 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4443 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4444 if (lastDrawn[row][column] != board[row][column]) {
\r
4445 SquareToPos(row, column, &x, &y);
\r
4446 clips[num_clips++] =
\r
4447 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4451 for (i=0; i<2; i++) {
\r
4452 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4453 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4454 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4455 lastDrawnHighlight.sq[i].y >= 0) {
\r
4456 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4457 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4458 clips[num_clips++] =
\r
4459 CreateRectRgn(x - lineGap, y - lineGap,
\r
4460 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4462 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4463 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4464 clips[num_clips++] =
\r
4465 CreateRectRgn(x - lineGap, y - lineGap,
\r
4466 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4470 for (i=0; i<2; i++) {
\r
4471 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4472 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4473 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4474 lastDrawnPremove.sq[i].y >= 0) {
\r
4475 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4476 lastDrawnPremove.sq[i].x, &x, &y);
\r
4477 clips[num_clips++] =
\r
4478 CreateRectRgn(x - lineGap, y - lineGap,
\r
4479 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4481 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4482 premoveHighlightInfo.sq[i].y >= 0) {
\r
4483 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4484 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4485 clips[num_clips++] =
\r
4486 CreateRectRgn(x - lineGap, y - lineGap,
\r
4487 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4492 fullrepaint = TRUE;
\r
4495 /* Create a buffer bitmap - this is the actual bitmap
\r
4496 * being written to. When all the work is done, we can
\r
4497 * copy it to the real DC (the screen). This avoids
\r
4498 * the problems with flickering.
\r
4500 GetClientRect(hwndMain, &Rect);
\r
4501 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4502 Rect.bottom-Rect.top+1);
\r
4503 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4504 if (!appData.monoMode) {
\r
4505 SelectPalette(hdcmem, hPal, FALSE);
\r
4508 /* Create clips for dragging */
\r
4509 if (!fullrepaint) {
\r
4510 if (dragInfo.from.x >= 0) {
\r
4511 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4512 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4514 if (dragInfo.start.x >= 0) {
\r
4515 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4516 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4518 if (dragInfo.pos.x >= 0) {
\r
4519 x = dragInfo.pos.x - squareSize / 2;
\r
4520 y = dragInfo.pos.y - squareSize / 2;
\r
4521 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4523 if (dragInfo.lastpos.x >= 0) {
\r
4524 x = dragInfo.lastpos.x - squareSize / 2;
\r
4525 y = dragInfo.lastpos.y - squareSize / 2;
\r
4526 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4530 /* Are we animating a move?
\r
4532 * - remove the piece from the board (temporarely)
\r
4533 * - calculate the clipping region
\r
4535 if (!fullrepaint) {
\r
4536 if (animInfo.piece != EmptySquare) {
\r
4537 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4538 x = boardRect.left + animInfo.lastpos.x;
\r
4539 y = boardRect.top + animInfo.lastpos.y;
\r
4540 x2 = boardRect.left + animInfo.pos.x;
\r
4541 y2 = boardRect.top + animInfo.pos.y;
\r
4542 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4543 /* Slight kludge. The real problem is that after AnimateMove is
\r
4544 done, the position on the screen does not match lastDrawn.
\r
4545 This currently causes trouble only on e.p. captures in
\r
4546 atomic, where the piece moves to an empty square and then
\r
4547 explodes. The old and new positions both had an empty square
\r
4548 at the destination, but animation has drawn a piece there and
\r
4549 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4550 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4554 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4555 if (num_clips == 0)
\r
4556 fullrepaint = TRUE;
\r
4558 /* Set clipping on the memory DC */
\r
4559 if (!fullrepaint) {
\r
4560 SelectClipRgn(hdcmem, clips[0]);
\r
4561 for (x = 1; x < num_clips; x++) {
\r
4562 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4563 abort(); // this should never ever happen!
\r
4567 /* Do all the drawing to the memory DC */
\r
4568 if(explodeInfo.radius) { // [HGM] atomic
\r
4570 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4571 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4572 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4573 x += squareSize/2;
\r
4574 y += squareSize/2;
\r
4575 if(!fullrepaint) {
\r
4576 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4577 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4579 DrawGridOnDC(hdcmem);
\r
4580 DrawHighlightsOnDC(hdcmem);
\r
4581 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4582 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4583 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4584 SelectObject(hdcmem, oldBrush);
\r
4586 DrawGridOnDC(hdcmem);
\r
4587 DrawHighlightsOnDC(hdcmem);
\r
4588 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4591 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4592 if(appData.autoLogo) {
\r
4594 switch(gameMode) { // pick logos based on game mode
\r
4595 case IcsObserving:
\r
4596 whiteLogo = second.programLogo; // ICS logo
\r
4597 blackLogo = second.programLogo;
\r
4600 case IcsPlayingWhite:
\r
4601 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4602 blackLogo = second.programLogo; // ICS logo
\r
4604 case IcsPlayingBlack:
\r
4605 whiteLogo = second.programLogo; // ICS logo
\r
4606 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4608 case TwoMachinesPlay:
\r
4609 if(first.twoMachinesColor[0] == 'b') {
\r
4610 whiteLogo = second.programLogo;
\r
4611 blackLogo = first.programLogo;
\r
4614 case MachinePlaysWhite:
\r
4615 blackLogo = userLogo;
\r
4617 case MachinePlaysBlack:
\r
4618 whiteLogo = userLogo;
\r
4619 blackLogo = first.programLogo;
\r
4622 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4623 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4626 if( appData.highlightMoveWithArrow ) {
\r
4627 DrawArrowHighlight(hdcmem);
\r
4630 DrawCoordsOnDC(hdcmem);
\r
4632 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4633 /* to make sure lastDrawn contains what is actually drawn */
\r
4635 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4636 if (dragged_piece != EmptySquare) {
\r
4637 /* [HGM] or restack */
\r
4638 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4639 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4641 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4642 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4643 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4644 x = dragInfo.pos.x - squareSize / 2;
\r
4645 y = dragInfo.pos.y - squareSize / 2;
\r
4646 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4647 ((int) dragged_piece < (int) BlackPawn),
\r
4648 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4651 /* Put the animated piece back into place and draw it */
\r
4652 if (animInfo.piece != EmptySquare) {
\r
4653 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4654 x = boardRect.left + animInfo.pos.x;
\r
4655 y = boardRect.top + animInfo.pos.y;
\r
4656 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4657 ((int) animInfo.piece < (int) BlackPawn),
\r
4658 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4661 /* Release the bufferBitmap by selecting in the old bitmap
\r
4662 * and delete the memory DC
\r
4664 SelectObject(hdcmem, oldBitmap);
\r
4667 /* Set clipping on the target DC */
\r
4668 if (!fullrepaint) {
\r
4669 SelectClipRgn(hdc, clips[0]);
\r
4670 for (x = 1; x < num_clips; x++) {
\r
4671 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4672 abort(); // this should never ever happen!
\r
4676 /* Copy the new bitmap onto the screen in one go.
\r
4677 * This way we avoid any flickering
\r
4679 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4680 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4681 boardRect.right - boardRect.left,
\r
4682 boardRect.bottom - boardRect.top,
\r
4683 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4684 if(saveDiagFlag) {
\r
4685 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4686 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4688 GetObject(bufferBitmap, sizeof(b), &b);
\r
4689 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4690 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4691 bih.biWidth = b.bmWidth;
\r
4692 bih.biHeight = b.bmHeight;
\r
4694 bih.biBitCount = b.bmBitsPixel;
\r
4695 bih.biCompression = 0;
\r
4696 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4697 bih.biXPelsPerMeter = 0;
\r
4698 bih.biYPelsPerMeter = 0;
\r
4699 bih.biClrUsed = 0;
\r
4700 bih.biClrImportant = 0;
\r
4701 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4702 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4703 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4704 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4706 wb = b.bmWidthBytes;
\r
4708 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4709 int k = ((int*) pData)[i];
\r
4710 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4711 if(j >= 16) break;
\r
4713 if(j >= nrColors) nrColors = j+1;
\r
4715 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4717 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4718 for(w=0; w<(wb>>2); w+=2) {
\r
4719 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4720 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4721 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4722 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4723 pData[p++] = m | j<<4;
\r
4725 while(p&3) pData[p++] = 0;
\r
4728 wb = ((wb+31)>>5)<<2;
\r
4730 // write BITMAPFILEHEADER
\r
4731 fprintf(diagFile, "BM");
\r
4732 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4733 fputDW(diagFile, 0);
\r
4734 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4735 // write BITMAPINFOHEADER
\r
4736 fputDW(diagFile, 40);
\r
4737 fputDW(diagFile, b.bmWidth);
\r
4738 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4739 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4740 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4741 fputDW(diagFile, 0);
\r
4742 fputDW(diagFile, 0);
\r
4743 fputDW(diagFile, 0);
\r
4744 fputDW(diagFile, 0);
\r
4745 fputDW(diagFile, 0);
\r
4746 fputDW(diagFile, 0);
\r
4747 // write color table
\r
4749 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4750 // write bitmap data
\r
4751 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4752 fputc(pData[i], diagFile);
\r
4756 SelectObject(tmphdc, oldBitmap);
\r
4758 /* Massive cleanup */
\r
4759 for (x = 0; x < num_clips; x++)
\r
4760 DeleteObject(clips[x]);
\r
4763 DeleteObject(bufferBitmap);
\r
4766 ReleaseDC(hwndMain, hdc);
\r
4768 if (lastDrawnFlipView != flipView) {
\r
4770 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4772 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4775 /* CopyBoard(lastDrawn, board);*/
\r
4776 lastDrawnHighlight = highlightInfo;
\r
4777 lastDrawnPremove = premoveHighlightInfo;
\r
4778 lastDrawnFlipView = flipView;
\r
4779 lastDrawnValid = 1;
\r
4782 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4787 saveDiagFlag = 1; diagFile = f;
\r
4788 HDCDrawPosition(NULL, TRUE, NULL);
\r
4792 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4799 /*---------------------------------------------------------------------------*\
\r
4800 | CLIENT PAINT PROCEDURE
\r
4801 | This is the main event-handler for the WM_PAINT message.
\r
4803 \*---------------------------------------------------------------------------*/
\r
4805 PaintProc(HWND hwnd)
\r
4811 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4812 if (IsIconic(hwnd)) {
\r
4813 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4815 if (!appData.monoMode) {
\r
4816 SelectPalette(hdc, hPal, FALSE);
\r
4817 RealizePalette(hdc);
\r
4819 HDCDrawPosition(hdc, 1, NULL);
\r
4821 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4822 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4823 ETO_CLIPPED|ETO_OPAQUE,
\r
4824 &messageRect, messageText, strlen(messageText), NULL);
\r
4825 SelectObject(hdc, oldFont);
\r
4826 DisplayBothClocks();
\r
4828 EndPaint(hwnd,&ps);
\r
4836 * If the user selects on a border boundary, return -1; if off the board,
\r
4837 * return -2. Otherwise map the event coordinate to the square.
\r
4838 * The offset boardRect.left or boardRect.top must already have been
\r
4839 * subtracted from x.
\r
4842 EventToSquare(int x)
\r
4849 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4851 x /= (squareSize + lineGap);
\r
4852 if (x >= BOARD_SIZE)
\r
4863 DropEnable dropEnables[] = {
\r
4864 { 'P', DP_Pawn, "Pawn" },
\r
4865 { 'N', DP_Knight, "Knight" },
\r
4866 { 'B', DP_Bishop, "Bishop" },
\r
4867 { 'R', DP_Rook, "Rook" },
\r
4868 { 'Q', DP_Queen, "Queen" },
\r
4872 SetupDropMenu(HMENU hmenu)
\r
4874 int i, count, enable;
\r
4876 extern char white_holding[], black_holding[];
\r
4877 char item[MSG_SIZ];
\r
4879 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4880 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4881 dropEnables[i].piece);
\r
4883 while (p && *p++ == dropEnables[i].piece) count++;
\r
4884 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4885 enable = count > 0 || !appData.testLegality
\r
4886 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4887 && !appData.icsActive);
\r
4888 ModifyMenu(hmenu, dropEnables[i].command,
\r
4889 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4890 dropEnables[i].command, item);
\r
4894 /* Event handler for mouse messages */
\r
4896 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4900 static int recursive = 0;
\r
4902 // BOOLEAN needsRedraw = FALSE;
\r
4903 BOOLEAN saveAnimate;
\r
4904 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4905 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4906 ChessMove moveType;
\r
4909 if (message == WM_MBUTTONUP) {
\r
4910 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4911 to the middle button: we simulate pressing the left button too!
\r
4913 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4914 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4920 pt.x = LOWORD(lParam);
\r
4921 pt.y = HIWORD(lParam);
\r
4922 x = EventToSquare(pt.x - boardRect.left);
\r
4923 y = EventToSquare(pt.y - boardRect.top);
\r
4924 if (!flipView && y >= 0) {
\r
4925 y = BOARD_HEIGHT - 1 - y;
\r
4927 if (flipView && x >= 0) {
\r
4928 x = BOARD_WIDTH - 1 - x;
\r
4931 switch (message) {
\r
4932 case WM_LBUTTONDOWN:
\r
4933 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4934 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4935 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4936 if(gameInfo.holdingsWidth &&
\r
4937 (WhiteOnMove(currentMove)
\r
4938 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4939 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4940 // click in right holdings, for determining promotion piece
\r
4941 ChessSquare p = boards[currentMove][y][x];
\r
4942 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4943 if(p != EmptySquare) {
\r
4944 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4945 fromX = fromY = -1;
\r
4949 DrawPosition(FALSE, boards[currentMove]);
\r
4953 sameAgain = FALSE;
\r
4955 /* Downclick vertically off board; check if on clock */
\r
4956 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4957 if (gameMode == EditPosition) {
\r
4958 SetWhiteToPlayEvent();
\r
4959 } else if (gameMode == IcsPlayingBlack ||
\r
4960 gameMode == MachinePlaysWhite) {
\r
4962 } else if (gameMode == EditGame) {
\r
4963 AdjustClock(flipClock, -1);
\r
4965 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4966 if (gameMode == EditPosition) {
\r
4967 SetBlackToPlayEvent();
\r
4968 } else if (gameMode == IcsPlayingWhite ||
\r
4969 gameMode == MachinePlaysBlack) {
\r
4971 } else if (gameMode == EditGame) {
\r
4972 AdjustClock(!flipClock, -1);
\r
4975 if (!appData.highlightLastMove) {
\r
4976 ClearHighlights();
\r
4977 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4979 fromX = fromY = -1;
\r
4980 dragInfo.start.x = dragInfo.start.y = -1;
\r
4981 dragInfo.from = dragInfo.start;
\r
4983 } else if (x < 0 || y < 0
\r
4984 /* [HGM] block clicks between board and holdings */
\r
4985 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4986 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4987 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4988 /* EditPosition, empty square, or different color piece;
\r
4989 click-click move is possible */
\r
4992 } else if (fromX == x && fromY == y) {
\r
4993 /* Downclick on same square again */
\r
4994 ClearHighlights();
\r
4995 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4996 sameAgain = TRUE;
\r
4997 } else if (fromX != -1 &&
\r
4998 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5000 /* Downclick on different square. */
\r
5001 /* [HGM] if on holdings file, should count as new first click ! */
\r
5002 /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5005 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5006 to make sure move is legal before showing promotion popup */
\r
5007 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, FALSE);
\r
5008 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5009 fromX = fromY = -1;
\r
5010 ClearHighlights();
\r
5011 DrawPosition(FALSE, boards[currentMove]);
\r
5014 if(moveType != ImpossibleMove && moveType != Comment) {
\r
5015 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5016 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5017 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5018 appData.alwaysPromoteToQueen)) {
\r
5019 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5020 if (!appData.highlightLastMove) {
\r
5021 ClearHighlights();
\r
5022 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5025 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5026 SetHighlights(fromX, fromY, toX, toY);
\r
5027 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5028 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5029 If promotion to Q is legal, all are legal! */
\r
5030 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5031 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5032 // kludge to temporarily execute move on display, without promoting yet
\r
5033 promotionChoice = TRUE;
\r
5034 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5035 boards[currentMove][toY][toX] = p;
\r
5036 DrawPosition(FALSE, boards[currentMove]);
\r
5037 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5038 boards[currentMove][toY][toX] = q;
\r
5039 DisplayMessage("Select piece from holdings", "");
\r
5041 PromotionPopup(hwnd);
\r
5043 } else { // not a promotion. Move can be illegal if testLegality off, and should be made then.
\r
5044 if (appData.animate || appData.highlightLastMove) {
\r
5045 SetHighlights(fromX, fromY, toX, toY);
\r
5047 ClearHighlights();
\r
5049 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5050 if (appData.animate && !appData.highlightLastMove) {
\r
5051 ClearHighlights();
\r
5052 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5055 fromX = fromY = -1;
\r
5059 if (gotPremove && moveType != Comment) {
\r
5060 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5061 // DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5062 } else ClearHighlights();
\r
5063 fromX = fromY = -1;
\r
5064 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5065 if(moveType != Comment) break;
\r
5067 /* First downclick, or restart on a square with same color piece */
\r
5068 if (!frozen && OKToStartUserMove(x, y)) {
\r
5071 dragInfo.lastpos = pt;
\r
5072 dragInfo.from.x = fromX;
\r
5073 dragInfo.from.y = fromY;
\r
5074 dragInfo.start = dragInfo.from;
\r
5075 SetCapture(hwndMain);
\r
5077 fromX = fromY = -1;
\r
5078 dragInfo.start.x = dragInfo.start.y = -1;
\r
5079 dragInfo.from = dragInfo.start;
\r
5080 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5084 case WM_LBUTTONUP:
\r
5086 if (fromX == -1) break;
\r
5087 if (x == fromX && y == fromY) {
\r
5088 dragInfo.from.x = dragInfo.from.y = -1;
\r
5089 /* Upclick on same square */
\r
5091 /* Clicked same square twice: abort click-click move */
\r
5092 fromX = fromY = -1;
\r
5094 ClearPremoveHighlights();
\r
5096 /* First square clicked: start click-click move */
\r
5097 SetHighlights(fromX, fromY, -1, -1);
\r
5099 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5100 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5101 /* Errant click; ignore */
\r
5104 /* Finish drag move. */
\r
5105 if (appData.debugMode) {
\r
5106 fprintf(debugFP, "release\n");
\r
5108 dragInfo.from.x = dragInfo.from.y = -1;
\r
5111 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5112 appData.animate = appData.animate && !appData.animateDragging;
\r
5113 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, TRUE);
\r
5114 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5115 fromX = fromY = -1;
\r
5116 ClearHighlights();
\r
5117 DrawPosition(FALSE, boards[currentMove]);
\r
5118 appData.animate = saveAnimate;
\r
5121 if(moveType != ImpossibleMove) {
\r
5122 /* [HGM] use move type to determine if move is promotion.
\r
5123 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5124 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5125 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5126 appData.alwaysPromoteToQueen))
\r
5127 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5129 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5130 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5131 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5132 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5133 // kludge to temporarily execute move on display, wthout promotng yet
\r
5134 promotionChoice = TRUE;
\r
5135 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5136 boards[currentMove][toY][toX] = p;
\r
5137 DrawPosition(FALSE, boards[currentMove]);
\r
5138 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5139 boards[currentMove][toY][toX] = q;
\r
5140 appData.animate = saveAnimate;
\r
5141 DisplayMessage("Select piece from holdings", "");
\r
5144 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5146 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5147 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5148 moveType == WhiteCapturesEnPassant ||
\r
5149 moveType == BlackCapturesEnPassant ) )
\r
5150 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5151 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5154 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5155 appData.animate = saveAnimate;
\r
5156 fromX = fromY = -1;
\r
5157 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5158 ClearHighlights();
\r
5160 if (appData.animate || appData.animateDragging ||
\r
5161 appData.highlightDragging || gotPremove) {
\r
5162 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5165 dragInfo.start.x = dragInfo.start.y = -1;
\r
5166 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5169 case WM_MOUSEMOVE:
\r
5170 if ((appData.animateDragging || appData.highlightDragging)
\r
5171 && (wParam & MK_LBUTTON)
\r
5172 && dragInfo.from.x >= 0)
\r
5174 BOOL full_repaint = FALSE;
\r
5176 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5177 if (appData.animateDragging) {
\r
5178 dragInfo.pos = pt;
\r
5180 if (appData.highlightDragging) {
\r
5181 SetHighlights(fromX, fromY, x, y);
\r
5182 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5183 full_repaint = TRUE;
\r
5187 DrawPosition( full_repaint, NULL);
\r
5189 dragInfo.lastpos = dragInfo.pos;
\r
5193 case WM_MOUSEWHEEL: // [DM]
\r
5194 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5195 /* Mouse Wheel is being rolled forward
\r
5196 * Play moves forward
\r
5198 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5199 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5200 /* Mouse Wheel is being rolled backward
\r
5201 * Play moves backward
\r
5203 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5204 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5208 case WM_MBUTTONDOWN:
\r
5209 case WM_RBUTTONDOWN:
\r
5212 fromX = fromY = -1;
\r
5213 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5214 dragInfo.start.x = dragInfo.start.y = -1;
\r
5215 dragInfo.from = dragInfo.start;
\r
5216 dragInfo.lastpos = dragInfo.pos;
\r
5217 if (appData.highlightDragging) {
\r
5218 ClearHighlights();
\r
5221 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5222 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5223 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5224 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5225 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5228 DrawPosition(TRUE, NULL);
\r
5230 switch (gameMode) {
\r
5231 case EditPosition:
\r
5232 case IcsExamining:
\r
5233 if (x < 0 || y < 0) break;
\r
5236 if (message == WM_MBUTTONDOWN) {
\r
5237 buttonCount = 3; /* even if system didn't think so */
\r
5238 if (wParam & MK_SHIFT)
\r
5239 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5241 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5242 } else { /* message == WM_RBUTTONDOWN */
\r
5243 /* Just have one menu, on the right button. Windows users don't
\r
5244 think to try the middle one, and sometimes other software steals
\r
5245 it, or it doesn't really exist. */
\r
5246 if(gameInfo.variant != VariantShogi)
\r
5247 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5249 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5252 case IcsPlayingWhite:
\r
5253 case IcsPlayingBlack:
\r
5255 case MachinePlaysWhite:
\r
5256 case MachinePlaysBlack:
\r
5257 if (appData.testLegality &&
\r
5258 gameInfo.variant != VariantBughouse &&
\r
5259 gameInfo.variant != VariantCrazyhouse) break;
\r
5260 if (x < 0 || y < 0) break;
\r
5263 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5264 SetupDropMenu(hmenu);
\r
5265 MenuPopup(hwnd, pt, hmenu, -1);
\r
5276 /* Preprocess messages for buttons in main window */
\r
5278 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5280 int id = GetWindowLong(hwnd, GWL_ID);
\r
5283 for (i=0; i<N_BUTTONS; i++) {
\r
5284 if (buttonDesc[i].id == id) break;
\r
5286 if (i == N_BUTTONS) return 0;
\r
5287 switch (message) {
\r
5292 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5293 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5300 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5303 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5304 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5305 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5306 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5308 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5310 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5311 PopUpMoveDialog((char)wParam);
\r
5317 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5320 /* Process messages for Promotion dialog box */
\r
5322 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5326 switch (message) {
\r
5327 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5328 /* Center the dialog over the application window */
\r
5329 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5330 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5331 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5332 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5333 SW_SHOW : SW_HIDE);
\r
5334 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5335 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5336 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5337 PieceToChar(WhiteAngel) != '~') ||
\r
5338 (PieceToChar(BlackAngel) >= 'A' &&
\r
5339 PieceToChar(BlackAngel) != '~') ) ?
\r
5340 SW_SHOW : SW_HIDE);
\r
5341 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5342 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5343 PieceToChar(WhiteMarshall) != '~') ||
\r
5344 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5345 PieceToChar(BlackMarshall) != '~') ) ?
\r
5346 SW_SHOW : SW_HIDE);
\r
5347 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5348 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5349 gameInfo.variant != VariantShogi ?
\r
5350 SW_SHOW : SW_HIDE);
\r
5351 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5352 gameInfo.variant != VariantShogi ?
\r
5353 SW_SHOW : SW_HIDE);
\r
5354 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5355 gameInfo.variant == VariantShogi ?
\r
5356 SW_SHOW : SW_HIDE);
\r
5357 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5358 gameInfo.variant == VariantShogi ?
\r
5359 SW_SHOW : SW_HIDE);
\r
5360 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5361 gameInfo.variant == VariantSuper ?
\r
5362 SW_SHOW : SW_HIDE);
\r
5365 case WM_COMMAND: /* message: received a command */
\r
5366 switch (LOWORD(wParam)) {
\r
5368 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5369 ClearHighlights();
\r
5370 DrawPosition(FALSE, NULL);
\r
5373 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5376 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5379 promoChar = PieceToChar(BlackRook);
\r
5382 promoChar = PieceToChar(BlackBishop);
\r
5384 case PB_Chancellor:
\r
5385 promoChar = PieceToChar(BlackMarshall);
\r
5387 case PB_Archbishop:
\r
5388 promoChar = PieceToChar(BlackAngel);
\r
5391 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5396 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5397 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5398 only show the popup when we are already sure the move is valid or
\r
5399 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5400 will figure out it is a promotion from the promoChar. */
\r
5401 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5402 if (!appData.highlightLastMove) {
\r
5403 ClearHighlights();
\r
5404 DrawPosition(FALSE, NULL);
\r
5411 /* Pop up promotion dialog */
\r
5413 PromotionPopup(HWND hwnd)
\r
5417 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5418 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5419 hwnd, (DLGPROC)lpProc);
\r
5420 FreeProcInstance(lpProc);
\r
5423 /* Toggle ShowThinking */
\r
5425 ToggleShowThinking()
\r
5427 appData.showThinking = !appData.showThinking;
\r
5428 ShowThinkingEvent();
\r
5432 LoadGameDialog(HWND hwnd, char* title)
\r
5436 char fileTitle[MSG_SIZ];
\r
5437 f = OpenFileDialog(hwnd, "rb", "",
\r
5438 appData.oldSaveStyle ? "gam" : "pgn",
\r
5440 title, &number, fileTitle, NULL);
\r
5442 cmailMsgLoaded = FALSE;
\r
5443 if (number == 0) {
\r
5444 int error = GameListBuild(f);
\r
5446 DisplayError("Cannot build game list", error);
\r
5447 } else if (!ListEmpty(&gameList) &&
\r
5448 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5449 GameListPopUp(f, fileTitle);
\r
5452 GameListDestroy();
\r
5455 LoadGame(f, number, fileTitle, FALSE);
\r
5460 ChangedConsoleFont()
\r
5463 CHARRANGE tmpsel, sel;
\r
5464 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5465 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5466 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5469 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5470 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5471 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5472 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5473 * size. This was undocumented in the version of MSVC++ that I had
\r
5474 * when I wrote the code, but is apparently documented now.
\r
5476 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5477 cfmt.bCharSet = f->lf.lfCharSet;
\r
5478 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5479 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5480 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5481 /* Why are the following seemingly needed too? */
\r
5482 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5483 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5484 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5486 tmpsel.cpMax = -1; /*999999?*/
\r
5487 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5488 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5489 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5490 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5492 paraf.cbSize = sizeof(paraf);
\r
5493 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5494 paraf.dxStartIndent = 0;
\r
5495 paraf.dxOffset = WRAP_INDENT;
\r
5496 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5497 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5500 /*---------------------------------------------------------------------------*\
\r
5502 * Window Proc for main window
\r
5504 \*---------------------------------------------------------------------------*/
\r
5506 /* Process messages for main window, etc. */
\r
5508 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5511 int wmId, wmEvent;
\r
5515 char fileTitle[MSG_SIZ];
\r
5516 char buf[MSG_SIZ];
\r
5517 static SnapData sd;
\r
5519 switch (message) {
\r
5521 case WM_PAINT: /* message: repaint portion of window */
\r
5525 case WM_ERASEBKGND:
\r
5526 if (IsIconic(hwnd)) {
\r
5527 /* Cheat; change the message */
\r
5528 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5530 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5534 case WM_LBUTTONDOWN:
\r
5535 case WM_MBUTTONDOWN:
\r
5536 case WM_RBUTTONDOWN:
\r
5537 case WM_LBUTTONUP:
\r
5538 case WM_MBUTTONUP:
\r
5539 case WM_RBUTTONUP:
\r
5540 case WM_MOUSEMOVE:
\r
5541 case WM_MOUSEWHEEL:
\r
5542 MouseEvent(hwnd, message, wParam, lParam);
\r
5545 JAWS_KB_NAVIGATION
\r
5549 JAWS_ALT_INTERCEPT
\r
5551 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5552 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5553 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5554 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5556 SendMessage(h, message, wParam, lParam);
\r
5557 } else if(lParam != KF_REPEAT) {
\r
5558 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5559 PopUpMoveDialog((char)wParam);
\r
5560 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5561 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5566 case WM_PALETTECHANGED:
\r
5567 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5569 HDC hdc = GetDC(hwndMain);
\r
5570 SelectPalette(hdc, hPal, TRUE);
\r
5571 nnew = RealizePalette(hdc);
\r
5573 paletteChanged = TRUE;
\r
5574 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5576 ReleaseDC(hwnd, hdc);
\r
5580 case WM_QUERYNEWPALETTE:
\r
5581 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5583 HDC hdc = GetDC(hwndMain);
\r
5584 paletteChanged = FALSE;
\r
5585 SelectPalette(hdc, hPal, FALSE);
\r
5586 nnew = RealizePalette(hdc);
\r
5588 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5590 ReleaseDC(hwnd, hdc);
\r
5595 case WM_COMMAND: /* message: command from application menu */
\r
5596 wmId = LOWORD(wParam);
\r
5597 wmEvent = HIWORD(wParam);
\r
5602 AnalysisPopDown();
\r
5603 SAY("new game enter a move to play against the computer with white");
\r
5606 case IDM_NewGameFRC:
\r
5607 if( NewGameFRC() == 0 ) {
\r
5609 AnalysisPopDown();
\r
5613 case IDM_NewVariant:
\r
5614 NewVariantPopup(hwnd);
\r
5617 case IDM_LoadGame:
\r
5618 LoadGameDialog(hwnd, "Load Game from File");
\r
5621 case IDM_LoadNextGame:
\r
5625 case IDM_LoadPrevGame:
\r
5629 case IDM_ReloadGame:
\r
5633 case IDM_LoadPosition:
\r
5634 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5635 Reset(FALSE, TRUE);
\r
5638 f = OpenFileDialog(hwnd, "rb", "",
\r
5639 appData.oldSaveStyle ? "pos" : "fen",
\r
5641 "Load Position from File", &number, fileTitle, NULL);
\r
5643 LoadPosition(f, number, fileTitle);
\r
5647 case IDM_LoadNextPosition:
\r
5648 ReloadPosition(1);
\r
5651 case IDM_LoadPrevPosition:
\r
5652 ReloadPosition(-1);
\r
5655 case IDM_ReloadPosition:
\r
5656 ReloadPosition(0);
\r
5659 case IDM_SaveGame:
\r
5660 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5661 f = OpenFileDialog(hwnd, "a", defName,
\r
5662 appData.oldSaveStyle ? "gam" : "pgn",
\r
5664 "Save Game to File", NULL, fileTitle, NULL);
\r
5666 SaveGame(f, 0, "");
\r
5670 case IDM_SavePosition:
\r
5671 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5672 f = OpenFileDialog(hwnd, "a", defName,
\r
5673 appData.oldSaveStyle ? "pos" : "fen",
\r
5675 "Save Position to File", NULL, fileTitle, NULL);
\r
5677 SavePosition(f, 0, "");
\r
5681 case IDM_SaveDiagram:
\r
5682 defName = "diagram";
\r
5683 f = OpenFileDialog(hwnd, "wb", defName,
\r
5686 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5692 case IDM_CopyGame:
\r
5693 CopyGameToClipboard();
\r
5696 case IDM_PasteGame:
\r
5697 PasteGameFromClipboard();
\r
5700 case IDM_CopyGameListToClipboard:
\r
5701 CopyGameListToClipboard();
\r
5704 /* [AS] Autodetect FEN or PGN data */
\r
5705 case IDM_PasteAny:
\r
5706 PasteGameOrFENFromClipboard();
\r
5709 /* [AS] Move history */
\r
5710 case IDM_ShowMoveHistory:
\r
5711 if( MoveHistoryIsUp() ) {
\r
5712 MoveHistoryPopDown();
\r
5715 MoveHistoryPopUp();
\r
5719 /* [AS] Eval graph */
\r
5720 case IDM_ShowEvalGraph:
\r
5721 if( EvalGraphIsUp() ) {
\r
5722 EvalGraphPopDown();
\r
5726 SetFocus(hwndMain);
\r
5730 /* [AS] Engine output */
\r
5731 case IDM_ShowEngineOutput:
\r
5732 if( EngineOutputIsUp() ) {
\r
5733 EngineOutputPopDown();
\r
5736 EngineOutputPopUp();
\r
5740 /* [AS] User adjudication */
\r
5741 case IDM_UserAdjudication_White:
\r
5742 UserAdjudicationEvent( +1 );
\r
5745 case IDM_UserAdjudication_Black:
\r
5746 UserAdjudicationEvent( -1 );
\r
5749 case IDM_UserAdjudication_Draw:
\r
5750 UserAdjudicationEvent( 0 );
\r
5753 /* [AS] Game list options dialog */
\r
5754 case IDM_GameListOptions:
\r
5755 GameListOptions();
\r
5762 case IDM_CopyPosition:
\r
5763 CopyFENToClipboard();
\r
5766 case IDM_PastePosition:
\r
5767 PasteFENFromClipboard();
\r
5770 case IDM_MailMove:
\r
5774 case IDM_ReloadCMailMsg:
\r
5775 Reset(TRUE, TRUE);
\r
5776 ReloadCmailMsgEvent(FALSE);
\r
5779 case IDM_Minimize:
\r
5780 ShowWindow(hwnd, SW_MINIMIZE);
\r
5787 case IDM_MachineWhite:
\r
5788 MachineWhiteEvent();
\r
5790 * refresh the tags dialog only if it's visible
\r
5792 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5794 tags = PGNTags(&gameInfo);
\r
5795 TagsPopUp(tags, CmailMsg());
\r
5798 SAY("computer starts playing white");
\r
5801 case IDM_MachineBlack:
\r
5802 MachineBlackEvent();
\r
5804 * refresh the tags dialog only if it's visible
\r
5806 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5808 tags = PGNTags(&gameInfo);
\r
5809 TagsPopUp(tags, CmailMsg());
\r
5812 SAY("computer starts playing black");
\r
5815 case IDM_TwoMachines:
\r
5816 TwoMachinesEvent();
\r
5818 * refresh the tags dialog only if it's visible
\r
5820 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5822 tags = PGNTags(&gameInfo);
\r
5823 TagsPopUp(tags, CmailMsg());
\r
5826 SAY("programs start playing each other");
\r
5829 case IDM_AnalysisMode:
\r
5830 if (!first.analysisSupport) {
\r
5831 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5832 DisplayError(buf, 0);
\r
5834 SAY("analyzing current position");
\r
5835 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5836 if (appData.icsActive) {
\r
5837 if (gameMode != IcsObserving) {
\r
5838 sprintf(buf, "You are not observing a game");
\r
5839 DisplayError(buf, 0);
\r
5840 /* secure check */
\r
5841 if (appData.icsEngineAnalyze) {
\r
5842 if (appData.debugMode)
\r
5843 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5844 ExitAnalyzeMode();
\r
5850 /* if enable, user want disable icsEngineAnalyze */
\r
5851 if (appData.icsEngineAnalyze) {
\r
5852 ExitAnalyzeMode();
\r
5856 appData.icsEngineAnalyze = TRUE;
\r
5857 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5860 if (!appData.showThinking) ToggleShowThinking();
\r
5861 AnalyzeModeEvent();
\r
5865 case IDM_AnalyzeFile:
\r
5866 if (!first.analysisSupport) {
\r
5867 char buf[MSG_SIZ];
\r
5868 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5869 DisplayError(buf, 0);
\r
5871 if (!appData.showThinking) ToggleShowThinking();
\r
5872 AnalyzeFileEvent();
\r
5873 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5874 AnalysisPeriodicEvent(1);
\r
5878 case IDM_IcsClient:
\r
5882 case IDM_EditGame:
\r
5887 case IDM_EditPosition:
\r
5888 EditPositionEvent();
\r
5889 SAY("to set up a position type a FEN");
\r
5892 case IDM_Training:
\r
5896 case IDM_ShowGameList:
\r
5897 ShowGameListProc();
\r
5900 case IDM_EditTags:
\r
5904 case IDM_EditComment:
\r
5905 if (commentDialogUp && editComment) {
\r
5908 EditCommentEvent();
\r
5928 case IDM_CallFlag:
\r
5948 case IDM_StopObserving:
\r
5949 StopObservingEvent();
\r
5952 case IDM_StopExamining:
\r
5953 StopExaminingEvent();
\r
5956 case IDM_TypeInMove:
\r
5957 PopUpMoveDialog('\000');
\r
5960 case IDM_TypeInName:
\r
5961 PopUpNameDialog('\000');
\r
5964 case IDM_Backward:
\r
5966 SetFocus(hwndMain);
\r
5973 SetFocus(hwndMain);
\r
5978 SetFocus(hwndMain);
\r
5983 SetFocus(hwndMain);
\r
5990 case IDM_TruncateGame:
\r
5991 TruncateGameEvent();
\r
5998 case IDM_RetractMove:
\r
5999 RetractMoveEvent();
\r
6002 case IDM_FlipView:
\r
6003 flipView = !flipView;
\r
6004 DrawPosition(FALSE, NULL);
\r
6007 case IDM_FlipClock:
\r
6008 flipClock = !flipClock;
\r
6009 DisplayBothClocks();
\r
6010 DrawPosition(FALSE, NULL);
\r
6013 case IDM_MuteSounds:
\r
6014 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
6015 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
6016 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
6019 case IDM_GeneralOptions:
\r
6020 GeneralOptionsPopup(hwnd);
\r
6021 DrawPosition(TRUE, NULL);
\r
6024 case IDM_BoardOptions:
\r
6025 BoardOptionsPopup(hwnd);
\r
6028 case IDM_EnginePlayOptions:
\r
6029 EnginePlayOptionsPopup(hwnd);
\r
6032 case IDM_Engine1Options:
\r
6033 EngineOptionsPopup(hwnd, &first);
\r
6036 case IDM_Engine2Options:
\r
6037 EngineOptionsPopup(hwnd, &second);
\r
6040 case IDM_OptionsUCI:
\r
6041 UciOptionsPopup(hwnd);
\r
6044 case IDM_IcsOptions:
\r
6045 IcsOptionsPopup(hwnd);
\r
6049 FontsOptionsPopup(hwnd);
\r
6053 SoundOptionsPopup(hwnd);
\r
6056 case IDM_CommPort:
\r
6057 CommPortOptionsPopup(hwnd);
\r
6060 case IDM_LoadOptions:
\r
6061 LoadOptionsPopup(hwnd);
\r
6064 case IDM_SaveOptions:
\r
6065 SaveOptionsPopup(hwnd);
\r
6068 case IDM_TimeControl:
\r
6069 TimeControlOptionsPopup(hwnd);
\r
6072 case IDM_SaveSettings:
\r
6073 SaveSettings(settingsFileName);
\r
6076 case IDM_SaveSettingsOnExit:
\r
6077 saveSettingsOnExit = !saveSettingsOnExit;
\r
6078 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6079 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6080 MF_CHECKED : MF_UNCHECKED));
\r
6091 case IDM_AboutGame:
\r
6096 appData.debugMode = !appData.debugMode;
\r
6097 if (appData.debugMode) {
\r
6098 char dir[MSG_SIZ];
\r
6099 GetCurrentDirectory(MSG_SIZ, dir);
\r
6100 SetCurrentDirectory(installDir);
\r
6101 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6102 SetCurrentDirectory(dir);
\r
6103 setbuf(debugFP, NULL);
\r
6110 case IDM_HELPCONTENTS:
\r
6111 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6112 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6113 MessageBox (GetFocus(),
\r
6114 "Unable to activate help",
\r
6115 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6119 case IDM_HELPSEARCH:
\r
6120 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6121 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6122 MessageBox (GetFocus(),
\r
6123 "Unable to activate help",
\r
6124 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6128 case IDM_HELPHELP:
\r
6129 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6130 MessageBox (GetFocus(),
\r
6131 "Unable to activate help",
\r
6132 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6137 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6139 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6140 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6141 FreeProcInstance(lpProc);
\r
6144 case IDM_DirectCommand1:
\r
6145 AskQuestionEvent("Direct Command",
\r
6146 "Send to chess program:", "", "1");
\r
6148 case IDM_DirectCommand2:
\r
6149 AskQuestionEvent("Direct Command",
\r
6150 "Send to second chess program:", "", "2");
\r
6153 case EP_WhitePawn:
\r
6154 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6155 fromX = fromY = -1;
\r
6158 case EP_WhiteKnight:
\r
6159 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6160 fromX = fromY = -1;
\r
6163 case EP_WhiteBishop:
\r
6164 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6165 fromX = fromY = -1;
\r
6168 case EP_WhiteRook:
\r
6169 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6170 fromX = fromY = -1;
\r
6173 case EP_WhiteQueen:
\r
6174 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6175 fromX = fromY = -1;
\r
6178 case EP_WhiteFerz:
\r
6179 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6180 fromX = fromY = -1;
\r
6183 case EP_WhiteWazir:
\r
6184 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6185 fromX = fromY = -1;
\r
6188 case EP_WhiteAlfil:
\r
6189 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6190 fromX = fromY = -1;
\r
6193 case EP_WhiteCannon:
\r
6194 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6195 fromX = fromY = -1;
\r
6198 case EP_WhiteCardinal:
\r
6199 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6200 fromX = fromY = -1;
\r
6203 case EP_WhiteMarshall:
\r
6204 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6205 fromX = fromY = -1;
\r
6208 case EP_WhiteKing:
\r
6209 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6210 fromX = fromY = -1;
\r
6213 case EP_BlackPawn:
\r
6214 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6215 fromX = fromY = -1;
\r
6218 case EP_BlackKnight:
\r
6219 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6220 fromX = fromY = -1;
\r
6223 case EP_BlackBishop:
\r
6224 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6225 fromX = fromY = -1;
\r
6228 case EP_BlackRook:
\r
6229 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6230 fromX = fromY = -1;
\r
6233 case EP_BlackQueen:
\r
6234 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6235 fromX = fromY = -1;
\r
6238 case EP_BlackFerz:
\r
6239 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6240 fromX = fromY = -1;
\r
6243 case EP_BlackWazir:
\r
6244 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6245 fromX = fromY = -1;
\r
6248 case EP_BlackAlfil:
\r
6249 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6250 fromX = fromY = -1;
\r
6253 case EP_BlackCannon:
\r
6254 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6255 fromX = fromY = -1;
\r
6258 case EP_BlackCardinal:
\r
6259 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6260 fromX = fromY = -1;
\r
6263 case EP_BlackMarshall:
\r
6264 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6265 fromX = fromY = -1;
\r
6268 case EP_BlackKing:
\r
6269 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6270 fromX = fromY = -1;
\r
6273 case EP_EmptySquare:
\r
6274 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6275 fromX = fromY = -1;
\r
6278 case EP_ClearBoard:
\r
6279 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6280 fromX = fromY = -1;
\r
6284 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6285 fromX = fromY = -1;
\r
6289 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6290 fromX = fromY = -1;
\r
6294 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6295 fromX = fromY = -1;
\r
6299 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6300 fromX = fromY = -1;
\r
6304 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6305 fromX = fromY = -1;
\r
6309 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6310 fromX = fromY = -1;
\r
6314 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6315 fromX = fromY = -1;
\r
6319 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6320 fromX = fromY = -1;
\r
6324 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6325 fromX = fromY = -1;
\r
6329 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6335 case CLOCK_TIMER_ID:
\r
6336 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6337 clockTimerEvent = 0;
\r
6338 DecrementClocks(); /* call into back end */
\r
6340 case LOAD_GAME_TIMER_ID:
\r
6341 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6342 loadGameTimerEvent = 0;
\r
6343 AutoPlayGameLoop(); /* call into back end */
\r
6345 case ANALYSIS_TIMER_ID:
\r
6346 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6347 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6348 AnalysisPeriodicEvent(0);
\r
6350 KillTimer(hwnd, analysisTimerEvent);
\r
6351 analysisTimerEvent = 0;
\r
6354 case DELAYED_TIMER_ID:
\r
6355 KillTimer(hwnd, delayedTimerEvent);
\r
6356 delayedTimerEvent = 0;
\r
6357 delayedTimerCallback();
\r
6362 case WM_USER_Input:
\r
6363 InputEvent(hwnd, message, wParam, lParam);
\r
6366 /* [AS] Also move "attached" child windows */
\r
6367 case WM_WINDOWPOSCHANGING:
\r
6369 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6370 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6372 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6373 /* Window is moving */
\r
6376 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6377 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6378 rcMain.right = boardX + winWidth;
\r
6379 rcMain.top = boardY;
\r
6380 rcMain.bottom = boardY + winHeight;
\r
6382 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6383 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6384 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6385 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6386 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6393 /* [AS] Snapping */
\r
6394 case WM_ENTERSIZEMOVE:
\r
6395 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6396 if (hwnd == hwndMain) {
\r
6397 doingSizing = TRUE;
\r
6400 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6404 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6405 if (hwnd == hwndMain) {
\r
6406 lastSizing = wParam;
\r
6411 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6412 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6414 case WM_EXITSIZEMOVE:
\r
6415 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6416 if (hwnd == hwndMain) {
\r
6418 doingSizing = FALSE;
\r
6419 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6420 GetClientRect(hwnd, &client);
\r
6421 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6423 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6425 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6428 case WM_DESTROY: /* message: window being destroyed */
\r
6429 PostQuitMessage(0);
\r
6433 if (hwnd == hwndMain) {
\r
6438 default: /* Passes it on if unprocessed */
\r
6439 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6444 /*---------------------------------------------------------------------------*\
\r
6446 * Misc utility routines
\r
6448 \*---------------------------------------------------------------------------*/
\r
6451 * Decent random number generator, at least not as bad as Windows
\r
6452 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6454 unsigned int randstate;
\r
6459 randstate = randstate * 1664525 + 1013904223;
\r
6460 return (int) randstate & 0x7fffffff;
\r
6464 mysrandom(unsigned int seed)
\r
6471 * returns TRUE if user selects a different color, FALSE otherwise
\r
6475 ChangeColor(HWND hwnd, COLORREF *which)
\r
6477 static BOOL firstTime = TRUE;
\r
6478 static DWORD customColors[16];
\r
6480 COLORREF newcolor;
\r
6485 /* Make initial colors in use available as custom colors */
\r
6486 /* Should we put the compiled-in defaults here instead? */
\r
6488 customColors[i++] = lightSquareColor & 0xffffff;
\r
6489 customColors[i++] = darkSquareColor & 0xffffff;
\r
6490 customColors[i++] = whitePieceColor & 0xffffff;
\r
6491 customColors[i++] = blackPieceColor & 0xffffff;
\r
6492 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6493 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6495 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6496 customColors[i++] = textAttribs[ccl].color;
\r
6498 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6499 firstTime = FALSE;
\r
6502 cc.lStructSize = sizeof(cc);
\r
6503 cc.hwndOwner = hwnd;
\r
6504 cc.hInstance = NULL;
\r
6505 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6506 cc.lpCustColors = (LPDWORD) customColors;
\r
6507 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6509 if (!ChooseColor(&cc)) return FALSE;
\r
6511 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6512 if (newcolor == *which) return FALSE;
\r
6513 *which = newcolor;
\r
6517 InitDrawingColors();
\r
6518 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6523 MyLoadSound(MySound *ms)
\r
6529 if (ms->data) free(ms->data);
\r
6532 switch (ms->name[0]) {
\r
6538 /* System sound from Control Panel. Don't preload here. */
\r
6542 if (ms->name[1] == NULLCHAR) {
\r
6543 /* "!" alone = silence */
\r
6546 /* Builtin wave resource. Error if not found. */
\r
6547 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6548 if (h == NULL) break;
\r
6549 ms->data = (void *)LoadResource(hInst, h);
\r
6550 if (h == NULL) break;
\r
6555 /* .wav file. Error if not found. */
\r
6556 f = fopen(ms->name, "rb");
\r
6557 if (f == NULL) break;
\r
6558 if (fstat(fileno(f), &st) < 0) break;
\r
6559 ms->data = malloc(st.st_size);
\r
6560 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6566 char buf[MSG_SIZ];
\r
6567 sprintf(buf, "Error loading sound %s", ms->name);
\r
6568 DisplayError(buf, GetLastError());
\r
6574 MyPlaySound(MySound *ms)
\r
6576 BOOLEAN ok = FALSE;
\r
6578 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6579 switch (ms->name[0]) {
\r
6581 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6586 /* System sound from Control Panel (deprecated feature).
\r
6587 "$" alone or an unset sound name gets default beep (still in use). */
\r
6588 if (ms->name[1]) {
\r
6589 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6591 if (!ok) ok = MessageBeep(MB_OK);
\r
6594 /* Builtin wave resource, or "!" alone for silence */
\r
6595 if (ms->name[1]) {
\r
6596 if (ms->data == NULL) return FALSE;
\r
6597 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6603 /* .wav file. Error if not found. */
\r
6604 if (ms->data == NULL) return FALSE;
\r
6605 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6608 /* Don't print an error: this can happen innocently if the sound driver
\r
6609 is busy; for instance, if another instance of WinBoard is playing
\r
6610 a sound at about the same time. */
\r
6616 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6619 OPENFILENAME *ofn;
\r
6620 static UINT *number; /* gross that this is static */
\r
6622 switch (message) {
\r
6623 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6624 /* Center the dialog over the application window */
\r
6625 ofn = (OPENFILENAME *) lParam;
\r
6626 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6627 number = (UINT *) ofn->lCustData;
\r
6628 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6632 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6633 return FALSE; /* Allow for further processing */
\r
6636 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6637 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6639 return FALSE; /* Allow for further processing */
\r
6645 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6647 static UINT *number;
\r
6648 OPENFILENAME *ofname;
\r
6651 case WM_INITDIALOG:
\r
6652 ofname = (OPENFILENAME *)lParam;
\r
6653 number = (UINT *)(ofname->lCustData);
\r
6656 ofnot = (OFNOTIFY *)lParam;
\r
6657 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6658 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6667 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6668 char *nameFilt, char *dlgTitle, UINT *number,
\r
6669 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6671 OPENFILENAME openFileName;
\r
6672 char buf1[MSG_SIZ];
\r
6675 if (fileName == NULL) fileName = buf1;
\r
6676 if (defName == NULL) {
\r
6677 strcpy(fileName, "*.");
\r
6678 strcat(fileName, defExt);
\r
6680 strcpy(fileName, defName);
\r
6682 if (fileTitle) strcpy(fileTitle, "");
\r
6683 if (number) *number = 0;
\r
6685 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6686 openFileName.hwndOwner = hwnd;
\r
6687 openFileName.hInstance = (HANDLE) hInst;
\r
6688 openFileName.lpstrFilter = nameFilt;
\r
6689 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6690 openFileName.nMaxCustFilter = 0L;
\r
6691 openFileName.nFilterIndex = 1L;
\r
6692 openFileName.lpstrFile = fileName;
\r
6693 openFileName.nMaxFile = MSG_SIZ;
\r
6694 openFileName.lpstrFileTitle = fileTitle;
\r
6695 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6696 openFileName.lpstrInitialDir = NULL;
\r
6697 openFileName.lpstrTitle = dlgTitle;
\r
6698 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6699 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6700 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6701 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6702 openFileName.nFileOffset = 0;
\r
6703 openFileName.nFileExtension = 0;
\r
6704 openFileName.lpstrDefExt = defExt;
\r
6705 openFileName.lCustData = (LONG) number;
\r
6706 openFileName.lpfnHook = oldDialog ?
\r
6707 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6708 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6710 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6711 GetOpenFileName(&openFileName)) {
\r
6712 /* open the file */
\r
6713 f = fopen(openFileName.lpstrFile, write);
\r
6715 MessageBox(hwnd, "File open failed", NULL,
\r
6716 MB_OK|MB_ICONEXCLAMATION);
\r
6720 int err = CommDlgExtendedError();
\r
6721 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6730 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6732 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6735 * Get the first pop-up menu in the menu template. This is the
\r
6736 * menu that TrackPopupMenu displays.
\r
6738 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6740 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6743 * TrackPopup uses screen coordinates, so convert the
\r
6744 * coordinates of the mouse click to screen coordinates.
\r
6746 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6748 /* Draw and track the floating pop-up menu. */
\r
6749 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6750 pt.x, pt.y, 0, hwnd, NULL);
\r
6752 /* Destroy the menu.*/
\r
6753 DestroyMenu(hmenu);
\r
6758 int sizeX, sizeY, newSizeX, newSizeY;
\r
6760 } ResizeEditPlusButtonsClosure;
\r
6763 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6765 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6769 if (hChild == cl->hText) return TRUE;
\r
6770 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6771 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6772 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6773 ScreenToClient(cl->hDlg, &pt);
\r
6774 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6775 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6779 /* Resize a dialog that has a (rich) edit field filling most of
\r
6780 the top, with a row of buttons below */
\r
6782 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6785 int newTextHeight, newTextWidth;
\r
6786 ResizeEditPlusButtonsClosure cl;
\r
6788 /*if (IsIconic(hDlg)) return;*/
\r
6789 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6791 cl.hdwp = BeginDeferWindowPos(8);
\r
6793 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6794 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6795 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6796 if (newTextHeight < 0) {
\r
6797 newSizeY += -newTextHeight;
\r
6798 newTextHeight = 0;
\r
6800 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6801 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6807 cl.newSizeX = newSizeX;
\r
6808 cl.newSizeY = newSizeY;
\r
6809 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6811 EndDeferWindowPos(cl.hdwp);
\r
6814 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6816 RECT rChild, rParent;
\r
6817 int wChild, hChild, wParent, hParent;
\r
6818 int wScreen, hScreen, xNew, yNew;
\r
6821 /* Get the Height and Width of the child window */
\r
6822 GetWindowRect (hwndChild, &rChild);
\r
6823 wChild = rChild.right - rChild.left;
\r
6824 hChild = rChild.bottom - rChild.top;
\r
6826 /* Get the Height and Width of the parent window */
\r
6827 GetWindowRect (hwndParent, &rParent);
\r
6828 wParent = rParent.right - rParent.left;
\r
6829 hParent = rParent.bottom - rParent.top;
\r
6831 /* Get the display limits */
\r
6832 hdc = GetDC (hwndChild);
\r
6833 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6834 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6835 ReleaseDC(hwndChild, hdc);
\r
6837 /* Calculate new X position, then adjust for screen */
\r
6838 xNew = rParent.left + ((wParent - wChild) /2);
\r
6841 } else if ((xNew+wChild) > wScreen) {
\r
6842 xNew = wScreen - wChild;
\r
6845 /* Calculate new Y position, then adjust for screen */
\r
6847 yNew = rParent.top + ((hParent - hChild) /2);
\r
6850 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6855 } else if ((yNew+hChild) > hScreen) {
\r
6856 yNew = hScreen - hChild;
\r
6859 /* Set it, and return */
\r
6860 return SetWindowPos (hwndChild, NULL,
\r
6861 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6864 /* Center one window over another */
\r
6865 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6867 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6870 /*---------------------------------------------------------------------------*\
\r
6872 * Startup Dialog functions
\r
6874 \*---------------------------------------------------------------------------*/
\r
6876 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6878 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6880 while (*cd != NULL) {
\r
6881 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6887 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6889 char buf1[ARG_MAX];
\r
6892 if (str[0] == '@') {
\r
6893 FILE* f = fopen(str + 1, "r");
\r
6895 DisplayFatalError(str + 1, errno, 2);
\r
6898 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6900 buf1[len] = NULLCHAR;
\r
6904 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6907 char buf[MSG_SIZ];
\r
6908 char *end = strchr(str, '\n');
\r
6909 if (end == NULL) return;
\r
6910 memcpy(buf, str, end - str);
\r
6911 buf[end - str] = NULLCHAR;
\r
6912 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6918 SetStartupDialogEnables(HWND hDlg)
\r
6920 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6921 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6922 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6923 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6924 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6925 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6926 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6927 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6928 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6929 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6930 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6931 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6932 IsDlgButtonChecked(hDlg, OPT_View));
\r
6936 QuoteForFilename(char *filename)
\r
6938 int dquote, space;
\r
6939 dquote = strchr(filename, '"') != NULL;
\r
6940 space = strchr(filename, ' ') != NULL;
\r
6941 if (dquote || space) {
\r
6953 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6955 char buf[MSG_SIZ];
\r
6958 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6959 q = QuoteForFilename(nthcp);
\r
6960 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6961 if (*nthdir != NULLCHAR) {
\r
6962 q = QuoteForFilename(nthdir);
\r
6963 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6965 if (*nthcp == NULLCHAR) {
\r
6966 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6967 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6968 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6969 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6974 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6976 char buf[MSG_SIZ];
\r
6980 switch (message) {
\r
6981 case WM_INITDIALOG:
\r
6982 /* Center the dialog */
\r
6983 CenterWindow (hDlg, GetDesktopWindow());
\r
6984 /* Initialize the dialog items */
\r
6985 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6986 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6987 firstChessProgramNames);
\r
6988 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6989 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6990 secondChessProgramNames);
\r
6991 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6992 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6993 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6994 if (*appData.icsHelper != NULLCHAR) {
\r
6995 char *q = QuoteForFilename(appData.icsHelper);
\r
6996 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6998 if (*appData.icsHost == NULLCHAR) {
\r
6999 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7000 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7001 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7002 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7003 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7006 if (appData.icsActive) {
\r
7007 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7009 else if (appData.noChessProgram) {
\r
7010 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7013 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7016 SetStartupDialogEnables(hDlg);
\r
7020 switch (LOWORD(wParam)) {
\r
7022 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7023 strcpy(buf, "/fcp=");
\r
7024 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7026 ParseArgs(StringGet, &p);
\r
7027 strcpy(buf, "/scp=");
\r
7028 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7030 ParseArgs(StringGet, &p);
\r
7031 appData.noChessProgram = FALSE;
\r
7032 appData.icsActive = FALSE;
\r
7033 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7034 strcpy(buf, "/ics /icshost=");
\r
7035 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7037 ParseArgs(StringGet, &p);
\r
7038 if (appData.zippyPlay) {
\r
7039 strcpy(buf, "/fcp=");
\r
7040 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7042 ParseArgs(StringGet, &p);
\r
7044 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7045 appData.noChessProgram = TRUE;
\r
7046 appData.icsActive = FALSE;
\r
7048 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7049 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7052 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7053 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7055 ParseArgs(StringGet, &p);
\r
7057 EndDialog(hDlg, TRUE);
\r
7064 case IDM_HELPCONTENTS:
\r
7065 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7066 MessageBox (GetFocus(),
\r
7067 "Unable to activate help",
\r
7068 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7073 SetStartupDialogEnables(hDlg);
\r
7081 /*---------------------------------------------------------------------------*\
\r
7083 * About box dialog functions
\r
7085 \*---------------------------------------------------------------------------*/
\r
7087 /* Process messages for "About" dialog box */
\r
7089 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7091 switch (message) {
\r
7092 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7093 /* Center the dialog over the application window */
\r
7094 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7095 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7099 case WM_COMMAND: /* message: received a command */
\r
7100 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7101 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7102 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7110 /*---------------------------------------------------------------------------*\
\r
7112 * Comment Dialog functions
\r
7114 \*---------------------------------------------------------------------------*/
\r
7117 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7119 static HANDLE hwndText = NULL;
\r
7120 int len, newSizeX, newSizeY, flags;
\r
7121 static int sizeX, sizeY;
\r
7126 switch (message) {
\r
7127 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7128 /* Initialize the dialog items */
\r
7129 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7130 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7131 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7132 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7133 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7134 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7135 SetWindowText(hDlg, commentTitle);
\r
7136 if (editComment) {
\r
7137 SetFocus(hwndText);
\r
7139 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7141 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7142 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7143 MAKELPARAM(FALSE, 0));
\r
7144 /* Size and position the dialog */
\r
7145 if (!commentDialog) {
\r
7146 commentDialog = hDlg;
\r
7147 flags = SWP_NOZORDER;
\r
7148 GetClientRect(hDlg, &rect);
\r
7149 sizeX = rect.right;
\r
7150 sizeY = rect.bottom;
\r
7151 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7152 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7153 WINDOWPLACEMENT wp;
\r
7154 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7155 wp.length = sizeof(WINDOWPLACEMENT);
\r
7157 wp.showCmd = SW_SHOW;
\r
7158 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7159 wp.rcNormalPosition.left = commentX;
\r
7160 wp.rcNormalPosition.right = commentX + commentW;
\r
7161 wp.rcNormalPosition.top = commentY;
\r
7162 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7163 SetWindowPlacement(hDlg, &wp);
\r
7165 GetClientRect(hDlg, &rect);
\r
7166 newSizeX = rect.right;
\r
7167 newSizeY = rect.bottom;
\r
7168 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7169 newSizeX, newSizeY);
\r
7176 case WM_COMMAND: /* message: received a command */
\r
7177 switch (LOWORD(wParam)) {
\r
7179 if (editComment) {
\r
7181 /* Read changed options from the dialog box */
\r
7182 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7183 len = GetWindowTextLength(hwndText);
\r
7184 str = (char *) malloc(len + 1);
\r
7185 GetWindowText(hwndText, str, len + 1);
\r
7194 ReplaceComment(commentIndex, str);
\r
7201 case OPT_CancelComment:
\r
7205 case OPT_ClearComment:
\r
7206 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7209 case OPT_EditComment:
\r
7210 EditCommentEvent();
\r
7219 newSizeX = LOWORD(lParam);
\r
7220 newSizeY = HIWORD(lParam);
\r
7221 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7226 case WM_GETMINMAXINFO:
\r
7227 /* Prevent resizing window too small */
\r
7228 mmi = (MINMAXINFO *) lParam;
\r
7229 mmi->ptMinTrackSize.x = 100;
\r
7230 mmi->ptMinTrackSize.y = 100;
\r
7237 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7242 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7244 if (str == NULL) str = "";
\r
7245 p = (char *) malloc(2 * strlen(str) + 2);
\r
7248 if (*str == '\n') *q++ = '\r';
\r
7252 if (commentText != NULL) free(commentText);
\r
7254 commentIndex = index;
\r
7255 commentTitle = title;
\r
7257 editComment = edit;
\r
7259 if (commentDialog) {
\r
7260 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7261 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7263 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7264 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7265 hwndMain, (DLGPROC)lpProc);
\r
7266 FreeProcInstance(lpProc);
\r
7268 commentDialogUp = TRUE;
\r
7272 /*---------------------------------------------------------------------------*\
\r
7274 * Type-in move dialog functions
\r
7276 \*---------------------------------------------------------------------------*/
\r
7279 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7281 char move[MSG_SIZ];
\r
7283 ChessMove moveType;
\r
7284 int fromX, fromY, toX, toY;
\r
7287 switch (message) {
\r
7288 case WM_INITDIALOG:
\r
7289 move[0] = (char) lParam;
\r
7290 move[1] = NULLCHAR;
\r
7291 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7292 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7293 SetWindowText(hInput, move);
\r
7295 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7299 switch (LOWORD(wParam)) {
\r
7301 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7302 { int n; Board board;
\r
7304 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7305 EditPositionPasteFEN(move);
\r
7306 EndDialog(hDlg, TRUE);
\r
7309 // [HGM] movenum: allow move number to be typed in any mode
\r
7310 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7311 currentMove = 2*n-1;
\r
7312 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7313 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7314 EndDialog(hDlg, TRUE);
\r
7315 DrawPosition(TRUE, boards[currentMove]);
\r
7316 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7317 else DisplayMessage("", "");
\r
7321 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7322 gameMode != Training) {
\r
7323 DisplayMoveError("Displayed move is not current");
\r
7325 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7326 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7327 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7328 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7329 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7330 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7331 if (gameMode != Training)
\r
7332 forwardMostMove = currentMove;
\r
7333 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7335 DisplayMoveError("Could not parse move");
\r
7338 EndDialog(hDlg, TRUE);
\r
7341 EndDialog(hDlg, FALSE);
\r
7352 PopUpMoveDialog(char firstchar)
\r
7356 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7357 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7358 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7359 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7360 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7361 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7362 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7363 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7364 gameMode == Training) {
\r
7365 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7366 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7367 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7368 FreeProcInstance(lpProc);
\r
7372 /*---------------------------------------------------------------------------*\
\r
7374 * Type-in name dialog functions
\r
7376 \*---------------------------------------------------------------------------*/
\r
7379 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7381 char move[MSG_SIZ];
\r
7384 switch (message) {
\r
7385 case WM_INITDIALOG:
\r
7386 move[0] = (char) lParam;
\r
7387 move[1] = NULLCHAR;
\r
7388 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7389 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7390 SetWindowText(hInput, move);
\r
7392 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7396 switch (LOWORD(wParam)) {
\r
7398 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7399 appData.userName = strdup(move);
\r
7402 EndDialog(hDlg, TRUE);
\r
7405 EndDialog(hDlg, FALSE);
\r
7416 PopUpNameDialog(char firstchar)
\r
7420 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7421 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7422 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7423 FreeProcInstance(lpProc);
\r
7426 /*---------------------------------------------------------------------------*\
\r
7430 \*---------------------------------------------------------------------------*/
\r
7432 /* Nonmodal error box */
\r
7433 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7434 WPARAM wParam, LPARAM lParam);
\r
7437 ErrorPopUp(char *title, char *content)
\r
7441 BOOLEAN modal = hwndMain == NULL;
\r
7459 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7460 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7463 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7465 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7466 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7467 hwndMain, (DLGPROC)lpProc);
\r
7468 FreeProcInstance(lpProc);
\r
7475 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7476 if (errorDialog == NULL) return;
\r
7477 DestroyWindow(errorDialog);
\r
7478 errorDialog = NULL;
\r
7482 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7487 switch (message) {
\r
7488 case WM_INITDIALOG:
\r
7489 GetWindowRect(hDlg, &rChild);
\r
7492 SetWindowPos(hDlg, NULL, rChild.left,
\r
7493 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7494 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7498 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7499 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7500 and it doesn't work when you resize the dialog.
\r
7501 For now, just give it a default position.
\r
7503 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7505 errorDialog = hDlg;
\r
7506 SetWindowText(hDlg, errorTitle);
\r
7507 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7508 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7512 switch (LOWORD(wParam)) {
\r
7515 if (errorDialog == hDlg) errorDialog = NULL;
\r
7516 DestroyWindow(hDlg);
\r
7528 HWND gothicDialog = NULL;
\r
7531 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7535 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7537 switch (message) {
\r
7538 case WM_INITDIALOG:
\r
7539 GetWindowRect(hDlg, &rChild);
\r
7541 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7545 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7546 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7547 and it doesn't work when you resize the dialog.
\r
7548 For now, just give it a default position.
\r
7550 gothicDialog = hDlg;
\r
7551 SetWindowText(hDlg, errorTitle);
\r
7552 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7553 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7557 switch (LOWORD(wParam)) {
\r
7560 if (errorDialog == hDlg) errorDialog = NULL;
\r
7561 DestroyWindow(hDlg);
\r
7573 GothicPopUp(char *title, VariantClass variant)
\r
7576 static char *lastTitle;
\r
7578 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7579 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7581 if(lastTitle != title && gothicDialog != NULL) {
\r
7582 DestroyWindow(gothicDialog);
\r
7583 gothicDialog = NULL;
\r
7585 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7586 title = lastTitle;
\r
7587 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7588 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7589 hwndMain, (DLGPROC)lpProc);
\r
7590 FreeProcInstance(lpProc);
\r
7595 /*---------------------------------------------------------------------------*\
\r
7597 * Ics Interaction console functions
\r
7599 \*---------------------------------------------------------------------------*/
\r
7601 #define HISTORY_SIZE 64
\r
7602 static char *history[HISTORY_SIZE];
\r
7603 int histIn = 0, histP = 0;
\r
7606 SaveInHistory(char *cmd)
\r
7608 if (history[histIn] != NULL) {
\r
7609 free(history[histIn]);
\r
7610 history[histIn] = NULL;
\r
7612 if (*cmd == NULLCHAR) return;
\r
7613 history[histIn] = StrSave(cmd);
\r
7614 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7615 if (history[histIn] != NULL) {
\r
7616 free(history[histIn]);
\r
7617 history[histIn] = NULL;
\r
7623 PrevInHistory(char *cmd)
\r
7626 if (histP == histIn) {
\r
7627 if (history[histIn] != NULL) free(history[histIn]);
\r
7628 history[histIn] = StrSave(cmd);
\r
7630 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7631 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7633 return history[histP];
\r
7639 if (histP == histIn) return NULL;
\r
7640 histP = (histP + 1) % HISTORY_SIZE;
\r
7641 return history[histP];
\r
7648 BOOLEAN immediate;
\r
7649 } IcsTextMenuEntry;
\r
7650 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7651 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7654 ParseIcsTextMenu(char *icsTextMenuString)
\r
7657 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7658 char *p = icsTextMenuString;
\r
7659 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7662 if (e->command != NULL) {
\r
7664 e->command = NULL;
\r
7668 e = icsTextMenuEntry;
\r
7669 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7670 if (*p == ';' || *p == '\n') {
\r
7671 e->item = strdup("-");
\r
7672 e->command = NULL;
\r
7674 } else if (*p == '-') {
\r
7675 e->item = strdup("-");
\r
7676 e->command = NULL;
\r
7680 char *q, *r, *s, *t;
\r
7682 q = strchr(p, ',');
\r
7683 if (q == NULL) break;
\r
7685 r = strchr(q + 1, ',');
\r
7686 if (r == NULL) break;
\r
7688 s = strchr(r + 1, ',');
\r
7689 if (s == NULL) break;
\r
7692 t = strchr(s + 1, c);
\r
7695 t = strchr(s + 1, c);
\r
7697 if (t != NULL) *t = NULLCHAR;
\r
7698 e->item = strdup(p);
\r
7699 e->command = strdup(q + 1);
\r
7700 e->getname = *(r + 1) != '0';
\r
7701 e->immediate = *(s + 1) != '0';
\r
7705 if (t == NULL) break;
\r
7714 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7718 hmenu = LoadMenu(hInst, "TextMenu");
\r
7719 h = GetSubMenu(hmenu, 0);
\r
7721 if (strcmp(e->item, "-") == 0) {
\r
7722 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7724 if (e->item[0] == '|') {
\r
7725 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7726 IDM_CommandX + i, &e->item[1]);
\r
7728 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7737 WNDPROC consoleTextWindowProc;
\r
7740 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7742 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7743 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7747 SetWindowText(hInput, command);
\r
7749 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7751 sel.cpMin = 999999;
\r
7752 sel.cpMax = 999999;
\r
7753 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7758 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7759 if (sel.cpMin == sel.cpMax) {
\r
7760 /* Expand to surrounding word */
\r
7763 tr.chrg.cpMax = sel.cpMin;
\r
7764 tr.chrg.cpMin = --sel.cpMin;
\r
7765 if (sel.cpMin < 0) break;
\r
7766 tr.lpstrText = name;
\r
7767 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7768 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7772 tr.chrg.cpMin = sel.cpMax;
\r
7773 tr.chrg.cpMax = ++sel.cpMax;
\r
7774 tr.lpstrText = name;
\r
7775 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7776 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7779 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7780 MessageBeep(MB_ICONEXCLAMATION);
\r
7784 tr.lpstrText = name;
\r
7785 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7787 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7788 MessageBeep(MB_ICONEXCLAMATION);
\r
7791 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7794 sprintf(buf, "%s %s", command, name);
\r
7795 SetWindowText(hInput, buf);
\r
7796 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7798 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7799 SetWindowText(hInput, buf);
\r
7800 sel.cpMin = 999999;
\r
7801 sel.cpMax = 999999;
\r
7802 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7808 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7813 switch (message) {
\r
7815 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7818 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7821 sel.cpMin = 999999;
\r
7822 sel.cpMax = 999999;
\r
7823 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7824 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7829 if(wParam != '\022') {
\r
7830 if (wParam == '\t') {
\r
7831 if (GetKeyState(VK_SHIFT) < 0) {
\r
7833 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7834 if (buttonDesc[0].hwnd) {
\r
7835 SetFocus(buttonDesc[0].hwnd);
\r
7837 SetFocus(hwndMain);
\r
7841 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7844 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7845 JAWS_DELETE( SetFocus(hInput); )
\r
7846 SendMessage(hInput, message, wParam, lParam);
\r
7849 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7850 case WM_RBUTTONUP:
\r
7851 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7852 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7853 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7856 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7857 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7858 if (sel.cpMin == sel.cpMax) {
\r
7859 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7860 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7862 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7863 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7865 pt.x = LOWORD(lParam);
\r
7866 pt.y = HIWORD(lParam);
\r
7867 MenuPopup(hwnd, pt, hmenu, -1);
\r
7871 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7873 return SendMessage(hInput, message, wParam, lParam);
\r
7874 case WM_MBUTTONDOWN:
\r
7875 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7876 case WM_RBUTTONDOWN:
\r
7877 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7878 /* Move selection here if it was empty */
\r
7880 pt.x = LOWORD(lParam);
\r
7881 pt.y = HIWORD(lParam);
\r
7882 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7883 if (sel.cpMin == sel.cpMax) {
\r
7884 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7885 sel.cpMax = sel.cpMin;
\r
7886 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7888 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7892 switch (LOWORD(wParam)) {
\r
7893 case IDM_QuickPaste:
\r
7895 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7896 if (sel.cpMin == sel.cpMax) {
\r
7897 MessageBeep(MB_ICONEXCLAMATION);
\r
7900 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7901 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7902 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7907 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7910 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7913 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7917 int i = LOWORD(wParam) - IDM_CommandX;
\r
7918 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7919 icsTextMenuEntry[i].command != NULL) {
\r
7920 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7921 icsTextMenuEntry[i].getname,
\r
7922 icsTextMenuEntry[i].immediate);
\r
7930 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7933 WNDPROC consoleInputWindowProc;
\r
7936 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7938 char buf[MSG_SIZ];
\r
7940 static BOOL sendNextChar = FALSE;
\r
7941 static BOOL quoteNextChar = FALSE;
\r
7942 InputSource *is = consoleInputSource;
\r
7946 switch (message) {
\r
7948 if (!appData.localLineEditing || sendNextChar) {
\r
7949 is->buf[0] = (CHAR) wParam;
\r
7951 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7952 sendNextChar = FALSE;
\r
7955 if (quoteNextChar) {
\r
7956 buf[0] = (char) wParam;
\r
7957 buf[1] = NULLCHAR;
\r
7958 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7959 quoteNextChar = FALSE;
\r
7963 case '\r': /* Enter key */
\r
7964 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7965 if (consoleEcho) SaveInHistory(is->buf);
\r
7966 is->buf[is->count++] = '\n';
\r
7967 is->buf[is->count] = NULLCHAR;
\r
7968 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7969 if (consoleEcho) {
\r
7970 ConsoleOutput(is->buf, is->count, TRUE);
\r
7971 } else if (appData.localLineEditing) {
\r
7972 ConsoleOutput("\n", 1, TRUE);
\r
7975 case '\033': /* Escape key */
\r
7976 SetWindowText(hwnd, "");
\r
7977 cf.cbSize = sizeof(CHARFORMAT);
\r
7978 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7979 if (consoleEcho) {
\r
7980 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7982 cf.crTextColor = COLOR_ECHOOFF;
\r
7984 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7985 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7987 case '\t': /* Tab key */
\r
7988 if (GetKeyState(VK_SHIFT) < 0) {
\r
7990 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7993 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7994 if (buttonDesc[0].hwnd) {
\r
7995 SetFocus(buttonDesc[0].hwnd);
\r
7997 SetFocus(hwndMain);
\r
8001 case '\023': /* Ctrl+S */
\r
8002 sendNextChar = TRUE;
\r
8004 case '\021': /* Ctrl+Q */
\r
8005 quoteNextChar = TRUE;
\r
8015 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8016 p = PrevInHistory(buf);
\r
8018 SetWindowText(hwnd, p);
\r
8019 sel.cpMin = 999999;
\r
8020 sel.cpMax = 999999;
\r
8021 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8026 p = NextInHistory();
\r
8028 SetWindowText(hwnd, p);
\r
8029 sel.cpMin = 999999;
\r
8030 sel.cpMax = 999999;
\r
8031 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8037 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8041 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8045 case WM_MBUTTONDOWN:
\r
8046 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8047 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8049 case WM_RBUTTONUP:
\r
8050 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8051 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8052 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8056 hmenu = LoadMenu(hInst, "InputMenu");
\r
8057 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8058 if (sel.cpMin == sel.cpMax) {
\r
8059 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8060 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8062 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8063 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8065 pt.x = LOWORD(lParam);
\r
8066 pt.y = HIWORD(lParam);
\r
8067 MenuPopup(hwnd, pt, hmenu, -1);
\r
8071 switch (LOWORD(wParam)) {
\r
8073 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8075 case IDM_SelectAll:
\r
8077 sel.cpMax = -1; /*999999?*/
\r
8078 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8081 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8084 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8087 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8092 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8095 #define CO_MAX 100000
\r
8096 #define CO_TRIM 1000
\r
8099 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8101 static SnapData sd;
\r
8102 static HWND hText, hInput /*, hFocus*/;
\r
8103 // InputSource *is = consoleInputSource;
\r
8105 static int sizeX, sizeY;
\r
8106 int newSizeX, newSizeY;
\r
8110 switch (message) {
\r
8112 if (((NMHDR*)lParam)->code == EN_LINK)
\r
8114 ENLINK *pLink = (ENLINK*)lParam;
\r
8115 if (pLink->msg == WM_LBUTTONUP)
\r
8119 tr.chrg = pLink->chrg;
\r
8120 tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);
\r
8121 SendMessage(hText, EM_GETTEXTRANGE, 0, (LPARAM)&tr);
\r
8122 ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);
\r
8123 free(tr.lpstrText);
\r
8127 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8128 hwndConsole = hDlg;
\r
8129 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8130 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8132 consoleTextWindowProc = (WNDPROC)
\r
8133 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8134 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8135 consoleInputWindowProc = (WNDPROC)
\r
8136 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8137 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8138 Colorize(ColorNormal, TRUE);
\r
8139 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8140 ChangedConsoleFont();
\r
8141 GetClientRect(hDlg, &rect);
\r
8142 sizeX = rect.right;
\r
8143 sizeY = rect.bottom;
\r
8144 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8145 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8146 WINDOWPLACEMENT wp;
\r
8147 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8148 wp.length = sizeof(WINDOWPLACEMENT);
\r
8150 wp.showCmd = SW_SHOW;
\r
8151 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8152 wp.rcNormalPosition.left = wpConsole.x;
\r
8153 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8154 wp.rcNormalPosition.top = wpConsole.y;
\r
8155 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8156 SetWindowPlacement(hDlg, &wp);
\r
8159 // [HGM] Chessknight's change 2004-07-13
\r
8160 else { /* Determine Defaults */
\r
8161 WINDOWPLACEMENT wp;
\r
8162 wpConsole.x = winWidth + 1;
\r
8163 wpConsole.y = boardY;
\r
8164 wpConsole.width = screenWidth - winWidth;
\r
8165 wpConsole.height = winHeight;
\r
8166 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8167 wp.length = sizeof(WINDOWPLACEMENT);
\r
8169 wp.showCmd = SW_SHOW;
\r
8170 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8171 wp.rcNormalPosition.left = wpConsole.x;
\r
8172 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8173 wp.rcNormalPosition.top = wpConsole.y;
\r
8174 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8175 SetWindowPlacement(hDlg, &wp);
\r
8178 // Allow hText to highlight URLs and send notifications on them
\r
8179 wMask = SendMessage(hText, EM_GETEVENTMASK, 0, 0L);
\r
8180 SendMessage(hText, EM_SETEVENTMASK, 0, wMask | ENM_LINK);
\r
8181 SendMessage(hText, EM_AUTOURLDETECT, TRUE, 0L);
\r
8195 if (IsIconic(hDlg)) break;
\r
8196 newSizeX = LOWORD(lParam);
\r
8197 newSizeY = HIWORD(lParam);
\r
8198 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8199 RECT rectText, rectInput;
\r
8201 int newTextHeight, newTextWidth;
\r
8202 GetWindowRect(hText, &rectText);
\r
8203 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8204 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8205 if (newTextHeight < 0) {
\r
8206 newSizeY += -newTextHeight;
\r
8207 newTextHeight = 0;
\r
8209 SetWindowPos(hText, NULL, 0, 0,
\r
8210 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8211 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8212 pt.x = rectInput.left;
\r
8213 pt.y = rectInput.top + newSizeY - sizeY;
\r
8214 ScreenToClient(hDlg, &pt);
\r
8215 SetWindowPos(hInput, NULL,
\r
8216 pt.x, pt.y, /* needs client coords */
\r
8217 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8218 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8224 case WM_GETMINMAXINFO:
\r
8225 /* Prevent resizing window too small */
\r
8226 mmi = (MINMAXINFO *) lParam;
\r
8227 mmi->ptMinTrackSize.x = 100;
\r
8228 mmi->ptMinTrackSize.y = 100;
\r
8231 /* [AS] Snapping */
\r
8232 case WM_ENTERSIZEMOVE:
\r
8233 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8236 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8239 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8241 case WM_EXITSIZEMOVE:
\r
8242 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8245 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8253 if (hwndConsole) return;
\r
8254 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8255 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8260 ConsoleOutput(char* data, int length, int forceVisible)
\r
8265 char buf[CO_MAX+1];
\r
8268 static int delayLF = 0;
\r
8269 CHARRANGE savesel, sel;
\r
8271 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8279 while (length--) {
\r
8287 } else if (*p == '\007') {
\r
8288 MyPlaySound(&sounds[(int)SoundBell]);
\r
8295 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8296 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8297 /* Save current selection */
\r
8298 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8299 exlen = GetWindowTextLength(hText);
\r
8300 /* Find out whether current end of text is visible */
\r
8301 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8302 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8303 /* Trim existing text if it's too long */
\r
8304 if (exlen + (q - buf) > CO_MAX) {
\r
8305 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8308 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8309 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8311 savesel.cpMin -= trim;
\r
8312 savesel.cpMax -= trim;
\r
8313 if (exlen < 0) exlen = 0;
\r
8314 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8315 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8317 /* Append the new text */
\r
8318 sel.cpMin = exlen;
\r
8319 sel.cpMax = exlen;
\r
8320 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8321 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8322 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8323 if (forceVisible || exlen == 0 ||
\r
8324 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8325 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8326 /* Scroll to make new end of text visible if old end of text
\r
8327 was visible or new text is an echo of user typein */
\r
8328 sel.cpMin = 9999999;
\r
8329 sel.cpMax = 9999999;
\r
8330 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8331 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8332 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8333 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8335 if (savesel.cpMax == exlen || forceVisible) {
\r
8336 /* Move insert point to new end of text if it was at the old
\r
8337 end of text or if the new text is an echo of user typein */
\r
8338 sel.cpMin = 9999999;
\r
8339 sel.cpMax = 9999999;
\r
8340 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8342 /* Restore previous selection */
\r
8343 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8345 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8352 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8356 COLORREF oldFg, oldBg;
\r
8360 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8362 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8363 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8364 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8367 rect.right = x + squareSize;
\r
8369 rect.bottom = y + squareSize;
\r
8372 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8373 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8374 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8375 &rect, str, strlen(str), NULL);
\r
8377 (void) SetTextColor(hdc, oldFg);
\r
8378 (void) SetBkColor(hdc, oldBg);
\r
8379 (void) SelectObject(hdc, oldFont);
\r
8383 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8384 RECT *rect, char *color, char *flagFell)
\r
8388 COLORREF oldFg, oldBg;
\r
8391 if (appData.clockMode) {
\r
8393 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8395 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8402 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8403 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8405 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8406 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8408 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8412 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8413 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8414 rect, str, strlen(str), NULL);
\r
8415 if(logoHeight > 0 && appData.clockMode) {
\r
8417 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8418 r.top = rect->top + logoHeight/2;
\r
8419 r.left = rect->left;
\r
8420 r.right = rect->right;
\r
8421 r.bottom = rect->bottom;
\r
8422 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8423 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8424 &r, str, strlen(str), NULL);
\r
8426 (void) SetTextColor(hdc, oldFg);
\r
8427 (void) SetBkColor(hdc, oldBg);
\r
8428 (void) SelectObject(hdc, oldFont);
\r
8433 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8439 if( count <= 0 ) {
\r
8440 if (appData.debugMode) {
\r
8441 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8444 return ERROR_INVALID_USER_BUFFER;
\r
8447 ResetEvent(ovl->hEvent);
\r
8448 ovl->Offset = ovl->OffsetHigh = 0;
\r
8449 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8453 err = GetLastError();
\r
8454 if (err == ERROR_IO_PENDING) {
\r
8455 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8459 err = GetLastError();
\r
8466 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8471 ResetEvent(ovl->hEvent);
\r
8472 ovl->Offset = ovl->OffsetHigh = 0;
\r
8473 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8477 err = GetLastError();
\r
8478 if (err == ERROR_IO_PENDING) {
\r
8479 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8483 err = GetLastError();
\r
8489 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8490 void CheckForInputBufferFull( InputSource * is )
\r
8492 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8493 /* Look for end of line */
\r
8494 char * p = is->buf;
\r
8496 while( p < is->next && *p != '\n' ) {
\r
8500 if( p >= is->next ) {
\r
8501 if (appData.debugMode) {
\r
8502 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8505 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8506 is->count = (DWORD) -1;
\r
8507 is->next = is->buf;
\r
8513 InputThread(LPVOID arg)
\r
8518 is = (InputSource *) arg;
\r
8519 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8520 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8521 while (is->hThread != NULL) {
\r
8522 is->error = DoReadFile(is->hFile, is->next,
\r
8523 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8524 &is->count, &ovl);
\r
8525 if (is->error == NO_ERROR) {
\r
8526 is->next += is->count;
\r
8528 if (is->error == ERROR_BROKEN_PIPE) {
\r
8529 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8532 is->count = (DWORD) -1;
\r
8533 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8538 CheckForInputBufferFull( is );
\r
8540 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8542 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8544 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8547 CloseHandle(ovl.hEvent);
\r
8548 CloseHandle(is->hFile);
\r
8550 if (appData.debugMode) {
\r
8551 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8558 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8560 NonOvlInputThread(LPVOID arg)
\r
8567 is = (InputSource *) arg;
\r
8568 while (is->hThread != NULL) {
\r
8569 is->error = ReadFile(is->hFile, is->next,
\r
8570 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8571 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8572 if (is->error == NO_ERROR) {
\r
8573 /* Change CRLF to LF */
\r
8574 if (is->next > is->buf) {
\r
8576 i = is->count + 1;
\r
8584 if (prev == '\r' && *p == '\n') {
\r
8596 if (is->error == ERROR_BROKEN_PIPE) {
\r
8597 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8600 is->count = (DWORD) -1;
\r
8604 CheckForInputBufferFull( is );
\r
8606 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8608 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8610 if (is->count < 0) break; /* Quit on error */
\r
8612 CloseHandle(is->hFile);
\r
8617 SocketInputThread(LPVOID arg)
\r
8621 is = (InputSource *) arg;
\r
8622 while (is->hThread != NULL) {
\r
8623 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8624 if ((int)is->count == SOCKET_ERROR) {
\r
8625 is->count = (DWORD) -1;
\r
8626 is->error = WSAGetLastError();
\r
8628 is->error = NO_ERROR;
\r
8629 is->next += is->count;
\r
8630 if (is->count == 0 && is->second == is) {
\r
8631 /* End of file on stderr; quit with no message */
\r
8635 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8637 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8639 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8645 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8649 is = (InputSource *) lParam;
\r
8650 if (is->lineByLine) {
\r
8651 /* Feed in lines one by one */
\r
8652 char *p = is->buf;
\r
8654 while (q < is->next) {
\r
8655 if (*q++ == '\n') {
\r
8656 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8661 /* Move any partial line to the start of the buffer */
\r
8663 while (p < is->next) {
\r
8668 if (is->error != NO_ERROR || is->count == 0) {
\r
8669 /* Notify backend of the error. Note: If there was a partial
\r
8670 line at the end, it is not flushed through. */
\r
8671 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8674 /* Feed in the whole chunk of input at once */
\r
8675 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8676 is->next = is->buf;
\r
8680 /*---------------------------------------------------------------------------*\
\r
8682 * Menu enables. Used when setting various modes.
\r
8684 \*---------------------------------------------------------------------------*/
\r
8692 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8694 while (enab->item > 0) {
\r
8695 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8700 Enables gnuEnables[] = {
\r
8701 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8702 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8703 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8704 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8705 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8706 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8707 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8708 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8709 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8710 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8714 Enables icsEnables[] = {
\r
8715 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8716 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8717 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8718 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8719 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8720 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8721 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8722 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8723 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8724 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8725 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8726 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8731 Enables zippyEnables[] = {
\r
8732 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8733 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8734 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8739 Enables ncpEnables[] = {
\r
8740 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8741 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8742 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8743 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8744 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8745 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8746 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8747 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8748 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8749 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8750 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8751 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8752 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8753 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8754 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8758 Enables trainingOnEnables[] = {
\r
8759 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8760 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8761 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8762 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8763 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8764 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8765 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8766 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8770 Enables trainingOffEnables[] = {
\r
8771 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8772 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8773 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8774 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8775 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8776 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8777 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8778 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8782 /* These modify either ncpEnables or gnuEnables */
\r
8783 Enables cmailEnables[] = {
\r
8784 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8785 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8786 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8787 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8788 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8789 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8790 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8794 Enables machineThinkingEnables[] = {
\r
8795 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8796 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8797 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8798 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8799 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8800 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8801 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8802 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8803 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8804 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8805 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8806 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8807 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8808 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8809 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8813 Enables userThinkingEnables[] = {
\r
8814 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8815 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8816 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8817 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8818 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8819 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8820 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8821 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8822 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8823 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8824 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8825 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8826 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8827 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8828 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8832 /*---------------------------------------------------------------------------*\
\r
8834 * Front-end interface functions exported by XBoard.
\r
8835 * Functions appear in same order as prototypes in frontend.h.
\r
8837 \*---------------------------------------------------------------------------*/
\r
8841 static UINT prevChecked = 0;
\r
8842 static int prevPausing = 0;
\r
8845 if (pausing != prevPausing) {
\r
8846 prevPausing = pausing;
\r
8847 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8848 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8849 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8852 switch (gameMode) {
\r
8853 case BeginningOfGame:
\r
8854 if (appData.icsActive)
\r
8855 nowChecked = IDM_IcsClient;
\r
8856 else if (appData.noChessProgram)
\r
8857 nowChecked = IDM_EditGame;
\r
8859 nowChecked = IDM_MachineBlack;
\r
8861 case MachinePlaysBlack:
\r
8862 nowChecked = IDM_MachineBlack;
\r
8864 case MachinePlaysWhite:
\r
8865 nowChecked = IDM_MachineWhite;
\r
8867 case TwoMachinesPlay:
\r
8868 nowChecked = IDM_TwoMachines;
\r
8871 nowChecked = IDM_AnalysisMode;
\r
8874 nowChecked = IDM_AnalyzeFile;
\r
8877 nowChecked = IDM_EditGame;
\r
8879 case PlayFromGameFile:
\r
8880 nowChecked = IDM_LoadGame;
\r
8882 case EditPosition:
\r
8883 nowChecked = IDM_EditPosition;
\r
8886 nowChecked = IDM_Training;
\r
8888 case IcsPlayingWhite:
\r
8889 case IcsPlayingBlack:
\r
8890 case IcsObserving:
\r
8892 nowChecked = IDM_IcsClient;
\r
8899 if (prevChecked != 0)
\r
8900 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8901 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8902 if (nowChecked != 0)
\r
8903 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8904 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8906 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8907 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8908 MF_BYCOMMAND|MF_ENABLED);
\r
8910 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8911 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8914 prevChecked = nowChecked;
\r
8916 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8917 if (appData.icsActive) {
\r
8918 if (appData.icsEngineAnalyze) {
\r
8919 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8920 MF_BYCOMMAND|MF_CHECKED);
\r
8922 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8923 MF_BYCOMMAND|MF_UNCHECKED);
\r
8931 HMENU hmenu = GetMenu(hwndMain);
\r
8932 SetMenuEnables(hmenu, icsEnables);
\r
8933 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8934 MF_BYPOSITION|MF_ENABLED);
\r
8936 if (appData.zippyPlay) {
\r
8937 SetMenuEnables(hmenu, zippyEnables);
\r
8938 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8939 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8940 MF_BYCOMMAND|MF_ENABLED);
\r
8948 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8954 HMENU hmenu = GetMenu(hwndMain);
\r
8955 SetMenuEnables(hmenu, ncpEnables);
\r
8956 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8957 MF_BYPOSITION|MF_GRAYED);
\r
8958 DrawMenuBar(hwndMain);
\r
8964 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8968 SetTrainingModeOn()
\r
8971 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8972 for (i = 0; i < N_BUTTONS; i++) {
\r
8973 if (buttonDesc[i].hwnd != NULL)
\r
8974 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8979 VOID SetTrainingModeOff()
\r
8982 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8983 for (i = 0; i < N_BUTTONS; i++) {
\r
8984 if (buttonDesc[i].hwnd != NULL)
\r
8985 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8991 SetUserThinkingEnables()
\r
8993 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8997 SetMachineThinkingEnables()
\r
8999 HMENU hMenu = GetMenu(hwndMain);
\r
9000 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9002 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9004 if (gameMode == MachinePlaysBlack) {
\r
9005 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9006 } else if (gameMode == MachinePlaysWhite) {
\r
9007 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9008 } else if (gameMode == TwoMachinesPlay) {
\r
9009 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9015 DisplayTitle(char *str)
\r
9017 char title[MSG_SIZ], *host;
\r
9018 if (str[0] != NULLCHAR) {
\r
9019 strcpy(title, str);
\r
9020 } else if (appData.icsActive) {
\r
9021 if (appData.icsCommPort[0] != NULLCHAR)
\r
9024 host = appData.icsHost;
\r
9025 sprintf(title, "%s: %s", szTitle, host);
\r
9026 } else if (appData.noChessProgram) {
\r
9027 strcpy(title, szTitle);
\r
9029 strcpy(title, szTitle);
\r
9030 strcat(title, ": ");
\r
9031 strcat(title, first.tidy);
\r
9033 SetWindowText(hwndMain, title);
\r
9038 DisplayMessage(char *str1, char *str2)
\r
9042 int remain = MESSAGE_TEXT_MAX - 1;
\r
9045 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9046 messageText[0] = NULLCHAR;
\r
9048 len = strlen(str1);
\r
9049 if (len > remain) len = remain;
\r
9050 strncpy(messageText, str1, len);
\r
9051 messageText[len] = NULLCHAR;
\r
9054 if (*str2 && remain >= 2) {
\r
9056 strcat(messageText, " ");
\r
9059 len = strlen(str2);
\r
9060 if (len > remain) len = remain;
\r
9061 strncat(messageText, str2, len);
\r
9063 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9065 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9069 hdc = GetDC(hwndMain);
\r
9070 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9071 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9072 &messageRect, messageText, strlen(messageText), NULL);
\r
9073 (void) SelectObject(hdc, oldFont);
\r
9074 (void) ReleaseDC(hwndMain, hdc);
\r
9078 DisplayError(char *str, int error)
\r
9080 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9086 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9087 NULL, error, LANG_NEUTRAL,
\r
9088 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9090 sprintf(buf, "%s:\n%s", str, buf2);
\r
9092 ErrorMap *em = errmap;
\r
9093 while (em->err != 0 && em->err != error) em++;
\r
9094 if (em->err != 0) {
\r
9095 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9097 sprintf(buf, "%s:\nError code %d", str, error);
\r
9102 ErrorPopUp("Error", buf);
\r
9107 DisplayMoveError(char *str)
\r
9109 fromX = fromY = -1;
\r
9110 ClearHighlights();
\r
9111 DrawPosition(FALSE, NULL);
\r
9112 if (appData.popupMoveErrors) {
\r
9113 ErrorPopUp("Error", str);
\r
9115 DisplayMessage(str, "");
\r
9116 moveErrorMessageUp = TRUE;
\r
9121 DisplayFatalError(char *str, int error, int exitStatus)
\r
9123 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9125 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9128 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9129 NULL, error, LANG_NEUTRAL,
\r
9130 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9132 sprintf(buf, "%s:\n%s", str, buf2);
\r
9134 ErrorMap *em = errmap;
\r
9135 while (em->err != 0 && em->err != error) em++;
\r
9136 if (em->err != 0) {
\r
9137 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9139 sprintf(buf, "%s:\nError code %d", str, error);
\r
9144 if (appData.debugMode) {
\r
9145 fprintf(debugFP, "%s: %s\n", label, str);
\r
9147 if (appData.popupExitMessage) {
\r
9148 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9149 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9151 ExitEvent(exitStatus);
\r
9156 DisplayInformation(char *str)
\r
9158 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9163 DisplayNote(char *str)
\r
9165 ErrorPopUp("Note", str);
\r
9170 char *title, *question, *replyPrefix;
\r
9175 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9177 static QuestionParams *qp;
\r
9178 char reply[MSG_SIZ];
\r
9181 switch (message) {
\r
9182 case WM_INITDIALOG:
\r
9183 qp = (QuestionParams *) lParam;
\r
9184 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9185 SetWindowText(hDlg, qp->title);
\r
9186 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9187 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9191 switch (LOWORD(wParam)) {
\r
9193 strcpy(reply, qp->replyPrefix);
\r
9194 if (*reply) strcat(reply, " ");
\r
9195 len = strlen(reply);
\r
9196 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9197 strcat(reply, "\n");
\r
9198 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9199 EndDialog(hDlg, TRUE);
\r
9200 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9203 EndDialog(hDlg, FALSE);
\r
9214 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9216 QuestionParams qp;
\r
9220 qp.question = question;
\r
9221 qp.replyPrefix = replyPrefix;
\r
9223 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9224 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9225 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9226 FreeProcInstance(lpProc);
\r
9229 /* [AS] Pick FRC position */
\r
9230 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9232 static int * lpIndexFRC;
\r
9238 case WM_INITDIALOG:
\r
9239 lpIndexFRC = (int *) lParam;
\r
9241 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9243 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9244 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9245 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9246 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9251 switch( LOWORD(wParam) ) {
\r
9253 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9254 EndDialog( hDlg, 0 );
\r
9255 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9258 EndDialog( hDlg, 1 );
\r
9260 case IDC_NFG_Edit:
\r
9261 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9262 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9264 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9267 case IDC_NFG_Random:
\r
9268 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9269 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9282 int index = appData.defaultFrcPosition;
\r
9283 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9285 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9287 if( result == 0 ) {
\r
9288 appData.defaultFrcPosition = index;
\r
9294 /* [AS] Game list options */
\r
9300 static GLT_Item GLT_ItemInfo[] = {
\r
9301 { GLT_EVENT, "Event" },
\r
9302 { GLT_SITE, "Site" },
\r
9303 { GLT_DATE, "Date" },
\r
9304 { GLT_ROUND, "Round" },
\r
9305 { GLT_PLAYERS, "Players" },
\r
9306 { GLT_RESULT, "Result" },
\r
9307 { GLT_WHITE_ELO, "White Rating" },
\r
9308 { GLT_BLACK_ELO, "Black Rating" },
\r
9309 { GLT_TIME_CONTROL,"Time Control" },
\r
9310 { GLT_VARIANT, "Variant" },
\r
9311 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9312 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9316 const char * GLT_FindItem( char id )
\r
9318 const char * result = 0;
\r
9320 GLT_Item * list = GLT_ItemInfo;
\r
9322 while( list->id != 0 ) {
\r
9323 if( list->id == id ) {
\r
9324 result = list->name;
\r
9334 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9336 const char * name = GLT_FindItem( id );
\r
9339 if( index >= 0 ) {
\r
9340 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9343 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9348 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9352 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9355 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9359 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9361 pc = GLT_ALL_TAGS;
\r
9364 if( strchr( tags, *pc ) == 0 ) {
\r
9365 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9370 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9373 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9375 char result = '\0';
\r
9378 GLT_Item * list = GLT_ItemInfo;
\r
9380 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9381 while( list->id != 0 ) {
\r
9382 if( strcmp( list->name, name ) == 0 ) {
\r
9383 result = list->id;
\r
9394 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9396 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9397 int idx2 = idx1 + delta;
\r
9398 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9400 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9403 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9404 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9405 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9406 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9410 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9412 static char glt[64];
\r
9413 static char * lpUserGLT;
\r
9417 case WM_INITDIALOG:
\r
9418 lpUserGLT = (char *) lParam;
\r
9420 strcpy( glt, lpUserGLT );
\r
9422 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9424 /* Initialize list */
\r
9425 GLT_TagsToList( hDlg, glt );
\r
9427 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9432 switch( LOWORD(wParam) ) {
\r
9435 char * pc = lpUserGLT;
\r
9437 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9441 id = GLT_ListItemToTag( hDlg, idx );
\r
9445 } while( id != '\0' );
\r
9447 EndDialog( hDlg, 0 );
\r
9450 EndDialog( hDlg, 1 );
\r
9453 case IDC_GLT_Default:
\r
9454 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9455 GLT_TagsToList( hDlg, glt );
\r
9458 case IDC_GLT_Restore:
\r
9459 strcpy( glt, lpUserGLT );
\r
9460 GLT_TagsToList( hDlg, glt );
\r
9464 GLT_MoveSelection( hDlg, -1 );
\r
9467 case IDC_GLT_Down:
\r
9468 GLT_MoveSelection( hDlg, +1 );
\r
9478 int GameListOptions()
\r
9482 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9484 strcpy( glt, appData.gameListTags );
\r
9486 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9488 if( result == 0 ) {
\r
9489 /* [AS] Memory leak here! */
\r
9490 appData.gameListTags = strdup( glt );
\r
9498 DisplayIcsInteractionTitle(char *str)
\r
9500 char consoleTitle[MSG_SIZ];
\r
9502 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9503 SetWindowText(hwndConsole, consoleTitle);
\r
9507 DrawPosition(int fullRedraw, Board board)
\r
9509 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9516 fromX = fromY = -1;
\r
9517 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9518 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9519 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9520 dragInfo.lastpos = dragInfo.pos;
\r
9521 dragInfo.start.x = dragInfo.start.y = -1;
\r
9522 dragInfo.from = dragInfo.start;
\r
9524 DrawPosition(TRUE, NULL);
\r
9530 CommentPopUp(char *title, char *str)
\r
9532 HWND hwnd = GetActiveWindow();
\r
9533 EitherCommentPopUp(0, title, str, FALSE);
\r
9535 SetActiveWindow(hwnd);
\r
9539 CommentPopDown(void)
\r
9541 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9542 if (commentDialog) {
\r
9543 ShowWindow(commentDialog, SW_HIDE);
\r
9545 commentDialogUp = FALSE;
\r
9549 EditCommentPopUp(int index, char *title, char *str)
\r
9551 EitherCommentPopUp(index, title, str, TRUE);
\r
9558 MyPlaySound(&sounds[(int)SoundMove]);
\r
9561 VOID PlayIcsWinSound()
\r
9563 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9566 VOID PlayIcsLossSound()
\r
9568 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9571 VOID PlayIcsDrawSound()
\r
9573 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9576 VOID PlayIcsUnfinishedSound()
\r
9578 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9584 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9592 consoleEcho = TRUE;
\r
9593 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9594 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9595 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9604 consoleEcho = FALSE;
\r
9605 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9606 /* This works OK: set text and background both to the same color */
\r
9608 cf.crTextColor = COLOR_ECHOOFF;
\r
9609 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9610 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9613 /* No Raw()...? */
\r
9615 void Colorize(ColorClass cc, int continuation)
\r
9617 currentColorClass = cc;
\r
9618 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9619 consoleCF.crTextColor = textAttribs[cc].color;
\r
9620 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9621 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9627 static char buf[MSG_SIZ];
\r
9628 DWORD bufsiz = MSG_SIZ;
\r
9630 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9631 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9633 if (!GetUserName(buf, &bufsiz)) {
\r
9634 /*DisplayError("Error getting user name", GetLastError());*/
\r
9635 strcpy(buf, "User");
\r
9643 static char buf[MSG_SIZ];
\r
9644 DWORD bufsiz = MSG_SIZ;
\r
9646 if (!GetComputerName(buf, &bufsiz)) {
\r
9647 /*DisplayError("Error getting host name", GetLastError());*/
\r
9648 strcpy(buf, "Unknown");
\r
9655 ClockTimerRunning()
\r
9657 return clockTimerEvent != 0;
\r
9663 if (clockTimerEvent == 0) return FALSE;
\r
9664 KillTimer(hwndMain, clockTimerEvent);
\r
9665 clockTimerEvent = 0;
\r
9670 StartClockTimer(long millisec)
\r
9672 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9673 (UINT) millisec, NULL);
\r
9677 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9680 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9682 if(appData.noGUI) return;
\r
9683 hdc = GetDC(hwndMain);
\r
9684 if (!IsIconic(hwndMain)) {
\r
9685 DisplayAClock(hdc, timeRemaining, highlight,
\r
9686 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9688 if (highlight && iconCurrent == iconBlack) {
\r
9689 iconCurrent = iconWhite;
\r
9690 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9691 if (IsIconic(hwndMain)) {
\r
9692 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9695 (void) ReleaseDC(hwndMain, hdc);
\r
9697 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9701 DisplayBlackClock(long timeRemaining, int highlight)
\r
9704 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9706 if(appData.noGUI) return;
\r
9707 hdc = GetDC(hwndMain);
\r
9708 if (!IsIconic(hwndMain)) {
\r
9709 DisplayAClock(hdc, timeRemaining, highlight,
\r
9710 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9712 if (highlight && iconCurrent == iconWhite) {
\r
9713 iconCurrent = iconBlack;
\r
9714 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9715 if (IsIconic(hwndMain)) {
\r
9716 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9719 (void) ReleaseDC(hwndMain, hdc);
\r
9721 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9726 LoadGameTimerRunning()
\r
9728 return loadGameTimerEvent != 0;
\r
9732 StopLoadGameTimer()
\r
9734 if (loadGameTimerEvent == 0) return FALSE;
\r
9735 KillTimer(hwndMain, loadGameTimerEvent);
\r
9736 loadGameTimerEvent = 0;
\r
9741 StartLoadGameTimer(long millisec)
\r
9743 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9744 (UINT) millisec, NULL);
\r
9752 char fileTitle[MSG_SIZ];
\r
9754 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9755 f = OpenFileDialog(hwndMain, "a", defName,
\r
9756 appData.oldSaveStyle ? "gam" : "pgn",
\r
9758 "Save Game to File", NULL, fileTitle, NULL);
\r
9760 SaveGame(f, 0, "");
\r
9767 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9769 if (delayedTimerEvent != 0) {
\r
9770 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9771 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9773 KillTimer(hwndMain, delayedTimerEvent);
\r
9774 delayedTimerEvent = 0;
\r
9775 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9776 delayedTimerCallback();
\r
9778 delayedTimerCallback = cb;
\r
9779 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9780 (UINT) millisec, NULL);
\r
9783 DelayedEventCallback
\r
9786 if (delayedTimerEvent) {
\r
9787 return delayedTimerCallback;
\r
9794 CancelDelayedEvent()
\r
9796 if (delayedTimerEvent) {
\r
9797 KillTimer(hwndMain, delayedTimerEvent);
\r
9798 delayedTimerEvent = 0;
\r
9802 DWORD GetWin32Priority(int nice)
\r
9803 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9805 REALTIME_PRIORITY_CLASS 0x00000100
\r
9806 HIGH_PRIORITY_CLASS 0x00000080
\r
9807 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9808 NORMAL_PRIORITY_CLASS 0x00000020
\r
9809 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9810 IDLE_PRIORITY_CLASS 0x00000040
\r
9812 if (nice < -15) return 0x00000080;
\r
9813 if (nice < 0) return 0x00008000;
\r
9814 if (nice == 0) return 0x00000020;
\r
9815 if (nice < 15) return 0x00004000;
\r
9816 return 0x00000040;
\r
9819 /* Start a child process running the given program.
\r
9820 The process's standard output can be read from "from", and its
\r
9821 standard input can be written to "to".
\r
9822 Exit with fatal error if anything goes wrong.
\r
9823 Returns an opaque pointer that can be used to destroy the process
\r
9827 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9829 #define BUFSIZE 4096
\r
9831 HANDLE hChildStdinRd, hChildStdinWr,
\r
9832 hChildStdoutRd, hChildStdoutWr;
\r
9833 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9834 SECURITY_ATTRIBUTES saAttr;
\r
9836 PROCESS_INFORMATION piProcInfo;
\r
9837 STARTUPINFO siStartInfo;
\r
9839 char buf[MSG_SIZ];
\r
9842 if (appData.debugMode) {
\r
9843 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9848 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9849 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9850 saAttr.bInheritHandle = TRUE;
\r
9851 saAttr.lpSecurityDescriptor = NULL;
\r
9854 * The steps for redirecting child's STDOUT:
\r
9855 * 1. Create anonymous pipe to be STDOUT for child.
\r
9856 * 2. Create a noninheritable duplicate of read handle,
\r
9857 * and close the inheritable read handle.
\r
9860 /* Create a pipe for the child's STDOUT. */
\r
9861 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9862 return GetLastError();
\r
9865 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9866 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9867 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9868 FALSE, /* not inherited */
\r
9869 DUPLICATE_SAME_ACCESS);
\r
9871 return GetLastError();
\r
9873 CloseHandle(hChildStdoutRd);
\r
9876 * The steps for redirecting child's STDIN:
\r
9877 * 1. Create anonymous pipe to be STDIN for child.
\r
9878 * 2. Create a noninheritable duplicate of write handle,
\r
9879 * and close the inheritable write handle.
\r
9882 /* Create a pipe for the child's STDIN. */
\r
9883 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9884 return GetLastError();
\r
9887 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9888 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9889 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9890 FALSE, /* not inherited */
\r
9891 DUPLICATE_SAME_ACCESS);
\r
9893 return GetLastError();
\r
9895 CloseHandle(hChildStdinWr);
\r
9897 /* Arrange to (1) look in dir for the child .exe file, and
\r
9898 * (2) have dir be the child's working directory. Interpret
\r
9899 * dir relative to the directory WinBoard loaded from. */
\r
9900 GetCurrentDirectory(MSG_SIZ, buf);
\r
9901 SetCurrentDirectory(installDir);
\r
9902 SetCurrentDirectory(dir);
\r
9904 /* Now create the child process. */
\r
9906 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9907 siStartInfo.lpReserved = NULL;
\r
9908 siStartInfo.lpDesktop = NULL;
\r
9909 siStartInfo.lpTitle = NULL;
\r
9910 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9911 siStartInfo.cbReserved2 = 0;
\r
9912 siStartInfo.lpReserved2 = NULL;
\r
9913 siStartInfo.hStdInput = hChildStdinRd;
\r
9914 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9915 siStartInfo.hStdError = hChildStdoutWr;
\r
9917 fSuccess = CreateProcess(NULL,
\r
9918 cmdLine, /* command line */
\r
9919 NULL, /* process security attributes */
\r
9920 NULL, /* primary thread security attrs */
\r
9921 TRUE, /* handles are inherited */
\r
9922 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9923 NULL, /* use parent's environment */
\r
9925 &siStartInfo, /* STARTUPINFO pointer */
\r
9926 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9928 err = GetLastError();
\r
9929 SetCurrentDirectory(buf); /* return to prev directory */
\r
9934 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9935 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9936 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9939 /* Close the handles we don't need in the parent */
\r
9940 CloseHandle(piProcInfo.hThread);
\r
9941 CloseHandle(hChildStdinRd);
\r
9942 CloseHandle(hChildStdoutWr);
\r
9944 /* Prepare return value */
\r
9945 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9946 cp->kind = CPReal;
\r
9947 cp->hProcess = piProcInfo.hProcess;
\r
9948 cp->pid = piProcInfo.dwProcessId;
\r
9949 cp->hFrom = hChildStdoutRdDup;
\r
9950 cp->hTo = hChildStdinWrDup;
\r
9952 *pr = (void *) cp;
\r
9954 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9955 2000 where engines sometimes don't see the initial command(s)
\r
9956 from WinBoard and hang. I don't understand how that can happen,
\r
9957 but the Sleep is harmless, so I've put it in. Others have also
\r
9958 reported what may be the same problem, so hopefully this will fix
\r
9959 it for them too. */
\r
9967 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9969 ChildProc *cp; int result;
\r
9971 cp = (ChildProc *) pr;
\r
9972 if (cp == NULL) return;
\r
9974 switch (cp->kind) {
\r
9976 /* TerminateProcess is considered harmful, so... */
\r
9977 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9978 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9979 /* The following doesn't work because the chess program
\r
9980 doesn't "have the same console" as WinBoard. Maybe
\r
9981 we could arrange for this even though neither WinBoard
\r
9982 nor the chess program uses a console for stdio? */
\r
9983 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9985 /* [AS] Special termination modes for misbehaving programs... */
\r
9986 if( signal == 9 ) {
\r
9987 result = TerminateProcess( cp->hProcess, 0 );
\r
9989 if ( appData.debugMode) {
\r
9990 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9993 else if( signal == 10 ) {
\r
9994 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9996 if( dw != WAIT_OBJECT_0 ) {
\r
9997 result = TerminateProcess( cp->hProcess, 0 );
\r
9999 if ( appData.debugMode) {
\r
10000 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10006 CloseHandle(cp->hProcess);
\r
10010 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10014 closesocket(cp->sock);
\r
10019 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10020 closesocket(cp->sock);
\r
10021 closesocket(cp->sock2);
\r
10029 InterruptChildProcess(ProcRef pr)
\r
10033 cp = (ChildProc *) pr;
\r
10034 if (cp == NULL) return;
\r
10035 switch (cp->kind) {
\r
10037 /* The following doesn't work because the chess program
\r
10038 doesn't "have the same console" as WinBoard. Maybe
\r
10039 we could arrange for this even though neither WinBoard
\r
10040 nor the chess program uses a console for stdio */
\r
10041 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10046 /* Can't interrupt */
\r
10050 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10057 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10059 char cmdLine[MSG_SIZ];
\r
10061 if (port[0] == NULLCHAR) {
\r
10062 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10064 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10066 return StartChildProcess(cmdLine, "", pr);
\r
10070 /* Code to open TCP sockets */
\r
10073 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10078 struct sockaddr_in sa, mysa;
\r
10079 struct hostent FAR *hp;
\r
10080 unsigned short uport;
\r
10081 WORD wVersionRequested;
\r
10084 /* Initialize socket DLL */
\r
10085 wVersionRequested = MAKEWORD(1, 1);
\r
10086 err = WSAStartup(wVersionRequested, &wsaData);
\r
10087 if (err != 0) return err;
\r
10089 /* Make socket */
\r
10090 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10091 err = WSAGetLastError();
\r
10096 /* Bind local address using (mostly) don't-care values.
\r
10098 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10099 mysa.sin_family = AF_INET;
\r
10100 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10101 uport = (unsigned short) 0;
\r
10102 mysa.sin_port = htons(uport);
\r
10103 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10104 == SOCKET_ERROR) {
\r
10105 err = WSAGetLastError();
\r
10110 /* Resolve remote host name */
\r
10111 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10112 if (!(hp = gethostbyname(host))) {
\r
10113 unsigned int b0, b1, b2, b3;
\r
10115 err = WSAGetLastError();
\r
10117 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10118 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10119 hp->h_addrtype = AF_INET;
\r
10120 hp->h_length = 4;
\r
10121 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10122 hp->h_addr_list[0] = (char *) malloc(4);
\r
10123 hp->h_addr_list[0][0] = (char) b0;
\r
10124 hp->h_addr_list[0][1] = (char) b1;
\r
10125 hp->h_addr_list[0][2] = (char) b2;
\r
10126 hp->h_addr_list[0][3] = (char) b3;
\r
10132 sa.sin_family = hp->h_addrtype;
\r
10133 uport = (unsigned short) atoi(port);
\r
10134 sa.sin_port = htons(uport);
\r
10135 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10137 /* Make connection */
\r
10138 if (connect(s, (struct sockaddr *) &sa,
\r
10139 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10140 err = WSAGetLastError();
\r
10145 /* Prepare return value */
\r
10146 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10147 cp->kind = CPSock;
\r
10149 *pr = (ProcRef *) cp;
\r
10155 OpenCommPort(char *name, ProcRef *pr)
\r
10160 char fullname[MSG_SIZ];
\r
10162 if (*name != '\\')
\r
10163 sprintf(fullname, "\\\\.\\%s", name);
\r
10165 strcpy(fullname, name);
\r
10167 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10168 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10169 if (h == (HANDLE) -1) {
\r
10170 return GetLastError();
\r
10174 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10176 /* Accumulate characters until a 100ms pause, then parse */
\r
10177 ct.ReadIntervalTimeout = 100;
\r
10178 ct.ReadTotalTimeoutMultiplier = 0;
\r
10179 ct.ReadTotalTimeoutConstant = 0;
\r
10180 ct.WriteTotalTimeoutMultiplier = 0;
\r
10181 ct.WriteTotalTimeoutConstant = 0;
\r
10182 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10184 /* Prepare return value */
\r
10185 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10186 cp->kind = CPComm;
\r
10189 *pr = (ProcRef *) cp;
\r
10195 OpenLoopback(ProcRef *pr)
\r
10197 DisplayFatalError("Not implemented", 0, 1);
\r
10203 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10207 SOCKET s, s2, s3;
\r
10208 struct sockaddr_in sa, mysa;
\r
10209 struct hostent FAR *hp;
\r
10210 unsigned short uport;
\r
10211 WORD wVersionRequested;
\r
10214 char stderrPortStr[MSG_SIZ];
\r
10216 /* Initialize socket DLL */
\r
10217 wVersionRequested = MAKEWORD(1, 1);
\r
10218 err = WSAStartup(wVersionRequested, &wsaData);
\r
10219 if (err != 0) return err;
\r
10221 /* Resolve remote host name */
\r
10222 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10223 if (!(hp = gethostbyname(host))) {
\r
10224 unsigned int b0, b1, b2, b3;
\r
10226 err = WSAGetLastError();
\r
10228 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10229 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10230 hp->h_addrtype = AF_INET;
\r
10231 hp->h_length = 4;
\r
10232 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10233 hp->h_addr_list[0] = (char *) malloc(4);
\r
10234 hp->h_addr_list[0][0] = (char) b0;
\r
10235 hp->h_addr_list[0][1] = (char) b1;
\r
10236 hp->h_addr_list[0][2] = (char) b2;
\r
10237 hp->h_addr_list[0][3] = (char) b3;
\r
10243 sa.sin_family = hp->h_addrtype;
\r
10244 uport = (unsigned short) 514;
\r
10245 sa.sin_port = htons(uport);
\r
10246 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10248 /* Bind local socket to unused "privileged" port address
\r
10250 s = INVALID_SOCKET;
\r
10251 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10252 mysa.sin_family = AF_INET;
\r
10253 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10254 for (fromPort = 1023;; fromPort--) {
\r
10255 if (fromPort < 0) {
\r
10257 return WSAEADDRINUSE;
\r
10259 if (s == INVALID_SOCKET) {
\r
10260 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10261 err = WSAGetLastError();
\r
10266 uport = (unsigned short) fromPort;
\r
10267 mysa.sin_port = htons(uport);
\r
10268 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10269 == SOCKET_ERROR) {
\r
10270 err = WSAGetLastError();
\r
10271 if (err == WSAEADDRINUSE) continue;
\r
10275 if (connect(s, (struct sockaddr *) &sa,
\r
10276 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10277 err = WSAGetLastError();
\r
10278 if (err == WSAEADDRINUSE) {
\r
10289 /* Bind stderr local socket to unused "privileged" port address
\r
10291 s2 = INVALID_SOCKET;
\r
10292 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10293 mysa.sin_family = AF_INET;
\r
10294 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10295 for (fromPort = 1023;; fromPort--) {
\r
10296 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10297 if (fromPort < 0) {
\r
10298 (void) closesocket(s);
\r
10300 return WSAEADDRINUSE;
\r
10302 if (s2 == INVALID_SOCKET) {
\r
10303 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10304 err = WSAGetLastError();
\r
10310 uport = (unsigned short) fromPort;
\r
10311 mysa.sin_port = htons(uport);
\r
10312 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10313 == SOCKET_ERROR) {
\r
10314 err = WSAGetLastError();
\r
10315 if (err == WSAEADDRINUSE) continue;
\r
10316 (void) closesocket(s);
\r
10320 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10321 err = WSAGetLastError();
\r
10322 if (err == WSAEADDRINUSE) {
\r
10324 s2 = INVALID_SOCKET;
\r
10327 (void) closesocket(s);
\r
10328 (void) closesocket(s2);
\r
10334 prevStderrPort = fromPort; // remember port used
\r
10335 sprintf(stderrPortStr, "%d", fromPort);
\r
10337 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10338 err = WSAGetLastError();
\r
10339 (void) closesocket(s);
\r
10340 (void) closesocket(s2);
\r
10345 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10346 err = WSAGetLastError();
\r
10347 (void) closesocket(s);
\r
10348 (void) closesocket(s2);
\r
10352 if (*user == NULLCHAR) user = UserName();
\r
10353 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10354 err = WSAGetLastError();
\r
10355 (void) closesocket(s);
\r
10356 (void) closesocket(s2);
\r
10360 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10361 err = WSAGetLastError();
\r
10362 (void) closesocket(s);
\r
10363 (void) closesocket(s2);
\r
10368 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10369 err = WSAGetLastError();
\r
10370 (void) closesocket(s);
\r
10371 (void) closesocket(s2);
\r
10375 (void) closesocket(s2); /* Stop listening */
\r
10377 /* Prepare return value */
\r
10378 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10379 cp->kind = CPRcmd;
\r
10382 *pr = (ProcRef *) cp;
\r
10389 AddInputSource(ProcRef pr, int lineByLine,
\r
10390 InputCallback func, VOIDSTAR closure)
\r
10392 InputSource *is, *is2 = NULL;
\r
10393 ChildProc *cp = (ChildProc *) pr;
\r
10395 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10396 is->lineByLine = lineByLine;
\r
10398 is->closure = closure;
\r
10399 is->second = NULL;
\r
10400 is->next = is->buf;
\r
10401 if (pr == NoProc) {
\r
10402 is->kind = CPReal;
\r
10403 consoleInputSource = is;
\r
10405 is->kind = cp->kind;
\r
10407 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10408 we create all threads suspended so that the is->hThread variable can be
\r
10409 safely assigned, then let the threads start with ResumeThread.
\r
10411 switch (cp->kind) {
\r
10413 is->hFile = cp->hFrom;
\r
10414 cp->hFrom = NULL; /* now owned by InputThread */
\r
10416 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10417 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10421 is->hFile = cp->hFrom;
\r
10422 cp->hFrom = NULL; /* now owned by InputThread */
\r
10424 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10425 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10429 is->sock = cp->sock;
\r
10431 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10432 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10436 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10438 is->sock = cp->sock;
\r
10439 is->second = is2;
\r
10440 is2->sock = cp->sock2;
\r
10441 is2->second = is2;
\r
10443 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10444 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10446 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10447 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10451 if( is->hThread != NULL ) {
\r
10452 ResumeThread( is->hThread );
\r
10455 if( is2 != NULL && is2->hThread != NULL ) {
\r
10456 ResumeThread( is2->hThread );
\r
10460 return (InputSourceRef) is;
\r
10464 RemoveInputSource(InputSourceRef isr)
\r
10468 is = (InputSource *) isr;
\r
10469 is->hThread = NULL; /* tell thread to stop */
\r
10470 CloseHandle(is->hThread);
\r
10471 if (is->second != NULL) {
\r
10472 is->second->hThread = NULL;
\r
10473 CloseHandle(is->second->hThread);
\r
10479 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10482 int outCount = SOCKET_ERROR;
\r
10483 ChildProc *cp = (ChildProc *) pr;
\r
10484 static OVERLAPPED ovl;
\r
10486 if (pr == NoProc) {
\r
10487 ConsoleOutput(message, count, FALSE);
\r
10491 if (ovl.hEvent == NULL) {
\r
10492 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10494 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10496 switch (cp->kind) {
\r
10499 outCount = send(cp->sock, message, count, 0);
\r
10500 if (outCount == SOCKET_ERROR) {
\r
10501 *outError = WSAGetLastError();
\r
10503 *outError = NO_ERROR;
\r
10508 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10509 &dOutCount, NULL)) {
\r
10510 *outError = NO_ERROR;
\r
10511 outCount = (int) dOutCount;
\r
10513 *outError = GetLastError();
\r
10518 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10519 &dOutCount, &ovl);
\r
10520 if (*outError == NO_ERROR) {
\r
10521 outCount = (int) dOutCount;
\r
10529 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10532 /* Ignore delay, not implemented for WinBoard */
\r
10533 return OutputToProcess(pr, message, count, outError);
\r
10538 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10539 char *buf, int count, int error)
\r
10541 DisplayFatalError("Not implemented", 0, 1);
\r
10544 /* see wgamelist.c for Game List functions */
\r
10545 /* see wedittags.c for Edit Tags functions */
\r
10552 char buf[MSG_SIZ];
\r
10555 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10556 f = fopen(buf, "r");
\r
10558 ProcessICSInitScript(f);
\r
10566 StartAnalysisClock()
\r
10568 if (analysisTimerEvent) return;
\r
10569 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10570 (UINT) 2000, NULL);
\r
10574 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10576 static HANDLE hwndText;
\r
10578 static int sizeX, sizeY;
\r
10579 int newSizeX, newSizeY, flags;
\r
10582 switch (message) {
\r
10583 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10584 /* Initialize the dialog items */
\r
10585 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10586 SetWindowText(hDlg, analysisTitle);
\r
10587 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10588 /* Size and position the dialog */
\r
10589 if (!analysisDialog) {
\r
10590 analysisDialog = hDlg;
\r
10591 flags = SWP_NOZORDER;
\r
10592 GetClientRect(hDlg, &rect);
\r
10593 sizeX = rect.right;
\r
10594 sizeY = rect.bottom;
\r
10595 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10596 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10597 WINDOWPLACEMENT wp;
\r
10598 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10599 wp.length = sizeof(WINDOWPLACEMENT);
\r
10601 wp.showCmd = SW_SHOW;
\r
10602 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10603 wp.rcNormalPosition.left = analysisX;
\r
10604 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10605 wp.rcNormalPosition.top = analysisY;
\r
10606 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10607 SetWindowPlacement(hDlg, &wp);
\r
10609 GetClientRect(hDlg, &rect);
\r
10610 newSizeX = rect.right;
\r
10611 newSizeY = rect.bottom;
\r
10612 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10613 newSizeX, newSizeY);
\r
10614 sizeX = newSizeX;
\r
10615 sizeY = newSizeY;
\r
10620 case WM_COMMAND: /* message: received a command */
\r
10621 switch (LOWORD(wParam)) {
\r
10623 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10624 ExitAnalyzeMode();
\r
10636 newSizeX = LOWORD(lParam);
\r
10637 newSizeY = HIWORD(lParam);
\r
10638 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10639 sizeX = newSizeX;
\r
10640 sizeY = newSizeY;
\r
10643 case WM_GETMINMAXINFO:
\r
10644 /* Prevent resizing window too small */
\r
10645 mmi = (MINMAXINFO *) lParam;
\r
10646 mmi->ptMinTrackSize.x = 100;
\r
10647 mmi->ptMinTrackSize.y = 100;
\r
10654 AnalysisPopUp(char* title, char* str)
\r
10660 EngineOutputPopUp();
\r
10663 if (str == NULL) str = "";
\r
10664 p = (char *) malloc(2 * strlen(str) + 2);
\r
10667 if (*str == '\n') *q++ = '\r';
\r
10671 if (analysisText != NULL) free(analysisText);
\r
10672 analysisText = p;
\r
10674 if (analysisDialog) {
\r
10675 SetWindowText(analysisDialog, title);
\r
10676 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10677 ShowWindow(analysisDialog, SW_SHOW);
\r
10679 analysisTitle = title;
\r
10680 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10681 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10682 hwndMain, (DLGPROC)lpProc);
\r
10683 FreeProcInstance(lpProc);
\r
10685 analysisDialogUp = TRUE;
\r
10689 AnalysisPopDown()
\r
10691 if (analysisDialog) {
\r
10692 ShowWindow(analysisDialog, SW_HIDE);
\r
10694 analysisDialogUp = FALSE;
\r
10699 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10701 highlightInfo.sq[0].x = fromX;
\r
10702 highlightInfo.sq[0].y = fromY;
\r
10703 highlightInfo.sq[1].x = toX;
\r
10704 highlightInfo.sq[1].y = toY;
\r
10708 ClearHighlights()
\r
10710 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10711 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10715 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10717 premoveHighlightInfo.sq[0].x = fromX;
\r
10718 premoveHighlightInfo.sq[0].y = fromY;
\r
10719 premoveHighlightInfo.sq[1].x = toX;
\r
10720 premoveHighlightInfo.sq[1].y = toY;
\r
10724 ClearPremoveHighlights()
\r
10726 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10727 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10731 ShutDownFrontEnd()
\r
10733 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10734 DeleteClipboardTempFiles();
\r
10740 if (IsIconic(hwndMain))
\r
10741 ShowWindow(hwndMain, SW_RESTORE);
\r
10743 SetActiveWindow(hwndMain);
\r
10747 * Prototypes for animation support routines
\r
10749 static void ScreenSquare(int column, int row, POINT * pt);
\r
10750 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10751 POINT frames[], int * nFrames);
\r
10755 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10756 { // [HGM] atomic: animate blast wave
\r
10758 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10759 explodeInfo.fromX = fromX;
\r
10760 explodeInfo.fromY = fromY;
\r
10761 explodeInfo.toX = toX;
\r
10762 explodeInfo.toY = toY;
\r
10763 for(i=1; i<nFrames; i++) {
\r
10764 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10765 DrawPosition(FALSE, NULL);
\r
10766 Sleep(appData.animSpeed);
\r
10768 explodeInfo.radius = 0;
\r
10769 DrawPosition(TRUE, NULL);
\r
10772 #define kFactor 4
\r
10775 AnimateMove(board, fromX, fromY, toX, toY)
\r
10782 ChessSquare piece;
\r
10783 POINT start, finish, mid;
\r
10784 POINT frames[kFactor * 2 + 1];
\r
10787 if (!appData.animate) return;
\r
10788 if (doingSizing) return;
\r
10789 if (fromY < 0 || fromX < 0) return;
\r
10790 piece = board[fromY][fromX];
\r
10791 if (piece >= EmptySquare) return;
\r
10793 ScreenSquare(fromX, fromY, &start);
\r
10794 ScreenSquare(toX, toY, &finish);
\r
10796 /* All pieces except knights move in straight line */
\r
10797 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10798 mid.x = start.x + (finish.x - start.x) / 2;
\r
10799 mid.y = start.y + (finish.y - start.y) / 2;
\r
10801 /* Knight: make diagonal movement then straight */
\r
10802 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10803 mid.x = start.x + (finish.x - start.x) / 2;
\r
10804 mid.y = finish.y;
\r
10806 mid.x = finish.x;
\r
10807 mid.y = start.y + (finish.y - start.y) / 2;
\r
10811 /* Don't use as many frames for very short moves */
\r
10812 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10813 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10815 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10817 animInfo.from.x = fromX;
\r
10818 animInfo.from.y = fromY;
\r
10819 animInfo.to.x = toX;
\r
10820 animInfo.to.y = toY;
\r
10821 animInfo.lastpos = start;
\r
10822 animInfo.piece = piece;
\r
10823 for (n = 0; n < nFrames; n++) {
\r
10824 animInfo.pos = frames[n];
\r
10825 DrawPosition(FALSE, NULL);
\r
10826 animInfo.lastpos = animInfo.pos;
\r
10827 Sleep(appData.animSpeed);
\r
10829 animInfo.pos = finish;
\r
10830 DrawPosition(FALSE, NULL);
\r
10831 animInfo.piece = EmptySquare;
\r
10832 if(gameInfo.variant == VariantAtomic &&
\r
10833 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10834 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10837 /* Convert board position to corner of screen rect and color */
\r
10840 ScreenSquare(column, row, pt)
\r
10841 int column; int row; POINT * pt;
\r
10844 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10845 pt->y = lineGap + row * (squareSize + lineGap);
\r
10847 pt->x = lineGap + column * (squareSize + lineGap);
\r
10848 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10852 /* Generate a series of frame coords from start->mid->finish.
\r
10853 The movement rate doubles until the half way point is
\r
10854 reached, then halves back down to the final destination,
\r
10855 which gives a nice slow in/out effect. The algorithmn
\r
10856 may seem to generate too many intermediates for short
\r
10857 moves, but remember that the purpose is to attract the
\r
10858 viewers attention to the piece about to be moved and
\r
10859 then to where it ends up. Too few frames would be less
\r
10863 Tween(start, mid, finish, factor, frames, nFrames)
\r
10864 POINT * start; POINT * mid;
\r
10865 POINT * finish; int factor;
\r
10866 POINT frames[]; int * nFrames;
\r
10868 int n, fraction = 1, count = 0;
\r
10870 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10871 for (n = 0; n < factor; n++)
\r
10873 for (n = 0; n < factor; n++) {
\r
10874 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10875 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10877 fraction = fraction / 2;
\r
10881 frames[count] = *mid;
\r
10884 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10886 for (n = 0; n < factor; n++) {
\r
10887 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10888 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10890 fraction = fraction * 2;
\r
10892 *nFrames = count;
\r
10896 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10898 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10900 EvalGraphSet( first, last, current, pvInfoList );
\r
10903 void SetProgramStats( FrontEndProgramStats * stats )
\r
10905 EngineOutputUpdate( stats );
\r