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
1109 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1110 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1112 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1113 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1114 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1115 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1116 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1117 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1118 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1119 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1120 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1121 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1122 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1123 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1124 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1125 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1126 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1127 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1128 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1129 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1130 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1131 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1132 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1133 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1134 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1135 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1136 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1137 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1138 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1139 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1140 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1141 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1142 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1143 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1144 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1145 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1146 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1147 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1148 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1149 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1150 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1151 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1152 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1153 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1154 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1155 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1156 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1157 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1158 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1159 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1160 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1161 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1162 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1163 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1164 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1165 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1166 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1167 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1168 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1169 { "highlightLastMove", ArgBoolean,
\r
1170 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1171 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1172 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1173 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1174 { "highlightDragging", ArgBoolean,
\r
1175 (LPVOID) &appData.highlightDragging, TRUE },
\r
1176 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1177 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1178 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1179 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1180 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1181 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1182 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1183 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1184 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1185 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1186 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1187 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1188 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1189 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1190 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1191 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1192 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1193 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1194 { "soundShout", ArgFilename,
\r
1195 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1196 { "soundSShout", ArgFilename,
\r
1197 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1198 { "soundChannel1", ArgFilename,
\r
1199 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1200 { "soundChannel", ArgFilename,
\r
1201 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1202 { "soundKibitz", ArgFilename,
\r
1203 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1204 { "soundTell", ArgFilename,
\r
1205 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1206 { "soundChallenge", ArgFilename,
\r
1207 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1208 { "soundRequest", ArgFilename,
\r
1209 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1210 { "soundSeek", ArgFilename,
\r
1211 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1212 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1213 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1214 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1215 { "soundIcsLoss", ArgFilename,
\r
1216 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1217 { "soundIcsDraw", ArgFilename,
\r
1218 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1219 { "soundIcsUnfinished", ArgFilename,
\r
1220 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1221 { "soundIcsAlarm", ArgFilename,
\r
1222 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1223 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1224 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1225 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1226 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1227 { "reuseChessPrograms", ArgBoolean,
\r
1228 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1229 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1230 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1231 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1232 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1233 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1234 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1235 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1236 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1237 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1238 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1239 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1240 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1241 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1242 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1243 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1245 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1247 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1248 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1249 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1250 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1251 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1252 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1253 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1254 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1255 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1256 /* [AS] New features */
\r
1257 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1258 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1259 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1260 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1261 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1262 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1263 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1264 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1265 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1266 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1267 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1268 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1269 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1270 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1271 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1272 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1273 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1274 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1275 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1276 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1277 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1278 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1279 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1280 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1281 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1282 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1283 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1284 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1285 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1286 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1287 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1288 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1289 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1290 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1291 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1292 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1293 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1294 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1295 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1296 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1297 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1298 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1299 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1300 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1301 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1302 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1303 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1304 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1305 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1306 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1308 /* [HGM] board-size, adjudication and misc. options */
\r
1309 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1310 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1311 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1312 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1313 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1314 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1315 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1316 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1317 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1318 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1319 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1320 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1321 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1322 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1323 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1324 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1325 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1326 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1327 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1328 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1329 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1330 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1331 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1332 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1333 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1334 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1335 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1336 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1337 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1338 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1339 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1340 { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },
\r
1341 { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },
\r
1342 { "forceIllegalMoves", ArgTrue, (LPVOID) &appData.forceIllegal, FALSE },
\r
1345 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1346 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1347 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1348 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1349 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1350 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1351 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1352 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1353 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1354 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1355 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1356 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1357 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1359 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1360 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1361 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1362 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1363 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1364 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1365 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1367 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1368 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1369 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1370 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1371 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1372 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1373 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1374 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1375 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1376 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1377 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1378 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1379 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1380 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1381 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1382 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1383 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1384 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1385 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1387 /* [HGM] options for broadcasting and time odds */
\r
1388 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1389 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1390 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1391 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1392 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1393 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1394 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1395 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1396 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1397 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1398 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1400 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1401 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1402 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1403 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1404 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1405 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1406 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1407 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1408 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1409 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1410 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1411 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1412 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1413 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1414 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1415 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1416 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1417 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1418 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1419 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1420 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1421 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1422 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1423 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1424 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1425 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1426 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1427 /* [AS] Layout stuff */
\r
1428 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1429 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1430 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1431 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1432 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1434 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1435 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1436 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1437 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1438 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1440 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1441 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1442 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1443 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1444 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1446 { NULL, ArgNone, NULL, FALSE }
\r
1450 /* Kludge for indirection files on command line */
\r
1451 char* lastIndirectionFilename;
\r
1452 ArgDescriptor argDescriptorIndirection =
\r
1453 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1457 ExitArgError(char *msg, char *badArg)
\r
1459 char buf[MSG_SIZ];
\r
1461 sprintf(buf, "%s %s", msg, badArg);
\r
1462 DisplayFatalError(buf, 0, 2);
\r
1466 /* Command line font name parser. NULL name means do nothing.
\r
1467 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1468 For backward compatibility, syntax without the colon is also
\r
1469 accepted, but font names with digits in them won't work in that case.
\r
1472 ParseFontName(char *name, MyFontParams *mfp)
\r
1475 if (name == NULL) return;
\r
1477 q = strchr(p, ':');
\r
1479 if (q - p >= sizeof(mfp->faceName))
\r
1480 ExitArgError("Font name too long:", name);
\r
1481 memcpy(mfp->faceName, p, q - p);
\r
1482 mfp->faceName[q - p] = NULLCHAR;
\r
1485 q = mfp->faceName;
\r
1486 while (*p && !isdigit(*p)) {
\r
1488 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1489 ExitArgError("Font name too long:", name);
\r
1491 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1494 if (!*p) ExitArgError("Font point size missing:", name);
\r
1495 mfp->pointSize = (float) atof(p);
\r
1496 mfp->bold = (strchr(p, 'b') != NULL);
\r
1497 mfp->italic = (strchr(p, 'i') != NULL);
\r
1498 mfp->underline = (strchr(p, 'u') != NULL);
\r
1499 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1502 /* Color name parser.
\r
1503 X version accepts X color names, but this one
\r
1504 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1506 ParseColorName(char *name)
\r
1508 int red, green, blue, count;
\r
1509 char buf[MSG_SIZ];
\r
1511 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1513 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1514 &red, &green, &blue);
\r
1517 sprintf(buf, "Can't parse color name %s", name);
\r
1518 DisplayError(buf, 0);
\r
1519 return RGB(0, 0, 0);
\r
1521 return PALETTERGB(red, green, blue);
\r
1525 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1527 char *e = argValue;
\r
1531 if (*e == 'b') eff |= CFE_BOLD;
\r
1532 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1533 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1534 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1535 else if (*e == '#' || isdigit(*e)) break;
\r
1539 *color = ParseColorName(e);
\r
1544 ParseBoardSize(char *name)
\r
1546 BoardSize bs = SizeTiny;
\r
1547 while (sizeInfo[bs].name != NULL) {
\r
1548 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1551 ExitArgError("Unrecognized board size value", name);
\r
1552 return bs; /* not reached */
\r
1557 StringGet(void *getClosure)
\r
1559 char **p = (char **) getClosure;
\r
1564 FileGet(void *getClosure)
\r
1567 FILE* f = (FILE*) getClosure;
\r
1570 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1577 /* Parse settings file named "name". If file found, return the
\r
1578 full name in fullname and return TRUE; else return FALSE */
\r
1580 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1584 int ok; char buf[MSG_SIZ];
\r
1586 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1587 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1588 sprintf(buf, "%s.ini", name);
\r
1589 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1592 f = fopen(fullname, "r");
\r
1594 ParseArgs(FileGet, f);
\r
1603 ParseArgs(GetFunc get, void *cl)
\r
1605 char argName[ARG_MAX];
\r
1606 char argValue[ARG_MAX];
\r
1607 ArgDescriptor *ad;
\r
1616 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1617 if (ch == NULLCHAR) break;
\r
1619 /* Comment to end of line */
\r
1621 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1623 } else if (ch == '/' || ch == '-') {
\r
1626 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1627 ch != '\n' && ch != '\t') {
\r
1633 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1634 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1636 if (ad->argName == NULL)
\r
1637 ExitArgError("Unrecognized argument", argName);
\r
1639 } else if (ch == '@') {
\r
1640 /* Indirection file */
\r
1641 ad = &argDescriptorIndirection;
\r
1644 /* Positional argument */
\r
1645 ad = &argDescriptors[posarg++];
\r
1646 strcpy(argName, ad->argName);
\r
1649 if (ad->argType == ArgTrue) {
\r
1650 *(Boolean *) ad->argLoc = TRUE;
\r
1653 if (ad->argType == ArgFalse) {
\r
1654 *(Boolean *) ad->argLoc = FALSE;
\r
1658 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1659 if (ch == NULLCHAR || ch == '\n') {
\r
1660 ExitArgError("No value provided for argument", argName);
\r
1664 // Quoting with { }. No characters have to (or can) be escaped.
\r
1665 // Thus the string cannot contain a '}' character.
\r
1685 } else if (ch == '\'' || ch == '"') {
\r
1686 // Quoting with ' ' or " ", with \ as escape character.
\r
1687 // Inconvenient for long strings that may contain Windows filenames.
\r
1704 if (ch == start) {
\r
1713 if (ad->argType == ArgFilename
\r
1714 || ad->argType == ArgSettingsFilename) {
\r
1720 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1744 for (i = 0; i < 3; i++) {
\r
1745 if (ch >= '0' && ch <= '7') {
\r
1746 octval = octval*8 + (ch - '0');
\r
1753 *q++ = (char) octval;
\r
1764 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1771 switch (ad->argType) {
\r
1773 *(int *) ad->argLoc = atoi(argValue);
\r
1777 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1781 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1785 *(int *) ad->argLoc = atoi(argValue);
\r
1786 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1790 *(float *) ad->argLoc = (float) atof(argValue);
\r
1795 *(char **) ad->argLoc = strdup(argValue);
\r
1798 case ArgSettingsFilename:
\r
1800 char fullname[MSG_SIZ];
\r
1801 if (ParseSettingsFile(argValue, fullname)) {
\r
1802 if (ad->argLoc != NULL) {
\r
1803 *(char **) ad->argLoc = strdup(fullname);
\r
1806 if (ad->argLoc != NULL) {
\r
1808 ExitArgError("Failed to open indirection file", argValue);
\r
1815 switch (argValue[0]) {
\r
1818 *(Boolean *) ad->argLoc = TRUE;
\r
1822 *(Boolean *) ad->argLoc = FALSE;
\r
1825 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1831 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1834 case ArgAttribs: {
\r
1835 ColorClass cc = (ColorClass)ad->argLoc;
\r
1836 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1840 case ArgBoardSize:
\r
1841 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1845 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1848 case ArgCommSettings:
\r
1849 ParseCommSettings(argValue, &dcb);
\r
1853 ExitArgError("Unrecognized argument", argValue);
\r
1862 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1864 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1865 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1868 lf->lfEscapement = 0;
\r
1869 lf->lfOrientation = 0;
\r
1870 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1871 lf->lfItalic = mfp->italic;
\r
1872 lf->lfUnderline = mfp->underline;
\r
1873 lf->lfStrikeOut = mfp->strikeout;
\r
1874 lf->lfCharSet = DEFAULT_CHARSET;
\r
1875 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1876 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1877 lf->lfQuality = DEFAULT_QUALITY;
\r
1878 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1879 strcpy(lf->lfFaceName, mfp->faceName);
\r
1883 CreateFontInMF(MyFont *mf)
\r
1885 LFfromMFP(&mf->lf, &mf->mfp);
\r
1886 if (mf->hf) DeleteObject(mf->hf);
\r
1887 mf->hf = CreateFontIndirect(&mf->lf);
\r
1891 SetDefaultTextAttribs()
\r
1894 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1895 ParseAttribs(&textAttribs[cc].color,
\r
1896 &textAttribs[cc].effects,
\r
1897 defaultTextAttribs[cc]);
\r
1902 SetDefaultSounds()
\r
1906 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1907 textAttribs[cc].sound.name = strdup("");
\r
1908 textAttribs[cc].sound.data = NULL;
\r
1910 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1911 sounds[sc].name = strdup("");
\r
1912 sounds[sc].data = NULL;
\r
1914 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1922 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1923 MyLoadSound(&textAttribs[cc].sound);
\r
1925 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1926 MyLoadSound(&sounds[sc]);
\r
1931 InitAppData(LPSTR lpCmdLine)
\r
1934 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1937 programName = szAppName;
\r
1939 /* Initialize to defaults */
\r
1940 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1941 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1942 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1943 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1944 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1945 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1946 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1947 SetDefaultTextAttribs();
\r
1948 SetDefaultSounds();
\r
1949 appData.movesPerSession = MOVES_PER_SESSION;
\r
1950 appData.initString = INIT_STRING;
\r
1951 appData.secondInitString = INIT_STRING;
\r
1952 appData.firstComputerString = COMPUTER_STRING;
\r
1953 appData.secondComputerString = COMPUTER_STRING;
\r
1954 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1955 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1956 appData.firstPlaysBlack = FALSE;
\r
1957 appData.noChessProgram = FALSE;
\r
1958 chessProgram = FALSE;
\r
1959 appData.firstHost = FIRST_HOST;
\r
1960 appData.secondHost = SECOND_HOST;
\r
1961 appData.firstDirectory = FIRST_DIRECTORY;
\r
1962 appData.secondDirectory = SECOND_DIRECTORY;
\r
1963 appData.bitmapDirectory = "";
\r
1964 appData.remoteShell = REMOTE_SHELL;
\r
1965 appData.remoteUser = "";
\r
1966 appData.timeDelay = TIME_DELAY;
\r
1967 appData.timeControl = TIME_CONTROL;
\r
1968 appData.timeIncrement = TIME_INCREMENT;
\r
1969 appData.icsActive = FALSE;
\r
1970 appData.icsHost = "";
\r
1971 appData.icsPort = ICS_PORT;
\r
1972 appData.icsCommPort = ICS_COMM_PORT;
\r
1973 appData.icsLogon = ICS_LOGON;
\r
1974 appData.icsHelper = "";
\r
1975 appData.useTelnet = FALSE;
\r
1976 appData.telnetProgram = TELNET_PROGRAM;
\r
1977 appData.gateway = "";
\r
1978 appData.loadGameFile = "";
\r
1979 appData.loadGameIndex = 0;
\r
1980 appData.saveGameFile = "";
\r
1981 appData.autoSaveGames = FALSE;
\r
1982 appData.loadPositionFile = "";
\r
1983 appData.loadPositionIndex = 1;
\r
1984 appData.savePositionFile = "";
\r
1985 appData.matchMode = FALSE;
\r
1986 appData.matchGames = 0;
\r
1987 appData.monoMode = FALSE;
\r
1988 appData.debugMode = FALSE;
\r
1989 appData.clockMode = TRUE;
\r
1990 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1991 appData.Iconic = FALSE; /*unused*/
\r
1992 appData.searchTime = "";
\r
1993 appData.searchDepth = 0;
\r
1994 appData.showCoords = FALSE;
\r
1995 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1996 appData.autoCallFlag = FALSE;
\r
1997 appData.flipView = FALSE;
\r
1998 appData.autoFlipView = TRUE;
\r
1999 appData.cmailGameName = "";
\r
2000 appData.alwaysPromoteToQueen = FALSE;
\r
2001 appData.oldSaveStyle = FALSE;
\r
2002 appData.quietPlay = FALSE;
\r
2003 appData.showThinking = FALSE;
\r
2004 appData.ponderNextMove = TRUE;
\r
2005 appData.periodicUpdates = TRUE;
\r
2006 appData.popupExitMessage = TRUE;
\r
2007 appData.popupMoveErrors = FALSE;
\r
2008 appData.autoObserve = FALSE;
\r
2009 appData.autoComment = FALSE;
\r
2010 appData.animate = TRUE;
\r
2011 appData.animSpeed = 10;
\r
2012 appData.animateDragging = TRUE;
\r
2013 appData.highlightLastMove = TRUE;
\r
2014 appData.getMoveList = TRUE;
\r
2015 appData.testLegality = TRUE;
\r
2016 appData.premove = TRUE;
\r
2017 appData.premoveWhite = FALSE;
\r
2018 appData.premoveWhiteText = "";
\r
2019 appData.premoveBlack = FALSE;
\r
2020 appData.premoveBlackText = "";
\r
2021 appData.icsAlarm = TRUE;
\r
2022 appData.icsAlarmTime = 5000;
\r
2023 appData.autoRaiseBoard = TRUE;
\r
2024 appData.localLineEditing = TRUE;
\r
2025 appData.colorize = TRUE;
\r
2026 appData.reuseFirst = TRUE;
\r
2027 appData.reuseSecond = TRUE;
\r
2028 appData.blindfold = FALSE;
\r
2029 appData.icsEngineAnalyze = FALSE;
\r
2030 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2031 dcb.DCBlength = sizeof(DCB);
\r
2032 dcb.BaudRate = 9600;
\r
2033 dcb.fBinary = TRUE;
\r
2034 dcb.fParity = FALSE;
\r
2035 dcb.fOutxCtsFlow = FALSE;
\r
2036 dcb.fOutxDsrFlow = FALSE;
\r
2037 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2038 dcb.fDsrSensitivity = FALSE;
\r
2039 dcb.fTXContinueOnXoff = TRUE;
\r
2040 dcb.fOutX = FALSE;
\r
2042 dcb.fNull = FALSE;
\r
2043 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2044 dcb.fAbortOnError = FALSE;
\r
2046 dcb.Parity = SPACEPARITY;
\r
2047 dcb.StopBits = ONESTOPBIT;
\r
2048 settingsFileName = SETTINGS_FILE;
\r
2049 saveSettingsOnExit = TRUE;
\r
2050 boardX = CW_USEDEFAULT;
\r
2051 boardY = CW_USEDEFAULT;
\r
2052 analysisX = CW_USEDEFAULT;
\r
2053 analysisY = CW_USEDEFAULT;
\r
2054 analysisW = CW_USEDEFAULT;
\r
2055 analysisH = CW_USEDEFAULT;
\r
2056 commentX = CW_USEDEFAULT;
\r
2057 commentY = CW_USEDEFAULT;
\r
2058 commentW = CW_USEDEFAULT;
\r
2059 commentH = CW_USEDEFAULT;
\r
2060 editTagsX = CW_USEDEFAULT;
\r
2061 editTagsY = CW_USEDEFAULT;
\r
2062 editTagsW = CW_USEDEFAULT;
\r
2063 editTagsH = CW_USEDEFAULT;
\r
2064 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2065 icsNames = ICS_NAMES;
\r
2066 firstChessProgramNames = FCP_NAMES;
\r
2067 secondChessProgramNames = SCP_NAMES;
\r
2068 appData.initialMode = "";
\r
2069 appData.variant = "normal";
\r
2070 appData.firstProtocolVersion = PROTOVER;
\r
2071 appData.secondProtocolVersion = PROTOVER;
\r
2072 appData.showButtonBar = TRUE;
\r
2074 /* [AS] New properties (see comments in header file) */
\r
2075 appData.firstScoreIsAbsolute = FALSE;
\r
2076 appData.secondScoreIsAbsolute = FALSE;
\r
2077 appData.saveExtendedInfoInPGN = FALSE;
\r
2078 appData.hideThinkingFromHuman = FALSE;
\r
2079 appData.liteBackTextureFile = "";
\r
2080 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2081 appData.darkBackTextureFile = "";
\r
2082 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2083 appData.renderPiecesWithFont = "";
\r
2084 appData.fontToPieceTable = "";
\r
2085 appData.fontBackColorWhite = 0;
\r
2086 appData.fontForeColorWhite = 0;
\r
2087 appData.fontBackColorBlack = 0;
\r
2088 appData.fontForeColorBlack = 0;
\r
2089 appData.fontPieceSize = 80;
\r
2090 appData.overrideLineGap = 1;
\r
2091 appData.adjudicateLossThreshold = 0;
\r
2092 appData.delayBeforeQuit = 0;
\r
2093 appData.delayAfterQuit = 0;
\r
2094 appData.nameOfDebugFile = "winboard.debug";
\r
2095 appData.pgnEventHeader = "Computer Chess Game";
\r
2096 appData.defaultFrcPosition = -1;
\r
2097 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2098 appData.saveOutOfBookInfo = TRUE;
\r
2099 appData.showEvalInMoveHistory = TRUE;
\r
2100 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2101 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2102 appData.highlightMoveWithArrow = FALSE;
\r
2103 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2104 appData.useStickyWindows = TRUE;
\r
2105 appData.adjudicateDrawMoves = 0;
\r
2106 appData.autoDisplayComment = TRUE;
\r
2107 appData.autoDisplayTags = TRUE;
\r
2108 appData.firstIsUCI = FALSE;
\r
2109 appData.secondIsUCI = FALSE;
\r
2110 appData.firstHasOwnBookUCI = TRUE;
\r
2111 appData.secondHasOwnBookUCI = TRUE;
\r
2112 appData.polyglotDir = "";
\r
2113 appData.usePolyglotBook = FALSE;
\r
2114 appData.polyglotBook = "";
\r
2115 appData.defaultHashSize = 64;
\r
2116 appData.defaultCacheSizeEGTB = 4;
\r
2117 appData.defaultPathEGTB = "c:\\egtb";
\r
2118 appData.firstOptions = "";
\r
2119 appData.secondOptions = "";
\r
2121 InitWindowPlacement( &wpGameList );
\r
2122 InitWindowPlacement( &wpMoveHistory );
\r
2123 InitWindowPlacement( &wpEvalGraph );
\r
2124 InitWindowPlacement( &wpEngineOutput );
\r
2125 InitWindowPlacement( &wpConsole );
\r
2127 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2128 appData.NrFiles = -1;
\r
2129 appData.NrRanks = -1;
\r
2130 appData.holdingsSize = -1;
\r
2131 appData.testClaims = FALSE;
\r
2132 appData.checkMates = FALSE;
\r
2133 appData.materialDraws= FALSE;
\r
2134 appData.trivialDraws = FALSE;
\r
2135 appData.ruleMoves = 51;
\r
2136 appData.drawRepeats = 6;
\r
2137 appData.matchPause = 10000;
\r
2138 appData.alphaRank = FALSE;
\r
2139 appData.allWhite = FALSE;
\r
2140 appData.upsideDown = FALSE;
\r
2141 appData.serverPause = 15;
\r
2142 appData.serverMovesName = NULL;
\r
2143 appData.suppressLoadMoves = FALSE;
\r
2144 appData.firstTimeOdds = 1;
\r
2145 appData.secondTimeOdds = 1;
\r
2146 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2147 appData.secondAccumulateTC = 1;
\r
2148 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2149 appData.secondNPS = -1;
\r
2150 appData.engineComments = 1;
\r
2151 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2152 appData.egtFormats = "";
\r
2155 appData.zippyTalk = ZIPPY_TALK;
\r
2156 appData.zippyPlay = ZIPPY_PLAY;
\r
2157 appData.zippyLines = ZIPPY_LINES;
\r
2158 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2159 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2160 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2161 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2162 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2163 appData.zippyUseI = ZIPPY_USE_I;
\r
2164 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2165 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2166 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2167 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2168 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2169 appData.zippyAbort = ZIPPY_ABORT;
\r
2170 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2171 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2172 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2175 /* Point font array elements to structures and
\r
2176 parse default font names */
\r
2177 for (i=0; i<NUM_FONTS; i++) {
\r
2178 for (j=0; j<NUM_SIZES; j++) {
\r
2179 font[j][i] = &fontRec[j][i];
\r
2180 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2184 /* Parse default settings file if any */
\r
2185 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2186 settingsFileName = strdup(buf);
\r
2189 /* Parse command line */
\r
2190 ParseArgs(StringGet, &lpCmdLine);
\r
2192 /* [HGM] make sure board size is acceptable */
\r
2193 if(appData.NrFiles > BOARD_SIZE ||
\r
2194 appData.NrRanks > BOARD_SIZE )
\r
2195 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2197 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2198 * with options from the command line, we now make an even higher priority
\r
2199 * overrule by WB options attached to the engine command line. This so that
\r
2200 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2203 if(appData.firstChessProgram != NULL) {
\r
2204 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2205 static char *f = "first";
\r
2206 char buf[MSG_SIZ], *q = buf;
\r
2207 if(p != NULL) { // engine command line contains WinBoard options
\r
2208 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2209 ParseArgs(StringGet, &q);
\r
2210 p[-1] = 0; // cut them offengine command line
\r
2213 // now do same for second chess program
\r
2214 if(appData.secondChessProgram != NULL) {
\r
2215 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2216 static char *s = "second";
\r
2217 char buf[MSG_SIZ], *q = buf;
\r
2218 if(p != NULL) { // engine command line contains WinBoard options
\r
2219 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2220 ParseArgs(StringGet, &q);
\r
2221 p[-1] = 0; // cut them offengine command line
\r
2226 /* Propagate options that affect others */
\r
2227 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2228 if (appData.icsActive || appData.noChessProgram) {
\r
2229 chessProgram = FALSE; /* not local chess program mode */
\r
2232 /* Open startup dialog if needed */
\r
2233 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2234 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2235 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2236 *appData.secondChessProgram == NULLCHAR))) {
\r
2239 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2240 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2241 FreeProcInstance(lpProc);
\r
2244 /* Make sure save files land in the right (?) directory */
\r
2245 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2246 appData.saveGameFile = strdup(buf);
\r
2248 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2249 appData.savePositionFile = strdup(buf);
\r
2252 /* Finish initialization for fonts and sounds */
\r
2253 for (i=0; i<NUM_FONTS; i++) {
\r
2254 for (j=0; j<NUM_SIZES; j++) {
\r
2255 CreateFontInMF(font[j][i]);
\r
2258 /* xboard, and older WinBoards, controlled the move sound with the
\r
2259 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2260 always turn the option on (so that the backend will call us),
\r
2261 then let the user turn the sound off by setting it to silence if
\r
2262 desired. To accommodate old winboard.ini files saved by old
\r
2263 versions of WinBoard, we also turn off the sound if the option
\r
2264 was initially set to false. */
\r
2265 if (!appData.ringBellAfterMoves) {
\r
2266 sounds[(int)SoundMove].name = strdup("");
\r
2267 appData.ringBellAfterMoves = TRUE;
\r
2269 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2270 SetCurrentDirectory(installDir);
\r
2272 SetCurrentDirectory(currDir);
\r
2274 p = icsTextMenuString;
\r
2275 if (p[0] == '@') {
\r
2276 FILE* f = fopen(p + 1, "r");
\r
2278 DisplayFatalError(p + 1, errno, 2);
\r
2281 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2283 buf[i] = NULLCHAR;
\r
2286 ParseIcsTextMenu(strdup(p));
\r
2293 HMENU hmenu = GetMenu(hwndMain);
\r
2295 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2296 MF_BYCOMMAND|((appData.icsActive &&
\r
2297 *appData.icsCommPort != NULLCHAR) ?
\r
2298 MF_ENABLED : MF_GRAYED));
\r
2299 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2300 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2301 MF_CHECKED : MF_UNCHECKED));
\r
2306 SaveSettings(char* name)
\r
2309 ArgDescriptor *ad;
\r
2310 WINDOWPLACEMENT wp;
\r
2311 char dir[MSG_SIZ];
\r
2313 if (!hwndMain) return;
\r
2315 GetCurrentDirectory(MSG_SIZ, dir);
\r
2316 SetCurrentDirectory(installDir);
\r
2317 f = fopen(name, "w");
\r
2318 SetCurrentDirectory(dir);
\r
2320 DisplayError(name, errno);
\r
2323 fprintf(f, ";\n");
\r
2324 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2325 fprintf(f, ";\n");
\r
2326 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2327 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2328 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2329 fprintf(f, ";\n");
\r
2331 wp.length = sizeof(WINDOWPLACEMENT);
\r
2332 GetWindowPlacement(hwndMain, &wp);
\r
2333 boardX = wp.rcNormalPosition.left;
\r
2334 boardY = wp.rcNormalPosition.top;
\r
2336 if (hwndConsole) {
\r
2337 GetWindowPlacement(hwndConsole, &wp);
\r
2338 wpConsole.x = wp.rcNormalPosition.left;
\r
2339 wpConsole.y = wp.rcNormalPosition.top;
\r
2340 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2341 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2344 if (analysisDialog) {
\r
2345 GetWindowPlacement(analysisDialog, &wp);
\r
2346 analysisX = wp.rcNormalPosition.left;
\r
2347 analysisY = wp.rcNormalPosition.top;
\r
2348 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2349 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2352 if (commentDialog) {
\r
2353 GetWindowPlacement(commentDialog, &wp);
\r
2354 commentX = wp.rcNormalPosition.left;
\r
2355 commentY = wp.rcNormalPosition.top;
\r
2356 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2357 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2360 if (editTagsDialog) {
\r
2361 GetWindowPlacement(editTagsDialog, &wp);
\r
2362 editTagsX = wp.rcNormalPosition.left;
\r
2363 editTagsY = wp.rcNormalPosition.top;
\r
2364 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2365 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2368 if (gameListDialog) {
\r
2369 GetWindowPlacement(gameListDialog, &wp);
\r
2370 wpGameList.x = wp.rcNormalPosition.left;
\r
2371 wpGameList.y = wp.rcNormalPosition.top;
\r
2372 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2373 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2376 /* [AS] Move history */
\r
2377 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2379 if( moveHistoryDialog ) {
\r
2380 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2381 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2382 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2383 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2384 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2387 /* [AS] Eval graph */
\r
2388 wpEvalGraph.visible = EvalGraphIsUp();
\r
2390 if( evalGraphDialog ) {
\r
2391 GetWindowPlacement(evalGraphDialog, &wp);
\r
2392 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2393 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2394 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2395 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2398 /* [AS] Engine output */
\r
2399 wpEngineOutput.visible = EngineOutputIsUp();
\r
2401 if( engineOutputDialog ) {
\r
2402 GetWindowPlacement(engineOutputDialog, &wp);
\r
2403 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2404 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2405 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2406 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2409 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2410 if (!ad->save) continue;
\r
2411 switch (ad->argType) {
\r
2414 char *p = *(char **)ad->argLoc;
\r
2415 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2416 /* Quote multiline values or \-containing values
\r
2417 with { } if possible */
\r
2418 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2420 /* Else quote with " " */
\r
2421 fprintf(f, "/%s=\"", ad->argName);
\r
2423 if (*p == '\n') fprintf(f, "\n");
\r
2424 else if (*p == '\r') fprintf(f, "\\r");
\r
2425 else if (*p == '\t') fprintf(f, "\\t");
\r
2426 else if (*p == '\b') fprintf(f, "\\b");
\r
2427 else if (*p == '\f') fprintf(f, "\\f");
\r
2428 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2429 else if (*p == '\"') fprintf(f, "\\\"");
\r
2430 else if (*p == '\\') fprintf(f, "\\\\");
\r
2434 fprintf(f, "\"\n");
\r
2440 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2443 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2446 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2449 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2452 fprintf(f, "/%s=%s\n", ad->argName,
\r
2453 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2456 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2459 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2463 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2464 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2465 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2470 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2471 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2472 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2473 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2474 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2475 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2476 (ta->effects) ? " " : "",
\r
2477 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2481 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2482 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2484 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2487 case ArgBoardSize:
\r
2488 fprintf(f, "/%s=%s\n", ad->argName,
\r
2489 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2494 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2495 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2496 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2497 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2498 ad->argName, mfp->faceName, mfp->pointSize,
\r
2499 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2500 mfp->bold ? "b" : "",
\r
2501 mfp->italic ? "i" : "",
\r
2502 mfp->underline ? "u" : "",
\r
2503 mfp->strikeout ? "s" : "");
\r
2507 case ArgCommSettings:
\r
2508 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2510 case ArgSettingsFilename: ;
\r
2518 /*---------------------------------------------------------------------------*\
\r
2520 * GDI board drawing routines
\r
2522 \*---------------------------------------------------------------------------*/
\r
2524 /* [AS] Draw square using background texture */
\r
2525 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2530 return; /* Should never happen! */
\r
2533 SetGraphicsMode( dst, GM_ADVANCED );
\r
2540 /* X reflection */
\r
2545 x.eDx = (FLOAT) dw + dx - 1;
\r
2548 SetWorldTransform( dst, &x );
\r
2551 /* Y reflection */
\r
2557 x.eDy = (FLOAT) dh + dy - 1;
\r
2559 SetWorldTransform( dst, &x );
\r
2567 x.eDx = (FLOAT) dx;
\r
2568 x.eDy = (FLOAT) dy;
\r
2571 SetWorldTransform( dst, &x );
\r
2575 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2583 SetWorldTransform( dst, &x );
\r
2585 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2588 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2590 PM_WP = (int) WhitePawn,
\r
2591 PM_WN = (int) WhiteKnight,
\r
2592 PM_WB = (int) WhiteBishop,
\r
2593 PM_WR = (int) WhiteRook,
\r
2594 PM_WQ = (int) WhiteQueen,
\r
2595 PM_WF = (int) WhiteFerz,
\r
2596 PM_WW = (int) WhiteWazir,
\r
2597 PM_WE = (int) WhiteAlfil,
\r
2598 PM_WM = (int) WhiteMan,
\r
2599 PM_WO = (int) WhiteCannon,
\r
2600 PM_WU = (int) WhiteUnicorn,
\r
2601 PM_WH = (int) WhiteNightrider,
\r
2602 PM_WA = (int) WhiteAngel,
\r
2603 PM_WC = (int) WhiteMarshall,
\r
2604 PM_WAB = (int) WhiteCardinal,
\r
2605 PM_WD = (int) WhiteDragon,
\r
2606 PM_WL = (int) WhiteLance,
\r
2607 PM_WS = (int) WhiteCobra,
\r
2608 PM_WV = (int) WhiteFalcon,
\r
2609 PM_WSG = (int) WhiteSilver,
\r
2610 PM_WG = (int) WhiteGrasshopper,
\r
2611 PM_WK = (int) WhiteKing,
\r
2612 PM_BP = (int) BlackPawn,
\r
2613 PM_BN = (int) BlackKnight,
\r
2614 PM_BB = (int) BlackBishop,
\r
2615 PM_BR = (int) BlackRook,
\r
2616 PM_BQ = (int) BlackQueen,
\r
2617 PM_BF = (int) BlackFerz,
\r
2618 PM_BW = (int) BlackWazir,
\r
2619 PM_BE = (int) BlackAlfil,
\r
2620 PM_BM = (int) BlackMan,
\r
2621 PM_BO = (int) BlackCannon,
\r
2622 PM_BU = (int) BlackUnicorn,
\r
2623 PM_BH = (int) BlackNightrider,
\r
2624 PM_BA = (int) BlackAngel,
\r
2625 PM_BC = (int) BlackMarshall,
\r
2626 PM_BG = (int) BlackGrasshopper,
\r
2627 PM_BAB = (int) BlackCardinal,
\r
2628 PM_BD = (int) BlackDragon,
\r
2629 PM_BL = (int) BlackLance,
\r
2630 PM_BS = (int) BlackCobra,
\r
2631 PM_BV = (int) BlackFalcon,
\r
2632 PM_BSG = (int) BlackSilver,
\r
2633 PM_BK = (int) BlackKing
\r
2636 static HFONT hPieceFont = NULL;
\r
2637 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2638 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2639 static int fontBitmapSquareSize = 0;
\r
2640 static char pieceToFontChar[(int) EmptySquare] =
\r
2641 { 'p', 'n', 'b', 'r', 'q',
\r
2642 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2643 'k', 'o', 'm', 'v', 't', 'w',
\r
2644 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2647 extern BOOL SetCharTable( char *table, const char * map );
\r
2648 /* [HGM] moved to backend.c */
\r
2650 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2653 BYTE r1 = GetRValue( color );
\r
2654 BYTE g1 = GetGValue( color );
\r
2655 BYTE b1 = GetBValue( color );
\r
2661 /* Create a uniform background first */
\r
2662 hbrush = CreateSolidBrush( color );
\r
2663 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2664 FillRect( hdc, &rc, hbrush );
\r
2665 DeleteObject( hbrush );
\r
2668 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2669 int steps = squareSize / 2;
\r
2672 for( i=0; i<steps; i++ ) {
\r
2673 BYTE r = r1 - (r1-r2) * i / steps;
\r
2674 BYTE g = g1 - (g1-g2) * i / steps;
\r
2675 BYTE b = b1 - (b1-b2) * i / steps;
\r
2677 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2678 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2679 FillRect( hdc, &rc, hbrush );
\r
2680 DeleteObject(hbrush);
\r
2683 else if( mode == 2 ) {
\r
2684 /* Diagonal gradient, good more or less for every piece */
\r
2685 POINT triangle[3];
\r
2686 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2687 HBRUSH hbrush_old;
\r
2688 int steps = squareSize;
\r
2691 triangle[0].x = squareSize - steps;
\r
2692 triangle[0].y = squareSize;
\r
2693 triangle[1].x = squareSize;
\r
2694 triangle[1].y = squareSize;
\r
2695 triangle[2].x = squareSize;
\r
2696 triangle[2].y = squareSize - steps;
\r
2698 for( i=0; i<steps; i++ ) {
\r
2699 BYTE r = r1 - (r1-r2) * i / steps;
\r
2700 BYTE g = g1 - (g1-g2) * i / steps;
\r
2701 BYTE b = b1 - (b1-b2) * i / steps;
\r
2703 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2704 hbrush_old = SelectObject( hdc, hbrush );
\r
2705 Polygon( hdc, triangle, 3 );
\r
2706 SelectObject( hdc, hbrush_old );
\r
2707 DeleteObject(hbrush);
\r
2712 SelectObject( hdc, hpen );
\r
2717 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2718 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2719 piece: follow the steps as explained below.
\r
2721 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2725 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2729 int backColor = whitePieceColor;
\r
2730 int foreColor = blackPieceColor;
\r
2732 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2733 backColor = appData.fontBackColorWhite;
\r
2734 foreColor = appData.fontForeColorWhite;
\r
2736 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2737 backColor = appData.fontBackColorBlack;
\r
2738 foreColor = appData.fontForeColorBlack;
\r
2742 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2744 hbm_old = SelectObject( hdc, hbm );
\r
2748 rc.right = squareSize;
\r
2749 rc.bottom = squareSize;
\r
2751 /* Step 1: background is now black */
\r
2752 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2754 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2756 pt.x = (squareSize - sz.cx) / 2;
\r
2757 pt.y = (squareSize - sz.cy) / 2;
\r
2759 SetBkMode( hdc, TRANSPARENT );
\r
2760 SetTextColor( hdc, chroma );
\r
2761 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2762 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2764 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2765 /* Step 3: the area outside the piece is filled with white */
\r
2766 // FloodFill( hdc, 0, 0, chroma );
\r
2767 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2768 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2769 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2770 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2771 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2773 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2774 but if the start point is not inside the piece we're lost!
\r
2775 There should be a better way to do this... if we could create a region or path
\r
2776 from the fill operation we would be fine for example.
\r
2778 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2779 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2781 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2782 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2783 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2785 SelectObject( dc2, bm2 );
\r
2786 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2787 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2788 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2789 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2790 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2793 DeleteObject( bm2 );
\r
2796 SetTextColor( hdc, 0 );
\r
2798 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2799 draw the piece again in black for safety.
\r
2801 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2803 SelectObject( hdc, hbm_old );
\r
2805 if( hPieceMask[index] != NULL ) {
\r
2806 DeleteObject( hPieceMask[index] );
\r
2809 hPieceMask[index] = hbm;
\r
2812 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2814 SelectObject( hdc, hbm );
\r
2817 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2818 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2819 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2821 SelectObject( dc1, hPieceMask[index] );
\r
2822 SelectObject( dc2, bm2 );
\r
2823 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2824 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2827 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2828 the piece background and deletes (makes transparent) the rest.
\r
2829 Thanks to that mask, we are free to paint the background with the greates
\r
2830 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2831 We use this, to make gradients and give the pieces a "roundish" look.
\r
2833 SetPieceBackground( hdc, backColor, 2 );
\r
2834 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2838 DeleteObject( bm2 );
\r
2841 SetTextColor( hdc, foreColor );
\r
2842 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2844 SelectObject( hdc, hbm_old );
\r
2846 if( hPieceFace[index] != NULL ) {
\r
2847 DeleteObject( hPieceFace[index] );
\r
2850 hPieceFace[index] = hbm;
\r
2853 static int TranslatePieceToFontPiece( int piece )
\r
2883 case BlackMarshall:
\r
2887 case BlackNightrider:
\r
2893 case BlackUnicorn:
\r
2897 case BlackGrasshopper:
\r
2909 case BlackCardinal:
\r
2916 case WhiteMarshall:
\r
2920 case WhiteNightrider:
\r
2926 case WhiteUnicorn:
\r
2930 case WhiteGrasshopper:
\r
2942 case WhiteCardinal:
\r
2951 void CreatePiecesFromFont()
\r
2954 HDC hdc_window = NULL;
\r
2960 if( fontBitmapSquareSize < 0 ) {
\r
2961 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2965 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2966 fontBitmapSquareSize = -1;
\r
2970 if( fontBitmapSquareSize != squareSize ) {
\r
2971 hdc_window = GetDC( hwndMain );
\r
2972 hdc = CreateCompatibleDC( hdc_window );
\r
2974 if( hPieceFont != NULL ) {
\r
2975 DeleteObject( hPieceFont );
\r
2978 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2979 hPieceMask[i] = NULL;
\r
2980 hPieceFace[i] = NULL;
\r
2986 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2987 fontHeight = appData.fontPieceSize;
\r
2990 fontHeight = (fontHeight * squareSize) / 100;
\r
2992 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2994 lf.lfEscapement = 0;
\r
2995 lf.lfOrientation = 0;
\r
2996 lf.lfWeight = FW_NORMAL;
\r
2998 lf.lfUnderline = 0;
\r
2999 lf.lfStrikeOut = 0;
\r
3000 lf.lfCharSet = DEFAULT_CHARSET;
\r
3001 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
3002 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
3003 lf.lfQuality = PROOF_QUALITY;
\r
3004 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
3005 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3006 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3008 hPieceFont = CreateFontIndirect( &lf );
\r
3010 if( hPieceFont == NULL ) {
\r
3011 fontBitmapSquareSize = -2;
\r
3014 /* Setup font-to-piece character table */
\r
3015 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3016 /* No (or wrong) global settings, try to detect the font */
\r
3017 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3019 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3021 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3022 /* DiagramTT* family */
\r
3023 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3025 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3026 /* Fairy symbols */
\r
3027 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3029 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3030 /* Good Companion (Some characters get warped as literal :-( */
\r
3031 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3032 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3033 SetCharTable(pieceToFontChar, s);
\r
3036 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3037 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3041 /* Create bitmaps */
\r
3042 hfont_old = SelectObject( hdc, hPieceFont );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3048 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3050 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3051 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3055 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3063 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3064 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3065 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3066 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3067 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3068 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3069 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3070 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3071 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3072 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3073 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3074 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3075 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3076 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3077 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3078 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3079 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3080 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3081 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3082 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3083 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3084 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3085 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3086 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3087 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3088 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3090 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3091 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3092 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3094 SelectObject( hdc, hfont_old );
\r
3096 fontBitmapSquareSize = squareSize;
\r
3100 if( hdc != NULL ) {
\r
3104 if( hdc_window != NULL ) {
\r
3105 ReleaseDC( hwndMain, hdc_window );
\r
3110 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3114 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3115 if (gameInfo.event &&
\r
3116 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3117 strcmp(name, "k80s") == 0) {
\r
3118 strcpy(name, "tim");
\r
3120 return LoadBitmap(hinst, name);
\r
3124 /* Insert a color into the program's logical palette
\r
3125 structure. This code assumes the given color is
\r
3126 the result of the RGB or PALETTERGB macro, and it
\r
3127 knows how those macros work (which is documented).
\r
3130 InsertInPalette(COLORREF color)
\r
3132 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3134 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3135 DisplayFatalError("Too many colors", 0, 1);
\r
3136 pLogPal->palNumEntries--;
\r
3140 pe->peFlags = (char) 0;
\r
3141 pe->peRed = (char) (0xFF & color);
\r
3142 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3143 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3149 InitDrawingColors()
\r
3151 if (pLogPal == NULL) {
\r
3152 /* Allocate enough memory for a logical palette with
\r
3153 * PALETTESIZE entries and set the size and version fields
\r
3154 * of the logical palette structure.
\r
3156 pLogPal = (NPLOGPALETTE)
\r
3157 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3158 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3159 pLogPal->palVersion = 0x300;
\r
3161 pLogPal->palNumEntries = 0;
\r
3163 InsertInPalette(lightSquareColor);
\r
3164 InsertInPalette(darkSquareColor);
\r
3165 InsertInPalette(whitePieceColor);
\r
3166 InsertInPalette(blackPieceColor);
\r
3167 InsertInPalette(highlightSquareColor);
\r
3168 InsertInPalette(premoveHighlightColor);
\r
3170 /* create a logical color palette according the information
\r
3171 * in the LOGPALETTE structure.
\r
3173 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3175 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3176 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3177 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3178 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3179 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3180 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3181 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3182 /* [AS] Force rendering of the font-based pieces */
\r
3183 if( fontBitmapSquareSize > 0 ) {
\r
3184 fontBitmapSquareSize = 0;
\r
3190 BoardWidth(int boardSize, int n)
\r
3191 { /* [HGM] argument n added to allow different width and height */
\r
3192 int lineGap = sizeInfo[boardSize].lineGap;
\r
3194 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3195 lineGap = appData.overrideLineGap;
\r
3198 return (n + 1) * lineGap +
\r
3199 n * sizeInfo[boardSize].squareSize;
\r
3202 /* Respond to board resize by dragging edge */
\r
3204 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3206 BoardSize newSize = NUM_SIZES - 1;
\r
3207 static int recurse = 0;
\r
3208 if (IsIconic(hwndMain)) return;
\r
3209 if (recurse > 0) return;
\r
3211 while (newSize > 0) {
\r
3212 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3213 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3214 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3217 boardSize = newSize;
\r
3218 InitDrawingSizes(boardSize, flags);
\r
3225 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3227 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3228 ChessSquare piece;
\r
3229 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3231 SIZE clockSize, messageSize;
\r
3233 char buf[MSG_SIZ];
\r
3235 HMENU hmenu = GetMenu(hwndMain);
\r
3236 RECT crect, wrect, oldRect;
\r
3238 LOGBRUSH logbrush;
\r
3240 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3241 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3243 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3244 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3246 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3247 oldRect.top = boardY;
\r
3248 oldRect.right = boardX + winWidth;
\r
3249 oldRect.bottom = boardY + winHeight;
\r
3251 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3252 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3253 squareSize = sizeInfo[boardSize].squareSize;
\r
3254 lineGap = sizeInfo[boardSize].lineGap;
\r
3255 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3257 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3258 lineGap = appData.overrideLineGap;
\r
3261 if (tinyLayout != oldTinyLayout) {
\r
3262 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3264 style &= ~WS_SYSMENU;
\r
3265 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3266 "&Minimize\tCtrl+F4");
\r
3268 style |= WS_SYSMENU;
\r
3269 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3271 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3273 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3274 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3275 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3277 DrawMenuBar(hwndMain);
\r
3280 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3281 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3283 /* Get text area sizes */
\r
3284 hdc = GetDC(hwndMain);
\r
3285 if (appData.clockMode) {
\r
3286 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3288 sprintf(buf, "White");
\r
3290 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3291 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3292 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3293 str = "We only care about the height here";
\r
3294 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3295 SelectObject(hdc, oldFont);
\r
3296 ReleaseDC(hwndMain, hdc);
\r
3298 /* Compute where everything goes */
\r
3299 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3300 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3301 logoHeight = 2*clockSize.cy;
\r
3302 leftLogoRect.left = OUTER_MARGIN;
\r
3303 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3304 leftLogoRect.top = OUTER_MARGIN;
\r
3305 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3307 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3308 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3309 rightLogoRect.top = OUTER_MARGIN;
\r
3310 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3313 whiteRect.left = leftLogoRect.right;
\r
3314 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3315 whiteRect.top = OUTER_MARGIN;
\r
3316 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3318 blackRect.right = rightLogoRect.left;
\r
3319 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3320 blackRect.top = whiteRect.top;
\r
3321 blackRect.bottom = whiteRect.bottom;
\r
3323 whiteRect.left = OUTER_MARGIN;
\r
3324 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3325 whiteRect.top = OUTER_MARGIN;
\r
3326 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3328 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3329 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3330 blackRect.top = whiteRect.top;
\r
3331 blackRect.bottom = whiteRect.bottom;
\r
3334 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3335 if (appData.showButtonBar) {
\r
3336 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3337 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3339 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3341 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3342 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3344 boardRect.left = OUTER_MARGIN;
\r
3345 boardRect.right = boardRect.left + boardWidth;
\r
3346 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3347 boardRect.bottom = boardRect.top + boardHeight;
\r
3349 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3350 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3351 oldBoardSize = boardSize;
\r
3352 oldTinyLayout = tinyLayout;
\r
3353 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3354 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3355 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3356 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3357 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3358 winHeight = winH; // without disturbing window attachments
\r
3359 GetWindowRect(hwndMain, &wrect);
\r
3360 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3361 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3363 // [HGM] placement: let attached windows follow size change.
\r
3364 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3365 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3366 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3367 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3368 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3370 /* compensate if menu bar wrapped */
\r
3371 GetClientRect(hwndMain, &crect);
\r
3372 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3373 winHeight += offby;
\r
3375 case WMSZ_TOPLEFT:
\r
3376 SetWindowPos(hwndMain, NULL,
\r
3377 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3378 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3381 case WMSZ_TOPRIGHT:
\r
3383 SetWindowPos(hwndMain, NULL,
\r
3384 wrect.left, wrect.bottom - winHeight,
\r
3385 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3388 case WMSZ_BOTTOMLEFT:
\r
3390 SetWindowPos(hwndMain, NULL,
\r
3391 wrect.right - winWidth, wrect.top,
\r
3392 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3395 case WMSZ_BOTTOMRIGHT:
\r
3399 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3400 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3405 for (i = 0; i < N_BUTTONS; i++) {
\r
3406 if (buttonDesc[i].hwnd != NULL) {
\r
3407 DestroyWindow(buttonDesc[i].hwnd);
\r
3408 buttonDesc[i].hwnd = NULL;
\r
3410 if (appData.showButtonBar) {
\r
3411 buttonDesc[i].hwnd =
\r
3412 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3413 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3414 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3415 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3416 (HMENU) buttonDesc[i].id,
\r
3417 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3419 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3420 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3421 MAKELPARAM(FALSE, 0));
\r
3423 if (buttonDesc[i].id == IDM_Pause)
\r
3424 hwndPause = buttonDesc[i].hwnd;
\r
3425 buttonDesc[i].wndproc = (WNDPROC)
\r
3426 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3429 if (gridPen != NULL) DeleteObject(gridPen);
\r
3430 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3431 if (premovePen != NULL) DeleteObject(premovePen);
\r
3432 if (lineGap != 0) {
\r
3433 logbrush.lbStyle = BS_SOLID;
\r
3434 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3436 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3437 lineGap, &logbrush, 0, NULL);
\r
3438 logbrush.lbColor = highlightSquareColor;
\r
3440 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3441 lineGap, &logbrush, 0, NULL);
\r
3443 logbrush.lbColor = premoveHighlightColor;
\r
3445 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3446 lineGap, &logbrush, 0, NULL);
\r
3448 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3449 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3450 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3451 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3452 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3453 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3454 BOARD_WIDTH * (squareSize + lineGap);
\r
3455 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3457 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3458 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3459 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3460 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3461 lineGap / 2 + (i * (squareSize + lineGap));
\r
3462 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3463 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3464 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3468 /* [HGM] Licensing requirement */
\r
3470 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3473 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3475 GothicPopUp( "", VariantNormal);
\r
3478 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3480 /* Load piece bitmaps for this board size */
\r
3481 for (i=0; i<=2; i++) {
\r
3482 for (piece = WhitePawn;
\r
3483 (int) piece < (int) BlackPawn;
\r
3484 piece = (ChessSquare) ((int) piece + 1)) {
\r
3485 if (pieceBitmap[i][piece] != NULL)
\r
3486 DeleteObject(pieceBitmap[i][piece]);
\r
3490 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3491 // Orthodox Chess pieces
\r
3492 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3493 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3494 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3495 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3496 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3497 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3498 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3499 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3500 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3501 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3502 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3503 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3504 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3505 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3506 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3507 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3508 // in Shogi, Hijack the unused Queen for Lance
\r
3509 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3510 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3511 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3513 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3514 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3515 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3518 if(squareSize <= 72 && squareSize >= 33) {
\r
3519 /* A & C are available in most sizes now */
\r
3520 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3521 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3522 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3523 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3524 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3525 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3526 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3527 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3528 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3529 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3530 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3531 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3532 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3533 } else { // Smirf-like
\r
3534 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3535 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3536 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3538 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3539 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3540 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3541 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3542 } else { // WinBoard standard
\r
3543 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3544 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3545 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3550 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3551 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3552 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3553 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3554 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3555 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3556 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3557 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3558 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3559 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3560 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3561 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3562 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3563 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3564 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3565 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3566 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3567 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3568 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3569 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3570 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3571 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3572 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3573 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3574 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3575 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3576 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3577 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3578 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3579 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3580 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3582 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3583 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3584 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3585 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3586 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3587 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3588 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3589 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3590 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3591 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3592 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3593 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3594 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3596 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3597 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3598 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3599 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3600 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3601 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3602 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3603 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3604 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3605 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3606 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3607 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3610 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3611 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3612 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3613 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3614 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3615 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3616 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3617 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3618 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3619 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3620 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3621 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3622 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3623 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3624 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3628 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3629 /* special Shogi support in this size */
\r
3630 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3631 for (piece = WhitePawn;
\r
3632 (int) piece < (int) BlackPawn;
\r
3633 piece = (ChessSquare) ((int) piece + 1)) {
\r
3634 if (pieceBitmap[i][piece] != NULL)
\r
3635 DeleteObject(pieceBitmap[i][piece]);
\r
3638 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3639 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3640 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3641 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3642 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3643 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3644 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3645 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3646 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3647 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3648 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3649 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3650 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3651 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3652 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3653 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3654 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3655 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3656 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3657 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3658 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3659 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3660 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3661 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3662 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3663 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3664 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3665 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3666 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3667 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3668 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3669 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3670 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3671 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3672 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3673 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3674 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3675 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3676 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3677 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3678 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3679 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3685 PieceBitmap(ChessSquare p, int kind)
\r
3687 if ((int) p >= (int) BlackPawn)
\r
3688 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3690 return pieceBitmap[kind][(int) p];
\r
3693 /***************************************************************/
\r
3695 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3696 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3698 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3699 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3703 SquareToPos(int row, int column, int * x, int * y)
\r
3706 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3707 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3709 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3710 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3715 DrawCoordsOnDC(HDC hdc)
\r
3717 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
3718 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
3719 char str[2] = { NULLCHAR, NULLCHAR };
\r
3720 int oldMode, oldAlign, x, y, start, i;
\r
3724 if (!appData.showCoords)
\r
3727 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3729 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3730 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3731 oldAlign = GetTextAlign(hdc);
\r
3732 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3734 y = boardRect.top + lineGap;
\r
3735 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3737 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3738 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3739 str[0] = files[start + i];
\r
3740 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3741 y += squareSize + lineGap;
\r
3744 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3746 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3747 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3748 str[0] = ranks[start + i];
\r
3749 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3750 x += squareSize + lineGap;
\r
3753 SelectObject(hdc, oldBrush);
\r
3754 SetBkMode(hdc, oldMode);
\r
3755 SetTextAlign(hdc, oldAlign);
\r
3756 SelectObject(hdc, oldFont);
\r
3760 DrawGridOnDC(HDC hdc)
\r
3764 if (lineGap != 0) {
\r
3765 oldPen = SelectObject(hdc, gridPen);
\r
3766 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3767 SelectObject(hdc, oldPen);
\r
3771 #define HIGHLIGHT_PEN 0
\r
3772 #define PREMOVE_PEN 1
\r
3775 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3778 HPEN oldPen, hPen;
\r
3779 if (lineGap == 0) return;
\r
3781 x1 = boardRect.left +
\r
3782 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3783 y1 = boardRect.top +
\r
3784 lineGap/2 + y * (squareSize + lineGap);
\r
3786 x1 = boardRect.left +
\r
3787 lineGap/2 + x * (squareSize + lineGap);
\r
3788 y1 = boardRect.top +
\r
3789 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3791 hPen = pen ? premovePen : highlightPen;
\r
3792 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3793 MoveToEx(hdc, x1, y1, NULL);
\r
3794 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3795 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3796 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3797 LineTo(hdc, x1, y1);
\r
3798 SelectObject(hdc, oldPen);
\r
3802 DrawHighlightsOnDC(HDC hdc)
\r
3805 for (i=0; i<2; i++) {
\r
3806 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3807 DrawHighlightOnDC(hdc, TRUE,
\r
3808 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3811 for (i=0; i<2; i++) {
\r
3812 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3813 premoveHighlightInfo.sq[i].y >= 0) {
\r
3814 DrawHighlightOnDC(hdc, TRUE,
\r
3815 premoveHighlightInfo.sq[i].x,
\r
3816 premoveHighlightInfo.sq[i].y,
\r
3822 /* Note: sqcolor is used only in monoMode */
\r
3823 /* Note that this code is largely duplicated in woptions.c,
\r
3824 function DrawSampleSquare, so that needs to be updated too */
\r
3826 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3828 HBITMAP oldBitmap;
\r
3832 if (appData.blindfold) return;
\r
3834 /* [AS] Use font-based pieces if needed */
\r
3835 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3836 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3837 CreatePiecesFromFont();
\r
3839 if( fontBitmapSquareSize == squareSize ) {
\r
3840 int index = TranslatePieceToFontPiece(piece);
\r
3842 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3846 squareSize, squareSize,
\r
3851 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3855 squareSize, squareSize,
\r
3864 if (appData.monoMode) {
\r
3865 SelectObject(tmphdc, PieceBitmap(piece,
\r
3866 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3867 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3868 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3870 tmpSize = squareSize;
\r
3872 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3873 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3874 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3875 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3876 x += (squareSize - minorSize)>>1;
\r
3877 y += squareSize - minorSize - 2;
\r
3878 tmpSize = minorSize;
\r
3880 if (color || appData.allWhite ) {
\r
3881 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3883 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3884 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3885 if(appData.upsideDown && color==flipView)
\r
3886 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3888 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3890 /* Use black piece color for outline of white pieces */
\r
3891 /* Not sure this looks really good (though xboard does it).
\r
3892 Maybe better to have another selectable color, default black */
\r
3893 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3894 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3895 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3897 /* Use black for outline of white pieces */
\r
3898 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3899 if(appData.upsideDown && color==flipView)
\r
3900 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3902 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3906 /* Use white piece color for details of black pieces */
\r
3907 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3908 WHITE_PIECE ones aren't always the right shape. */
\r
3909 /* Not sure this looks really good (though xboard does it).
\r
3910 Maybe better to have another selectable color, default medium gray? */
\r
3911 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3912 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3913 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3914 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3915 SelectObject(hdc, blackPieceBrush);
\r
3916 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3918 /* Use square color for details of black pieces */
\r
3919 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3920 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3921 if(appData.upsideDown && !flipView)
\r
3922 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3924 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3927 SelectObject(hdc, oldBrush);
\r
3928 SelectObject(tmphdc, oldBitmap);
\r
3932 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3933 int GetBackTextureMode( int algo )
\r
3935 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3939 case BACK_TEXTURE_MODE_PLAIN:
\r
3940 result = 1; /* Always use identity map */
\r
3942 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3943 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3951 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3952 to handle redraws cleanly (as random numbers would always be different).
\r
3954 VOID RebuildTextureSquareInfo()
\r
3964 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3966 if( liteBackTexture != NULL ) {
\r
3967 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3968 lite_w = bi.bmWidth;
\r
3969 lite_h = bi.bmHeight;
\r
3973 if( darkBackTexture != NULL ) {
\r
3974 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3975 dark_w = bi.bmWidth;
\r
3976 dark_h = bi.bmHeight;
\r
3980 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3981 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3982 if( (col + row) & 1 ) {
\r
3984 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3985 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3986 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3987 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3992 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3993 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3994 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3995 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
4002 /* [AS] Arrow highlighting support */
\r
4004 static int A_WIDTH = 5; /* Width of arrow body */
\r
4006 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
4007 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
4009 static double Sqr( double x )
\r
4014 static int Round( double x )
\r
4016 return (int) (x + 0.5);
\r
4019 /* Draw an arrow between two points using current settings */
\r
4020 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
4023 double dx, dy, j, k, x, y;
\r
4025 if( d_x == s_x ) {
\r
4026 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4028 arrow[0].x = s_x + A_WIDTH;
\r
4031 arrow[1].x = s_x + A_WIDTH;
\r
4032 arrow[1].y = d_y - h;
\r
4034 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4035 arrow[2].y = d_y - h;
\r
4040 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4041 arrow[4].y = d_y - h;
\r
4043 arrow[5].x = s_x - A_WIDTH;
\r
4044 arrow[5].y = d_y - h;
\r
4046 arrow[6].x = s_x - A_WIDTH;
\r
4049 else if( d_y == s_y ) {
\r
4050 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4053 arrow[0].y = s_y + A_WIDTH;
\r
4055 arrow[1].x = d_x - w;
\r
4056 arrow[1].y = s_y + A_WIDTH;
\r
4058 arrow[2].x = d_x - w;
\r
4059 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4064 arrow[4].x = d_x - w;
\r
4065 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4067 arrow[5].x = d_x - w;
\r
4068 arrow[5].y = s_y - A_WIDTH;
\r
4071 arrow[6].y = s_y - A_WIDTH;
\r
4074 /* [AS] Needed a lot of paper for this! :-) */
\r
4075 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4076 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4078 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4080 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4085 arrow[0].x = Round(x - j);
\r
4086 arrow[0].y = Round(y + j*dx);
\r
4088 arrow[1].x = Round(x + j);
\r
4089 arrow[1].y = Round(y - j*dx);
\r
4092 x = (double) d_x - k;
\r
4093 y = (double) d_y - k*dy;
\r
4096 x = (double) d_x + k;
\r
4097 y = (double) d_y + k*dy;
\r
4100 arrow[2].x = Round(x + j);
\r
4101 arrow[2].y = Round(y - j*dx);
\r
4103 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4104 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4109 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4110 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4112 arrow[6].x = Round(x - j);
\r
4113 arrow[6].y = Round(y + j*dx);
\r
4116 Polygon( hdc, arrow, 7 );
\r
4119 /* [AS] Draw an arrow between two squares */
\r
4120 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4122 int s_x, s_y, d_x, d_y;
\r
4129 if( s_col == d_col && s_row == d_row ) {
\r
4133 /* Get source and destination points */
\r
4134 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4135 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4138 d_y += squareSize / 4;
\r
4140 else if( d_y < s_y ) {
\r
4141 d_y += 3 * squareSize / 4;
\r
4144 d_y += squareSize / 2;
\r
4148 d_x += squareSize / 4;
\r
4150 else if( d_x < s_x ) {
\r
4151 d_x += 3 * squareSize / 4;
\r
4154 d_x += squareSize / 2;
\r
4157 s_x += squareSize / 2;
\r
4158 s_y += squareSize / 2;
\r
4160 /* Adjust width */
\r
4161 A_WIDTH = squareSize / 14;
\r
4164 stLB.lbStyle = BS_SOLID;
\r
4165 stLB.lbColor = appData.highlightArrowColor;
\r
4168 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4169 holdpen = SelectObject( hdc, hpen );
\r
4170 hbrush = CreateBrushIndirect( &stLB );
\r
4171 holdbrush = SelectObject( hdc, hbrush );
\r
4173 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4175 SelectObject( hdc, holdpen );
\r
4176 SelectObject( hdc, holdbrush );
\r
4177 DeleteObject( hpen );
\r
4178 DeleteObject( hbrush );
\r
4181 BOOL HasHighlightInfo()
\r
4183 BOOL result = FALSE;
\r
4185 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4186 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4194 BOOL IsDrawArrowEnabled()
\r
4196 BOOL result = FALSE;
\r
4198 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4205 VOID DrawArrowHighlight( HDC hdc )
\r
4207 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4208 DrawArrowBetweenSquares( hdc,
\r
4209 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4210 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4214 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4216 HRGN result = NULL;
\r
4218 if( HasHighlightInfo() ) {
\r
4219 int x1, y1, x2, y2;
\r
4220 int sx, sy, dx, dy;
\r
4222 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4223 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4225 sx = MIN( x1, x2 );
\r
4226 sy = MIN( y1, y2 );
\r
4227 dx = MAX( x1, x2 ) + squareSize;
\r
4228 dy = MAX( y1, y2 ) + squareSize;
\r
4230 result = CreateRectRgn( sx, sy, dx, dy );
\r
4237 Warning: this function modifies the behavior of several other functions.
\r
4239 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4240 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4241 repaint is scattered all over the place, which is not good for features such as
\r
4242 "arrow highlighting" that require a full repaint of the board.
\r
4244 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4245 user interaction, when speed is not so important) but especially to avoid errors
\r
4246 in the displayed graphics.
\r
4248 In such patched places, I always try refer to this function so there is a single
\r
4249 place to maintain knowledge.
\r
4251 To restore the original behavior, just return FALSE unconditionally.
\r
4253 BOOL IsFullRepaintPreferrable()
\r
4255 BOOL result = FALSE;
\r
4257 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4258 /* Arrow may appear on the board */
\r
4266 This function is called by DrawPosition to know whether a full repaint must
\r
4269 Only DrawPosition may directly call this function, which makes use of
\r
4270 some state information. Other function should call DrawPosition specifying
\r
4271 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4273 BOOL DrawPositionNeedsFullRepaint()
\r
4275 BOOL result = FALSE;
\r
4278 Probably a slightly better policy would be to trigger a full repaint
\r
4279 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4280 but animation is fast enough that it's difficult to notice.
\r
4282 if( animInfo.piece == EmptySquare ) {
\r
4283 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4292 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4294 int row, column, x, y, square_color, piece_color;
\r
4295 ChessSquare piece;
\r
4297 HDC texture_hdc = NULL;
\r
4299 /* [AS] Initialize background textures if needed */
\r
4300 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4301 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4302 if( backTextureSquareSize != squareSize
\r
4303 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4304 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4305 backTextureSquareSize = squareSize;
\r
4306 RebuildTextureSquareInfo();
\r
4309 texture_hdc = CreateCompatibleDC( hdc );
\r
4312 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4313 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4315 SquareToPos(row, column, &x, &y);
\r
4317 piece = board[row][column];
\r
4319 square_color = ((column + row) % 2) == 1;
\r
4320 if( gameInfo.variant == VariantXiangqi ) {
\r
4321 square_color = !InPalace(row, column);
\r
4322 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4323 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4325 piece_color = (int) piece < (int) BlackPawn;
\r
4328 /* [HGM] holdings file: light square or black */
\r
4329 if(column == BOARD_LEFT-2) {
\r
4330 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4333 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4337 if(column == BOARD_RGHT + 1 ) {
\r
4338 if( row < gameInfo.holdingsSize )
\r
4341 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4345 if(column == BOARD_LEFT-1 ) /* left align */
\r
4346 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4347 else if( column == BOARD_RGHT) /* right align */
\r
4348 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4350 if (appData.monoMode) {
\r
4351 if (piece == EmptySquare) {
\r
4352 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4353 square_color ? WHITENESS : BLACKNESS);
\r
4355 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4358 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4359 /* [AS] Draw the square using a texture bitmap */
\r
4360 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4361 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4362 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4365 squareSize, squareSize,
\r
4368 backTextureSquareInfo[r][c].mode,
\r
4369 backTextureSquareInfo[r][c].x,
\r
4370 backTextureSquareInfo[r][c].y );
\r
4372 SelectObject( texture_hdc, hbm );
\r
4374 if (piece != EmptySquare) {
\r
4375 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4379 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4381 oldBrush = SelectObject(hdc, brush );
\r
4382 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4383 SelectObject(hdc, oldBrush);
\r
4384 if (piece != EmptySquare)
\r
4385 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4390 if( texture_hdc != NULL ) {
\r
4391 DeleteDC( texture_hdc );
\r
4395 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4396 void fputDW(FILE *f, int x)
\r
4398 fputc(x & 255, f);
\r
4399 fputc(x>>8 & 255, f);
\r
4400 fputc(x>>16 & 255, f);
\r
4401 fputc(x>>24 & 255, f);
\r
4404 #define MAX_CLIPS 200 /* more than enough */
\r
4407 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4409 // HBITMAP bufferBitmap;
\r
4414 int w = 100, h = 50;
\r
4416 if(logo == NULL) return;
\r
4417 // GetClientRect(hwndMain, &Rect);
\r
4418 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4419 // Rect.bottom-Rect.top+1);
\r
4420 tmphdc = CreateCompatibleDC(hdc);
\r
4421 hbm = SelectObject(tmphdc, logo);
\r
4422 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4426 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4427 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4428 SelectObject(tmphdc, hbm);
\r
4433 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4435 static Board lastReq, lastDrawn;
\r
4436 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4437 static int lastDrawnFlipView = 0;
\r
4438 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4439 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4442 HBITMAP bufferBitmap;
\r
4443 HBITMAP oldBitmap;
\r
4445 HRGN clips[MAX_CLIPS];
\r
4446 ChessSquare dragged_piece = EmptySquare;
\r
4448 /* I'm undecided on this - this function figures out whether a full
\r
4449 * repaint is necessary on its own, so there's no real reason to have the
\r
4450 * caller tell it that. I think this can safely be set to FALSE - but
\r
4451 * if we trust the callers not to request full repaints unnessesarily, then
\r
4452 * we could skip some clipping work. In other words, only request a full
\r
4453 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4454 * gamestart and similar) --Hawk
\r
4456 Boolean fullrepaint = repaint;
\r
4458 if( DrawPositionNeedsFullRepaint() ) {
\r
4459 fullrepaint = TRUE;
\r
4463 if( fullrepaint ) {
\r
4464 static int repaint_count = 0;
\r
4468 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4469 OutputDebugString( buf );
\r
4473 if (board == NULL) {
\r
4474 if (!lastReqValid) {
\r
4479 CopyBoard(lastReq, board);
\r
4483 if (doingSizing) {
\r
4487 if (IsIconic(hwndMain)) {
\r
4491 if (hdc == NULL) {
\r
4492 hdc = GetDC(hwndMain);
\r
4493 if (!appData.monoMode) {
\r
4494 SelectPalette(hdc, hPal, FALSE);
\r
4495 RealizePalette(hdc);
\r
4499 releaseDC = FALSE;
\r
4503 fprintf(debugFP, "*******************************\n"
\r
4505 "dragInfo.from (%d,%d)\n"
\r
4506 "dragInfo.start (%d,%d)\n"
\r
4507 "dragInfo.pos (%d,%d)\n"
\r
4508 "dragInfo.lastpos (%d,%d)\n",
\r
4509 repaint ? "TRUE" : "FALSE",
\r
4510 dragInfo.from.x, dragInfo.from.y,
\r
4511 dragInfo.start.x, dragInfo.start.y,
\r
4512 dragInfo.pos.x, dragInfo.pos.y,
\r
4513 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4514 fprintf(debugFP, "prev: ");
\r
4515 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4516 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4517 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4520 fprintf(debugFP, "\n");
\r
4521 fprintf(debugFP, "board: ");
\r
4522 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4523 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4524 fprintf(debugFP, "%d ", board[row][column]);
\r
4527 fprintf(debugFP, "\n");
\r
4531 /* Create some work-DCs */
\r
4532 hdcmem = CreateCompatibleDC(hdc);
\r
4533 tmphdc = CreateCompatibleDC(hdc);
\r
4535 /* If dragging is in progress, we temporarely remove the piece */
\r
4536 /* [HGM] or temporarily decrease count if stacked */
\r
4537 /* !! Moved to before board compare !! */
\r
4538 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4539 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4540 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4541 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4542 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4544 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4545 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4546 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4548 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4551 /* Figure out which squares need updating by comparing the
\r
4552 * newest board with the last drawn board and checking if
\r
4553 * flipping has changed.
\r
4555 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4556 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4557 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4558 if (lastDrawn[row][column] != board[row][column]) {
\r
4559 SquareToPos(row, column, &x, &y);
\r
4560 clips[num_clips++] =
\r
4561 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4565 for (i=0; i<2; i++) {
\r
4566 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4567 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4568 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4569 lastDrawnHighlight.sq[i].y >= 0) {
\r
4570 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4571 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4572 clips[num_clips++] =
\r
4573 CreateRectRgn(x - lineGap, y - lineGap,
\r
4574 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4576 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4577 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4578 clips[num_clips++] =
\r
4579 CreateRectRgn(x - lineGap, y - lineGap,
\r
4580 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4584 for (i=0; i<2; i++) {
\r
4585 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4586 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4587 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4588 lastDrawnPremove.sq[i].y >= 0) {
\r
4589 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4590 lastDrawnPremove.sq[i].x, &x, &y);
\r
4591 clips[num_clips++] =
\r
4592 CreateRectRgn(x - lineGap, y - lineGap,
\r
4593 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4595 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4596 premoveHighlightInfo.sq[i].y >= 0) {
\r
4597 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4598 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4599 clips[num_clips++] =
\r
4600 CreateRectRgn(x - lineGap, y - lineGap,
\r
4601 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4606 fullrepaint = TRUE;
\r
4609 /* Create a buffer bitmap - this is the actual bitmap
\r
4610 * being written to. When all the work is done, we can
\r
4611 * copy it to the real DC (the screen). This avoids
\r
4612 * the problems with flickering.
\r
4614 GetClientRect(hwndMain, &Rect);
\r
4615 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4616 Rect.bottom-Rect.top+1);
\r
4617 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4618 if (!appData.monoMode) {
\r
4619 SelectPalette(hdcmem, hPal, FALSE);
\r
4622 /* Create clips for dragging */
\r
4623 if (!fullrepaint) {
\r
4624 if (dragInfo.from.x >= 0) {
\r
4625 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4626 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4628 if (dragInfo.start.x >= 0) {
\r
4629 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4630 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4632 if (dragInfo.pos.x >= 0) {
\r
4633 x = dragInfo.pos.x - squareSize / 2;
\r
4634 y = dragInfo.pos.y - squareSize / 2;
\r
4635 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4637 if (dragInfo.lastpos.x >= 0) {
\r
4638 x = dragInfo.lastpos.x - squareSize / 2;
\r
4639 y = dragInfo.lastpos.y - squareSize / 2;
\r
4640 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4644 /* Are we animating a move?
\r
4646 * - remove the piece from the board (temporarely)
\r
4647 * - calculate the clipping region
\r
4649 if (!fullrepaint) {
\r
4650 if (animInfo.piece != EmptySquare) {
\r
4651 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4652 x = boardRect.left + animInfo.lastpos.x;
\r
4653 y = boardRect.top + animInfo.lastpos.y;
\r
4654 x2 = boardRect.left + animInfo.pos.x;
\r
4655 y2 = boardRect.top + animInfo.pos.y;
\r
4656 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4657 /* Slight kludge. The real problem is that after AnimateMove is
\r
4658 done, the position on the screen does not match lastDrawn.
\r
4659 This currently causes trouble only on e.p. captures in
\r
4660 atomic, where the piece moves to an empty square and then
\r
4661 explodes. The old and new positions both had an empty square
\r
4662 at the destination, but animation has drawn a piece there and
\r
4663 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4664 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4668 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4669 if (num_clips == 0)
\r
4670 fullrepaint = TRUE;
\r
4672 /* Set clipping on the memory DC */
\r
4673 if (!fullrepaint) {
\r
4674 SelectClipRgn(hdcmem, clips[0]);
\r
4675 for (x = 1; x < num_clips; x++) {
\r
4676 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4677 abort(); // this should never ever happen!
\r
4681 /* Do all the drawing to the memory DC */
\r
4682 if(explodeInfo.radius) { // [HGM] atomic
\r
4684 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4685 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4686 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4687 x += squareSize/2;
\r
4688 y += squareSize/2;
\r
4689 if(!fullrepaint) {
\r
4690 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4691 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4693 DrawGridOnDC(hdcmem);
\r
4694 DrawHighlightsOnDC(hdcmem);
\r
4695 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4696 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4697 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4698 SelectObject(hdcmem, oldBrush);
\r
4700 DrawGridOnDC(hdcmem);
\r
4701 DrawHighlightsOnDC(hdcmem);
\r
4702 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4705 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4706 if(appData.autoLogo) {
\r
4708 switch(gameMode) { // pick logos based on game mode
\r
4709 case IcsObserving:
\r
4710 whiteLogo = second.programLogo; // ICS logo
\r
4711 blackLogo = second.programLogo;
\r
4714 case IcsPlayingWhite:
\r
4715 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4716 blackLogo = second.programLogo; // ICS logo
\r
4718 case IcsPlayingBlack:
\r
4719 whiteLogo = second.programLogo; // ICS logo
\r
4720 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4722 case TwoMachinesPlay:
\r
4723 if(first.twoMachinesColor[0] == 'b') {
\r
4724 whiteLogo = second.programLogo;
\r
4725 blackLogo = first.programLogo;
\r
4728 case MachinePlaysWhite:
\r
4729 blackLogo = userLogo;
\r
4731 case MachinePlaysBlack:
\r
4732 whiteLogo = userLogo;
\r
4733 blackLogo = first.programLogo;
\r
4736 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4737 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4740 if( appData.highlightMoveWithArrow ) {
\r
4741 DrawArrowHighlight(hdcmem);
\r
4744 DrawCoordsOnDC(hdcmem);
\r
4746 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4747 /* to make sure lastDrawn contains what is actually drawn */
\r
4749 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4750 if (dragged_piece != EmptySquare) {
\r
4751 /* [HGM] or restack */
\r
4752 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4753 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4755 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4756 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4757 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4758 x = dragInfo.pos.x - squareSize / 2;
\r
4759 y = dragInfo.pos.y - squareSize / 2;
\r
4760 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4761 ((int) dragged_piece < (int) BlackPawn),
\r
4762 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4765 /* Put the animated piece back into place and draw it */
\r
4766 if (animInfo.piece != EmptySquare) {
\r
4767 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4768 x = boardRect.left + animInfo.pos.x;
\r
4769 y = boardRect.top + animInfo.pos.y;
\r
4770 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4771 ((int) animInfo.piece < (int) BlackPawn),
\r
4772 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4775 /* Release the bufferBitmap by selecting in the old bitmap
\r
4776 * and delete the memory DC
\r
4778 SelectObject(hdcmem, oldBitmap);
\r
4781 /* Set clipping on the target DC */
\r
4782 if (!fullrepaint) {
\r
4783 SelectClipRgn(hdc, clips[0]);
\r
4784 for (x = 1; x < num_clips; x++) {
\r
4785 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4786 abort(); // this should never ever happen!
\r
4790 /* Copy the new bitmap onto the screen in one go.
\r
4791 * This way we avoid any flickering
\r
4793 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4794 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4795 boardRect.right - boardRect.left,
\r
4796 boardRect.bottom - boardRect.top,
\r
4797 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4798 if(saveDiagFlag) {
\r
4799 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4800 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4802 GetObject(bufferBitmap, sizeof(b), &b);
\r
4803 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4804 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4805 bih.biWidth = b.bmWidth;
\r
4806 bih.biHeight = b.bmHeight;
\r
4808 bih.biBitCount = b.bmBitsPixel;
\r
4809 bih.biCompression = 0;
\r
4810 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4811 bih.biXPelsPerMeter = 0;
\r
4812 bih.biYPelsPerMeter = 0;
\r
4813 bih.biClrUsed = 0;
\r
4814 bih.biClrImportant = 0;
\r
4815 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4816 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4817 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4818 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4821 wb = b.bmWidthBytes;
\r
4823 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4824 int k = ((int*) pData)[i];
\r
4825 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4826 if(j >= 16) break;
\r
4828 if(j >= nrColors) nrColors = j+1;
\r
4830 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4832 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4833 for(w=0; w<(wb>>2); w+=2) {
\r
4834 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4835 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4836 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4837 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4838 pData[p++] = m | j<<4;
\r
4840 while(p&3) pData[p++] = 0;
\r
4843 wb = ((wb+31)>>5)<<2;
\r
4845 // write BITMAPFILEHEADER
\r
4846 fprintf(diagFile, "BM");
\r
4847 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4848 fputDW(diagFile, 0);
\r
4849 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4850 // write BITMAPINFOHEADER
\r
4851 fputDW(diagFile, 40);
\r
4852 fputDW(diagFile, b.bmWidth);
\r
4853 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4854 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4855 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4856 fputDW(diagFile, 0);
\r
4857 fputDW(diagFile, 0);
\r
4858 fputDW(diagFile, 0);
\r
4859 fputDW(diagFile, 0);
\r
4860 fputDW(diagFile, 0);
\r
4861 fputDW(diagFile, 0);
\r
4862 // write color table
\r
4864 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4865 // write bitmap data
\r
4866 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4867 fputc(pData[i], diagFile);
\r
4872 SelectObject(tmphdc, oldBitmap);
\r
4874 /* Massive cleanup */
\r
4875 for (x = 0; x < num_clips; x++)
\r
4876 DeleteObject(clips[x]);
\r
4879 DeleteObject(bufferBitmap);
\r
4882 ReleaseDC(hwndMain, hdc);
\r
4884 if (lastDrawnFlipView != flipView) {
\r
4886 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4888 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4891 /* CopyBoard(lastDrawn, board);*/
\r
4892 lastDrawnHighlight = highlightInfo;
\r
4893 lastDrawnPremove = premoveHighlightInfo;
\r
4894 lastDrawnFlipView = flipView;
\r
4895 lastDrawnValid = 1;
\r
4898 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4903 saveDiagFlag = 1; diagFile = f;
\r
4904 HDCDrawPosition(NULL, TRUE, NULL);
\r
4908 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4915 /*---------------------------------------------------------------------------*\
\r
4916 | CLIENT PAINT PROCEDURE
\r
4917 | This is the main event-handler for the WM_PAINT message.
\r
4919 \*---------------------------------------------------------------------------*/
\r
4921 PaintProc(HWND hwnd)
\r
4927 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4928 if (IsIconic(hwnd)) {
\r
4929 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4931 if (!appData.monoMode) {
\r
4932 SelectPalette(hdc, hPal, FALSE);
\r
4933 RealizePalette(hdc);
\r
4935 HDCDrawPosition(hdc, 1, NULL);
\r
4937 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4938 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4939 ETO_CLIPPED|ETO_OPAQUE,
\r
4940 &messageRect, messageText, strlen(messageText), NULL);
\r
4941 SelectObject(hdc, oldFont);
\r
4942 DisplayBothClocks();
\r
4944 EndPaint(hwnd,&ps);
\r
4952 * If the user selects on a border boundary, return -1; if off the board,
\r
4953 * return -2. Otherwise map the event coordinate to the square.
\r
4954 * The offset boardRect.left or boardRect.top must already have been
\r
4955 * subtracted from x.
\r
4958 EventToSquare(int x)
\r
4965 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4967 x /= (squareSize + lineGap);
\r
4968 if (x >= BOARD_SIZE)
\r
4979 DropEnable dropEnables[] = {
\r
4980 { 'P', DP_Pawn, "Pawn" },
\r
4981 { 'N', DP_Knight, "Knight" },
\r
4982 { 'B', DP_Bishop, "Bishop" },
\r
4983 { 'R', DP_Rook, "Rook" },
\r
4984 { 'Q', DP_Queen, "Queen" },
\r
4988 SetupDropMenu(HMENU hmenu)
\r
4990 int i, count, enable;
\r
4992 extern char white_holding[], black_holding[];
\r
4993 char item[MSG_SIZ];
\r
4995 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4996 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4997 dropEnables[i].piece);
\r
4999 while (p && *p++ == dropEnables[i].piece) count++;
\r
5000 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
5001 enable = count > 0 || !appData.testLegality
\r
5002 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
5003 && !appData.icsActive);
\r
5004 ModifyMenu(hmenu, dropEnables[i].command,
\r
5005 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
5006 dropEnables[i].command, item);
\r
5010 /* Event handler for mouse messages */
\r
5012 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5016 static int recursive = 0;
\r
5018 // BOOLEAN needsRedraw = FALSE;
\r
5019 BOOLEAN saveAnimate;
\r
5020 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
5021 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
5022 ChessMove moveType;
\r
5025 if (message == WM_MBUTTONUP) {
\r
5026 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5027 to the middle button: we simulate pressing the left button too!
\r
5029 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5030 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5036 pt.x = LOWORD(lParam);
\r
5037 pt.y = HIWORD(lParam);
\r
5038 x = EventToSquare(pt.x - boardRect.left);
\r
5039 y = EventToSquare(pt.y - boardRect.top);
\r
5040 if (!flipView && y >= 0) {
\r
5041 y = BOARD_HEIGHT - 1 - y;
\r
5043 if (flipView && x >= 0) {
\r
5044 x = BOARD_WIDTH - 1 - x;
\r
5047 switch (message) {
\r
5048 case WM_LBUTTONDOWN:
\r
5049 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5050 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5051 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5052 if(gameInfo.holdingsWidth &&
\r
5053 (WhiteOnMove(currentMove)
\r
5054 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5055 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5056 // click in right holdings, for determining promotion piece
\r
5057 ChessSquare p = boards[currentMove][y][x];
\r
5058 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5059 if(p != EmptySquare) {
\r
5060 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5061 fromX = fromY = -1;
\r
5065 DrawPosition(FALSE, boards[currentMove]);
\r
5069 sameAgain = FALSE;
\r
5071 /* Downclick vertically off board; check if on clock */
\r
5072 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5073 if (gameMode == EditPosition) {
\r
5074 SetWhiteToPlayEvent();
\r
5075 } else if (gameMode == IcsPlayingBlack ||
\r
5076 gameMode == MachinePlaysWhite) {
\r
5078 } else if (gameMode == EditGame) {
\r
5079 AdjustClock(flipClock, -1);
\r
5081 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5082 if (gameMode == EditPosition) {
\r
5083 SetBlackToPlayEvent();
\r
5084 } else if (gameMode == IcsPlayingWhite ||
\r
5085 gameMode == MachinePlaysBlack) {
\r
5087 } else if (gameMode == EditGame) {
\r
5088 AdjustClock(!flipClock, -1);
\r
5091 if (!appData.highlightLastMove) {
\r
5092 ClearHighlights();
\r
5093 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5095 fromX = fromY = -1;
\r
5096 dragInfo.start.x = dragInfo.start.y = -1;
\r
5097 dragInfo.from = dragInfo.start;
\r
5099 } else if (x < 0 || y < 0
\r
5100 /* [HGM] block clicks between board and holdings */
\r
5101 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5102 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5103 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5104 /* EditPosition, empty square, or different color piece;
\r
5105 click-click move is possible */
\r
5108 } else if (fromX == x && fromY == y) {
\r
5109 /* Downclick on same square again */
\r
5110 ClearHighlights();
\r
5111 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5112 sameAgain = TRUE;
\r
5113 } else if (fromX != -1 &&
\r
5114 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5116 /* Downclick on different square. */
\r
5117 /* [HGM] if on holdings file, should count as new first click ! */
\r
5118 /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5121 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5122 to make sure move is legal before showing promotion popup */
\r
5123 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, FALSE);
\r
5124 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5125 fromX = fromY = -1;
\r
5126 ClearHighlights();
\r
5127 DrawPosition(FALSE, boards[currentMove]);
\r
5130 if(moveType != ImpossibleMove && moveType != Comment) {
\r
5131 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5132 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5133 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5134 appData.alwaysPromoteToQueen)) {
\r
5135 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5136 if (!appData.highlightLastMove) {
\r
5137 ClearHighlights();
\r
5138 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5141 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5142 SetHighlights(fromX, fromY, toX, toY);
\r
5143 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5144 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5145 If promotion to Q is legal, all are legal! */
\r
5146 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5147 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5148 // kludge to temporarily execute move on display, without promoting yet
\r
5149 promotionChoice = TRUE;
\r
5150 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5151 boards[currentMove][toY][toX] = p;
\r
5152 DrawPosition(FALSE, boards[currentMove]);
\r
5153 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5154 boards[currentMove][toY][toX] = q;
\r
5155 DisplayMessage("Select piece from holdings", "");
\r
5157 PromotionPopup(hwnd);
\r
5159 } else { // not a promotion. Move can be illegal if testLegality off, and should be made then.
\r
5160 if (appData.animate || appData.highlightLastMove) {
\r
5161 SetHighlights(fromX, fromY, toX, toY);
\r
5163 ClearHighlights();
\r
5165 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5166 if (appData.animate && !appData.highlightLastMove) {
\r
5167 ClearHighlights();
\r
5168 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5171 fromX = fromY = -1;
\r
5175 if (gotPremove && moveType != Comment) {
\r
5176 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5177 // DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5178 } else ClearHighlights();
\r
5179 fromX = fromY = -1;
\r
5180 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5181 if(moveType != Comment) break;
\r
5183 /* First downclick, or restart on a square with same color piece */
\r
5184 if (!frozen && OKToStartUserMove(x, y)) {
\r
5187 dragInfo.lastpos = pt;
\r
5188 dragInfo.from.x = fromX;
\r
5189 dragInfo.from.y = fromY;
\r
5190 dragInfo.start = dragInfo.from;
\r
5191 SetCapture(hwndMain);
\r
5193 fromX = fromY = -1;
\r
5194 dragInfo.start.x = dragInfo.start.y = -1;
\r
5195 dragInfo.from = dragInfo.start;
\r
5196 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5200 case WM_LBUTTONUP:
\r
5202 if (fromX == -1) break;
\r
5203 if (x == fromX && y == fromY) {
\r
5204 dragInfo.from.x = dragInfo.from.y = -1;
\r
5205 /* Upclick on same square */
\r
5207 /* Clicked same square twice: abort click-click move */
\r
5208 fromX = fromY = -1;
\r
5210 ClearPremoveHighlights();
\r
5212 /* First square clicked: start click-click move */
\r
5213 SetHighlights(fromX, fromY, -1, -1);
\r
5215 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5216 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5217 /* Errant click; ignore */
\r
5220 /* Finish drag move. */
\r
5221 if (appData.debugMode) {
\r
5222 fprintf(debugFP, "release\n");
\r
5224 dragInfo.from.x = dragInfo.from.y = -1;
\r
5227 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5228 appData.animate = appData.animate && !appData.animateDragging;
\r
5229 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR, TRUE);
\r
5230 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5231 fromX = fromY = -1;
\r
5232 ClearHighlights();
\r
5233 DrawPosition(FALSE, boards[currentMove]);
\r
5234 appData.animate = saveAnimate;
\r
5237 if(moveType != ImpossibleMove) {
\r
5238 /* [HGM] use move type to determine if move is promotion.
\r
5239 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5240 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5241 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5242 appData.alwaysPromoteToQueen))
\r
5243 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5245 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5246 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5247 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5248 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5249 // kludge to temporarily execute move on display, wthout promotng yet
\r
5250 promotionChoice = TRUE;
\r
5251 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5252 boards[currentMove][toY][toX] = p;
\r
5253 DrawPosition(FALSE, boards[currentMove]);
\r
5254 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5255 boards[currentMove][toY][toX] = q;
\r
5256 appData.animate = saveAnimate;
\r
5257 DisplayMessage("Select piece from holdings", "");
\r
5260 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5262 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5263 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5264 moveType == WhiteCapturesEnPassant ||
\r
5265 moveType == BlackCapturesEnPassant ) )
\r
5266 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5267 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5270 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5271 appData.animate = saveAnimate;
\r
5272 fromX = fromY = -1;
\r
5273 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5274 ClearHighlights();
\r
5276 if (appData.animate || appData.animateDragging ||
\r
5277 appData.highlightDragging || gotPremove) {
\r
5278 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5281 dragInfo.start.x = dragInfo.start.y = -1;
\r
5282 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5285 case WM_MOUSEMOVE:
\r
5286 if ((appData.animateDragging || appData.highlightDragging)
\r
5287 && (wParam & MK_LBUTTON)
\r
5288 && dragInfo.from.x >= 0)
\r
5290 BOOL full_repaint = FALSE;
\r
5292 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5293 if (appData.animateDragging) {
\r
5294 dragInfo.pos = pt;
\r
5296 if (appData.highlightDragging) {
\r
5297 SetHighlights(fromX, fromY, x, y);
\r
5298 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5299 full_repaint = TRUE;
\r
5303 DrawPosition( full_repaint, NULL);
\r
5305 dragInfo.lastpos = dragInfo.pos;
\r
5309 case WM_MOUSEWHEEL: // [DM]
\r
5310 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5311 /* Mouse Wheel is being rolled forward
\r
5312 * Play moves forward
\r
5314 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5315 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5316 /* Mouse Wheel is being rolled backward
\r
5317 * Play moves backward
\r
5319 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5320 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5324 case WM_MBUTTONDOWN:
\r
5325 case WM_RBUTTONDOWN:
\r
5328 fromX = fromY = -1;
\r
5329 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5330 dragInfo.start.x = dragInfo.start.y = -1;
\r
5331 dragInfo.from = dragInfo.start;
\r
5332 dragInfo.lastpos = dragInfo.pos;
\r
5333 if (appData.highlightDragging) {
\r
5334 ClearHighlights();
\r
5337 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5338 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5339 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5340 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5341 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5344 DrawPosition(TRUE, NULL);
\r
5346 switch (gameMode) {
\r
5347 case EditPosition:
\r
5348 case IcsExamining:
\r
5349 if (x < 0 || y < 0) break;
\r
5352 if (message == WM_MBUTTONDOWN) {
\r
5353 buttonCount = 3; /* even if system didn't think so */
\r
5354 if (wParam & MK_SHIFT)
\r
5355 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5357 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5358 } else { /* message == WM_RBUTTONDOWN */
\r
5360 if (buttonCount == 3) {
\r
5361 if (wParam & MK_SHIFT)
\r
5362 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5364 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5366 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5369 /* Just have one menu, on the right button. Windows users don't
\r
5370 think to try the middle one, and sometimes other software steals
\r
5371 it, or it doesn't really exist. */
\r
5372 if(gameInfo.variant != VariantShogi)
\r
5373 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5375 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5379 case IcsPlayingWhite:
\r
5380 case IcsPlayingBlack:
\r
5382 case MachinePlaysWhite:
\r
5383 case MachinePlaysBlack:
\r
5384 if (appData.testLegality &&
\r
5385 gameInfo.variant != VariantBughouse &&
\r
5386 gameInfo.variant != VariantCrazyhouse) break;
\r
5387 if (x < 0 || y < 0) break;
\r
5390 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5391 SetupDropMenu(hmenu);
\r
5392 MenuPopup(hwnd, pt, hmenu, -1);
\r
5403 /* Preprocess messages for buttons in main window */
\r
5405 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5407 int id = GetWindowLong(hwnd, GWL_ID);
\r
5410 for (i=0; i<N_BUTTONS; i++) {
\r
5411 if (buttonDesc[i].id == id) break;
\r
5413 if (i == N_BUTTONS) return 0;
\r
5414 switch (message) {
\r
5419 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5420 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5427 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5430 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5431 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5432 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5433 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5435 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5437 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5438 PopUpMoveDialog((char)wParam);
\r
5444 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5447 /* Process messages for Promotion dialog box */
\r
5449 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5453 switch (message) {
\r
5454 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5455 /* Center the dialog over the application window */
\r
5456 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5457 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5458 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5459 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5460 SW_SHOW : SW_HIDE);
\r
5461 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5462 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5463 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5464 PieceToChar(WhiteAngel) != '~') ||
\r
5465 (PieceToChar(BlackAngel) >= 'A' &&
\r
5466 PieceToChar(BlackAngel) != '~') ) ?
\r
5467 SW_SHOW : SW_HIDE);
\r
5468 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5469 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5470 PieceToChar(WhiteMarshall) != '~') ||
\r
5471 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5472 PieceToChar(BlackMarshall) != '~') ) ?
\r
5473 SW_SHOW : SW_HIDE);
\r
5474 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5475 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5476 gameInfo.variant != VariantShogi ?
\r
5477 SW_SHOW : SW_HIDE);
\r
5478 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5479 gameInfo.variant != VariantShogi ?
\r
5480 SW_SHOW : SW_HIDE);
\r
5481 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5482 gameInfo.variant == VariantShogi ?
\r
5483 SW_SHOW : SW_HIDE);
\r
5484 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5485 gameInfo.variant == VariantShogi ?
\r
5486 SW_SHOW : SW_HIDE);
\r
5487 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5488 gameInfo.variant == VariantSuper ?
\r
5489 SW_SHOW : SW_HIDE);
\r
5492 case WM_COMMAND: /* message: received a command */
\r
5493 switch (LOWORD(wParam)) {
\r
5495 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5496 ClearHighlights();
\r
5497 DrawPosition(FALSE, NULL);
\r
5500 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5503 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5506 promoChar = PieceToChar(BlackRook);
\r
5509 promoChar = PieceToChar(BlackBishop);
\r
5511 case PB_Chancellor:
\r
5512 promoChar = PieceToChar(BlackMarshall);
\r
5514 case PB_Archbishop:
\r
5515 promoChar = PieceToChar(BlackAngel);
\r
5518 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5523 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5524 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5525 only show the popup when we are already sure the move is valid or
\r
5526 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5527 will figure out it is a promotion from the promoChar. */
\r
5528 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5529 if (!appData.highlightLastMove) {
\r
5530 ClearHighlights();
\r
5531 DrawPosition(FALSE, NULL);
\r
5538 /* Pop up promotion dialog */
\r
5540 PromotionPopup(HWND hwnd)
\r
5544 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5545 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5546 hwnd, (DLGPROC)lpProc);
\r
5547 FreeProcInstance(lpProc);
\r
5550 /* Toggle ShowThinking */
\r
5552 ToggleShowThinking()
\r
5554 appData.showThinking = !appData.showThinking;
\r
5555 ShowThinkingEvent();
\r
5559 LoadGameDialog(HWND hwnd, char* title)
\r
5563 char fileTitle[MSG_SIZ];
\r
5564 f = OpenFileDialog(hwnd, "rb", "",
\r
5565 appData.oldSaveStyle ? "gam" : "pgn",
\r
5567 title, &number, fileTitle, NULL);
\r
5569 cmailMsgLoaded = FALSE;
\r
5570 if (number == 0) {
\r
5571 int error = GameListBuild(f);
\r
5573 DisplayError("Cannot build game list", error);
\r
5574 } else if (!ListEmpty(&gameList) &&
\r
5575 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5576 GameListPopUp(f, fileTitle);
\r
5579 GameListDestroy();
\r
5582 LoadGame(f, number, fileTitle, FALSE);
\r
5587 ChangedConsoleFont()
\r
5590 CHARRANGE tmpsel, sel;
\r
5591 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5592 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5593 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5596 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5597 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5598 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5599 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5600 * size. This was undocumented in the version of MSVC++ that I had
\r
5601 * when I wrote the code, but is apparently documented now.
\r
5603 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5604 cfmt.bCharSet = f->lf.lfCharSet;
\r
5605 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5606 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5607 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5608 /* Why are the following seemingly needed too? */
\r
5609 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5610 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5611 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5613 tmpsel.cpMax = -1; /*999999?*/
\r
5614 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5615 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5616 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5617 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5619 paraf.cbSize = sizeof(paraf);
\r
5620 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5621 paraf.dxStartIndent = 0;
\r
5622 paraf.dxOffset = WRAP_INDENT;
\r
5623 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5624 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5627 /*---------------------------------------------------------------------------*\
\r
5629 * Window Proc for main window
\r
5631 \*---------------------------------------------------------------------------*/
\r
5633 /* Process messages for main window, etc. */
\r
5635 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5638 int wmId, wmEvent;
\r
5642 char fileTitle[MSG_SIZ];
\r
5643 char buf[MSG_SIZ];
\r
5644 static SnapData sd;
\r
5646 switch (message) {
\r
5648 case WM_PAINT: /* message: repaint portion of window */
\r
5652 case WM_ERASEBKGND:
\r
5653 if (IsIconic(hwnd)) {
\r
5654 /* Cheat; change the message */
\r
5655 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5657 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5661 case WM_LBUTTONDOWN:
\r
5662 case WM_MBUTTONDOWN:
\r
5663 case WM_RBUTTONDOWN:
\r
5664 case WM_LBUTTONUP:
\r
5665 case WM_MBUTTONUP:
\r
5666 case WM_RBUTTONUP:
\r
5667 case WM_MOUSEMOVE:
\r
5668 case WM_MOUSEWHEEL:
\r
5669 MouseEvent(hwnd, message, wParam, lParam);
\r
5672 JAWS_KB_NAVIGATION
\r
5676 JAWS_ALT_INTERCEPT
\r
5678 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5679 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5680 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5681 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5683 SendMessage(h, message, wParam, lParam);
\r
5684 } else if(lParam != KF_REPEAT) {
\r
5685 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5686 PopUpMoveDialog((char)wParam);
\r
5687 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5688 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5693 case WM_PALETTECHANGED:
\r
5694 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5696 HDC hdc = GetDC(hwndMain);
\r
5697 SelectPalette(hdc, hPal, TRUE);
\r
5698 nnew = RealizePalette(hdc);
\r
5700 paletteChanged = TRUE;
\r
5702 UpdateColors(hdc);
\r
5704 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5707 ReleaseDC(hwnd, hdc);
\r
5711 case WM_QUERYNEWPALETTE:
\r
5712 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5714 HDC hdc = GetDC(hwndMain);
\r
5715 paletteChanged = FALSE;
\r
5716 SelectPalette(hdc, hPal, FALSE);
\r
5717 nnew = RealizePalette(hdc);
\r
5719 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5721 ReleaseDC(hwnd, hdc);
\r
5726 case WM_COMMAND: /* message: command from application menu */
\r
5727 wmId = LOWORD(wParam);
\r
5728 wmEvent = HIWORD(wParam);
\r
5733 AnalysisPopDown();
\r
5734 SAY("new game enter a move to play against the computer with white");
\r
5737 case IDM_NewGameFRC:
\r
5738 if( NewGameFRC() == 0 ) {
\r
5740 AnalysisPopDown();
\r
5744 case IDM_NewVariant:
\r
5745 NewVariantPopup(hwnd);
\r
5748 case IDM_LoadGame:
\r
5749 LoadGameDialog(hwnd, "Load Game from File");
\r
5752 case IDM_LoadNextGame:
\r
5756 case IDM_LoadPrevGame:
\r
5760 case IDM_ReloadGame:
\r
5764 case IDM_LoadPosition:
\r
5765 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5766 Reset(FALSE, TRUE);
\r
5769 f = OpenFileDialog(hwnd, "rb", "",
\r
5770 appData.oldSaveStyle ? "pos" : "fen",
\r
5772 "Load Position from File", &number, fileTitle, NULL);
\r
5774 LoadPosition(f, number, fileTitle);
\r
5778 case IDM_LoadNextPosition:
\r
5779 ReloadPosition(1);
\r
5782 case IDM_LoadPrevPosition:
\r
5783 ReloadPosition(-1);
\r
5786 case IDM_ReloadPosition:
\r
5787 ReloadPosition(0);
\r
5790 case IDM_SaveGame:
\r
5791 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5792 f = OpenFileDialog(hwnd, "a", defName,
\r
5793 appData.oldSaveStyle ? "gam" : "pgn",
\r
5795 "Save Game to File", NULL, fileTitle, NULL);
\r
5797 SaveGame(f, 0, "");
\r
5801 case IDM_SavePosition:
\r
5802 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5803 f = OpenFileDialog(hwnd, "a", defName,
\r
5804 appData.oldSaveStyle ? "pos" : "fen",
\r
5806 "Save Position to File", NULL, fileTitle, NULL);
\r
5808 SavePosition(f, 0, "");
\r
5812 case IDM_SaveDiagram:
\r
5813 defName = "diagram";
\r
5814 f = OpenFileDialog(hwnd, "wb", defName,
\r
5817 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5823 case IDM_CopyGame:
\r
5824 CopyGameToClipboard();
\r
5827 case IDM_PasteGame:
\r
5828 PasteGameFromClipboard();
\r
5831 case IDM_CopyGameListToClipboard:
\r
5832 CopyGameListToClipboard();
\r
5835 /* [AS] Autodetect FEN or PGN data */
\r
5836 case IDM_PasteAny:
\r
5837 PasteGameOrFENFromClipboard();
\r
5840 /* [AS] Move history */
\r
5841 case IDM_ShowMoveHistory:
\r
5842 if( MoveHistoryIsUp() ) {
\r
5843 MoveHistoryPopDown();
\r
5846 MoveHistoryPopUp();
\r
5850 /* [AS] Eval graph */
\r
5851 case IDM_ShowEvalGraph:
\r
5852 if( EvalGraphIsUp() ) {
\r
5853 EvalGraphPopDown();
\r
5857 SetFocus(hwndMain);
\r
5861 /* [AS] Engine output */
\r
5862 case IDM_ShowEngineOutput:
\r
5863 if( EngineOutputIsUp() ) {
\r
5864 EngineOutputPopDown();
\r
5867 EngineOutputPopUp();
\r
5871 /* [AS] User adjudication */
\r
5872 case IDM_UserAdjudication_White:
\r
5873 UserAdjudicationEvent( +1 );
\r
5876 case IDM_UserAdjudication_Black:
\r
5877 UserAdjudicationEvent( -1 );
\r
5880 case IDM_UserAdjudication_Draw:
\r
5881 UserAdjudicationEvent( 0 );
\r
5884 /* [AS] Game list options dialog */
\r
5885 case IDM_GameListOptions:
\r
5886 GameListOptions();
\r
5893 case IDM_CopyPosition:
\r
5894 CopyFENToClipboard();
\r
5897 case IDM_PastePosition:
\r
5898 PasteFENFromClipboard();
\r
5901 case IDM_MailMove:
\r
5905 case IDM_ReloadCMailMsg:
\r
5906 Reset(TRUE, TRUE);
\r
5907 ReloadCmailMsgEvent(FALSE);
\r
5910 case IDM_Minimize:
\r
5911 ShowWindow(hwnd, SW_MINIMIZE);
\r
5918 case IDM_MachineWhite:
\r
5919 MachineWhiteEvent();
\r
5921 * refresh the tags dialog only if it's visible
\r
5923 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5925 tags = PGNTags(&gameInfo);
\r
5926 TagsPopUp(tags, CmailMsg());
\r
5929 SAY("computer starts playing white");
\r
5932 case IDM_MachineBlack:
\r
5933 MachineBlackEvent();
\r
5935 * refresh the tags dialog only if it's visible
\r
5937 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5939 tags = PGNTags(&gameInfo);
\r
5940 TagsPopUp(tags, CmailMsg());
\r
5943 SAY("computer starts playing black");
\r
5946 case IDM_TwoMachines:
\r
5947 TwoMachinesEvent();
\r
5949 * refresh the tags dialog only if it's visible
\r
5951 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5953 tags = PGNTags(&gameInfo);
\r
5954 TagsPopUp(tags, CmailMsg());
\r
5957 SAY("programs start playing each other");
\r
5960 case IDM_AnalysisMode:
\r
5961 if (!first.analysisSupport) {
\r
5962 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5963 DisplayError(buf, 0);
\r
5965 SAY("analyzing current position");
\r
5966 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5967 if (appData.icsActive) {
\r
5968 if (gameMode != IcsObserving) {
\r
5969 sprintf(buf, "You are not observing a game");
\r
5970 DisplayError(buf, 0);
\r
5971 /* secure check */
\r
5972 if (appData.icsEngineAnalyze) {
\r
5973 if (appData.debugMode)
\r
5974 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5975 ExitAnalyzeMode();
\r
5981 /* if enable, user want disable icsEngineAnalyze */
\r
5982 if (appData.icsEngineAnalyze) {
\r
5983 ExitAnalyzeMode();
\r
5987 appData.icsEngineAnalyze = TRUE;
\r
5988 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5991 if (!appData.showThinking) ToggleShowThinking();
\r
5992 AnalyzeModeEvent();
\r
5996 case IDM_AnalyzeFile:
\r
5997 if (!first.analysisSupport) {
\r
5998 char buf[MSG_SIZ];
\r
5999 sprintf(buf, "%s does not support analysis", first.tidy);
\r
6000 DisplayError(buf, 0);
\r
6002 if (!appData.showThinking) ToggleShowThinking();
\r
6003 AnalyzeFileEvent();
\r
6004 LoadGameDialog(hwnd, "Analyze Game from File");
\r
6005 AnalysisPeriodicEvent(1);
\r
6009 case IDM_IcsClient:
\r
6013 case IDM_EditGame:
\r
6018 case IDM_EditPosition:
\r
6019 EditPositionEvent();
\r
6020 SAY("to set up a position type a FEN");
\r
6023 case IDM_Training:
\r
6027 case IDM_ShowGameList:
\r
6028 ShowGameListProc();
\r
6031 case IDM_EditTags:
\r
6035 case IDM_EditComment:
\r
6036 if (commentDialogUp && editComment) {
\r
6039 EditCommentEvent();
\r
6059 case IDM_CallFlag:
\r
6079 case IDM_StopObserving:
\r
6080 StopObservingEvent();
\r
6083 case IDM_StopExamining:
\r
6084 StopExaminingEvent();
\r
6087 case IDM_TypeInMove:
\r
6088 PopUpMoveDialog('\000');
\r
6091 case IDM_TypeInName:
\r
6092 PopUpNameDialog('\000');
\r
6095 case IDM_Backward:
\r
6097 SetFocus(hwndMain);
\r
6104 SetFocus(hwndMain);
\r
6109 SetFocus(hwndMain);
\r
6114 SetFocus(hwndMain);
\r
6121 case IDM_TruncateGame:
\r
6122 TruncateGameEvent();
\r
6129 case IDM_RetractMove:
\r
6130 RetractMoveEvent();
\r
6133 case IDM_FlipView:
\r
6134 flipView = !flipView;
\r
6135 DrawPosition(FALSE, NULL);
\r
6138 case IDM_FlipClock:
\r
6139 flipClock = !flipClock;
\r
6140 DisplayBothClocks();
\r
6141 DrawPosition(FALSE, NULL);
\r
6144 case IDM_MuteSounds:
\r
6145 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
6146 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
6147 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
6150 case IDM_GeneralOptions:
\r
6151 GeneralOptionsPopup(hwnd);
\r
6152 DrawPosition(TRUE, NULL);
\r
6155 case IDM_BoardOptions:
\r
6156 BoardOptionsPopup(hwnd);
\r
6159 case IDM_EnginePlayOptions:
\r
6160 EnginePlayOptionsPopup(hwnd);
\r
6163 case IDM_Engine1Options:
\r
6164 EngineOptionsPopup(hwnd, &first);
\r
6167 case IDM_Engine2Options:
\r
6168 EngineOptionsPopup(hwnd, &second);
\r
6171 case IDM_OptionsUCI:
\r
6172 UciOptionsPopup(hwnd);
\r
6175 case IDM_IcsOptions:
\r
6176 IcsOptionsPopup(hwnd);
\r
6180 FontsOptionsPopup(hwnd);
\r
6184 SoundOptionsPopup(hwnd);
\r
6187 case IDM_CommPort:
\r
6188 CommPortOptionsPopup(hwnd);
\r
6191 case IDM_LoadOptions:
\r
6192 LoadOptionsPopup(hwnd);
\r
6195 case IDM_SaveOptions:
\r
6196 SaveOptionsPopup(hwnd);
\r
6199 case IDM_TimeControl:
\r
6200 TimeControlOptionsPopup(hwnd);
\r
6203 case IDM_SaveSettings:
\r
6204 SaveSettings(settingsFileName);
\r
6207 case IDM_SaveSettingsOnExit:
\r
6208 saveSettingsOnExit = !saveSettingsOnExit;
\r
6209 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6210 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6211 MF_CHECKED : MF_UNCHECKED));
\r
6222 case IDM_AboutGame:
\r
6227 appData.debugMode = !appData.debugMode;
\r
6228 if (appData.debugMode) {
\r
6229 char dir[MSG_SIZ];
\r
6230 GetCurrentDirectory(MSG_SIZ, dir);
\r
6231 SetCurrentDirectory(installDir);
\r
6232 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6233 SetCurrentDirectory(dir);
\r
6234 setbuf(debugFP, NULL);
\r
6241 case IDM_HELPCONTENTS:
\r
6242 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6243 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6244 MessageBox (GetFocus(),
\r
6245 "Unable to activate help",
\r
6246 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6250 case IDM_HELPSEARCH:
\r
6251 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6252 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6253 MessageBox (GetFocus(),
\r
6254 "Unable to activate help",
\r
6255 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6259 case IDM_HELPHELP:
\r
6260 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6261 MessageBox (GetFocus(),
\r
6262 "Unable to activate help",
\r
6263 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6268 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6270 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6271 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6272 FreeProcInstance(lpProc);
\r
6275 case IDM_DirectCommand1:
\r
6276 AskQuestionEvent("Direct Command",
\r
6277 "Send to chess program:", "", "1");
\r
6279 case IDM_DirectCommand2:
\r
6280 AskQuestionEvent("Direct Command",
\r
6281 "Send to second chess program:", "", "2");
\r
6284 case EP_WhitePawn:
\r
6285 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6286 fromX = fromY = -1;
\r
6289 case EP_WhiteKnight:
\r
6290 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6291 fromX = fromY = -1;
\r
6294 case EP_WhiteBishop:
\r
6295 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6296 fromX = fromY = -1;
\r
6299 case EP_WhiteRook:
\r
6300 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6301 fromX = fromY = -1;
\r
6304 case EP_WhiteQueen:
\r
6305 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6306 fromX = fromY = -1;
\r
6309 case EP_WhiteFerz:
\r
6310 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6311 fromX = fromY = -1;
\r
6314 case EP_WhiteWazir:
\r
6315 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6316 fromX = fromY = -1;
\r
6319 case EP_WhiteAlfil:
\r
6320 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6321 fromX = fromY = -1;
\r
6324 case EP_WhiteCannon:
\r
6325 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6326 fromX = fromY = -1;
\r
6329 case EP_WhiteCardinal:
\r
6330 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6331 fromX = fromY = -1;
\r
6334 case EP_WhiteMarshall:
\r
6335 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6336 fromX = fromY = -1;
\r
6339 case EP_WhiteKing:
\r
6340 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6341 fromX = fromY = -1;
\r
6344 case EP_BlackPawn:
\r
6345 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6346 fromX = fromY = -1;
\r
6349 case EP_BlackKnight:
\r
6350 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6351 fromX = fromY = -1;
\r
6354 case EP_BlackBishop:
\r
6355 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6356 fromX = fromY = -1;
\r
6359 case EP_BlackRook:
\r
6360 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6361 fromX = fromY = -1;
\r
6364 case EP_BlackQueen:
\r
6365 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6366 fromX = fromY = -1;
\r
6369 case EP_BlackFerz:
\r
6370 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6371 fromX = fromY = -1;
\r
6374 case EP_BlackWazir:
\r
6375 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6376 fromX = fromY = -1;
\r
6379 case EP_BlackAlfil:
\r
6380 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6381 fromX = fromY = -1;
\r
6384 case EP_BlackCannon:
\r
6385 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6386 fromX = fromY = -1;
\r
6389 case EP_BlackCardinal:
\r
6390 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6391 fromX = fromY = -1;
\r
6394 case EP_BlackMarshall:
\r
6395 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6396 fromX = fromY = -1;
\r
6399 case EP_BlackKing:
\r
6400 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6401 fromX = fromY = -1;
\r
6404 case EP_EmptySquare:
\r
6405 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6406 fromX = fromY = -1;
\r
6409 case EP_ClearBoard:
\r
6410 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6411 fromX = fromY = -1;
\r
6415 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6416 fromX = fromY = -1;
\r
6420 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6421 fromX = fromY = -1;
\r
6425 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6426 fromX = fromY = -1;
\r
6430 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6431 fromX = fromY = -1;
\r
6435 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6436 fromX = fromY = -1;
\r
6440 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6441 fromX = fromY = -1;
\r
6445 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6446 fromX = fromY = -1;
\r
6450 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6451 fromX = fromY = -1;
\r
6455 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6456 fromX = fromY = -1;
\r
6460 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6466 case CLOCK_TIMER_ID:
\r
6467 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6468 clockTimerEvent = 0;
\r
6469 DecrementClocks(); /* call into back end */
\r
6471 case LOAD_GAME_TIMER_ID:
\r
6472 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6473 loadGameTimerEvent = 0;
\r
6474 AutoPlayGameLoop(); /* call into back end */
\r
6476 case ANALYSIS_TIMER_ID:
\r
6477 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6478 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6479 AnalysisPeriodicEvent(0);
\r
6481 KillTimer(hwnd, analysisTimerEvent);
\r
6482 analysisTimerEvent = 0;
\r
6485 case DELAYED_TIMER_ID:
\r
6486 KillTimer(hwnd, delayedTimerEvent);
\r
6487 delayedTimerEvent = 0;
\r
6488 delayedTimerCallback();
\r
6493 case WM_USER_Input:
\r
6494 InputEvent(hwnd, message, wParam, lParam);
\r
6497 /* [AS] Also move "attached" child windows */
\r
6498 case WM_WINDOWPOSCHANGING:
\r
6500 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6501 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6503 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6504 /* Window is moving */
\r
6507 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6508 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6509 rcMain.right = boardX + winWidth;
\r
6510 rcMain.top = boardY;
\r
6511 rcMain.bottom = boardY + winHeight;
\r
6513 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6514 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6515 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6516 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6517 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6524 /* [AS] Snapping */
\r
6525 case WM_ENTERSIZEMOVE:
\r
6526 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6527 if (hwnd == hwndMain) {
\r
6528 doingSizing = TRUE;
\r
6531 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6535 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6536 if (hwnd == hwndMain) {
\r
6537 lastSizing = wParam;
\r
6542 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6543 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6545 case WM_EXITSIZEMOVE:
\r
6546 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6547 if (hwnd == hwndMain) {
\r
6549 doingSizing = FALSE;
\r
6550 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6551 GetClientRect(hwnd, &client);
\r
6552 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6554 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6556 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6559 case WM_DESTROY: /* message: window being destroyed */
\r
6560 PostQuitMessage(0);
\r
6564 if (hwnd == hwndMain) {
\r
6569 default: /* Passes it on if unprocessed */
\r
6570 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6575 /*---------------------------------------------------------------------------*\
\r
6577 * Misc utility routines
\r
6579 \*---------------------------------------------------------------------------*/
\r
6582 * Decent random number generator, at least not as bad as Windows
\r
6583 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6585 unsigned int randstate;
\r
6590 randstate = randstate * 1664525 + 1013904223;
\r
6591 return (int) randstate & 0x7fffffff;
\r
6595 mysrandom(unsigned int seed)
\r
6602 * returns TRUE if user selects a different color, FALSE otherwise
\r
6606 ChangeColor(HWND hwnd, COLORREF *which)
\r
6608 static BOOL firstTime = TRUE;
\r
6609 static DWORD customColors[16];
\r
6611 COLORREF newcolor;
\r
6616 /* Make initial colors in use available as custom colors */
\r
6617 /* Should we put the compiled-in defaults here instead? */
\r
6619 customColors[i++] = lightSquareColor & 0xffffff;
\r
6620 customColors[i++] = darkSquareColor & 0xffffff;
\r
6621 customColors[i++] = whitePieceColor & 0xffffff;
\r
6622 customColors[i++] = blackPieceColor & 0xffffff;
\r
6623 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6624 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6626 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6627 customColors[i++] = textAttribs[ccl].color;
\r
6629 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6630 firstTime = FALSE;
\r
6633 cc.lStructSize = sizeof(cc);
\r
6634 cc.hwndOwner = hwnd;
\r
6635 cc.hInstance = NULL;
\r
6636 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6637 cc.lpCustColors = (LPDWORD) customColors;
\r
6638 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6640 if (!ChooseColor(&cc)) return FALSE;
\r
6642 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6643 if (newcolor == *which) return FALSE;
\r
6644 *which = newcolor;
\r
6648 InitDrawingColors();
\r
6649 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6654 MyLoadSound(MySound *ms)
\r
6660 if (ms->data) free(ms->data);
\r
6663 switch (ms->name[0]) {
\r
6669 /* System sound from Control Panel. Don't preload here. */
\r
6673 if (ms->name[1] == NULLCHAR) {
\r
6674 /* "!" alone = silence */
\r
6677 /* Builtin wave resource. Error if not found. */
\r
6678 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6679 if (h == NULL) break;
\r
6680 ms->data = (void *)LoadResource(hInst, h);
\r
6681 if (h == NULL) break;
\r
6686 /* .wav file. Error if not found. */
\r
6687 f = fopen(ms->name, "rb");
\r
6688 if (f == NULL) break;
\r
6689 if (fstat(fileno(f), &st) < 0) break;
\r
6690 ms->data = malloc(st.st_size);
\r
6691 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6697 char buf[MSG_SIZ];
\r
6698 sprintf(buf, "Error loading sound %s", ms->name);
\r
6699 DisplayError(buf, GetLastError());
\r
6705 MyPlaySound(MySound *ms)
\r
6707 BOOLEAN ok = FALSE;
\r
6709 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6710 switch (ms->name[0]) {
\r
6712 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6717 /* System sound from Control Panel (deprecated feature).
\r
6718 "$" alone or an unset sound name gets default beep (still in use). */
\r
6719 if (ms->name[1]) {
\r
6720 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6722 if (!ok) ok = MessageBeep(MB_OK);
\r
6725 /* Builtin wave resource, or "!" alone for silence */
\r
6726 if (ms->name[1]) {
\r
6727 if (ms->data == NULL) return FALSE;
\r
6728 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6734 /* .wav file. Error if not found. */
\r
6735 if (ms->data == NULL) return FALSE;
\r
6736 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6739 /* Don't print an error: this can happen innocently if the sound driver
\r
6740 is busy; for instance, if another instance of WinBoard is playing
\r
6741 a sound at about the same time. */
\r
6744 char buf[MSG_SIZ];
\r
6745 sprintf(buf, "Error playing sound %s", ms->name);
\r
6746 DisplayError(buf, GetLastError());
\r
6754 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6757 OPENFILENAME *ofn;
\r
6758 static UINT *number; /* gross that this is static */
\r
6760 switch (message) {
\r
6761 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6762 /* Center the dialog over the application window */
\r
6763 ofn = (OPENFILENAME *) lParam;
\r
6764 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6765 number = (UINT *) ofn->lCustData;
\r
6766 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6770 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6771 return FALSE; /* Allow for further processing */
\r
6774 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6775 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6777 return FALSE; /* Allow for further processing */
\r
6783 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6785 static UINT *number;
\r
6786 OPENFILENAME *ofname;
\r
6789 case WM_INITDIALOG:
\r
6790 ofname = (OPENFILENAME *)lParam;
\r
6791 number = (UINT *)(ofname->lCustData);
\r
6794 ofnot = (OFNOTIFY *)lParam;
\r
6795 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6796 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6805 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6806 char *nameFilt, char *dlgTitle, UINT *number,
\r
6807 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6809 OPENFILENAME openFileName;
\r
6810 char buf1[MSG_SIZ];
\r
6813 if (fileName == NULL) fileName = buf1;
\r
6814 if (defName == NULL) {
\r
6815 strcpy(fileName, "*.");
\r
6816 strcat(fileName, defExt);
\r
6818 strcpy(fileName, defName);
\r
6820 if (fileTitle) strcpy(fileTitle, "");
\r
6821 if (number) *number = 0;
\r
6823 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6824 openFileName.hwndOwner = hwnd;
\r
6825 openFileName.hInstance = (HANDLE) hInst;
\r
6826 openFileName.lpstrFilter = nameFilt;
\r
6827 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6828 openFileName.nMaxCustFilter = 0L;
\r
6829 openFileName.nFilterIndex = 1L;
\r
6830 openFileName.lpstrFile = fileName;
\r
6831 openFileName.nMaxFile = MSG_SIZ;
\r
6832 openFileName.lpstrFileTitle = fileTitle;
\r
6833 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6834 openFileName.lpstrInitialDir = NULL;
\r
6835 openFileName.lpstrTitle = dlgTitle;
\r
6836 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6837 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6838 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6839 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6840 openFileName.nFileOffset = 0;
\r
6841 openFileName.nFileExtension = 0;
\r
6842 openFileName.lpstrDefExt = defExt;
\r
6843 openFileName.lCustData = (LONG) number;
\r
6844 openFileName.lpfnHook = oldDialog ?
\r
6845 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6846 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6848 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6849 GetOpenFileName(&openFileName)) {
\r
6850 /* open the file */
\r
6851 f = fopen(openFileName.lpstrFile, write);
\r
6853 MessageBox(hwnd, "File open failed", NULL,
\r
6854 MB_OK|MB_ICONEXCLAMATION);
\r
6858 int err = CommDlgExtendedError();
\r
6859 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6868 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6870 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6873 * Get the first pop-up menu in the menu template. This is the
\r
6874 * menu that TrackPopupMenu displays.
\r
6876 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6878 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6881 * TrackPopup uses screen coordinates, so convert the
\r
6882 * coordinates of the mouse click to screen coordinates.
\r
6884 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6886 /* Draw and track the floating pop-up menu. */
\r
6887 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6888 pt.x, pt.y, 0, hwnd, NULL);
\r
6890 /* Destroy the menu.*/
\r
6891 DestroyMenu(hmenu);
\r
6896 int sizeX, sizeY, newSizeX, newSizeY;
\r
6898 } ResizeEditPlusButtonsClosure;
\r
6901 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6903 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6907 if (hChild == cl->hText) return TRUE;
\r
6908 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6909 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6910 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6911 ScreenToClient(cl->hDlg, &pt);
\r
6912 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6913 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6917 /* Resize a dialog that has a (rich) edit field filling most of
\r
6918 the top, with a row of buttons below */
\r
6920 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6923 int newTextHeight, newTextWidth;
\r
6924 ResizeEditPlusButtonsClosure cl;
\r
6926 /*if (IsIconic(hDlg)) return;*/
\r
6927 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6929 cl.hdwp = BeginDeferWindowPos(8);
\r
6931 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6932 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6933 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6934 if (newTextHeight < 0) {
\r
6935 newSizeY += -newTextHeight;
\r
6936 newTextHeight = 0;
\r
6938 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6939 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6945 cl.newSizeX = newSizeX;
\r
6946 cl.newSizeY = newSizeY;
\r
6947 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6949 EndDeferWindowPos(cl.hdwp);
\r
6952 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6954 RECT rChild, rParent;
\r
6955 int wChild, hChild, wParent, hParent;
\r
6956 int wScreen, hScreen, xNew, yNew;
\r
6959 /* Get the Height and Width of the child window */
\r
6960 GetWindowRect (hwndChild, &rChild);
\r
6961 wChild = rChild.right - rChild.left;
\r
6962 hChild = rChild.bottom - rChild.top;
\r
6964 /* Get the Height and Width of the parent window */
\r
6965 GetWindowRect (hwndParent, &rParent);
\r
6966 wParent = rParent.right - rParent.left;
\r
6967 hParent = rParent.bottom - rParent.top;
\r
6969 /* Get the display limits */
\r
6970 hdc = GetDC (hwndChild);
\r
6971 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6972 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6973 ReleaseDC(hwndChild, hdc);
\r
6975 /* Calculate new X position, then adjust for screen */
\r
6976 xNew = rParent.left + ((wParent - wChild) /2);
\r
6979 } else if ((xNew+wChild) > wScreen) {
\r
6980 xNew = wScreen - wChild;
\r
6983 /* Calculate new Y position, then adjust for screen */
\r
6985 yNew = rParent.top + ((hParent - hChild) /2);
\r
6988 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6993 } else if ((yNew+hChild) > hScreen) {
\r
6994 yNew = hScreen - hChild;
\r
6997 /* Set it, and return */
\r
6998 return SetWindowPos (hwndChild, NULL,
\r
6999 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
7002 /* Center one window over another */
\r
7003 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
7005 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
7008 /*---------------------------------------------------------------------------*\
\r
7010 * Startup Dialog functions
\r
7012 \*---------------------------------------------------------------------------*/
\r
7014 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
7016 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7018 while (*cd != NULL) {
\r
7019 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
7025 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
7027 char buf1[ARG_MAX];
\r
7030 if (str[0] == '@') {
\r
7031 FILE* f = fopen(str + 1, "r");
\r
7033 DisplayFatalError(str + 1, errno, 2);
\r
7036 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
7038 buf1[len] = NULLCHAR;
\r
7042 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7045 char buf[MSG_SIZ];
\r
7046 char *end = strchr(str, '\n');
\r
7047 if (end == NULL) return;
\r
7048 memcpy(buf, str, end - str);
\r
7049 buf[end - str] = NULLCHAR;
\r
7050 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7056 SetStartupDialogEnables(HWND hDlg)
\r
7058 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7059 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7060 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7061 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7062 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7063 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7064 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7065 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7066 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7067 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7068 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7069 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7070 IsDlgButtonChecked(hDlg, OPT_View));
\r
7074 QuoteForFilename(char *filename)
\r
7076 int dquote, space;
\r
7077 dquote = strchr(filename, '"') != NULL;
\r
7078 space = strchr(filename, ' ') != NULL;
\r
7079 if (dquote || space) {
\r
7091 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7093 char buf[MSG_SIZ];
\r
7096 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7097 q = QuoteForFilename(nthcp);
\r
7098 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7099 if (*nthdir != NULLCHAR) {
\r
7100 q = QuoteForFilename(nthdir);
\r
7101 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7103 if (*nthcp == NULLCHAR) {
\r
7104 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7105 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7106 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7107 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7112 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7114 char buf[MSG_SIZ];
\r
7118 switch (message) {
\r
7119 case WM_INITDIALOG:
\r
7120 /* Center the dialog */
\r
7121 CenterWindow (hDlg, GetDesktopWindow());
\r
7122 /* Initialize the dialog items */
\r
7123 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7124 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7125 firstChessProgramNames);
\r
7126 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7127 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7128 secondChessProgramNames);
\r
7129 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7130 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7131 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7132 if (*appData.icsHelper != NULLCHAR) {
\r
7133 char *q = QuoteForFilename(appData.icsHelper);
\r
7134 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7136 if (*appData.icsHost == NULLCHAR) {
\r
7137 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7138 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7139 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7140 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7141 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7144 if (appData.icsActive) {
\r
7145 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7147 else if (appData.noChessProgram) {
\r
7148 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7151 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7154 SetStartupDialogEnables(hDlg);
\r
7158 switch (LOWORD(wParam)) {
\r
7160 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7161 strcpy(buf, "/fcp=");
\r
7162 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7164 ParseArgs(StringGet, &p);
\r
7165 strcpy(buf, "/scp=");
\r
7166 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7168 ParseArgs(StringGet, &p);
\r
7169 appData.noChessProgram = FALSE;
\r
7170 appData.icsActive = FALSE;
\r
7171 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7172 strcpy(buf, "/ics /icshost=");
\r
7173 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7175 ParseArgs(StringGet, &p);
\r
7176 if (appData.zippyPlay) {
\r
7177 strcpy(buf, "/fcp=");
\r
7178 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7180 ParseArgs(StringGet, &p);
\r
7182 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7183 appData.noChessProgram = TRUE;
\r
7184 appData.icsActive = FALSE;
\r
7186 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7187 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7190 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7191 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7193 ParseArgs(StringGet, &p);
\r
7195 EndDialog(hDlg, TRUE);
\r
7202 case IDM_HELPCONTENTS:
\r
7203 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7204 MessageBox (GetFocus(),
\r
7205 "Unable to activate help",
\r
7206 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7211 SetStartupDialogEnables(hDlg);
\r
7219 /*---------------------------------------------------------------------------*\
\r
7221 * About box dialog functions
\r
7223 \*---------------------------------------------------------------------------*/
\r
7225 /* Process messages for "About" dialog box */
\r
7227 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7229 switch (message) {
\r
7230 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7231 /* Center the dialog over the application window */
\r
7232 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7233 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7237 case WM_COMMAND: /* message: received a command */
\r
7238 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7239 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7240 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7248 /*---------------------------------------------------------------------------*\
\r
7250 * Comment Dialog functions
\r
7252 \*---------------------------------------------------------------------------*/
\r
7255 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7257 static HANDLE hwndText = NULL;
\r
7258 int len, newSizeX, newSizeY, flags;
\r
7259 static int sizeX, sizeY;
\r
7264 switch (message) {
\r
7265 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7266 /* Initialize the dialog items */
\r
7267 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7268 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7269 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7270 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7271 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7272 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7273 SetWindowText(hDlg, commentTitle);
\r
7274 if (editComment) {
\r
7275 SetFocus(hwndText);
\r
7277 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7279 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7280 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7281 MAKELPARAM(FALSE, 0));
\r
7282 /* Size and position the dialog */
\r
7283 if (!commentDialog) {
\r
7284 commentDialog = hDlg;
\r
7285 flags = SWP_NOZORDER;
\r
7286 GetClientRect(hDlg, &rect);
\r
7287 sizeX = rect.right;
\r
7288 sizeY = rect.bottom;
\r
7289 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7290 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7291 WINDOWPLACEMENT wp;
\r
7292 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7293 wp.length = sizeof(WINDOWPLACEMENT);
\r
7295 wp.showCmd = SW_SHOW;
\r
7296 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7297 wp.rcNormalPosition.left = commentX;
\r
7298 wp.rcNormalPosition.right = commentX + commentW;
\r
7299 wp.rcNormalPosition.top = commentY;
\r
7300 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7301 SetWindowPlacement(hDlg, &wp);
\r
7303 GetClientRect(hDlg, &rect);
\r
7304 newSizeX = rect.right;
\r
7305 newSizeY = rect.bottom;
\r
7306 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7307 newSizeX, newSizeY);
\r
7314 case WM_COMMAND: /* message: received a command */
\r
7315 switch (LOWORD(wParam)) {
\r
7317 if (editComment) {
\r
7319 /* Read changed options from the dialog box */
\r
7320 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7321 len = GetWindowTextLength(hwndText);
\r
7322 str = (char *) malloc(len + 1);
\r
7323 GetWindowText(hwndText, str, len + 1);
\r
7332 ReplaceComment(commentIndex, str);
\r
7339 case OPT_CancelComment:
\r
7343 case OPT_ClearComment:
\r
7344 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7347 case OPT_EditComment:
\r
7348 EditCommentEvent();
\r
7357 newSizeX = LOWORD(lParam);
\r
7358 newSizeY = HIWORD(lParam);
\r
7359 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7364 case WM_GETMINMAXINFO:
\r
7365 /* Prevent resizing window too small */
\r
7366 mmi = (MINMAXINFO *) lParam;
\r
7367 mmi->ptMinTrackSize.x = 100;
\r
7368 mmi->ptMinTrackSize.y = 100;
\r
7375 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7380 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7382 if (str == NULL) str = "";
\r
7383 p = (char *) malloc(2 * strlen(str) + 2);
\r
7386 if (*str == '\n') *q++ = '\r';
\r
7390 if (commentText != NULL) free(commentText);
\r
7392 commentIndex = index;
\r
7393 commentTitle = title;
\r
7395 editComment = edit;
\r
7397 if (commentDialog) {
\r
7398 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7399 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7401 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7402 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7403 hwndMain, (DLGPROC)lpProc);
\r
7404 FreeProcInstance(lpProc);
\r
7406 commentDialogUp = TRUE;
\r
7410 /*---------------------------------------------------------------------------*\
\r
7412 * Type-in move dialog functions
\r
7414 \*---------------------------------------------------------------------------*/
\r
7417 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7419 char move[MSG_SIZ];
\r
7421 ChessMove moveType;
\r
7422 int fromX, fromY, toX, toY;
\r
7425 switch (message) {
\r
7426 case WM_INITDIALOG:
\r
7427 move[0] = (char) lParam;
\r
7428 move[1] = NULLCHAR;
\r
7429 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7430 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7431 SetWindowText(hInput, move);
\r
7433 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7437 switch (LOWORD(wParam)) {
\r
7439 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7440 { int n; Board board;
\r
7442 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7443 EditPositionPasteFEN(move);
\r
7444 EndDialog(hDlg, TRUE);
\r
7447 // [HGM] movenum: allow move number to be typed in any mode
\r
7448 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7449 currentMove = 2*n-1;
\r
7450 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7451 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7452 EndDialog(hDlg, TRUE);
\r
7453 DrawPosition(TRUE, boards[currentMove]);
\r
7454 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7455 else DisplayMessage("", "");
\r
7459 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7460 gameMode != Training) {
\r
7461 DisplayMoveError("Displayed move is not current");
\r
7463 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7464 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7465 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7466 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7467 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7468 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7469 if (gameMode != Training)
\r
7470 forwardMostMove = currentMove;
\r
7471 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7473 DisplayMoveError("Could not parse move");
\r
7476 EndDialog(hDlg, TRUE);
\r
7479 EndDialog(hDlg, FALSE);
\r
7490 PopUpMoveDialog(char firstchar)
\r
7494 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7495 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7496 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7497 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7498 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7499 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7500 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7501 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7502 gameMode == Training) {
\r
7503 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7504 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7505 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7506 FreeProcInstance(lpProc);
\r
7510 /*---------------------------------------------------------------------------*\
\r
7512 * Type-in name dialog functions
\r
7514 \*---------------------------------------------------------------------------*/
\r
7517 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7519 char move[MSG_SIZ];
\r
7522 switch (message) {
\r
7523 case WM_INITDIALOG:
\r
7524 move[0] = (char) lParam;
\r
7525 move[1] = NULLCHAR;
\r
7526 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7527 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7528 SetWindowText(hInput, move);
\r
7530 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7534 switch (LOWORD(wParam)) {
\r
7536 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7537 appData.userName = strdup(move);
\r
7540 EndDialog(hDlg, TRUE);
\r
7543 EndDialog(hDlg, FALSE);
\r
7554 PopUpNameDialog(char firstchar)
\r
7558 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7559 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7560 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7561 FreeProcInstance(lpProc);
\r
7564 /*---------------------------------------------------------------------------*\
\r
7568 \*---------------------------------------------------------------------------*/
\r
7570 /* Nonmodal error box */
\r
7571 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7572 WPARAM wParam, LPARAM lParam);
\r
7575 ErrorPopUp(char *title, char *content)
\r
7579 BOOLEAN modal = hwndMain == NULL;
\r
7597 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7598 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7601 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7603 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7604 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7605 hwndMain, (DLGPROC)lpProc);
\r
7606 FreeProcInstance(lpProc);
\r
7613 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7614 if (errorDialog == NULL) return;
\r
7615 DestroyWindow(errorDialog);
\r
7616 errorDialog = NULL;
\r
7620 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7625 switch (message) {
\r
7626 case WM_INITDIALOG:
\r
7627 GetWindowRect(hDlg, &rChild);
\r
7630 SetWindowPos(hDlg, NULL, rChild.left,
\r
7631 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7632 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7636 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7637 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7638 and it doesn't work when you resize the dialog.
\r
7639 For now, just give it a default position.
\r
7641 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7643 errorDialog = hDlg;
\r
7644 SetWindowText(hDlg, errorTitle);
\r
7645 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7646 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7650 switch (LOWORD(wParam)) {
\r
7653 if (errorDialog == hDlg) errorDialog = NULL;
\r
7654 DestroyWindow(hDlg);
\r
7666 HWND gothicDialog = NULL;
\r
7669 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7673 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7675 switch (message) {
\r
7676 case WM_INITDIALOG:
\r
7677 GetWindowRect(hDlg, &rChild);
\r
7679 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7683 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7684 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7685 and it doesn't work when you resize the dialog.
\r
7686 For now, just give it a default position.
\r
7688 gothicDialog = hDlg;
\r
7689 SetWindowText(hDlg, errorTitle);
\r
7690 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7691 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7695 switch (LOWORD(wParam)) {
\r
7698 if (errorDialog == hDlg) errorDialog = NULL;
\r
7699 DestroyWindow(hDlg);
\r
7711 GothicPopUp(char *title, VariantClass variant)
\r
7714 static char *lastTitle;
\r
7716 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7717 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7719 if(lastTitle != title && gothicDialog != NULL) {
\r
7720 DestroyWindow(gothicDialog);
\r
7721 gothicDialog = NULL;
\r
7723 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7724 title = lastTitle;
\r
7725 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7726 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7727 hwndMain, (DLGPROC)lpProc);
\r
7728 FreeProcInstance(lpProc);
\r
7733 /*---------------------------------------------------------------------------*\
\r
7735 * Ics Interaction console functions
\r
7737 \*---------------------------------------------------------------------------*/
\r
7739 #define HISTORY_SIZE 64
\r
7740 static char *history[HISTORY_SIZE];
\r
7741 int histIn = 0, histP = 0;
\r
7744 SaveInHistory(char *cmd)
\r
7746 if (history[histIn] != NULL) {
\r
7747 free(history[histIn]);
\r
7748 history[histIn] = NULL;
\r
7750 if (*cmd == NULLCHAR) return;
\r
7751 history[histIn] = StrSave(cmd);
\r
7752 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7753 if (history[histIn] != NULL) {
\r
7754 free(history[histIn]);
\r
7755 history[histIn] = NULL;
\r
7761 PrevInHistory(char *cmd)
\r
7764 if (histP == histIn) {
\r
7765 if (history[histIn] != NULL) free(history[histIn]);
\r
7766 history[histIn] = StrSave(cmd);
\r
7768 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7769 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7771 return history[histP];
\r
7777 if (histP == histIn) return NULL;
\r
7778 histP = (histP + 1) % HISTORY_SIZE;
\r
7779 return history[histP];
\r
7786 BOOLEAN immediate;
\r
7787 } IcsTextMenuEntry;
\r
7788 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7789 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7792 ParseIcsTextMenu(char *icsTextMenuString)
\r
7795 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7796 char *p = icsTextMenuString;
\r
7797 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7800 if (e->command != NULL) {
\r
7802 e->command = NULL;
\r
7806 e = icsTextMenuEntry;
\r
7807 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7808 if (*p == ';' || *p == '\n') {
\r
7809 e->item = strdup("-");
\r
7810 e->command = NULL;
\r
7812 } else if (*p == '-') {
\r
7813 e->item = strdup("-");
\r
7814 e->command = NULL;
\r
7818 char *q, *r, *s, *t;
\r
7820 q = strchr(p, ',');
\r
7821 if (q == NULL) break;
\r
7823 r = strchr(q + 1, ',');
\r
7824 if (r == NULL) break;
\r
7826 s = strchr(r + 1, ',');
\r
7827 if (s == NULL) break;
\r
7830 t = strchr(s + 1, c);
\r
7833 t = strchr(s + 1, c);
\r
7835 if (t != NULL) *t = NULLCHAR;
\r
7836 e->item = strdup(p);
\r
7837 e->command = strdup(q + 1);
\r
7838 e->getname = *(r + 1) != '0';
\r
7839 e->immediate = *(s + 1) != '0';
\r
7843 if (t == NULL) break;
\r
7852 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7856 hmenu = LoadMenu(hInst, "TextMenu");
\r
7857 h = GetSubMenu(hmenu, 0);
\r
7859 if (strcmp(e->item, "-") == 0) {
\r
7860 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7862 if (e->item[0] == '|') {
\r
7863 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7864 IDM_CommandX + i, &e->item[1]);
\r
7866 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7875 WNDPROC consoleTextWindowProc;
\r
7878 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7880 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7881 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7885 SetWindowText(hInput, command);
\r
7887 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7889 sel.cpMin = 999999;
\r
7890 sel.cpMax = 999999;
\r
7891 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7896 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7897 if (sel.cpMin == sel.cpMax) {
\r
7898 /* Expand to surrounding word */
\r
7901 tr.chrg.cpMax = sel.cpMin;
\r
7902 tr.chrg.cpMin = --sel.cpMin;
\r
7903 if (sel.cpMin < 0) break;
\r
7904 tr.lpstrText = name;
\r
7905 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7906 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7910 tr.chrg.cpMin = sel.cpMax;
\r
7911 tr.chrg.cpMax = ++sel.cpMax;
\r
7912 tr.lpstrText = name;
\r
7913 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7914 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7917 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7918 MessageBeep(MB_ICONEXCLAMATION);
\r
7922 tr.lpstrText = name;
\r
7923 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7925 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7926 MessageBeep(MB_ICONEXCLAMATION);
\r
7929 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7932 sprintf(buf, "%s %s", command, name);
\r
7933 SetWindowText(hInput, buf);
\r
7934 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7936 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7937 SetWindowText(hInput, buf);
\r
7938 sel.cpMin = 999999;
\r
7939 sel.cpMax = 999999;
\r
7940 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7946 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7951 switch (message) {
\r
7953 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7956 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7959 sel.cpMin = 999999;
\r
7960 sel.cpMax = 999999;
\r
7961 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7962 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7967 if(wParam != '\022') {
\r
7968 if (wParam == '\t') {
\r
7969 if (GetKeyState(VK_SHIFT) < 0) {
\r
7971 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7972 if (buttonDesc[0].hwnd) {
\r
7973 SetFocus(buttonDesc[0].hwnd);
\r
7975 SetFocus(hwndMain);
\r
7979 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7982 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7983 JAWS_DELETE( SetFocus(hInput); )
\r
7984 SendMessage(hInput, message, wParam, lParam);
\r
7987 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7988 case WM_RBUTTONUP:
\r
7989 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7990 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7991 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7994 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7995 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7996 if (sel.cpMin == sel.cpMax) {
\r
7997 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7998 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
8000 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8001 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8003 pt.x = LOWORD(lParam);
\r
8004 pt.y = HIWORD(lParam);
\r
8005 MenuPopup(hwnd, pt, hmenu, -1);
\r
8009 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8011 return SendMessage(hInput, message, wParam, lParam);
\r
8012 case WM_MBUTTONDOWN:
\r
8013 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8014 case WM_RBUTTONDOWN:
\r
8015 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
8016 /* Move selection here if it was empty */
\r
8018 pt.x = LOWORD(lParam);
\r
8019 pt.y = HIWORD(lParam);
\r
8020 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8021 if (sel.cpMin == sel.cpMax) {
\r
8022 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
8023 sel.cpMax = sel.cpMin;
\r
8024 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8026 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
8030 switch (LOWORD(wParam)) {
\r
8031 case IDM_QuickPaste:
\r
8033 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8034 if (sel.cpMin == sel.cpMax) {
\r
8035 MessageBeep(MB_ICONEXCLAMATION);
\r
8038 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8039 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8040 SendMessage(hInput, WM_PASTE, 0, 0);
\r
8045 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8048 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8051 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8055 int i = LOWORD(wParam) - IDM_CommandX;
\r
8056 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8057 icsTextMenuEntry[i].command != NULL) {
\r
8058 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8059 icsTextMenuEntry[i].getname,
\r
8060 icsTextMenuEntry[i].immediate);
\r
8068 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8071 WNDPROC consoleInputWindowProc;
\r
8074 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8076 char buf[MSG_SIZ];
\r
8078 static BOOL sendNextChar = FALSE;
\r
8079 static BOOL quoteNextChar = FALSE;
\r
8080 InputSource *is = consoleInputSource;
\r
8084 switch (message) {
\r
8086 if (!appData.localLineEditing || sendNextChar) {
\r
8087 is->buf[0] = (CHAR) wParam;
\r
8089 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8090 sendNextChar = FALSE;
\r
8093 if (quoteNextChar) {
\r
8094 buf[0] = (char) wParam;
\r
8095 buf[1] = NULLCHAR;
\r
8096 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8097 quoteNextChar = FALSE;
\r
8101 case '\r': /* Enter key */
\r
8102 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8103 if (consoleEcho) SaveInHistory(is->buf);
\r
8104 is->buf[is->count++] = '\n';
\r
8105 is->buf[is->count] = NULLCHAR;
\r
8106 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8107 if (consoleEcho) {
\r
8108 ConsoleOutput(is->buf, is->count, TRUE);
\r
8109 } else if (appData.localLineEditing) {
\r
8110 ConsoleOutput("\n", 1, TRUE);
\r
8113 case '\033': /* Escape key */
\r
8114 SetWindowText(hwnd, "");
\r
8115 cf.cbSize = sizeof(CHARFORMAT);
\r
8116 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8117 if (consoleEcho) {
\r
8118 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8120 cf.crTextColor = COLOR_ECHOOFF;
\r
8122 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8123 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8125 case '\t': /* Tab key */
\r
8126 if (GetKeyState(VK_SHIFT) < 0) {
\r
8128 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8131 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8132 if (buttonDesc[0].hwnd) {
\r
8133 SetFocus(buttonDesc[0].hwnd);
\r
8135 SetFocus(hwndMain);
\r
8139 case '\023': /* Ctrl+S */
\r
8140 sendNextChar = TRUE;
\r
8142 case '\021': /* Ctrl+Q */
\r
8143 quoteNextChar = TRUE;
\r
8153 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8154 p = PrevInHistory(buf);
\r
8156 SetWindowText(hwnd, p);
\r
8157 sel.cpMin = 999999;
\r
8158 sel.cpMax = 999999;
\r
8159 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8164 p = NextInHistory();
\r
8166 SetWindowText(hwnd, p);
\r
8167 sel.cpMin = 999999;
\r
8168 sel.cpMax = 999999;
\r
8169 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8175 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8179 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8183 case WM_MBUTTONDOWN:
\r
8184 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8185 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8187 case WM_RBUTTONUP:
\r
8188 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8189 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8190 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8194 hmenu = LoadMenu(hInst, "InputMenu");
\r
8195 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8196 if (sel.cpMin == sel.cpMax) {
\r
8197 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8198 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8200 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8201 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8203 pt.x = LOWORD(lParam);
\r
8204 pt.y = HIWORD(lParam);
\r
8205 MenuPopup(hwnd, pt, hmenu, -1);
\r
8209 switch (LOWORD(wParam)) {
\r
8211 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8213 case IDM_SelectAll:
\r
8215 sel.cpMax = -1; /*999999?*/
\r
8216 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8219 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8222 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8225 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8230 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8233 #define CO_MAX 100000
\r
8234 #define CO_TRIM 1000
\r
8237 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8239 static SnapData sd;
\r
8240 static HWND hText, hInput /*, hFocus*/;
\r
8241 // InputSource *is = consoleInputSource;
\r
8243 static int sizeX, sizeY;
\r
8244 int newSizeX, newSizeY;
\r
8247 switch (message) {
\r
8248 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8249 hwndConsole = hDlg;
\r
8250 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8251 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8253 consoleTextWindowProc = (WNDPROC)
\r
8254 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8255 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8256 consoleInputWindowProc = (WNDPROC)
\r
8257 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8258 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8259 Colorize(ColorNormal, TRUE);
\r
8260 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8261 ChangedConsoleFont();
\r
8262 GetClientRect(hDlg, &rect);
\r
8263 sizeX = rect.right;
\r
8264 sizeY = rect.bottom;
\r
8265 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8266 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8267 WINDOWPLACEMENT wp;
\r
8268 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8269 wp.length = sizeof(WINDOWPLACEMENT);
\r
8271 wp.showCmd = SW_SHOW;
\r
8272 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8273 wp.rcNormalPosition.left = wpConsole.x;
\r
8274 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8275 wp.rcNormalPosition.top = wpConsole.y;
\r
8276 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8277 SetWindowPlacement(hDlg, &wp);
\r
8280 // [HGM] Chessknight's change 2004-07-13
\r
8281 else { /* Determine Defaults */
\r
8282 WINDOWPLACEMENT wp;
\r
8283 wpConsole.x = winWidth + 1;
\r
8284 wpConsole.y = boardY;
\r
8285 wpConsole.width = screenWidth - winWidth;
\r
8286 wpConsole.height = winHeight;
\r
8287 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8288 wp.length = sizeof(WINDOWPLACEMENT);
\r
8290 wp.showCmd = SW_SHOW;
\r
8291 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8292 wp.rcNormalPosition.left = wpConsole.x;
\r
8293 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8294 wp.rcNormalPosition.top = wpConsole.y;
\r
8295 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8296 SetWindowPlacement(hDlg, &wp);
\r
8311 if (IsIconic(hDlg)) break;
\r
8312 newSizeX = LOWORD(lParam);
\r
8313 newSizeY = HIWORD(lParam);
\r
8314 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8315 RECT rectText, rectInput;
\r
8317 int newTextHeight, newTextWidth;
\r
8318 GetWindowRect(hText, &rectText);
\r
8319 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8320 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8321 if (newTextHeight < 0) {
\r
8322 newSizeY += -newTextHeight;
\r
8323 newTextHeight = 0;
\r
8325 SetWindowPos(hText, NULL, 0, 0,
\r
8326 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8327 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8328 pt.x = rectInput.left;
\r
8329 pt.y = rectInput.top + newSizeY - sizeY;
\r
8330 ScreenToClient(hDlg, &pt);
\r
8331 SetWindowPos(hInput, NULL,
\r
8332 pt.x, pt.y, /* needs client coords */
\r
8333 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8334 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8340 case WM_GETMINMAXINFO:
\r
8341 /* Prevent resizing window too small */
\r
8342 mmi = (MINMAXINFO *) lParam;
\r
8343 mmi->ptMinTrackSize.x = 100;
\r
8344 mmi->ptMinTrackSize.y = 100;
\r
8347 /* [AS] Snapping */
\r
8348 case WM_ENTERSIZEMOVE:
\r
8349 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8352 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8355 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8357 case WM_EXITSIZEMOVE:
\r
8358 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8361 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8369 if (hwndConsole) return;
\r
8370 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8371 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8376 ConsoleOutput(char* data, int length, int forceVisible)
\r
8381 char buf[CO_MAX+1];
\r
8384 static int delayLF = 0;
\r
8385 CHARRANGE savesel, sel;
\r
8387 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8395 while (length--) {
\r
8403 } else if (*p == '\007') {
\r
8404 MyPlaySound(&sounds[(int)SoundBell]);
\r
8411 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8412 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8413 /* Save current selection */
\r
8414 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8415 exlen = GetWindowTextLength(hText);
\r
8416 /* Find out whether current end of text is visible */
\r
8417 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8418 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8419 /* Trim existing text if it's too long */
\r
8420 if (exlen + (q - buf) > CO_MAX) {
\r
8421 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8424 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8425 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8427 savesel.cpMin -= trim;
\r
8428 savesel.cpMax -= trim;
\r
8429 if (exlen < 0) exlen = 0;
\r
8430 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8431 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8433 /* Append the new text */
\r
8434 sel.cpMin = exlen;
\r
8435 sel.cpMax = exlen;
\r
8436 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8437 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8438 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8439 if (forceVisible || exlen == 0 ||
\r
8440 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8441 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8442 /* Scroll to make new end of text visible if old end of text
\r
8443 was visible or new text is an echo of user typein */
\r
8444 sel.cpMin = 9999999;
\r
8445 sel.cpMax = 9999999;
\r
8446 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8447 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8448 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8449 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8451 if (savesel.cpMax == exlen || forceVisible) {
\r
8452 /* Move insert point to new end of text if it was at the old
\r
8453 end of text or if the new text is an echo of user typein */
\r
8454 sel.cpMin = 9999999;
\r
8455 sel.cpMax = 9999999;
\r
8456 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8458 /* Restore previous selection */
\r
8459 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8461 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8468 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8472 COLORREF oldFg, oldBg;
\r
8476 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8478 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8479 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8480 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8483 rect.right = x + squareSize;
\r
8485 rect.bottom = y + squareSize;
\r
8488 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8489 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8490 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8491 &rect, str, strlen(str), NULL);
\r
8493 (void) SetTextColor(hdc, oldFg);
\r
8494 (void) SetBkColor(hdc, oldBg);
\r
8495 (void) SelectObject(hdc, oldFont);
\r
8499 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8500 RECT *rect, char *color, char *flagFell)
\r
8504 COLORREF oldFg, oldBg;
\r
8507 if (appData.clockMode) {
\r
8509 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8511 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8518 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8519 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8521 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8522 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8524 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8528 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8529 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8530 rect, str, strlen(str), NULL);
\r
8531 if(logoHeight > 0 && appData.clockMode) {
\r
8533 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8534 r.top = rect->top + logoHeight/2;
\r
8535 r.left = rect->left;
\r
8536 r.right = rect->right;
\r
8537 r.bottom = rect->bottom;
\r
8538 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8539 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8540 &r, str, strlen(str), NULL);
\r
8542 (void) SetTextColor(hdc, oldFg);
\r
8543 (void) SetBkColor(hdc, oldBg);
\r
8544 (void) SelectObject(hdc, oldFont);
\r
8549 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8555 if( count <= 0 ) {
\r
8556 if (appData.debugMode) {
\r
8557 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8560 return ERROR_INVALID_USER_BUFFER;
\r
8563 ResetEvent(ovl->hEvent);
\r
8564 ovl->Offset = ovl->OffsetHigh = 0;
\r
8565 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8569 err = GetLastError();
\r
8570 if (err == ERROR_IO_PENDING) {
\r
8571 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8575 err = GetLastError();
\r
8582 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8587 ResetEvent(ovl->hEvent);
\r
8588 ovl->Offset = ovl->OffsetHigh = 0;
\r
8589 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8593 err = GetLastError();
\r
8594 if (err == ERROR_IO_PENDING) {
\r
8595 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8599 err = GetLastError();
\r
8605 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8606 void CheckForInputBufferFull( InputSource * is )
\r
8608 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8609 /* Look for end of line */
\r
8610 char * p = is->buf;
\r
8612 while( p < is->next && *p != '\n' ) {
\r
8616 if( p >= is->next ) {
\r
8617 if (appData.debugMode) {
\r
8618 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8621 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8622 is->count = (DWORD) -1;
\r
8623 is->next = is->buf;
\r
8629 InputThread(LPVOID arg)
\r
8634 is = (InputSource *) arg;
\r
8635 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8636 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8637 while (is->hThread != NULL) {
\r
8638 is->error = DoReadFile(is->hFile, is->next,
\r
8639 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8640 &is->count, &ovl);
\r
8641 if (is->error == NO_ERROR) {
\r
8642 is->next += is->count;
\r
8644 if (is->error == ERROR_BROKEN_PIPE) {
\r
8645 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8648 is->count = (DWORD) -1;
\r
8649 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8654 CheckForInputBufferFull( is );
\r
8656 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8658 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8660 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8663 CloseHandle(ovl.hEvent);
\r
8664 CloseHandle(is->hFile);
\r
8666 if (appData.debugMode) {
\r
8667 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8674 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8676 NonOvlInputThread(LPVOID arg)
\r
8683 is = (InputSource *) arg;
\r
8684 while (is->hThread != NULL) {
\r
8685 is->error = ReadFile(is->hFile, is->next,
\r
8686 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8687 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8688 if (is->error == NO_ERROR) {
\r
8689 /* Change CRLF to LF */
\r
8690 if (is->next > is->buf) {
\r
8692 i = is->count + 1;
\r
8700 if (prev == '\r' && *p == '\n') {
\r
8712 if (is->error == ERROR_BROKEN_PIPE) {
\r
8713 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8716 is->count = (DWORD) -1;
\r
8720 CheckForInputBufferFull( is );
\r
8722 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8724 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8726 if (is->count < 0) break; /* Quit on error */
\r
8728 CloseHandle(is->hFile);
\r
8733 SocketInputThread(LPVOID arg)
\r
8737 is = (InputSource *) arg;
\r
8738 while (is->hThread != NULL) {
\r
8739 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8740 if ((int)is->count == SOCKET_ERROR) {
\r
8741 is->count = (DWORD) -1;
\r
8742 is->error = WSAGetLastError();
\r
8744 is->error = NO_ERROR;
\r
8745 is->next += is->count;
\r
8746 if (is->count == 0 && is->second == is) {
\r
8747 /* End of file on stderr; quit with no message */
\r
8751 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8753 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8755 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8761 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8765 is = (InputSource *) lParam;
\r
8766 if (is->lineByLine) {
\r
8767 /* Feed in lines one by one */
\r
8768 char *p = is->buf;
\r
8770 while (q < is->next) {
\r
8771 if (*q++ == '\n') {
\r
8772 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8777 /* Move any partial line to the start of the buffer */
\r
8779 while (p < is->next) {
\r
8784 if (is->error != NO_ERROR || is->count == 0) {
\r
8785 /* Notify backend of the error. Note: If there was a partial
\r
8786 line at the end, it is not flushed through. */
\r
8787 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8790 /* Feed in the whole chunk of input at once */
\r
8791 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8792 is->next = is->buf;
\r
8796 /*---------------------------------------------------------------------------*\
\r
8798 * Menu enables. Used when setting various modes.
\r
8800 \*---------------------------------------------------------------------------*/
\r
8808 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8810 while (enab->item > 0) {
\r
8811 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8816 Enables gnuEnables[] = {
\r
8817 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8818 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8819 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8820 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8822 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8823 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8824 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8825 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8826 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8830 Enables icsEnables[] = {
\r
8831 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8832 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8833 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8834 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8835 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8836 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8837 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8838 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8839 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8840 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8841 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8842 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8847 Enables zippyEnables[] = {
\r
8848 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8849 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8850 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8855 Enables ncpEnables[] = {
\r
8856 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8857 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8858 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8859 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8860 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8861 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8862 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8863 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8864 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8865 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8866 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8867 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8868 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8869 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8870 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8874 Enables trainingOnEnables[] = {
\r
8875 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8876 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8877 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8878 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8879 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8880 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8881 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8882 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8886 Enables trainingOffEnables[] = {
\r
8887 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8888 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8889 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8890 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8891 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8892 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8893 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8894 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8898 /* These modify either ncpEnables or gnuEnables */
\r
8899 Enables cmailEnables[] = {
\r
8900 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8901 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8902 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8903 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8904 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8905 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8906 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8910 Enables machineThinkingEnables[] = {
\r
8911 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8912 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8913 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8914 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8915 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8916 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8917 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8918 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8919 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8920 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8921 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8922 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8923 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8924 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8925 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8929 Enables userThinkingEnables[] = {
\r
8930 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8931 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8932 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8933 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8934 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8935 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8936 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8937 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8938 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8939 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8940 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8941 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8942 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8943 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8944 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8948 /*---------------------------------------------------------------------------*\
\r
8950 * Front-end interface functions exported by XBoard.
\r
8951 * Functions appear in same order as prototypes in frontend.h.
\r
8953 \*---------------------------------------------------------------------------*/
\r
8957 static UINT prevChecked = 0;
\r
8958 static int prevPausing = 0;
\r
8961 if (pausing != prevPausing) {
\r
8962 prevPausing = pausing;
\r
8963 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8964 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8965 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8968 switch (gameMode) {
\r
8969 case BeginningOfGame:
\r
8970 if (appData.icsActive)
\r
8971 nowChecked = IDM_IcsClient;
\r
8972 else if (appData.noChessProgram)
\r
8973 nowChecked = IDM_EditGame;
\r
8975 nowChecked = IDM_MachineBlack;
\r
8977 case MachinePlaysBlack:
\r
8978 nowChecked = IDM_MachineBlack;
\r
8980 case MachinePlaysWhite:
\r
8981 nowChecked = IDM_MachineWhite;
\r
8983 case TwoMachinesPlay:
\r
8984 nowChecked = IDM_TwoMachines;
\r
8987 nowChecked = IDM_AnalysisMode;
\r
8990 nowChecked = IDM_AnalyzeFile;
\r
8993 nowChecked = IDM_EditGame;
\r
8995 case PlayFromGameFile:
\r
8996 nowChecked = IDM_LoadGame;
\r
8998 case EditPosition:
\r
8999 nowChecked = IDM_EditPosition;
\r
9002 nowChecked = IDM_Training;
\r
9004 case IcsPlayingWhite:
\r
9005 case IcsPlayingBlack:
\r
9006 case IcsObserving:
\r
9008 nowChecked = IDM_IcsClient;
\r
9015 if (prevChecked != 0)
\r
9016 (void) CheckMenuItem(GetMenu(hwndMain),
\r
9017 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
9018 if (nowChecked != 0)
\r
9019 (void) CheckMenuItem(GetMenu(hwndMain),
\r
9020 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
9022 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
9023 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
9024 MF_BYCOMMAND|MF_ENABLED);
\r
9026 (void) EnableMenuItem(GetMenu(hwndMain),
\r
9027 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
9030 prevChecked = nowChecked;
\r
9032 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
9033 if (appData.icsActive) {
\r
9034 if (appData.icsEngineAnalyze) {
\r
9035 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9036 MF_BYCOMMAND|MF_CHECKED);
\r
9038 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9039 MF_BYCOMMAND|MF_UNCHECKED);
\r
9047 HMENU hmenu = GetMenu(hwndMain);
\r
9048 SetMenuEnables(hmenu, icsEnables);
\r
9049 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9050 MF_BYPOSITION|MF_ENABLED);
\r
9052 if (appData.zippyPlay) {
\r
9053 SetMenuEnables(hmenu, zippyEnables);
\r
9054 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9055 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9056 MF_BYCOMMAND|MF_ENABLED);
\r
9064 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9070 HMENU hmenu = GetMenu(hwndMain);
\r
9071 SetMenuEnables(hmenu, ncpEnables);
\r
9072 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9073 MF_BYPOSITION|MF_GRAYED);
\r
9074 DrawMenuBar(hwndMain);
\r
9080 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9084 SetTrainingModeOn()
\r
9087 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9088 for (i = 0; i < N_BUTTONS; i++) {
\r
9089 if (buttonDesc[i].hwnd != NULL)
\r
9090 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9095 VOID SetTrainingModeOff()
\r
9098 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9099 for (i = 0; i < N_BUTTONS; i++) {
\r
9100 if (buttonDesc[i].hwnd != NULL)
\r
9101 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9107 SetUserThinkingEnables()
\r
9109 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9113 SetMachineThinkingEnables()
\r
9115 HMENU hMenu = GetMenu(hwndMain);
\r
9116 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9118 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9120 if (gameMode == MachinePlaysBlack) {
\r
9121 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9122 } else if (gameMode == MachinePlaysWhite) {
\r
9123 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9124 } else if (gameMode == TwoMachinesPlay) {
\r
9125 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9131 DisplayTitle(char *str)
\r
9133 char title[MSG_SIZ], *host;
\r
9134 if (str[0] != NULLCHAR) {
\r
9135 strcpy(title, str);
\r
9136 } else if (appData.icsActive) {
\r
9137 if (appData.icsCommPort[0] != NULLCHAR)
\r
9140 host = appData.icsHost;
\r
9141 sprintf(title, "%s: %s", szTitle, host);
\r
9142 } else if (appData.noChessProgram) {
\r
9143 strcpy(title, szTitle);
\r
9145 strcpy(title, szTitle);
\r
9146 strcat(title, ": ");
\r
9147 strcat(title, first.tidy);
\r
9149 SetWindowText(hwndMain, title);
\r
9154 DisplayMessage(char *str1, char *str2)
\r
9158 int remain = MESSAGE_TEXT_MAX - 1;
\r
9161 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9162 messageText[0] = NULLCHAR;
\r
9164 len = strlen(str1);
\r
9165 if (len > remain) len = remain;
\r
9166 strncpy(messageText, str1, len);
\r
9167 messageText[len] = NULLCHAR;
\r
9170 if (*str2 && remain >= 2) {
\r
9172 strcat(messageText, " ");
\r
9175 len = strlen(str2);
\r
9176 if (len > remain) len = remain;
\r
9177 strncat(messageText, str2, len);
\r
9179 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9181 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9185 hdc = GetDC(hwndMain);
\r
9186 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9187 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9188 &messageRect, messageText, strlen(messageText), NULL);
\r
9189 (void) SelectObject(hdc, oldFont);
\r
9190 (void) ReleaseDC(hwndMain, hdc);
\r
9194 DisplayError(char *str, int error)
\r
9196 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9202 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9203 NULL, error, LANG_NEUTRAL,
\r
9204 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9206 sprintf(buf, "%s:\n%s", str, buf2);
\r
9208 ErrorMap *em = errmap;
\r
9209 while (em->err != 0 && em->err != error) em++;
\r
9210 if (em->err != 0) {
\r
9211 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9213 sprintf(buf, "%s:\nError code %d", str, error);
\r
9218 ErrorPopUp("Error", buf);
\r
9223 DisplayMoveError(char *str)
\r
9225 fromX = fromY = -1;
\r
9226 ClearHighlights();
\r
9227 DrawPosition(FALSE, NULL);
\r
9228 if (appData.popupMoveErrors) {
\r
9229 ErrorPopUp("Error", str);
\r
9231 DisplayMessage(str, "");
\r
9232 moveErrorMessageUp = TRUE;
\r
9237 DisplayFatalError(char *str, int error, int exitStatus)
\r
9239 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9241 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9244 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9245 NULL, error, LANG_NEUTRAL,
\r
9246 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9248 sprintf(buf, "%s:\n%s", str, buf2);
\r
9250 ErrorMap *em = errmap;
\r
9251 while (em->err != 0 && em->err != error) em++;
\r
9252 if (em->err != 0) {
\r
9253 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9255 sprintf(buf, "%s:\nError code %d", str, error);
\r
9260 if (appData.debugMode) {
\r
9261 fprintf(debugFP, "%s: %s\n", label, str);
\r
9263 if (appData.popupExitMessage) {
\r
9264 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9265 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9267 ExitEvent(exitStatus);
\r
9272 DisplayInformation(char *str)
\r
9274 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9279 DisplayNote(char *str)
\r
9281 ErrorPopUp("Note", str);
\r
9286 char *title, *question, *replyPrefix;
\r
9291 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9293 static QuestionParams *qp;
\r
9294 char reply[MSG_SIZ];
\r
9297 switch (message) {
\r
9298 case WM_INITDIALOG:
\r
9299 qp = (QuestionParams *) lParam;
\r
9300 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9301 SetWindowText(hDlg, qp->title);
\r
9302 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9303 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9307 switch (LOWORD(wParam)) {
\r
9309 strcpy(reply, qp->replyPrefix);
\r
9310 if (*reply) strcat(reply, " ");
\r
9311 len = strlen(reply);
\r
9312 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9313 strcat(reply, "\n");
\r
9314 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9315 EndDialog(hDlg, TRUE);
\r
9316 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9319 EndDialog(hDlg, FALSE);
\r
9330 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9332 QuestionParams qp;
\r
9336 qp.question = question;
\r
9337 qp.replyPrefix = replyPrefix;
\r
9339 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9340 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9341 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9342 FreeProcInstance(lpProc);
\r
9345 /* [AS] Pick FRC position */
\r
9346 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9348 static int * lpIndexFRC;
\r
9354 case WM_INITDIALOG:
\r
9355 lpIndexFRC = (int *) lParam;
\r
9357 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9359 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9360 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9361 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9362 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9367 switch( LOWORD(wParam) ) {
\r
9369 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9370 EndDialog( hDlg, 0 );
\r
9371 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9374 EndDialog( hDlg, 1 );
\r
9376 case IDC_NFG_Edit:
\r
9377 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9378 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9380 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9383 case IDC_NFG_Random:
\r
9384 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9385 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9398 int index = appData.defaultFrcPosition;
\r
9399 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9401 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9403 if( result == 0 ) {
\r
9404 appData.defaultFrcPosition = index;
\r
9410 /* [AS] Game list options */
\r
9416 static GLT_Item GLT_ItemInfo[] = {
\r
9417 { GLT_EVENT, "Event" },
\r
9418 { GLT_SITE, "Site" },
\r
9419 { GLT_DATE, "Date" },
\r
9420 { GLT_ROUND, "Round" },
\r
9421 { GLT_PLAYERS, "Players" },
\r
9422 { GLT_RESULT, "Result" },
\r
9423 { GLT_WHITE_ELO, "White Rating" },
\r
9424 { GLT_BLACK_ELO, "Black Rating" },
\r
9425 { GLT_TIME_CONTROL,"Time Control" },
\r
9426 { GLT_VARIANT, "Variant" },
\r
9427 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9428 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9432 const char * GLT_FindItem( char id )
\r
9434 const char * result = 0;
\r
9436 GLT_Item * list = GLT_ItemInfo;
\r
9438 while( list->id != 0 ) {
\r
9439 if( list->id == id ) {
\r
9440 result = list->name;
\r
9450 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9452 const char * name = GLT_FindItem( id );
\r
9455 if( index >= 0 ) {
\r
9456 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9459 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9464 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9468 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9471 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9475 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9477 pc = GLT_ALL_TAGS;
\r
9480 if( strchr( tags, *pc ) == 0 ) {
\r
9481 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9486 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9489 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9491 char result = '\0';
\r
9494 GLT_Item * list = GLT_ItemInfo;
\r
9496 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9497 while( list->id != 0 ) {
\r
9498 if( strcmp( list->name, name ) == 0 ) {
\r
9499 result = list->id;
\r
9510 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9512 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9513 int idx2 = idx1 + delta;
\r
9514 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9516 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9519 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9520 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9521 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9522 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9526 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9528 static char glt[64];
\r
9529 static char * lpUserGLT;
\r
9533 case WM_INITDIALOG:
\r
9534 lpUserGLT = (char *) lParam;
\r
9536 strcpy( glt, lpUserGLT );
\r
9538 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9540 /* Initialize list */
\r
9541 GLT_TagsToList( hDlg, glt );
\r
9543 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9548 switch( LOWORD(wParam) ) {
\r
9551 char * pc = lpUserGLT;
\r
9553 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9557 id = GLT_ListItemToTag( hDlg, idx );
\r
9561 } while( id != '\0' );
\r
9563 EndDialog( hDlg, 0 );
\r
9566 EndDialog( hDlg, 1 );
\r
9569 case IDC_GLT_Default:
\r
9570 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9571 GLT_TagsToList( hDlg, glt );
\r
9574 case IDC_GLT_Restore:
\r
9575 strcpy( glt, lpUserGLT );
\r
9576 GLT_TagsToList( hDlg, glt );
\r
9580 GLT_MoveSelection( hDlg, -1 );
\r
9583 case IDC_GLT_Down:
\r
9584 GLT_MoveSelection( hDlg, +1 );
\r
9594 int GameListOptions()
\r
9598 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9600 strcpy( glt, appData.gameListTags );
\r
9602 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9604 if( result == 0 ) {
\r
9605 /* [AS] Memory leak here! */
\r
9606 appData.gameListTags = strdup( glt );
\r
9614 DisplayIcsInteractionTitle(char *str)
\r
9616 char consoleTitle[MSG_SIZ];
\r
9618 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9619 SetWindowText(hwndConsole, consoleTitle);
\r
9623 DrawPosition(int fullRedraw, Board board)
\r
9625 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9632 fromX = fromY = -1;
\r
9633 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9634 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9635 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9636 dragInfo.lastpos = dragInfo.pos;
\r
9637 dragInfo.start.x = dragInfo.start.y = -1;
\r
9638 dragInfo.from = dragInfo.start;
\r
9640 DrawPosition(TRUE, NULL);
\r
9646 CommentPopUp(char *title, char *str)
\r
9648 HWND hwnd = GetActiveWindow();
\r
9649 EitherCommentPopUp(0, title, str, FALSE);
\r
9651 SetActiveWindow(hwnd);
\r
9655 CommentPopDown(void)
\r
9657 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9658 if (commentDialog) {
\r
9659 ShowWindow(commentDialog, SW_HIDE);
\r
9661 commentDialogUp = FALSE;
\r
9665 EditCommentPopUp(int index, char *title, char *str)
\r
9667 EitherCommentPopUp(index, title, str, TRUE);
\r
9674 MyPlaySound(&sounds[(int)SoundMove]);
\r
9677 VOID PlayIcsWinSound()
\r
9679 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9682 VOID PlayIcsLossSound()
\r
9684 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9687 VOID PlayIcsDrawSound()
\r
9689 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9692 VOID PlayIcsUnfinishedSound()
\r
9694 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9700 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9708 consoleEcho = TRUE;
\r
9709 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9710 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9711 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9720 consoleEcho = FALSE;
\r
9721 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9722 /* This works OK: set text and background both to the same color */
\r
9724 cf.crTextColor = COLOR_ECHOOFF;
\r
9725 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9726 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9729 /* No Raw()...? */
\r
9731 void Colorize(ColorClass cc, int continuation)
\r
9733 currentColorClass = cc;
\r
9734 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9735 consoleCF.crTextColor = textAttribs[cc].color;
\r
9736 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9737 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9743 static char buf[MSG_SIZ];
\r
9744 DWORD bufsiz = MSG_SIZ;
\r
9746 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9747 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9749 if (!GetUserName(buf, &bufsiz)) {
\r
9750 /*DisplayError("Error getting user name", GetLastError());*/
\r
9751 strcpy(buf, "User");
\r
9759 static char buf[MSG_SIZ];
\r
9760 DWORD bufsiz = MSG_SIZ;
\r
9762 if (!GetComputerName(buf, &bufsiz)) {
\r
9763 /*DisplayError("Error getting host name", GetLastError());*/
\r
9764 strcpy(buf, "Unknown");
\r
9771 ClockTimerRunning()
\r
9773 return clockTimerEvent != 0;
\r
9779 if (clockTimerEvent == 0) return FALSE;
\r
9780 KillTimer(hwndMain, clockTimerEvent);
\r
9781 clockTimerEvent = 0;
\r
9786 StartClockTimer(long millisec)
\r
9788 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9789 (UINT) millisec, NULL);
\r
9793 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9796 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9798 if(appData.noGUI) return;
\r
9799 hdc = GetDC(hwndMain);
\r
9800 if (!IsIconic(hwndMain)) {
\r
9801 DisplayAClock(hdc, timeRemaining, highlight,
\r
9802 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9804 if (highlight && iconCurrent == iconBlack) {
\r
9805 iconCurrent = iconWhite;
\r
9806 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9807 if (IsIconic(hwndMain)) {
\r
9808 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9811 (void) ReleaseDC(hwndMain, hdc);
\r
9813 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9817 DisplayBlackClock(long timeRemaining, int highlight)
\r
9820 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9822 if(appData.noGUI) return;
\r
9823 hdc = GetDC(hwndMain);
\r
9824 if (!IsIconic(hwndMain)) {
\r
9825 DisplayAClock(hdc, timeRemaining, highlight,
\r
9826 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9828 if (highlight && iconCurrent == iconWhite) {
\r
9829 iconCurrent = iconBlack;
\r
9830 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9831 if (IsIconic(hwndMain)) {
\r
9832 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9835 (void) ReleaseDC(hwndMain, hdc);
\r
9837 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9842 LoadGameTimerRunning()
\r
9844 return loadGameTimerEvent != 0;
\r
9848 StopLoadGameTimer()
\r
9850 if (loadGameTimerEvent == 0) return FALSE;
\r
9851 KillTimer(hwndMain, loadGameTimerEvent);
\r
9852 loadGameTimerEvent = 0;
\r
9857 StartLoadGameTimer(long millisec)
\r
9859 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9860 (UINT) millisec, NULL);
\r
9868 char fileTitle[MSG_SIZ];
\r
9870 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9871 f = OpenFileDialog(hwndMain, "a", defName,
\r
9872 appData.oldSaveStyle ? "gam" : "pgn",
\r
9874 "Save Game to File", NULL, fileTitle, NULL);
\r
9876 SaveGame(f, 0, "");
\r
9883 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9885 if (delayedTimerEvent != 0) {
\r
9886 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9887 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9889 KillTimer(hwndMain, delayedTimerEvent);
\r
9890 delayedTimerEvent = 0;
\r
9891 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9892 delayedTimerCallback();
\r
9894 delayedTimerCallback = cb;
\r
9895 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9896 (UINT) millisec, NULL);
\r
9899 DelayedEventCallback
\r
9902 if (delayedTimerEvent) {
\r
9903 return delayedTimerCallback;
\r
9910 CancelDelayedEvent()
\r
9912 if (delayedTimerEvent) {
\r
9913 KillTimer(hwndMain, delayedTimerEvent);
\r
9914 delayedTimerEvent = 0;
\r
9918 DWORD GetWin32Priority(int nice)
\r
9919 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9921 REALTIME_PRIORITY_CLASS 0x00000100
\r
9922 HIGH_PRIORITY_CLASS 0x00000080
\r
9923 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9924 NORMAL_PRIORITY_CLASS 0x00000020
\r
9925 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9926 IDLE_PRIORITY_CLASS 0x00000040
\r
9928 if (nice < -15) return 0x00000080;
\r
9929 if (nice < 0) return 0x00008000;
\r
9930 if (nice == 0) return 0x00000020;
\r
9931 if (nice < 15) return 0x00004000;
\r
9932 return 0x00000040;
\r
9935 /* Start a child process running the given program.
\r
9936 The process's standard output can be read from "from", and its
\r
9937 standard input can be written to "to".
\r
9938 Exit with fatal error if anything goes wrong.
\r
9939 Returns an opaque pointer that can be used to destroy the process
\r
9943 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9945 #define BUFSIZE 4096
\r
9947 HANDLE hChildStdinRd, hChildStdinWr,
\r
9948 hChildStdoutRd, hChildStdoutWr;
\r
9949 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9950 SECURITY_ATTRIBUTES saAttr;
\r
9952 PROCESS_INFORMATION piProcInfo;
\r
9953 STARTUPINFO siStartInfo;
\r
9955 char buf[MSG_SIZ];
\r
9958 if (appData.debugMode) {
\r
9959 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9964 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9965 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9966 saAttr.bInheritHandle = TRUE;
\r
9967 saAttr.lpSecurityDescriptor = NULL;
\r
9970 * The steps for redirecting child's STDOUT:
\r
9971 * 1. Create anonymous pipe to be STDOUT for child.
\r
9972 * 2. Create a noninheritable duplicate of read handle,
\r
9973 * and close the inheritable read handle.
\r
9976 /* Create a pipe for the child's STDOUT. */
\r
9977 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9978 return GetLastError();
\r
9981 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9982 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9983 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9984 FALSE, /* not inherited */
\r
9985 DUPLICATE_SAME_ACCESS);
\r
9987 return GetLastError();
\r
9989 CloseHandle(hChildStdoutRd);
\r
9992 * The steps for redirecting child's STDIN:
\r
9993 * 1. Create anonymous pipe to be STDIN for child.
\r
9994 * 2. Create a noninheritable duplicate of write handle,
\r
9995 * and close the inheritable write handle.
\r
9998 /* Create a pipe for the child's STDIN. */
\r
9999 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
10000 return GetLastError();
\r
10003 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
10004 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
10005 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
10006 FALSE, /* not inherited */
\r
10007 DUPLICATE_SAME_ACCESS);
\r
10008 if (! fSuccess) {
\r
10009 return GetLastError();
\r
10011 CloseHandle(hChildStdinWr);
\r
10013 /* Arrange to (1) look in dir for the child .exe file, and
\r
10014 * (2) have dir be the child's working directory. Interpret
\r
10015 * dir relative to the directory WinBoard loaded from. */
\r
10016 GetCurrentDirectory(MSG_SIZ, buf);
\r
10017 SetCurrentDirectory(installDir);
\r
10018 SetCurrentDirectory(dir);
\r
10020 /* Now create the child process. */
\r
10022 siStartInfo.cb = sizeof(STARTUPINFO);
\r
10023 siStartInfo.lpReserved = NULL;
\r
10024 siStartInfo.lpDesktop = NULL;
\r
10025 siStartInfo.lpTitle = NULL;
\r
10026 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
10027 siStartInfo.cbReserved2 = 0;
\r
10028 siStartInfo.lpReserved2 = NULL;
\r
10029 siStartInfo.hStdInput = hChildStdinRd;
\r
10030 siStartInfo.hStdOutput = hChildStdoutWr;
\r
10031 siStartInfo.hStdError = hChildStdoutWr;
\r
10033 fSuccess = CreateProcess(NULL,
\r
10034 cmdLine, /* command line */
\r
10035 NULL, /* process security attributes */
\r
10036 NULL, /* primary thread security attrs */
\r
10037 TRUE, /* handles are inherited */
\r
10038 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
10039 NULL, /* use parent's environment */
\r
10041 &siStartInfo, /* STARTUPINFO pointer */
\r
10042 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
10044 err = GetLastError();
\r
10045 SetCurrentDirectory(buf); /* return to prev directory */
\r
10046 if (! fSuccess) {
\r
10050 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10051 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10052 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10055 /* Close the handles we don't need in the parent */
\r
10056 CloseHandle(piProcInfo.hThread);
\r
10057 CloseHandle(hChildStdinRd);
\r
10058 CloseHandle(hChildStdoutWr);
\r
10060 /* Prepare return value */
\r
10061 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10062 cp->kind = CPReal;
\r
10063 cp->hProcess = piProcInfo.hProcess;
\r
10064 cp->pid = piProcInfo.dwProcessId;
\r
10065 cp->hFrom = hChildStdoutRdDup;
\r
10066 cp->hTo = hChildStdinWrDup;
\r
10068 *pr = (void *) cp;
\r
10070 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10071 2000 where engines sometimes don't see the initial command(s)
\r
10072 from WinBoard and hang. I don't understand how that can happen,
\r
10073 but the Sleep is harmless, so I've put it in. Others have also
\r
10074 reported what may be the same problem, so hopefully this will fix
\r
10075 it for them too. */
\r
10083 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10085 ChildProc *cp; int result;
\r
10087 cp = (ChildProc *) pr;
\r
10088 if (cp == NULL) return;
\r
10090 switch (cp->kind) {
\r
10092 /* TerminateProcess is considered harmful, so... */
\r
10093 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10094 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10095 /* The following doesn't work because the chess program
\r
10096 doesn't "have the same console" as WinBoard. Maybe
\r
10097 we could arrange for this even though neither WinBoard
\r
10098 nor the chess program uses a console for stdio? */
\r
10099 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10101 /* [AS] Special termination modes for misbehaving programs... */
\r
10102 if( signal == 9 ) {
\r
10103 result = TerminateProcess( cp->hProcess, 0 );
\r
10105 if ( appData.debugMode) {
\r
10106 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10109 else if( signal == 10 ) {
\r
10110 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10112 if( dw != WAIT_OBJECT_0 ) {
\r
10113 result = TerminateProcess( cp->hProcess, 0 );
\r
10115 if ( appData.debugMode) {
\r
10116 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10122 CloseHandle(cp->hProcess);
\r
10126 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10130 closesocket(cp->sock);
\r
10135 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10136 closesocket(cp->sock);
\r
10137 closesocket(cp->sock2);
\r
10145 InterruptChildProcess(ProcRef pr)
\r
10149 cp = (ChildProc *) pr;
\r
10150 if (cp == NULL) return;
\r
10151 switch (cp->kind) {
\r
10153 /* The following doesn't work because the chess program
\r
10154 doesn't "have the same console" as WinBoard. Maybe
\r
10155 we could arrange for this even though neither WinBoard
\r
10156 nor the chess program uses a console for stdio */
\r
10157 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10162 /* Can't interrupt */
\r
10166 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10173 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10175 char cmdLine[MSG_SIZ];
\r
10177 if (port[0] == NULLCHAR) {
\r
10178 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10180 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10182 return StartChildProcess(cmdLine, "", pr);
\r
10186 /* Code to open TCP sockets */
\r
10189 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10194 struct sockaddr_in sa, mysa;
\r
10195 struct hostent FAR *hp;
\r
10196 unsigned short uport;
\r
10197 WORD wVersionRequested;
\r
10200 /* Initialize socket DLL */
\r
10201 wVersionRequested = MAKEWORD(1, 1);
\r
10202 err = WSAStartup(wVersionRequested, &wsaData);
\r
10203 if (err != 0) return err;
\r
10205 /* Make socket */
\r
10206 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10207 err = WSAGetLastError();
\r
10212 /* Bind local address using (mostly) don't-care values.
\r
10214 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10215 mysa.sin_family = AF_INET;
\r
10216 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10217 uport = (unsigned short) 0;
\r
10218 mysa.sin_port = htons(uport);
\r
10219 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10220 == SOCKET_ERROR) {
\r
10221 err = WSAGetLastError();
\r
10226 /* Resolve remote host name */
\r
10227 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10228 if (!(hp = gethostbyname(host))) {
\r
10229 unsigned int b0, b1, b2, b3;
\r
10231 err = WSAGetLastError();
\r
10233 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10234 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10235 hp->h_addrtype = AF_INET;
\r
10236 hp->h_length = 4;
\r
10237 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10238 hp->h_addr_list[0] = (char *) malloc(4);
\r
10239 hp->h_addr_list[0][0] = (char) b0;
\r
10240 hp->h_addr_list[0][1] = (char) b1;
\r
10241 hp->h_addr_list[0][2] = (char) b2;
\r
10242 hp->h_addr_list[0][3] = (char) b3;
\r
10248 sa.sin_family = hp->h_addrtype;
\r
10249 uport = (unsigned short) atoi(port);
\r
10250 sa.sin_port = htons(uport);
\r
10251 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10253 /* Make connection */
\r
10254 if (connect(s, (struct sockaddr *) &sa,
\r
10255 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10256 err = WSAGetLastError();
\r
10261 /* Prepare return value */
\r
10262 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10263 cp->kind = CPSock;
\r
10265 *pr = (ProcRef *) cp;
\r
10271 OpenCommPort(char *name, ProcRef *pr)
\r
10276 char fullname[MSG_SIZ];
\r
10278 if (*name != '\\')
\r
10279 sprintf(fullname, "\\\\.\\%s", name);
\r
10281 strcpy(fullname, name);
\r
10283 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10284 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10285 if (h == (HANDLE) -1) {
\r
10286 return GetLastError();
\r
10290 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10292 /* Accumulate characters until a 100ms pause, then parse */
\r
10293 ct.ReadIntervalTimeout = 100;
\r
10294 ct.ReadTotalTimeoutMultiplier = 0;
\r
10295 ct.ReadTotalTimeoutConstant = 0;
\r
10296 ct.WriteTotalTimeoutMultiplier = 0;
\r
10297 ct.WriteTotalTimeoutConstant = 0;
\r
10298 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10300 /* Prepare return value */
\r
10301 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10302 cp->kind = CPComm;
\r
10305 *pr = (ProcRef *) cp;
\r
10311 OpenLoopback(ProcRef *pr)
\r
10313 DisplayFatalError("Not implemented", 0, 1);
\r
10319 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10323 SOCKET s, s2, s3;
\r
10324 struct sockaddr_in sa, mysa;
\r
10325 struct hostent FAR *hp;
\r
10326 unsigned short uport;
\r
10327 WORD wVersionRequested;
\r
10330 char stderrPortStr[MSG_SIZ];
\r
10332 /* Initialize socket DLL */
\r
10333 wVersionRequested = MAKEWORD(1, 1);
\r
10334 err = WSAStartup(wVersionRequested, &wsaData);
\r
10335 if (err != 0) return err;
\r
10337 /* Resolve remote host name */
\r
10338 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10339 if (!(hp = gethostbyname(host))) {
\r
10340 unsigned int b0, b1, b2, b3;
\r
10342 err = WSAGetLastError();
\r
10344 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10345 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10346 hp->h_addrtype = AF_INET;
\r
10347 hp->h_length = 4;
\r
10348 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10349 hp->h_addr_list[0] = (char *) malloc(4);
\r
10350 hp->h_addr_list[0][0] = (char) b0;
\r
10351 hp->h_addr_list[0][1] = (char) b1;
\r
10352 hp->h_addr_list[0][2] = (char) b2;
\r
10353 hp->h_addr_list[0][3] = (char) b3;
\r
10359 sa.sin_family = hp->h_addrtype;
\r
10360 uport = (unsigned short) 514;
\r
10361 sa.sin_port = htons(uport);
\r
10362 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10364 /* Bind local socket to unused "privileged" port address
\r
10366 s = INVALID_SOCKET;
\r
10367 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10368 mysa.sin_family = AF_INET;
\r
10369 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10370 for (fromPort = 1023;; fromPort--) {
\r
10371 if (fromPort < 0) {
\r
10373 return WSAEADDRINUSE;
\r
10375 if (s == INVALID_SOCKET) {
\r
10376 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10377 err = WSAGetLastError();
\r
10382 uport = (unsigned short) fromPort;
\r
10383 mysa.sin_port = htons(uport);
\r
10384 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10385 == SOCKET_ERROR) {
\r
10386 err = WSAGetLastError();
\r
10387 if (err == WSAEADDRINUSE) continue;
\r
10391 if (connect(s, (struct sockaddr *) &sa,
\r
10392 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10393 err = WSAGetLastError();
\r
10394 if (err == WSAEADDRINUSE) {
\r
10405 /* Bind stderr local socket to unused "privileged" port address
\r
10407 s2 = INVALID_SOCKET;
\r
10408 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10409 mysa.sin_family = AF_INET;
\r
10410 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10411 for (fromPort = 1023;; fromPort--) {
\r
10412 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10413 if (fromPort < 0) {
\r
10414 (void) closesocket(s);
\r
10416 return WSAEADDRINUSE;
\r
10418 if (s2 == INVALID_SOCKET) {
\r
10419 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10420 err = WSAGetLastError();
\r
10426 uport = (unsigned short) fromPort;
\r
10427 mysa.sin_port = htons(uport);
\r
10428 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10429 == SOCKET_ERROR) {
\r
10430 err = WSAGetLastError();
\r
10431 if (err == WSAEADDRINUSE) continue;
\r
10432 (void) closesocket(s);
\r
10436 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10437 err = WSAGetLastError();
\r
10438 if (err == WSAEADDRINUSE) {
\r
10440 s2 = INVALID_SOCKET;
\r
10443 (void) closesocket(s);
\r
10444 (void) closesocket(s2);
\r
10450 prevStderrPort = fromPort; // remember port used
\r
10451 sprintf(stderrPortStr, "%d", fromPort);
\r
10453 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10454 err = WSAGetLastError();
\r
10455 (void) closesocket(s);
\r
10456 (void) closesocket(s2);
\r
10461 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10462 err = WSAGetLastError();
\r
10463 (void) closesocket(s);
\r
10464 (void) closesocket(s2);
\r
10468 if (*user == NULLCHAR) user = UserName();
\r
10469 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10470 err = WSAGetLastError();
\r
10471 (void) closesocket(s);
\r
10472 (void) closesocket(s2);
\r
10476 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10477 err = WSAGetLastError();
\r
10478 (void) closesocket(s);
\r
10479 (void) closesocket(s2);
\r
10484 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10485 err = WSAGetLastError();
\r
10486 (void) closesocket(s);
\r
10487 (void) closesocket(s2);
\r
10491 (void) closesocket(s2); /* Stop listening */
\r
10493 /* Prepare return value */
\r
10494 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10495 cp->kind = CPRcmd;
\r
10498 *pr = (ProcRef *) cp;
\r
10505 AddInputSource(ProcRef pr, int lineByLine,
\r
10506 InputCallback func, VOIDSTAR closure)
\r
10508 InputSource *is, *is2 = NULL;
\r
10509 ChildProc *cp = (ChildProc *) pr;
\r
10511 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10512 is->lineByLine = lineByLine;
\r
10514 is->closure = closure;
\r
10515 is->second = NULL;
\r
10516 is->next = is->buf;
\r
10517 if (pr == NoProc) {
\r
10518 is->kind = CPReal;
\r
10519 consoleInputSource = is;
\r
10521 is->kind = cp->kind;
\r
10523 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10524 we create all threads suspended so that the is->hThread variable can be
\r
10525 safely assigned, then let the threads start with ResumeThread.
\r
10527 switch (cp->kind) {
\r
10529 is->hFile = cp->hFrom;
\r
10530 cp->hFrom = NULL; /* now owned by InputThread */
\r
10532 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10533 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10537 is->hFile = cp->hFrom;
\r
10538 cp->hFrom = NULL; /* now owned by InputThread */
\r
10540 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10541 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10545 is->sock = cp->sock;
\r
10547 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10548 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10552 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10554 is->sock = cp->sock;
\r
10555 is->second = is2;
\r
10556 is2->sock = cp->sock2;
\r
10557 is2->second = is2;
\r
10559 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10560 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10562 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10563 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10567 if( is->hThread != NULL ) {
\r
10568 ResumeThread( is->hThread );
\r
10571 if( is2 != NULL && is2->hThread != NULL ) {
\r
10572 ResumeThread( is2->hThread );
\r
10576 return (InputSourceRef) is;
\r
10580 RemoveInputSource(InputSourceRef isr)
\r
10584 is = (InputSource *) isr;
\r
10585 is->hThread = NULL; /* tell thread to stop */
\r
10586 CloseHandle(is->hThread);
\r
10587 if (is->second != NULL) {
\r
10588 is->second->hThread = NULL;
\r
10589 CloseHandle(is->second->hThread);
\r
10595 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10598 int outCount = SOCKET_ERROR;
\r
10599 ChildProc *cp = (ChildProc *) pr;
\r
10600 static OVERLAPPED ovl;
\r
10602 if (pr == NoProc) {
\r
10603 ConsoleOutput(message, count, FALSE);
\r
10607 if (ovl.hEvent == NULL) {
\r
10608 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10610 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10612 switch (cp->kind) {
\r
10615 outCount = send(cp->sock, message, count, 0);
\r
10616 if (outCount == SOCKET_ERROR) {
\r
10617 *outError = WSAGetLastError();
\r
10619 *outError = NO_ERROR;
\r
10624 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10625 &dOutCount, NULL)) {
\r
10626 *outError = NO_ERROR;
\r
10627 outCount = (int) dOutCount;
\r
10629 *outError = GetLastError();
\r
10634 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10635 &dOutCount, &ovl);
\r
10636 if (*outError == NO_ERROR) {
\r
10637 outCount = (int) dOutCount;
\r
10645 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10648 /* Ignore delay, not implemented for WinBoard */
\r
10649 return OutputToProcess(pr, message, count, outError);
\r
10654 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10655 char *buf, int count, int error)
\r
10657 DisplayFatalError("Not implemented", 0, 1);
\r
10660 /* see wgamelist.c for Game List functions */
\r
10661 /* see wedittags.c for Edit Tags functions */
\r
10668 char buf[MSG_SIZ];
\r
10671 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10672 f = fopen(buf, "r");
\r
10674 ProcessICSInitScript(f);
\r
10682 StartAnalysisClock()
\r
10684 if (analysisTimerEvent) return;
\r
10685 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10686 (UINT) 2000, NULL);
\r
10690 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10692 static HANDLE hwndText;
\r
10694 static int sizeX, sizeY;
\r
10695 int newSizeX, newSizeY, flags;
\r
10698 switch (message) {
\r
10699 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10700 /* Initialize the dialog items */
\r
10701 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10702 SetWindowText(hDlg, analysisTitle);
\r
10703 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10704 /* Size and position the dialog */
\r
10705 if (!analysisDialog) {
\r
10706 analysisDialog = hDlg;
\r
10707 flags = SWP_NOZORDER;
\r
10708 GetClientRect(hDlg, &rect);
\r
10709 sizeX = rect.right;
\r
10710 sizeY = rect.bottom;
\r
10711 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10712 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10713 WINDOWPLACEMENT wp;
\r
10714 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10715 wp.length = sizeof(WINDOWPLACEMENT);
\r
10717 wp.showCmd = SW_SHOW;
\r
10718 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10719 wp.rcNormalPosition.left = analysisX;
\r
10720 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10721 wp.rcNormalPosition.top = analysisY;
\r
10722 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10723 SetWindowPlacement(hDlg, &wp);
\r
10725 GetClientRect(hDlg, &rect);
\r
10726 newSizeX = rect.right;
\r
10727 newSizeY = rect.bottom;
\r
10728 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10729 newSizeX, newSizeY);
\r
10730 sizeX = newSizeX;
\r
10731 sizeY = newSizeY;
\r
10736 case WM_COMMAND: /* message: received a command */
\r
10737 switch (LOWORD(wParam)) {
\r
10739 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10740 ExitAnalyzeMode();
\r
10752 newSizeX = LOWORD(lParam);
\r
10753 newSizeY = HIWORD(lParam);
\r
10754 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10755 sizeX = newSizeX;
\r
10756 sizeY = newSizeY;
\r
10759 case WM_GETMINMAXINFO:
\r
10760 /* Prevent resizing window too small */
\r
10761 mmi = (MINMAXINFO *) lParam;
\r
10762 mmi->ptMinTrackSize.x = 100;
\r
10763 mmi->ptMinTrackSize.y = 100;
\r
10770 AnalysisPopUp(char* title, char* str)
\r
10776 EngineOutputPopUp();
\r
10779 if (str == NULL) str = "";
\r
10780 p = (char *) malloc(2 * strlen(str) + 2);
\r
10783 if (*str == '\n') *q++ = '\r';
\r
10787 if (analysisText != NULL) free(analysisText);
\r
10788 analysisText = p;
\r
10790 if (analysisDialog) {
\r
10791 SetWindowText(analysisDialog, title);
\r
10792 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10793 ShowWindow(analysisDialog, SW_SHOW);
\r
10795 analysisTitle = title;
\r
10796 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10797 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10798 hwndMain, (DLGPROC)lpProc);
\r
10799 FreeProcInstance(lpProc);
\r
10801 analysisDialogUp = TRUE;
\r
10805 AnalysisPopDown()
\r
10807 if (analysisDialog) {
\r
10808 ShowWindow(analysisDialog, SW_HIDE);
\r
10810 analysisDialogUp = FALSE;
\r
10815 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10817 highlightInfo.sq[0].x = fromX;
\r
10818 highlightInfo.sq[0].y = fromY;
\r
10819 highlightInfo.sq[1].x = toX;
\r
10820 highlightInfo.sq[1].y = toY;
\r
10824 ClearHighlights()
\r
10826 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10827 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10831 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10833 premoveHighlightInfo.sq[0].x = fromX;
\r
10834 premoveHighlightInfo.sq[0].y = fromY;
\r
10835 premoveHighlightInfo.sq[1].x = toX;
\r
10836 premoveHighlightInfo.sq[1].y = toY;
\r
10840 ClearPremoveHighlights()
\r
10842 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10843 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10847 ShutDownFrontEnd()
\r
10849 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10850 DeleteClipboardTempFiles();
\r
10856 if (IsIconic(hwndMain))
\r
10857 ShowWindow(hwndMain, SW_RESTORE);
\r
10859 SetActiveWindow(hwndMain);
\r
10863 * Prototypes for animation support routines
\r
10865 static void ScreenSquare(int column, int row, POINT * pt);
\r
10866 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10867 POINT frames[], int * nFrames);
\r
10871 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10872 { // [HGM] atomic: animate blast wave
\r
10874 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10875 explodeInfo.fromX = fromX;
\r
10876 explodeInfo.fromY = fromY;
\r
10877 explodeInfo.toX = toX;
\r
10878 explodeInfo.toY = toY;
\r
10879 for(i=1; i<nFrames; i++) {
\r
10880 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10881 DrawPosition(FALSE, NULL);
\r
10882 Sleep(appData.animSpeed);
\r
10884 explodeInfo.radius = 0;
\r
10885 DrawPosition(TRUE, NULL);
\r
10888 #define kFactor 4
\r
10891 AnimateMove(board, fromX, fromY, toX, toY)
\r
10898 ChessSquare piece;
\r
10899 POINT start, finish, mid;
\r
10900 POINT frames[kFactor * 2 + 1];
\r
10903 if (!appData.animate) return;
\r
10904 if (doingSizing) return;
\r
10905 if (fromY < 0 || fromX < 0) return;
\r
10906 piece = board[fromY][fromX];
\r
10907 if (piece >= EmptySquare) return;
\r
10909 ScreenSquare(fromX, fromY, &start);
\r
10910 ScreenSquare(toX, toY, &finish);
\r
10912 /* All pieces except knights move in straight line */
\r
10913 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10914 mid.x = start.x + (finish.x - start.x) / 2;
\r
10915 mid.y = start.y + (finish.y - start.y) / 2;
\r
10917 /* Knight: make diagonal movement then straight */
\r
10918 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10919 mid.x = start.x + (finish.x - start.x) / 2;
\r
10920 mid.y = finish.y;
\r
10922 mid.x = finish.x;
\r
10923 mid.y = start.y + (finish.y - start.y) / 2;
\r
10927 /* Don't use as many frames for very short moves */
\r
10928 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10929 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10931 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10933 animInfo.from.x = fromX;
\r
10934 animInfo.from.y = fromY;
\r
10935 animInfo.to.x = toX;
\r
10936 animInfo.to.y = toY;
\r
10937 animInfo.lastpos = start;
\r
10938 animInfo.piece = piece;
\r
10939 for (n = 0; n < nFrames; n++) {
\r
10940 animInfo.pos = frames[n];
\r
10941 DrawPosition(FALSE, NULL);
\r
10942 animInfo.lastpos = animInfo.pos;
\r
10943 Sleep(appData.animSpeed);
\r
10945 animInfo.pos = finish;
\r
10946 DrawPosition(FALSE, NULL);
\r
10947 animInfo.piece = EmptySquare;
\r
10948 if(gameInfo.variant == VariantAtomic &&
\r
10949 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10950 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10953 /* Convert board position to corner of screen rect and color */
\r
10956 ScreenSquare(column, row, pt)
\r
10957 int column; int row; POINT * pt;
\r
10960 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10961 pt->y = lineGap + row * (squareSize + lineGap);
\r
10963 pt->x = lineGap + column * (squareSize + lineGap);
\r
10964 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10968 /* Generate a series of frame coords from start->mid->finish.
\r
10969 The movement rate doubles until the half way point is
\r
10970 reached, then halves back down to the final destination,
\r
10971 which gives a nice slow in/out effect. The algorithmn
\r
10972 may seem to generate too many intermediates for short
\r
10973 moves, but remember that the purpose is to attract the
\r
10974 viewers attention to the piece about to be moved and
\r
10975 then to where it ends up. Too few frames would be less
\r
10979 Tween(start, mid, finish, factor, frames, nFrames)
\r
10980 POINT * start; POINT * mid;
\r
10981 POINT * finish; int factor;
\r
10982 POINT frames[]; int * nFrames;
\r
10984 int n, fraction = 1, count = 0;
\r
10986 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10987 for (n = 0; n < factor; n++)
\r
10989 for (n = 0; n < factor; n++) {
\r
10990 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10991 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10993 fraction = fraction / 2;
\r
10997 frames[count] = *mid;
\r
11000 /* Slow out, stepping 1/2, then 1/4, ... */
\r
11002 for (n = 0; n < factor; n++) {
\r
11003 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
11004 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
11006 fraction = fraction * 2;
\r
11008 *nFrames = count;
\r
11012 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
11017 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
11018 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
11020 OutputDebugString( buf );
\r
11023 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
11025 EvalGraphSet( first, last, current, pvInfoList );
\r
11028 void SetProgramStats( FrontEndProgramStats * stats )
\r
11033 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
11034 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
11036 OutputDebugString( buf );
\r
11039 EngineOutputUpdate( stats );
\r