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);
\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) {
\r
5131 if(moveType == IllegalMove) {
\r
5134 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5135 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5136 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5137 appData.alwaysPromoteToQueen)) {
\r
5138 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5139 if (!appData.highlightLastMove) {
\r
5140 ClearHighlights();
\r
5141 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5144 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5145 SetHighlights(fromX, fromY, toX, toY);
\r
5146 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5147 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5148 If promotion to Q is legal, all are legal! */
\r
5149 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5150 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5151 // kludge to temporarily execute move on display, without promoting yet
\r
5152 promotionChoice = TRUE;
\r
5153 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5154 boards[currentMove][toY][toX] = p;
\r
5155 DrawPosition(FALSE, boards[currentMove]);
\r
5156 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5157 boards[currentMove][toY][toX] = q;
\r
5159 PromotionPopup(hwnd);
\r
5160 } else { /* not a promotion */
\r
5161 if (appData.animate || appData.highlightLastMove) {
\r
5162 SetHighlights(fromX, fromY, toX, toY);
\r
5164 ClearHighlights();
\r
5166 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5167 if (appData.animate && !appData.highlightLastMove) {
\r
5168 ClearHighlights();
\r
5169 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5172 fromX = fromY = -1;
\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
5182 /* First downclick, or restart on a square with same color piece */
\r
5183 if (!frozen && OKToStartUserMove(x, y)) {
\r
5186 dragInfo.lastpos = pt;
\r
5187 dragInfo.from.x = fromX;
\r
5188 dragInfo.from.y = fromY;
\r
5189 dragInfo.start = dragInfo.from;
\r
5190 SetCapture(hwndMain);
\r
5192 fromX = fromY = -1;
\r
5193 dragInfo.start.x = dragInfo.start.y = -1;
\r
5194 dragInfo.from = dragInfo.start;
\r
5195 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5199 case WM_LBUTTONUP:
\r
5201 if (fromX == -1) break;
\r
5202 if (x == fromX && y == fromY) {
\r
5203 dragInfo.from.x = dragInfo.from.y = -1;
\r
5204 /* Upclick on same square */
\r
5206 /* Clicked same square twice: abort click-click move */
\r
5207 fromX = fromY = -1;
\r
5209 ClearPremoveHighlights();
\r
5211 /* First square clicked: start click-click move */
\r
5212 SetHighlights(fromX, fromY, -1, -1);
\r
5214 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5215 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5216 /* Errant click; ignore */
\r
5219 /* Finish drag move. */
\r
5220 if (appData.debugMode) {
\r
5221 fprintf(debugFP, "release\n");
\r
5223 dragInfo.from.x = dragInfo.from.y = -1;
\r
5226 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5227 appData.animate = appData.animate && !appData.animateDragging;
\r
5228 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5229 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5230 fromX = fromY = -1;
\r
5231 ClearHighlights();
\r
5232 DrawPosition(FALSE, boards[currentMove]);
\r
5233 appData.animate = saveAnimate;
\r
5236 if(moveType != ImpossibleMove) {
\r
5237 /* [HGM] use move type to determine if move is promotion.
\r
5238 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5239 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5240 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5241 appData.alwaysPromoteToQueen))
\r
5242 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5244 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5245 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5246 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5247 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5248 // kludge to temporarily execute move on display, wthout promotng yet
\r
5249 promotionChoice = TRUE;
\r
5250 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5251 boards[currentMove][toY][toX] = p;
\r
5252 DrawPosition(FALSE, boards[currentMove]);
\r
5253 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5254 boards[currentMove][toY][toX] = q;
\r
5255 appData.animate = saveAnimate;
\r
5258 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5260 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5261 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5262 moveType == WhiteCapturesEnPassant ||
\r
5263 moveType == BlackCapturesEnPassant ) )
\r
5264 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5265 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5268 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5269 appData.animate = saveAnimate;
\r
5270 fromX = fromY = -1;
\r
5271 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5272 ClearHighlights();
\r
5274 if (appData.animate || appData.animateDragging ||
\r
5275 appData.highlightDragging || gotPremove) {
\r
5276 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5279 dragInfo.start.x = dragInfo.start.y = -1;
\r
5280 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5283 case WM_MOUSEMOVE:
\r
5284 if ((appData.animateDragging || appData.highlightDragging)
\r
5285 && (wParam & MK_LBUTTON)
\r
5286 && dragInfo.from.x >= 0)
\r
5288 BOOL full_repaint = FALSE;
\r
5290 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5291 if (appData.animateDragging) {
\r
5292 dragInfo.pos = pt;
\r
5294 if (appData.highlightDragging) {
\r
5295 SetHighlights(fromX, fromY, x, y);
\r
5296 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5297 full_repaint = TRUE;
\r
5301 DrawPosition( full_repaint, NULL);
\r
5303 dragInfo.lastpos = dragInfo.pos;
\r
5307 case WM_MOUSEWHEEL: // [DM]
\r
5308 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5309 /* Mouse Wheel is being rolled forward
\r
5310 * Play moves forward
\r
5312 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5313 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5314 /* Mouse Wheel is being rolled backward
\r
5315 * Play moves backward
\r
5317 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5318 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5322 case WM_MBUTTONDOWN:
\r
5323 case WM_RBUTTONDOWN:
\r
5326 fromX = fromY = -1;
\r
5327 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5328 dragInfo.start.x = dragInfo.start.y = -1;
\r
5329 dragInfo.from = dragInfo.start;
\r
5330 dragInfo.lastpos = dragInfo.pos;
\r
5331 if (appData.highlightDragging) {
\r
5332 ClearHighlights();
\r
5335 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5336 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5337 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5338 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5339 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5342 DrawPosition(TRUE, NULL);
\r
5344 switch (gameMode) {
\r
5345 case EditPosition:
\r
5346 case IcsExamining:
\r
5347 if (x < 0 || y < 0) break;
\r
5350 if (message == WM_MBUTTONDOWN) {
\r
5351 buttonCount = 3; /* even if system didn't think so */
\r
5352 if (wParam & MK_SHIFT)
\r
5353 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5355 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5356 } else { /* message == WM_RBUTTONDOWN */
\r
5358 if (buttonCount == 3) {
\r
5359 if (wParam & MK_SHIFT)
\r
5360 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5362 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5364 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5367 /* Just have one menu, on the right button. Windows users don't
\r
5368 think to try the middle one, and sometimes other software steals
\r
5369 it, or it doesn't really exist. */
\r
5370 if(gameInfo.variant != VariantShogi)
\r
5371 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5373 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5377 case IcsPlayingWhite:
\r
5378 case IcsPlayingBlack:
\r
5380 case MachinePlaysWhite:
\r
5381 case MachinePlaysBlack:
\r
5382 if (appData.testLegality &&
\r
5383 gameInfo.variant != VariantBughouse &&
\r
5384 gameInfo.variant != VariantCrazyhouse) break;
\r
5385 if (x < 0 || y < 0) break;
\r
5388 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5389 SetupDropMenu(hmenu);
\r
5390 MenuPopup(hwnd, pt, hmenu, -1);
\r
5401 /* Preprocess messages for buttons in main window */
\r
5403 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5405 int id = GetWindowLong(hwnd, GWL_ID);
\r
5408 for (i=0; i<N_BUTTONS; i++) {
\r
5409 if (buttonDesc[i].id == id) break;
\r
5411 if (i == N_BUTTONS) return 0;
\r
5412 switch (message) {
\r
5417 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5418 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5425 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5428 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5429 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5430 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5431 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5433 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5435 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5436 PopUpMoveDialog((char)wParam);
\r
5442 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5445 /* Process messages for Promotion dialog box */
\r
5447 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5451 switch (message) {
\r
5452 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5453 /* Center the dialog over the application window */
\r
5454 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5455 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5456 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5457 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5458 SW_SHOW : SW_HIDE);
\r
5459 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5460 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5461 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5462 PieceToChar(WhiteAngel) != '~') ||
\r
5463 (PieceToChar(BlackAngel) >= 'A' &&
\r
5464 PieceToChar(BlackAngel) != '~') ) ?
\r
5465 SW_SHOW : SW_HIDE);
\r
5466 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5467 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5468 PieceToChar(WhiteMarshall) != '~') ||
\r
5469 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5470 PieceToChar(BlackMarshall) != '~') ) ?
\r
5471 SW_SHOW : SW_HIDE);
\r
5472 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5473 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5474 gameInfo.variant != VariantShogi ?
\r
5475 SW_SHOW : SW_HIDE);
\r
5476 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5477 gameInfo.variant != VariantShogi ?
\r
5478 SW_SHOW : SW_HIDE);
\r
5479 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5480 gameInfo.variant == VariantShogi ?
\r
5481 SW_SHOW : SW_HIDE);
\r
5482 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5483 gameInfo.variant == VariantShogi ?
\r
5484 SW_SHOW : SW_HIDE);
\r
5485 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5486 gameInfo.variant == VariantSuper ?
\r
5487 SW_SHOW : SW_HIDE);
\r
5490 case WM_COMMAND: /* message: received a command */
\r
5491 switch (LOWORD(wParam)) {
\r
5493 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5494 ClearHighlights();
\r
5495 DrawPosition(FALSE, NULL);
\r
5498 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5501 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5504 promoChar = PieceToChar(BlackRook);
\r
5507 promoChar = PieceToChar(BlackBishop);
\r
5509 case PB_Chancellor:
\r
5510 promoChar = PieceToChar(BlackMarshall);
\r
5512 case PB_Archbishop:
\r
5513 promoChar = PieceToChar(BlackAngel);
\r
5516 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5521 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5522 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5523 only show the popup when we are already sure the move is valid or
\r
5524 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5525 will figure out it is a promotion from the promoChar. */
\r
5526 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5527 if (!appData.highlightLastMove) {
\r
5528 ClearHighlights();
\r
5529 DrawPosition(FALSE, NULL);
\r
5536 /* Pop up promotion dialog */
\r
5538 PromotionPopup(HWND hwnd)
\r
5542 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5543 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5544 hwnd, (DLGPROC)lpProc);
\r
5545 FreeProcInstance(lpProc);
\r
5548 /* Toggle ShowThinking */
\r
5550 ToggleShowThinking()
\r
5552 appData.showThinking = !appData.showThinking;
\r
5553 ShowThinkingEvent();
\r
5557 LoadGameDialog(HWND hwnd, char* title)
\r
5561 char fileTitle[MSG_SIZ];
\r
5562 f = OpenFileDialog(hwnd, "rb", "",
\r
5563 appData.oldSaveStyle ? "gam" : "pgn",
\r
5565 title, &number, fileTitle, NULL);
\r
5567 cmailMsgLoaded = FALSE;
\r
5568 if (number == 0) {
\r
5569 int error = GameListBuild(f);
\r
5571 DisplayError("Cannot build game list", error);
\r
5572 } else if (!ListEmpty(&gameList) &&
\r
5573 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5574 GameListPopUp(f, fileTitle);
\r
5577 GameListDestroy();
\r
5580 LoadGame(f, number, fileTitle, FALSE);
\r
5585 ChangedConsoleFont()
\r
5588 CHARRANGE tmpsel, sel;
\r
5589 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5590 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5591 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5594 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5595 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5596 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5597 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5598 * size. This was undocumented in the version of MSVC++ that I had
\r
5599 * when I wrote the code, but is apparently documented now.
\r
5601 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5602 cfmt.bCharSet = f->lf.lfCharSet;
\r
5603 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5604 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5605 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5606 /* Why are the following seemingly needed too? */
\r
5607 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5608 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5609 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5611 tmpsel.cpMax = -1; /*999999?*/
\r
5612 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5613 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5614 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5615 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5617 paraf.cbSize = sizeof(paraf);
\r
5618 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5619 paraf.dxStartIndent = 0;
\r
5620 paraf.dxOffset = WRAP_INDENT;
\r
5621 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5622 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5625 /*---------------------------------------------------------------------------*\
\r
5627 * Window Proc for main window
\r
5629 \*---------------------------------------------------------------------------*/
\r
5631 /* Process messages for main window, etc. */
\r
5633 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5636 int wmId, wmEvent;
\r
5640 char fileTitle[MSG_SIZ];
\r
5641 char buf[MSG_SIZ];
\r
5642 static SnapData sd;
\r
5644 switch (message) {
\r
5646 case WM_PAINT: /* message: repaint portion of window */
\r
5650 case WM_ERASEBKGND:
\r
5651 if (IsIconic(hwnd)) {
\r
5652 /* Cheat; change the message */
\r
5653 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5655 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5659 case WM_LBUTTONDOWN:
\r
5660 case WM_MBUTTONDOWN:
\r
5661 case WM_RBUTTONDOWN:
\r
5662 case WM_LBUTTONUP:
\r
5663 case WM_MBUTTONUP:
\r
5664 case WM_RBUTTONUP:
\r
5665 case WM_MOUSEMOVE:
\r
5666 case WM_MOUSEWHEEL:
\r
5667 MouseEvent(hwnd, message, wParam, lParam);
\r
5670 JAWS_KB_NAVIGATION
\r
5674 JAWS_ALT_INTERCEPT
\r
5676 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5677 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5678 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5679 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5681 SendMessage(h, message, wParam, lParam);
\r
5682 } else if(lParam != KF_REPEAT) {
\r
5683 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5684 PopUpMoveDialog((char)wParam);
\r
5685 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5686 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5691 case WM_PALETTECHANGED:
\r
5692 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5694 HDC hdc = GetDC(hwndMain);
\r
5695 SelectPalette(hdc, hPal, TRUE);
\r
5696 nnew = RealizePalette(hdc);
\r
5698 paletteChanged = TRUE;
\r
5700 UpdateColors(hdc);
\r
5702 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5705 ReleaseDC(hwnd, hdc);
\r
5709 case WM_QUERYNEWPALETTE:
\r
5710 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5712 HDC hdc = GetDC(hwndMain);
\r
5713 paletteChanged = FALSE;
\r
5714 SelectPalette(hdc, hPal, FALSE);
\r
5715 nnew = RealizePalette(hdc);
\r
5717 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5719 ReleaseDC(hwnd, hdc);
\r
5724 case WM_COMMAND: /* message: command from application menu */
\r
5725 wmId = LOWORD(wParam);
\r
5726 wmEvent = HIWORD(wParam);
\r
5731 AnalysisPopDown();
\r
5732 SAY("new game enter a move to play against the computer with white");
\r
5735 case IDM_NewGameFRC:
\r
5736 if( NewGameFRC() == 0 ) {
\r
5738 AnalysisPopDown();
\r
5742 case IDM_NewVariant:
\r
5743 NewVariantPopup(hwnd);
\r
5746 case IDM_LoadGame:
\r
5747 LoadGameDialog(hwnd, "Load Game from File");
\r
5750 case IDM_LoadNextGame:
\r
5754 case IDM_LoadPrevGame:
\r
5758 case IDM_ReloadGame:
\r
5762 case IDM_LoadPosition:
\r
5763 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5764 Reset(FALSE, TRUE);
\r
5767 f = OpenFileDialog(hwnd, "rb", "",
\r
5768 appData.oldSaveStyle ? "pos" : "fen",
\r
5770 "Load Position from File", &number, fileTitle, NULL);
\r
5772 LoadPosition(f, number, fileTitle);
\r
5776 case IDM_LoadNextPosition:
\r
5777 ReloadPosition(1);
\r
5780 case IDM_LoadPrevPosition:
\r
5781 ReloadPosition(-1);
\r
5784 case IDM_ReloadPosition:
\r
5785 ReloadPosition(0);
\r
5788 case IDM_SaveGame:
\r
5789 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5790 f = OpenFileDialog(hwnd, "a", defName,
\r
5791 appData.oldSaveStyle ? "gam" : "pgn",
\r
5793 "Save Game to File", NULL, fileTitle, NULL);
\r
5795 SaveGame(f, 0, "");
\r
5799 case IDM_SavePosition:
\r
5800 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5801 f = OpenFileDialog(hwnd, "a", defName,
\r
5802 appData.oldSaveStyle ? "pos" : "fen",
\r
5804 "Save Position to File", NULL, fileTitle, NULL);
\r
5806 SavePosition(f, 0, "");
\r
5810 case IDM_SaveDiagram:
\r
5811 defName = "diagram";
\r
5812 f = OpenFileDialog(hwnd, "wb", defName,
\r
5815 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5821 case IDM_CopyGame:
\r
5822 CopyGameToClipboard();
\r
5825 case IDM_PasteGame:
\r
5826 PasteGameFromClipboard();
\r
5829 case IDM_CopyGameListToClipboard:
\r
5830 CopyGameListToClipboard();
\r
5833 /* [AS] Autodetect FEN or PGN data */
\r
5834 case IDM_PasteAny:
\r
5835 PasteGameOrFENFromClipboard();
\r
5838 /* [AS] Move history */
\r
5839 case IDM_ShowMoveHistory:
\r
5840 if( MoveHistoryIsUp() ) {
\r
5841 MoveHistoryPopDown();
\r
5844 MoveHistoryPopUp();
\r
5848 /* [AS] Eval graph */
\r
5849 case IDM_ShowEvalGraph:
\r
5850 if( EvalGraphIsUp() ) {
\r
5851 EvalGraphPopDown();
\r
5855 SetFocus(hwndMain);
\r
5859 /* [AS] Engine output */
\r
5860 case IDM_ShowEngineOutput:
\r
5861 if( EngineOutputIsUp() ) {
\r
5862 EngineOutputPopDown();
\r
5865 EngineOutputPopUp();
\r
5869 /* [AS] User adjudication */
\r
5870 case IDM_UserAdjudication_White:
\r
5871 UserAdjudicationEvent( +1 );
\r
5874 case IDM_UserAdjudication_Black:
\r
5875 UserAdjudicationEvent( -1 );
\r
5878 case IDM_UserAdjudication_Draw:
\r
5879 UserAdjudicationEvent( 0 );
\r
5882 /* [AS] Game list options dialog */
\r
5883 case IDM_GameListOptions:
\r
5884 GameListOptions();
\r
5891 case IDM_CopyPosition:
\r
5892 CopyFENToClipboard();
\r
5895 case IDM_PastePosition:
\r
5896 PasteFENFromClipboard();
\r
5899 case IDM_MailMove:
\r
5903 case IDM_ReloadCMailMsg:
\r
5904 Reset(TRUE, TRUE);
\r
5905 ReloadCmailMsgEvent(FALSE);
\r
5908 case IDM_Minimize:
\r
5909 ShowWindow(hwnd, SW_MINIMIZE);
\r
5916 case IDM_MachineWhite:
\r
5917 MachineWhiteEvent();
\r
5919 * refresh the tags dialog only if it's visible
\r
5921 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5923 tags = PGNTags(&gameInfo);
\r
5924 TagsPopUp(tags, CmailMsg());
\r
5927 SAY("computer starts playing white");
\r
5930 case IDM_MachineBlack:
\r
5931 MachineBlackEvent();
\r
5933 * refresh the tags dialog only if it's visible
\r
5935 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5937 tags = PGNTags(&gameInfo);
\r
5938 TagsPopUp(tags, CmailMsg());
\r
5941 SAY("computer starts playing black");
\r
5944 case IDM_TwoMachines:
\r
5945 TwoMachinesEvent();
\r
5947 * refresh the tags dialog only if it's visible
\r
5949 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5951 tags = PGNTags(&gameInfo);
\r
5952 TagsPopUp(tags, CmailMsg());
\r
5955 SAY("programs start playing each other");
\r
5958 case IDM_AnalysisMode:
\r
5959 if (!first.analysisSupport) {
\r
5960 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5961 DisplayError(buf, 0);
\r
5963 SAY("analyzing current position");
\r
5964 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5965 if (appData.icsActive) {
\r
5966 if (gameMode != IcsObserving) {
\r
5967 sprintf(buf, "You are not observing a game");
\r
5968 DisplayError(buf, 0);
\r
5969 /* secure check */
\r
5970 if (appData.icsEngineAnalyze) {
\r
5971 if (appData.debugMode)
\r
5972 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5973 ExitAnalyzeMode();
\r
5979 /* if enable, user want disable icsEngineAnalyze */
\r
5980 if (appData.icsEngineAnalyze) {
\r
5981 ExitAnalyzeMode();
\r
5985 appData.icsEngineAnalyze = TRUE;
\r
5986 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5989 if (!appData.showThinking) ToggleShowThinking();
\r
5990 AnalyzeModeEvent();
\r
5994 case IDM_AnalyzeFile:
\r
5995 if (!first.analysisSupport) {
\r
5996 char buf[MSG_SIZ];
\r
5997 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5998 DisplayError(buf, 0);
\r
6000 if (!appData.showThinking) ToggleShowThinking();
\r
6001 AnalyzeFileEvent();
\r
6002 LoadGameDialog(hwnd, "Analyze Game from File");
\r
6003 AnalysisPeriodicEvent(1);
\r
6007 case IDM_IcsClient:
\r
6011 case IDM_EditGame:
\r
6016 case IDM_EditPosition:
\r
6017 EditPositionEvent();
\r
6018 SAY("to set up a position type a FEN");
\r
6021 case IDM_Training:
\r
6025 case IDM_ShowGameList:
\r
6026 ShowGameListProc();
\r
6029 case IDM_EditTags:
\r
6033 case IDM_EditComment:
\r
6034 if (commentDialogUp && editComment) {
\r
6037 EditCommentEvent();
\r
6057 case IDM_CallFlag:
\r
6077 case IDM_StopObserving:
\r
6078 StopObservingEvent();
\r
6081 case IDM_StopExamining:
\r
6082 StopExaminingEvent();
\r
6085 case IDM_TypeInMove:
\r
6086 PopUpMoveDialog('\000');
\r
6089 case IDM_TypeInName:
\r
6090 PopUpNameDialog('\000');
\r
6093 case IDM_Backward:
\r
6095 SetFocus(hwndMain);
\r
6102 SetFocus(hwndMain);
\r
6107 SetFocus(hwndMain);
\r
6112 SetFocus(hwndMain);
\r
6119 case IDM_TruncateGame:
\r
6120 TruncateGameEvent();
\r
6127 case IDM_RetractMove:
\r
6128 RetractMoveEvent();
\r
6131 case IDM_FlipView:
\r
6132 flipView = !flipView;
\r
6133 DrawPosition(FALSE, NULL);
\r
6136 case IDM_FlipClock:
\r
6137 flipClock = !flipClock;
\r
6138 DisplayBothClocks();
\r
6139 DrawPosition(FALSE, NULL);
\r
6142 case IDM_MuteSounds:
\r
6143 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
6144 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
6145 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
6148 case IDM_GeneralOptions:
\r
6149 GeneralOptionsPopup(hwnd);
\r
6150 DrawPosition(TRUE, NULL);
\r
6153 case IDM_BoardOptions:
\r
6154 BoardOptionsPopup(hwnd);
\r
6157 case IDM_EnginePlayOptions:
\r
6158 EnginePlayOptionsPopup(hwnd);
\r
6161 case IDM_Engine1Options:
\r
6162 EngineOptionsPopup(hwnd, &first);
\r
6165 case IDM_Engine2Options:
\r
6166 EngineOptionsPopup(hwnd, &second);
\r
6169 case IDM_OptionsUCI:
\r
6170 UciOptionsPopup(hwnd);
\r
6173 case IDM_IcsOptions:
\r
6174 IcsOptionsPopup(hwnd);
\r
6178 FontsOptionsPopup(hwnd);
\r
6182 SoundOptionsPopup(hwnd);
\r
6185 case IDM_CommPort:
\r
6186 CommPortOptionsPopup(hwnd);
\r
6189 case IDM_LoadOptions:
\r
6190 LoadOptionsPopup(hwnd);
\r
6193 case IDM_SaveOptions:
\r
6194 SaveOptionsPopup(hwnd);
\r
6197 case IDM_TimeControl:
\r
6198 TimeControlOptionsPopup(hwnd);
\r
6201 case IDM_SaveSettings:
\r
6202 SaveSettings(settingsFileName);
\r
6205 case IDM_SaveSettingsOnExit:
\r
6206 saveSettingsOnExit = !saveSettingsOnExit;
\r
6207 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6208 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6209 MF_CHECKED : MF_UNCHECKED));
\r
6220 case IDM_AboutGame:
\r
6225 appData.debugMode = !appData.debugMode;
\r
6226 if (appData.debugMode) {
\r
6227 char dir[MSG_SIZ];
\r
6228 GetCurrentDirectory(MSG_SIZ, dir);
\r
6229 SetCurrentDirectory(installDir);
\r
6230 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6231 SetCurrentDirectory(dir);
\r
6232 setbuf(debugFP, NULL);
\r
6239 case IDM_HELPCONTENTS:
\r
6240 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6241 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6242 MessageBox (GetFocus(),
\r
6243 "Unable to activate help",
\r
6244 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6248 case IDM_HELPSEARCH:
\r
6249 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6250 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6251 MessageBox (GetFocus(),
\r
6252 "Unable to activate help",
\r
6253 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6257 case IDM_HELPHELP:
\r
6258 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6259 MessageBox (GetFocus(),
\r
6260 "Unable to activate help",
\r
6261 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6266 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6268 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6269 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6270 FreeProcInstance(lpProc);
\r
6273 case IDM_DirectCommand1:
\r
6274 AskQuestionEvent("Direct Command",
\r
6275 "Send to chess program:", "", "1");
\r
6277 case IDM_DirectCommand2:
\r
6278 AskQuestionEvent("Direct Command",
\r
6279 "Send to second chess program:", "", "2");
\r
6282 case EP_WhitePawn:
\r
6283 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6284 fromX = fromY = -1;
\r
6287 case EP_WhiteKnight:
\r
6288 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6289 fromX = fromY = -1;
\r
6292 case EP_WhiteBishop:
\r
6293 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6294 fromX = fromY = -1;
\r
6297 case EP_WhiteRook:
\r
6298 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6299 fromX = fromY = -1;
\r
6302 case EP_WhiteQueen:
\r
6303 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6304 fromX = fromY = -1;
\r
6307 case EP_WhiteFerz:
\r
6308 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6309 fromX = fromY = -1;
\r
6312 case EP_WhiteWazir:
\r
6313 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6314 fromX = fromY = -1;
\r
6317 case EP_WhiteAlfil:
\r
6318 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6319 fromX = fromY = -1;
\r
6322 case EP_WhiteCannon:
\r
6323 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6324 fromX = fromY = -1;
\r
6327 case EP_WhiteCardinal:
\r
6328 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6329 fromX = fromY = -1;
\r
6332 case EP_WhiteMarshall:
\r
6333 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6334 fromX = fromY = -1;
\r
6337 case EP_WhiteKing:
\r
6338 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6339 fromX = fromY = -1;
\r
6342 case EP_BlackPawn:
\r
6343 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6344 fromX = fromY = -1;
\r
6347 case EP_BlackKnight:
\r
6348 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6349 fromX = fromY = -1;
\r
6352 case EP_BlackBishop:
\r
6353 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6354 fromX = fromY = -1;
\r
6357 case EP_BlackRook:
\r
6358 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6359 fromX = fromY = -1;
\r
6362 case EP_BlackQueen:
\r
6363 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6364 fromX = fromY = -1;
\r
6367 case EP_BlackFerz:
\r
6368 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6369 fromX = fromY = -1;
\r
6372 case EP_BlackWazir:
\r
6373 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6374 fromX = fromY = -1;
\r
6377 case EP_BlackAlfil:
\r
6378 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6379 fromX = fromY = -1;
\r
6382 case EP_BlackCannon:
\r
6383 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6384 fromX = fromY = -1;
\r
6387 case EP_BlackCardinal:
\r
6388 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6389 fromX = fromY = -1;
\r
6392 case EP_BlackMarshall:
\r
6393 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6394 fromX = fromY = -1;
\r
6397 case EP_BlackKing:
\r
6398 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6399 fromX = fromY = -1;
\r
6402 case EP_EmptySquare:
\r
6403 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6404 fromX = fromY = -1;
\r
6407 case EP_ClearBoard:
\r
6408 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6409 fromX = fromY = -1;
\r
6413 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6414 fromX = fromY = -1;
\r
6418 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6419 fromX = fromY = -1;
\r
6423 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6424 fromX = fromY = -1;
\r
6428 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6429 fromX = fromY = -1;
\r
6433 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6434 fromX = fromY = -1;
\r
6438 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6439 fromX = fromY = -1;
\r
6443 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6444 fromX = fromY = -1;
\r
6448 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6449 fromX = fromY = -1;
\r
6453 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6454 fromX = fromY = -1;
\r
6458 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6464 case CLOCK_TIMER_ID:
\r
6465 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6466 clockTimerEvent = 0;
\r
6467 DecrementClocks(); /* call into back end */
\r
6469 case LOAD_GAME_TIMER_ID:
\r
6470 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6471 loadGameTimerEvent = 0;
\r
6472 AutoPlayGameLoop(); /* call into back end */
\r
6474 case ANALYSIS_TIMER_ID:
\r
6475 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6476 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6477 AnalysisPeriodicEvent(0);
\r
6479 KillTimer(hwnd, analysisTimerEvent);
\r
6480 analysisTimerEvent = 0;
\r
6483 case DELAYED_TIMER_ID:
\r
6484 KillTimer(hwnd, delayedTimerEvent);
\r
6485 delayedTimerEvent = 0;
\r
6486 delayedTimerCallback();
\r
6491 case WM_USER_Input:
\r
6492 InputEvent(hwnd, message, wParam, lParam);
\r
6495 /* [AS] Also move "attached" child windows */
\r
6496 case WM_WINDOWPOSCHANGING:
\r
6498 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6499 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6501 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6502 /* Window is moving */
\r
6505 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6506 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6507 rcMain.right = boardX + winWidth;
\r
6508 rcMain.top = boardY;
\r
6509 rcMain.bottom = boardY + winHeight;
\r
6511 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6512 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6513 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6514 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6515 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6522 /* [AS] Snapping */
\r
6523 case WM_ENTERSIZEMOVE:
\r
6524 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6525 if (hwnd == hwndMain) {
\r
6526 doingSizing = TRUE;
\r
6529 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6533 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6534 if (hwnd == hwndMain) {
\r
6535 lastSizing = wParam;
\r
6540 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6541 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6543 case WM_EXITSIZEMOVE:
\r
6544 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6545 if (hwnd == hwndMain) {
\r
6547 doingSizing = FALSE;
\r
6548 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6549 GetClientRect(hwnd, &client);
\r
6550 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6552 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6554 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6557 case WM_DESTROY: /* message: window being destroyed */
\r
6558 PostQuitMessage(0);
\r
6562 if (hwnd == hwndMain) {
\r
6567 default: /* Passes it on if unprocessed */
\r
6568 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6573 /*---------------------------------------------------------------------------*\
\r
6575 * Misc utility routines
\r
6577 \*---------------------------------------------------------------------------*/
\r
6580 * Decent random number generator, at least not as bad as Windows
\r
6581 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6583 unsigned int randstate;
\r
6588 randstate = randstate * 1664525 + 1013904223;
\r
6589 return (int) randstate & 0x7fffffff;
\r
6593 mysrandom(unsigned int seed)
\r
6600 * returns TRUE if user selects a different color, FALSE otherwise
\r
6604 ChangeColor(HWND hwnd, COLORREF *which)
\r
6606 static BOOL firstTime = TRUE;
\r
6607 static DWORD customColors[16];
\r
6609 COLORREF newcolor;
\r
6614 /* Make initial colors in use available as custom colors */
\r
6615 /* Should we put the compiled-in defaults here instead? */
\r
6617 customColors[i++] = lightSquareColor & 0xffffff;
\r
6618 customColors[i++] = darkSquareColor & 0xffffff;
\r
6619 customColors[i++] = whitePieceColor & 0xffffff;
\r
6620 customColors[i++] = blackPieceColor & 0xffffff;
\r
6621 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6622 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6624 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6625 customColors[i++] = textAttribs[ccl].color;
\r
6627 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6628 firstTime = FALSE;
\r
6631 cc.lStructSize = sizeof(cc);
\r
6632 cc.hwndOwner = hwnd;
\r
6633 cc.hInstance = NULL;
\r
6634 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6635 cc.lpCustColors = (LPDWORD) customColors;
\r
6636 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6638 if (!ChooseColor(&cc)) return FALSE;
\r
6640 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6641 if (newcolor == *which) return FALSE;
\r
6642 *which = newcolor;
\r
6646 InitDrawingColors();
\r
6647 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6652 MyLoadSound(MySound *ms)
\r
6658 if (ms->data) free(ms->data);
\r
6661 switch (ms->name[0]) {
\r
6667 /* System sound from Control Panel. Don't preload here. */
\r
6671 if (ms->name[1] == NULLCHAR) {
\r
6672 /* "!" alone = silence */
\r
6675 /* Builtin wave resource. Error if not found. */
\r
6676 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6677 if (h == NULL) break;
\r
6678 ms->data = (void *)LoadResource(hInst, h);
\r
6679 if (h == NULL) break;
\r
6684 /* .wav file. Error if not found. */
\r
6685 f = fopen(ms->name, "rb");
\r
6686 if (f == NULL) break;
\r
6687 if (fstat(fileno(f), &st) < 0) break;
\r
6688 ms->data = malloc(st.st_size);
\r
6689 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6695 char buf[MSG_SIZ];
\r
6696 sprintf(buf, "Error loading sound %s", ms->name);
\r
6697 DisplayError(buf, GetLastError());
\r
6703 MyPlaySound(MySound *ms)
\r
6705 BOOLEAN ok = FALSE;
\r
6707 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6708 switch (ms->name[0]) {
\r
6710 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6715 /* System sound from Control Panel (deprecated feature).
\r
6716 "$" alone or an unset sound name gets default beep (still in use). */
\r
6717 if (ms->name[1]) {
\r
6718 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6720 if (!ok) ok = MessageBeep(MB_OK);
\r
6723 /* Builtin wave resource, or "!" alone for silence */
\r
6724 if (ms->name[1]) {
\r
6725 if (ms->data == NULL) return FALSE;
\r
6726 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6732 /* .wav file. Error if not found. */
\r
6733 if (ms->data == NULL) return FALSE;
\r
6734 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6737 /* Don't print an error: this can happen innocently if the sound driver
\r
6738 is busy; for instance, if another instance of WinBoard is playing
\r
6739 a sound at about the same time. */
\r
6742 char buf[MSG_SIZ];
\r
6743 sprintf(buf, "Error playing sound %s", ms->name);
\r
6744 DisplayError(buf, GetLastError());
\r
6752 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6755 OPENFILENAME *ofn;
\r
6756 static UINT *number; /* gross that this is static */
\r
6758 switch (message) {
\r
6759 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6760 /* Center the dialog over the application window */
\r
6761 ofn = (OPENFILENAME *) lParam;
\r
6762 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6763 number = (UINT *) ofn->lCustData;
\r
6764 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6768 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6769 return FALSE; /* Allow for further processing */
\r
6772 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6773 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6775 return FALSE; /* Allow for further processing */
\r
6781 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6783 static UINT *number;
\r
6784 OPENFILENAME *ofname;
\r
6787 case WM_INITDIALOG:
\r
6788 ofname = (OPENFILENAME *)lParam;
\r
6789 number = (UINT *)(ofname->lCustData);
\r
6792 ofnot = (OFNOTIFY *)lParam;
\r
6793 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6794 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6803 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6804 char *nameFilt, char *dlgTitle, UINT *number,
\r
6805 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6807 OPENFILENAME openFileName;
\r
6808 char buf1[MSG_SIZ];
\r
6811 if (fileName == NULL) fileName = buf1;
\r
6812 if (defName == NULL) {
\r
6813 strcpy(fileName, "*.");
\r
6814 strcat(fileName, defExt);
\r
6816 strcpy(fileName, defName);
\r
6818 if (fileTitle) strcpy(fileTitle, "");
\r
6819 if (number) *number = 0;
\r
6821 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6822 openFileName.hwndOwner = hwnd;
\r
6823 openFileName.hInstance = (HANDLE) hInst;
\r
6824 openFileName.lpstrFilter = nameFilt;
\r
6825 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6826 openFileName.nMaxCustFilter = 0L;
\r
6827 openFileName.nFilterIndex = 1L;
\r
6828 openFileName.lpstrFile = fileName;
\r
6829 openFileName.nMaxFile = MSG_SIZ;
\r
6830 openFileName.lpstrFileTitle = fileTitle;
\r
6831 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6832 openFileName.lpstrInitialDir = NULL;
\r
6833 openFileName.lpstrTitle = dlgTitle;
\r
6834 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6835 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6836 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6837 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6838 openFileName.nFileOffset = 0;
\r
6839 openFileName.nFileExtension = 0;
\r
6840 openFileName.lpstrDefExt = defExt;
\r
6841 openFileName.lCustData = (LONG) number;
\r
6842 openFileName.lpfnHook = oldDialog ?
\r
6843 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6844 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6846 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6847 GetOpenFileName(&openFileName)) {
\r
6848 /* open the file */
\r
6849 f = fopen(openFileName.lpstrFile, write);
\r
6851 MessageBox(hwnd, "File open failed", NULL,
\r
6852 MB_OK|MB_ICONEXCLAMATION);
\r
6856 int err = CommDlgExtendedError();
\r
6857 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6866 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6868 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6871 * Get the first pop-up menu in the menu template. This is the
\r
6872 * menu that TrackPopupMenu displays.
\r
6874 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6876 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6879 * TrackPopup uses screen coordinates, so convert the
\r
6880 * coordinates of the mouse click to screen coordinates.
\r
6882 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6884 /* Draw and track the floating pop-up menu. */
\r
6885 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6886 pt.x, pt.y, 0, hwnd, NULL);
\r
6888 /* Destroy the menu.*/
\r
6889 DestroyMenu(hmenu);
\r
6894 int sizeX, sizeY, newSizeX, newSizeY;
\r
6896 } ResizeEditPlusButtonsClosure;
\r
6899 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6901 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6905 if (hChild == cl->hText) return TRUE;
\r
6906 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6907 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6908 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6909 ScreenToClient(cl->hDlg, &pt);
\r
6910 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6911 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6915 /* Resize a dialog that has a (rich) edit field filling most of
\r
6916 the top, with a row of buttons below */
\r
6918 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6921 int newTextHeight, newTextWidth;
\r
6922 ResizeEditPlusButtonsClosure cl;
\r
6924 /*if (IsIconic(hDlg)) return;*/
\r
6925 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6927 cl.hdwp = BeginDeferWindowPos(8);
\r
6929 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6930 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6931 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6932 if (newTextHeight < 0) {
\r
6933 newSizeY += -newTextHeight;
\r
6934 newTextHeight = 0;
\r
6936 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6937 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6943 cl.newSizeX = newSizeX;
\r
6944 cl.newSizeY = newSizeY;
\r
6945 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6947 EndDeferWindowPos(cl.hdwp);
\r
6950 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6952 RECT rChild, rParent;
\r
6953 int wChild, hChild, wParent, hParent;
\r
6954 int wScreen, hScreen, xNew, yNew;
\r
6957 /* Get the Height and Width of the child window */
\r
6958 GetWindowRect (hwndChild, &rChild);
\r
6959 wChild = rChild.right - rChild.left;
\r
6960 hChild = rChild.bottom - rChild.top;
\r
6962 /* Get the Height and Width of the parent window */
\r
6963 GetWindowRect (hwndParent, &rParent);
\r
6964 wParent = rParent.right - rParent.left;
\r
6965 hParent = rParent.bottom - rParent.top;
\r
6967 /* Get the display limits */
\r
6968 hdc = GetDC (hwndChild);
\r
6969 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6970 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6971 ReleaseDC(hwndChild, hdc);
\r
6973 /* Calculate new X position, then adjust for screen */
\r
6974 xNew = rParent.left + ((wParent - wChild) /2);
\r
6977 } else if ((xNew+wChild) > wScreen) {
\r
6978 xNew = wScreen - wChild;
\r
6981 /* Calculate new Y position, then adjust for screen */
\r
6983 yNew = rParent.top + ((hParent - hChild) /2);
\r
6986 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6991 } else if ((yNew+hChild) > hScreen) {
\r
6992 yNew = hScreen - hChild;
\r
6995 /* Set it, and return */
\r
6996 return SetWindowPos (hwndChild, NULL,
\r
6997 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
7000 /* Center one window over another */
\r
7001 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
7003 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
7006 /*---------------------------------------------------------------------------*\
\r
7008 * Startup Dialog functions
\r
7010 \*---------------------------------------------------------------------------*/
\r
7012 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
7014 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7016 while (*cd != NULL) {
\r
7017 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
7023 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
7025 char buf1[ARG_MAX];
\r
7028 if (str[0] == '@') {
\r
7029 FILE* f = fopen(str + 1, "r");
\r
7031 DisplayFatalError(str + 1, errno, 2);
\r
7034 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
7036 buf1[len] = NULLCHAR;
\r
7040 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7043 char buf[MSG_SIZ];
\r
7044 char *end = strchr(str, '\n');
\r
7045 if (end == NULL) return;
\r
7046 memcpy(buf, str, end - str);
\r
7047 buf[end - str] = NULLCHAR;
\r
7048 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7054 SetStartupDialogEnables(HWND hDlg)
\r
7056 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7057 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7058 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7059 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7060 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7061 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7062 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7063 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7064 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7065 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7066 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7067 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7068 IsDlgButtonChecked(hDlg, OPT_View));
\r
7072 QuoteForFilename(char *filename)
\r
7074 int dquote, space;
\r
7075 dquote = strchr(filename, '"') != NULL;
\r
7076 space = strchr(filename, ' ') != NULL;
\r
7077 if (dquote || space) {
\r
7089 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7091 char buf[MSG_SIZ];
\r
7094 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7095 q = QuoteForFilename(nthcp);
\r
7096 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7097 if (*nthdir != NULLCHAR) {
\r
7098 q = QuoteForFilename(nthdir);
\r
7099 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7101 if (*nthcp == NULLCHAR) {
\r
7102 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7103 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7104 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7105 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7110 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7112 char buf[MSG_SIZ];
\r
7116 switch (message) {
\r
7117 case WM_INITDIALOG:
\r
7118 /* Center the dialog */
\r
7119 CenterWindow (hDlg, GetDesktopWindow());
\r
7120 /* Initialize the dialog items */
\r
7121 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7122 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7123 firstChessProgramNames);
\r
7124 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7125 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7126 secondChessProgramNames);
\r
7127 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7128 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7129 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7130 if (*appData.icsHelper != NULLCHAR) {
\r
7131 char *q = QuoteForFilename(appData.icsHelper);
\r
7132 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7134 if (*appData.icsHost == NULLCHAR) {
\r
7135 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7136 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7137 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7138 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7139 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7142 if (appData.icsActive) {
\r
7143 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7145 else if (appData.noChessProgram) {
\r
7146 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7149 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7152 SetStartupDialogEnables(hDlg);
\r
7156 switch (LOWORD(wParam)) {
\r
7158 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7159 strcpy(buf, "/fcp=");
\r
7160 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7162 ParseArgs(StringGet, &p);
\r
7163 strcpy(buf, "/scp=");
\r
7164 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7166 ParseArgs(StringGet, &p);
\r
7167 appData.noChessProgram = FALSE;
\r
7168 appData.icsActive = FALSE;
\r
7169 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7170 strcpy(buf, "/ics /icshost=");
\r
7171 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7173 ParseArgs(StringGet, &p);
\r
7174 if (appData.zippyPlay) {
\r
7175 strcpy(buf, "/fcp=");
\r
7176 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7178 ParseArgs(StringGet, &p);
\r
7180 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7181 appData.noChessProgram = TRUE;
\r
7182 appData.icsActive = FALSE;
\r
7184 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7185 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7188 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7189 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7191 ParseArgs(StringGet, &p);
\r
7193 EndDialog(hDlg, TRUE);
\r
7200 case IDM_HELPCONTENTS:
\r
7201 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7202 MessageBox (GetFocus(),
\r
7203 "Unable to activate help",
\r
7204 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7209 SetStartupDialogEnables(hDlg);
\r
7217 /*---------------------------------------------------------------------------*\
\r
7219 * About box dialog functions
\r
7221 \*---------------------------------------------------------------------------*/
\r
7223 /* Process messages for "About" dialog box */
\r
7225 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7227 switch (message) {
\r
7228 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7229 /* Center the dialog over the application window */
\r
7230 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7231 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7235 case WM_COMMAND: /* message: received a command */
\r
7236 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7237 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7238 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7246 /*---------------------------------------------------------------------------*\
\r
7248 * Comment Dialog functions
\r
7250 \*---------------------------------------------------------------------------*/
\r
7253 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7255 static HANDLE hwndText = NULL;
\r
7256 int len, newSizeX, newSizeY, flags;
\r
7257 static int sizeX, sizeY;
\r
7262 switch (message) {
\r
7263 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7264 /* Initialize the dialog items */
\r
7265 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7266 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7267 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7268 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7269 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7270 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7271 SetWindowText(hDlg, commentTitle);
\r
7272 if (editComment) {
\r
7273 SetFocus(hwndText);
\r
7275 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7277 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7278 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7279 MAKELPARAM(FALSE, 0));
\r
7280 /* Size and position the dialog */
\r
7281 if (!commentDialog) {
\r
7282 commentDialog = hDlg;
\r
7283 flags = SWP_NOZORDER;
\r
7284 GetClientRect(hDlg, &rect);
\r
7285 sizeX = rect.right;
\r
7286 sizeY = rect.bottom;
\r
7287 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7288 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7289 WINDOWPLACEMENT wp;
\r
7290 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7291 wp.length = sizeof(WINDOWPLACEMENT);
\r
7293 wp.showCmd = SW_SHOW;
\r
7294 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7295 wp.rcNormalPosition.left = commentX;
\r
7296 wp.rcNormalPosition.right = commentX + commentW;
\r
7297 wp.rcNormalPosition.top = commentY;
\r
7298 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7299 SetWindowPlacement(hDlg, &wp);
\r
7301 GetClientRect(hDlg, &rect);
\r
7302 newSizeX = rect.right;
\r
7303 newSizeY = rect.bottom;
\r
7304 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7305 newSizeX, newSizeY);
\r
7312 case WM_COMMAND: /* message: received a command */
\r
7313 switch (LOWORD(wParam)) {
\r
7315 if (editComment) {
\r
7317 /* Read changed options from the dialog box */
\r
7318 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7319 len = GetWindowTextLength(hwndText);
\r
7320 str = (char *) malloc(len + 1);
\r
7321 GetWindowText(hwndText, str, len + 1);
\r
7330 ReplaceComment(commentIndex, str);
\r
7337 case OPT_CancelComment:
\r
7341 case OPT_ClearComment:
\r
7342 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7345 case OPT_EditComment:
\r
7346 EditCommentEvent();
\r
7355 newSizeX = LOWORD(lParam);
\r
7356 newSizeY = HIWORD(lParam);
\r
7357 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7362 case WM_GETMINMAXINFO:
\r
7363 /* Prevent resizing window too small */
\r
7364 mmi = (MINMAXINFO *) lParam;
\r
7365 mmi->ptMinTrackSize.x = 100;
\r
7366 mmi->ptMinTrackSize.y = 100;
\r
7373 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7378 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7380 if (str == NULL) str = "";
\r
7381 p = (char *) malloc(2 * strlen(str) + 2);
\r
7384 if (*str == '\n') *q++ = '\r';
\r
7388 if (commentText != NULL) free(commentText);
\r
7390 commentIndex = index;
\r
7391 commentTitle = title;
\r
7393 editComment = edit;
\r
7395 if (commentDialog) {
\r
7396 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7397 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7399 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7400 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7401 hwndMain, (DLGPROC)lpProc);
\r
7402 FreeProcInstance(lpProc);
\r
7404 commentDialogUp = TRUE;
\r
7408 /*---------------------------------------------------------------------------*\
\r
7410 * Type-in move dialog functions
\r
7412 \*---------------------------------------------------------------------------*/
\r
7415 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7417 char move[MSG_SIZ];
\r
7419 ChessMove moveType;
\r
7420 int fromX, fromY, toX, toY;
\r
7423 switch (message) {
\r
7424 case WM_INITDIALOG:
\r
7425 move[0] = (char) lParam;
\r
7426 move[1] = NULLCHAR;
\r
7427 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7428 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7429 SetWindowText(hInput, move);
\r
7431 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7435 switch (LOWORD(wParam)) {
\r
7437 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7438 { int n; Board board;
\r
7440 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7441 EditPositionPasteFEN(move);
\r
7442 EndDialog(hDlg, TRUE);
\r
7445 // [HGM] movenum: allow move number to be typed in any mode
\r
7446 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7447 currentMove = 2*n-1;
\r
7448 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7449 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7450 EndDialog(hDlg, TRUE);
\r
7451 DrawPosition(TRUE, boards[currentMove]);
\r
7452 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7453 else DisplayMessage("", "");
\r
7457 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7458 gameMode != Training) {
\r
7459 DisplayMoveError("Displayed move is not current");
\r
7461 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7462 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7463 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7464 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7465 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7466 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7467 if (gameMode != Training)
\r
7468 forwardMostMove = currentMove;
\r
7469 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7471 DisplayMoveError("Could not parse move");
\r
7474 EndDialog(hDlg, TRUE);
\r
7477 EndDialog(hDlg, FALSE);
\r
7488 PopUpMoveDialog(char firstchar)
\r
7492 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7493 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7494 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7495 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7496 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7497 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7498 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7499 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7500 gameMode == Training) {
\r
7501 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7502 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7503 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7504 FreeProcInstance(lpProc);
\r
7508 /*---------------------------------------------------------------------------*\
\r
7510 * Type-in name dialog functions
\r
7512 \*---------------------------------------------------------------------------*/
\r
7515 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7517 char move[MSG_SIZ];
\r
7520 switch (message) {
\r
7521 case WM_INITDIALOG:
\r
7522 move[0] = (char) lParam;
\r
7523 move[1] = NULLCHAR;
\r
7524 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7525 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7526 SetWindowText(hInput, move);
\r
7528 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7532 switch (LOWORD(wParam)) {
\r
7534 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7535 appData.userName = strdup(move);
\r
7538 EndDialog(hDlg, TRUE);
\r
7541 EndDialog(hDlg, FALSE);
\r
7552 PopUpNameDialog(char firstchar)
\r
7556 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7557 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7558 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7559 FreeProcInstance(lpProc);
\r
7562 /*---------------------------------------------------------------------------*\
\r
7566 \*---------------------------------------------------------------------------*/
\r
7568 /* Nonmodal error box */
\r
7569 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7570 WPARAM wParam, LPARAM lParam);
\r
7573 ErrorPopUp(char *title, char *content)
\r
7577 BOOLEAN modal = hwndMain == NULL;
\r
7595 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7596 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7599 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7601 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7602 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7603 hwndMain, (DLGPROC)lpProc);
\r
7604 FreeProcInstance(lpProc);
\r
7611 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7612 if (errorDialog == NULL) return;
\r
7613 DestroyWindow(errorDialog);
\r
7614 errorDialog = NULL;
\r
7618 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7623 switch (message) {
\r
7624 case WM_INITDIALOG:
\r
7625 GetWindowRect(hDlg, &rChild);
\r
7628 SetWindowPos(hDlg, NULL, rChild.left,
\r
7629 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7630 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7634 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7635 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7636 and it doesn't work when you resize the dialog.
\r
7637 For now, just give it a default position.
\r
7639 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7641 errorDialog = hDlg;
\r
7642 SetWindowText(hDlg, errorTitle);
\r
7643 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7644 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7648 switch (LOWORD(wParam)) {
\r
7651 if (errorDialog == hDlg) errorDialog = NULL;
\r
7652 DestroyWindow(hDlg);
\r
7664 HWND gothicDialog = NULL;
\r
7667 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7671 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7673 switch (message) {
\r
7674 case WM_INITDIALOG:
\r
7675 GetWindowRect(hDlg, &rChild);
\r
7677 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7681 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7682 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7683 and it doesn't work when you resize the dialog.
\r
7684 For now, just give it a default position.
\r
7686 gothicDialog = hDlg;
\r
7687 SetWindowText(hDlg, errorTitle);
\r
7688 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7689 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7693 switch (LOWORD(wParam)) {
\r
7696 if (errorDialog == hDlg) errorDialog = NULL;
\r
7697 DestroyWindow(hDlg);
\r
7709 GothicPopUp(char *title, VariantClass variant)
\r
7712 static char *lastTitle;
\r
7714 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7715 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7717 if(lastTitle != title && gothicDialog != NULL) {
\r
7718 DestroyWindow(gothicDialog);
\r
7719 gothicDialog = NULL;
\r
7721 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7722 title = lastTitle;
\r
7723 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7724 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7725 hwndMain, (DLGPROC)lpProc);
\r
7726 FreeProcInstance(lpProc);
\r
7731 /*---------------------------------------------------------------------------*\
\r
7733 * Ics Interaction console functions
\r
7735 \*---------------------------------------------------------------------------*/
\r
7737 #define HISTORY_SIZE 64
\r
7738 static char *history[HISTORY_SIZE];
\r
7739 int histIn = 0, histP = 0;
\r
7742 SaveInHistory(char *cmd)
\r
7744 if (history[histIn] != NULL) {
\r
7745 free(history[histIn]);
\r
7746 history[histIn] = NULL;
\r
7748 if (*cmd == NULLCHAR) return;
\r
7749 history[histIn] = StrSave(cmd);
\r
7750 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7751 if (history[histIn] != NULL) {
\r
7752 free(history[histIn]);
\r
7753 history[histIn] = NULL;
\r
7759 PrevInHistory(char *cmd)
\r
7762 if (histP == histIn) {
\r
7763 if (history[histIn] != NULL) free(history[histIn]);
\r
7764 history[histIn] = StrSave(cmd);
\r
7766 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7767 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7769 return history[histP];
\r
7775 if (histP == histIn) return NULL;
\r
7776 histP = (histP + 1) % HISTORY_SIZE;
\r
7777 return history[histP];
\r
7784 BOOLEAN immediate;
\r
7785 } IcsTextMenuEntry;
\r
7786 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7787 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7790 ParseIcsTextMenu(char *icsTextMenuString)
\r
7793 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7794 char *p = icsTextMenuString;
\r
7795 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7798 if (e->command != NULL) {
\r
7800 e->command = NULL;
\r
7804 e = icsTextMenuEntry;
\r
7805 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7806 if (*p == ';' || *p == '\n') {
\r
7807 e->item = strdup("-");
\r
7808 e->command = NULL;
\r
7810 } else if (*p == '-') {
\r
7811 e->item = strdup("-");
\r
7812 e->command = NULL;
\r
7816 char *q, *r, *s, *t;
\r
7818 q = strchr(p, ',');
\r
7819 if (q == NULL) break;
\r
7821 r = strchr(q + 1, ',');
\r
7822 if (r == NULL) break;
\r
7824 s = strchr(r + 1, ',');
\r
7825 if (s == NULL) break;
\r
7828 t = strchr(s + 1, c);
\r
7831 t = strchr(s + 1, c);
\r
7833 if (t != NULL) *t = NULLCHAR;
\r
7834 e->item = strdup(p);
\r
7835 e->command = strdup(q + 1);
\r
7836 e->getname = *(r + 1) != '0';
\r
7837 e->immediate = *(s + 1) != '0';
\r
7841 if (t == NULL) break;
\r
7850 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7854 hmenu = LoadMenu(hInst, "TextMenu");
\r
7855 h = GetSubMenu(hmenu, 0);
\r
7857 if (strcmp(e->item, "-") == 0) {
\r
7858 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7860 if (e->item[0] == '|') {
\r
7861 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7862 IDM_CommandX + i, &e->item[1]);
\r
7864 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7873 WNDPROC consoleTextWindowProc;
\r
7876 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7878 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7879 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7883 SetWindowText(hInput, command);
\r
7885 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7887 sel.cpMin = 999999;
\r
7888 sel.cpMax = 999999;
\r
7889 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7894 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7895 if (sel.cpMin == sel.cpMax) {
\r
7896 /* Expand to surrounding word */
\r
7899 tr.chrg.cpMax = sel.cpMin;
\r
7900 tr.chrg.cpMin = --sel.cpMin;
\r
7901 if (sel.cpMin < 0) break;
\r
7902 tr.lpstrText = name;
\r
7903 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7904 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7908 tr.chrg.cpMin = sel.cpMax;
\r
7909 tr.chrg.cpMax = ++sel.cpMax;
\r
7910 tr.lpstrText = name;
\r
7911 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7912 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7915 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7916 MessageBeep(MB_ICONEXCLAMATION);
\r
7920 tr.lpstrText = name;
\r
7921 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7923 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7924 MessageBeep(MB_ICONEXCLAMATION);
\r
7927 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7930 sprintf(buf, "%s %s", command, name);
\r
7931 SetWindowText(hInput, buf);
\r
7932 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7934 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7935 SetWindowText(hInput, buf);
\r
7936 sel.cpMin = 999999;
\r
7937 sel.cpMax = 999999;
\r
7938 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7944 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7949 switch (message) {
\r
7951 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7954 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7957 sel.cpMin = 999999;
\r
7958 sel.cpMax = 999999;
\r
7959 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7960 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7965 if(wParam != '\022') {
\r
7966 if (wParam == '\t') {
\r
7967 if (GetKeyState(VK_SHIFT) < 0) {
\r
7969 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7970 if (buttonDesc[0].hwnd) {
\r
7971 SetFocus(buttonDesc[0].hwnd);
\r
7973 SetFocus(hwndMain);
\r
7977 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7980 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7981 JAWS_DELETE( SetFocus(hInput); )
\r
7982 SendMessage(hInput, message, wParam, lParam);
\r
7985 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7986 case WM_RBUTTONUP:
\r
7987 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7988 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7989 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7992 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7993 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7994 if (sel.cpMin == sel.cpMax) {
\r
7995 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7996 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7998 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7999 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8001 pt.x = LOWORD(lParam);
\r
8002 pt.y = HIWORD(lParam);
\r
8003 MenuPopup(hwnd, pt, hmenu, -1);
\r
8007 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8009 return SendMessage(hInput, message, wParam, lParam);
\r
8010 case WM_MBUTTONDOWN:
\r
8011 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8012 case WM_RBUTTONDOWN:
\r
8013 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
8014 /* Move selection here if it was empty */
\r
8016 pt.x = LOWORD(lParam);
\r
8017 pt.y = HIWORD(lParam);
\r
8018 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8019 if (sel.cpMin == sel.cpMax) {
\r
8020 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
8021 sel.cpMax = sel.cpMin;
\r
8022 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8024 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
8028 switch (LOWORD(wParam)) {
\r
8029 case IDM_QuickPaste:
\r
8031 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8032 if (sel.cpMin == sel.cpMax) {
\r
8033 MessageBeep(MB_ICONEXCLAMATION);
\r
8036 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8037 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8038 SendMessage(hInput, WM_PASTE, 0, 0);
\r
8043 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8046 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8049 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8053 int i = LOWORD(wParam) - IDM_CommandX;
\r
8054 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8055 icsTextMenuEntry[i].command != NULL) {
\r
8056 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8057 icsTextMenuEntry[i].getname,
\r
8058 icsTextMenuEntry[i].immediate);
\r
8066 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8069 WNDPROC consoleInputWindowProc;
\r
8072 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8074 char buf[MSG_SIZ];
\r
8076 static BOOL sendNextChar = FALSE;
\r
8077 static BOOL quoteNextChar = FALSE;
\r
8078 InputSource *is = consoleInputSource;
\r
8082 switch (message) {
\r
8084 if (!appData.localLineEditing || sendNextChar) {
\r
8085 is->buf[0] = (CHAR) wParam;
\r
8087 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8088 sendNextChar = FALSE;
\r
8091 if (quoteNextChar) {
\r
8092 buf[0] = (char) wParam;
\r
8093 buf[1] = NULLCHAR;
\r
8094 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8095 quoteNextChar = FALSE;
\r
8099 case '\r': /* Enter key */
\r
8100 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8101 if (consoleEcho) SaveInHistory(is->buf);
\r
8102 is->buf[is->count++] = '\n';
\r
8103 is->buf[is->count] = NULLCHAR;
\r
8104 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8105 if (consoleEcho) {
\r
8106 ConsoleOutput(is->buf, is->count, TRUE);
\r
8107 } else if (appData.localLineEditing) {
\r
8108 ConsoleOutput("\n", 1, TRUE);
\r
8111 case '\033': /* Escape key */
\r
8112 SetWindowText(hwnd, "");
\r
8113 cf.cbSize = sizeof(CHARFORMAT);
\r
8114 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8115 if (consoleEcho) {
\r
8116 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8118 cf.crTextColor = COLOR_ECHOOFF;
\r
8120 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8121 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8123 case '\t': /* Tab key */
\r
8124 if (GetKeyState(VK_SHIFT) < 0) {
\r
8126 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8129 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8130 if (buttonDesc[0].hwnd) {
\r
8131 SetFocus(buttonDesc[0].hwnd);
\r
8133 SetFocus(hwndMain);
\r
8137 case '\023': /* Ctrl+S */
\r
8138 sendNextChar = TRUE;
\r
8140 case '\021': /* Ctrl+Q */
\r
8141 quoteNextChar = TRUE;
\r
8151 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8152 p = PrevInHistory(buf);
\r
8154 SetWindowText(hwnd, p);
\r
8155 sel.cpMin = 999999;
\r
8156 sel.cpMax = 999999;
\r
8157 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8162 p = NextInHistory();
\r
8164 SetWindowText(hwnd, p);
\r
8165 sel.cpMin = 999999;
\r
8166 sel.cpMax = 999999;
\r
8167 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8173 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8177 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8181 case WM_MBUTTONDOWN:
\r
8182 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8183 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8185 case WM_RBUTTONUP:
\r
8186 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8187 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8188 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8192 hmenu = LoadMenu(hInst, "InputMenu");
\r
8193 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8194 if (sel.cpMin == sel.cpMax) {
\r
8195 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8196 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8198 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8199 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8201 pt.x = LOWORD(lParam);
\r
8202 pt.y = HIWORD(lParam);
\r
8203 MenuPopup(hwnd, pt, hmenu, -1);
\r
8207 switch (LOWORD(wParam)) {
\r
8209 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8211 case IDM_SelectAll:
\r
8213 sel.cpMax = -1; /*999999?*/
\r
8214 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8217 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8220 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8223 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8228 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8231 #define CO_MAX 100000
\r
8232 #define CO_TRIM 1000
\r
8235 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8237 static SnapData sd;
\r
8238 static HWND hText, hInput /*, hFocus*/;
\r
8239 // InputSource *is = consoleInputSource;
\r
8241 static int sizeX, sizeY;
\r
8242 int newSizeX, newSizeY;
\r
8245 switch (message) {
\r
8246 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8247 hwndConsole = hDlg;
\r
8248 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8249 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8251 consoleTextWindowProc = (WNDPROC)
\r
8252 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8253 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8254 consoleInputWindowProc = (WNDPROC)
\r
8255 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8256 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8257 Colorize(ColorNormal, TRUE);
\r
8258 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8259 ChangedConsoleFont();
\r
8260 GetClientRect(hDlg, &rect);
\r
8261 sizeX = rect.right;
\r
8262 sizeY = rect.bottom;
\r
8263 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8264 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8265 WINDOWPLACEMENT wp;
\r
8266 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8267 wp.length = sizeof(WINDOWPLACEMENT);
\r
8269 wp.showCmd = SW_SHOW;
\r
8270 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8271 wp.rcNormalPosition.left = wpConsole.x;
\r
8272 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8273 wp.rcNormalPosition.top = wpConsole.y;
\r
8274 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8275 SetWindowPlacement(hDlg, &wp);
\r
8278 // [HGM] Chessknight's change 2004-07-13
\r
8279 else { /* Determine Defaults */
\r
8280 WINDOWPLACEMENT wp;
\r
8281 wpConsole.x = winWidth + 1;
\r
8282 wpConsole.y = boardY;
\r
8283 wpConsole.width = screenWidth - winWidth;
\r
8284 wpConsole.height = winHeight;
\r
8285 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8286 wp.length = sizeof(WINDOWPLACEMENT);
\r
8288 wp.showCmd = SW_SHOW;
\r
8289 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8290 wp.rcNormalPosition.left = wpConsole.x;
\r
8291 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8292 wp.rcNormalPosition.top = wpConsole.y;
\r
8293 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8294 SetWindowPlacement(hDlg, &wp);
\r
8309 if (IsIconic(hDlg)) break;
\r
8310 newSizeX = LOWORD(lParam);
\r
8311 newSizeY = HIWORD(lParam);
\r
8312 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8313 RECT rectText, rectInput;
\r
8315 int newTextHeight, newTextWidth;
\r
8316 GetWindowRect(hText, &rectText);
\r
8317 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8318 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8319 if (newTextHeight < 0) {
\r
8320 newSizeY += -newTextHeight;
\r
8321 newTextHeight = 0;
\r
8323 SetWindowPos(hText, NULL, 0, 0,
\r
8324 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8325 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8326 pt.x = rectInput.left;
\r
8327 pt.y = rectInput.top + newSizeY - sizeY;
\r
8328 ScreenToClient(hDlg, &pt);
\r
8329 SetWindowPos(hInput, NULL,
\r
8330 pt.x, pt.y, /* needs client coords */
\r
8331 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8332 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8338 case WM_GETMINMAXINFO:
\r
8339 /* Prevent resizing window too small */
\r
8340 mmi = (MINMAXINFO *) lParam;
\r
8341 mmi->ptMinTrackSize.x = 100;
\r
8342 mmi->ptMinTrackSize.y = 100;
\r
8345 /* [AS] Snapping */
\r
8346 case WM_ENTERSIZEMOVE:
\r
8347 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8350 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8353 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8355 case WM_EXITSIZEMOVE:
\r
8356 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8359 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8367 if (hwndConsole) return;
\r
8368 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8369 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8374 ConsoleOutput(char* data, int length, int forceVisible)
\r
8379 char buf[CO_MAX+1];
\r
8382 static int delayLF = 0;
\r
8383 CHARRANGE savesel, sel;
\r
8385 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8393 while (length--) {
\r
8401 } else if (*p == '\007') {
\r
8402 MyPlaySound(&sounds[(int)SoundBell]);
\r
8409 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8410 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8411 /* Save current selection */
\r
8412 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8413 exlen = GetWindowTextLength(hText);
\r
8414 /* Find out whether current end of text is visible */
\r
8415 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8416 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8417 /* Trim existing text if it's too long */
\r
8418 if (exlen + (q - buf) > CO_MAX) {
\r
8419 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8422 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8423 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8425 savesel.cpMin -= trim;
\r
8426 savesel.cpMax -= trim;
\r
8427 if (exlen < 0) exlen = 0;
\r
8428 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8429 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8431 /* Append the new text */
\r
8432 sel.cpMin = exlen;
\r
8433 sel.cpMax = exlen;
\r
8434 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8435 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8436 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8437 if (forceVisible || exlen == 0 ||
\r
8438 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8439 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8440 /* Scroll to make new end of text visible if old end of text
\r
8441 was visible or new text is an echo of user typein */
\r
8442 sel.cpMin = 9999999;
\r
8443 sel.cpMax = 9999999;
\r
8444 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8445 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8446 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8447 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8449 if (savesel.cpMax == exlen || forceVisible) {
\r
8450 /* Move insert point to new end of text if it was at the old
\r
8451 end of text or if the new text is an echo of user typein */
\r
8452 sel.cpMin = 9999999;
\r
8453 sel.cpMax = 9999999;
\r
8454 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8456 /* Restore previous selection */
\r
8457 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8459 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8466 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8470 COLORREF oldFg, oldBg;
\r
8474 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8476 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8477 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8478 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8481 rect.right = x + squareSize;
\r
8483 rect.bottom = y + squareSize;
\r
8486 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8487 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8488 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8489 &rect, str, strlen(str), NULL);
\r
8491 (void) SetTextColor(hdc, oldFg);
\r
8492 (void) SetBkColor(hdc, oldBg);
\r
8493 (void) SelectObject(hdc, oldFont);
\r
8497 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8498 RECT *rect, char *color, char *flagFell)
\r
8502 COLORREF oldFg, oldBg;
\r
8505 if (appData.clockMode) {
\r
8507 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8509 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8516 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8517 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8519 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8520 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8522 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8526 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8527 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8528 rect, str, strlen(str), NULL);
\r
8529 if(logoHeight > 0 && appData.clockMode) {
\r
8531 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8532 r.top = rect->top + logoHeight/2;
\r
8533 r.left = rect->left;
\r
8534 r.right = rect->right;
\r
8535 r.bottom = rect->bottom;
\r
8536 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8537 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8538 &r, str, strlen(str), NULL);
\r
8540 (void) SetTextColor(hdc, oldFg);
\r
8541 (void) SetBkColor(hdc, oldBg);
\r
8542 (void) SelectObject(hdc, oldFont);
\r
8547 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8553 if( count <= 0 ) {
\r
8554 if (appData.debugMode) {
\r
8555 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8558 return ERROR_INVALID_USER_BUFFER;
\r
8561 ResetEvent(ovl->hEvent);
\r
8562 ovl->Offset = ovl->OffsetHigh = 0;
\r
8563 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8567 err = GetLastError();
\r
8568 if (err == ERROR_IO_PENDING) {
\r
8569 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8573 err = GetLastError();
\r
8580 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8585 ResetEvent(ovl->hEvent);
\r
8586 ovl->Offset = ovl->OffsetHigh = 0;
\r
8587 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8591 err = GetLastError();
\r
8592 if (err == ERROR_IO_PENDING) {
\r
8593 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8597 err = GetLastError();
\r
8603 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8604 void CheckForInputBufferFull( InputSource * is )
\r
8606 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8607 /* Look for end of line */
\r
8608 char * p = is->buf;
\r
8610 while( p < is->next && *p != '\n' ) {
\r
8614 if( p >= is->next ) {
\r
8615 if (appData.debugMode) {
\r
8616 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8619 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8620 is->count = (DWORD) -1;
\r
8621 is->next = is->buf;
\r
8627 InputThread(LPVOID arg)
\r
8632 is = (InputSource *) arg;
\r
8633 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8634 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8635 while (is->hThread != NULL) {
\r
8636 is->error = DoReadFile(is->hFile, is->next,
\r
8637 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8638 &is->count, &ovl);
\r
8639 if (is->error == NO_ERROR) {
\r
8640 is->next += is->count;
\r
8642 if (is->error == ERROR_BROKEN_PIPE) {
\r
8643 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8646 is->count = (DWORD) -1;
\r
8647 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8652 CheckForInputBufferFull( is );
\r
8654 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8656 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8658 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8661 CloseHandle(ovl.hEvent);
\r
8662 CloseHandle(is->hFile);
\r
8664 if (appData.debugMode) {
\r
8665 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8672 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8674 NonOvlInputThread(LPVOID arg)
\r
8681 is = (InputSource *) arg;
\r
8682 while (is->hThread != NULL) {
\r
8683 is->error = ReadFile(is->hFile, is->next,
\r
8684 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8685 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8686 if (is->error == NO_ERROR) {
\r
8687 /* Change CRLF to LF */
\r
8688 if (is->next > is->buf) {
\r
8690 i = is->count + 1;
\r
8698 if (prev == '\r' && *p == '\n') {
\r
8710 if (is->error == ERROR_BROKEN_PIPE) {
\r
8711 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8714 is->count = (DWORD) -1;
\r
8718 CheckForInputBufferFull( is );
\r
8720 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8722 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8724 if (is->count < 0) break; /* Quit on error */
\r
8726 CloseHandle(is->hFile);
\r
8731 SocketInputThread(LPVOID arg)
\r
8735 is = (InputSource *) arg;
\r
8736 while (is->hThread != NULL) {
\r
8737 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8738 if ((int)is->count == SOCKET_ERROR) {
\r
8739 is->count = (DWORD) -1;
\r
8740 is->error = WSAGetLastError();
\r
8742 is->error = NO_ERROR;
\r
8743 is->next += is->count;
\r
8744 if (is->count == 0 && is->second == is) {
\r
8745 /* End of file on stderr; quit with no message */
\r
8749 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8751 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8753 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8759 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8763 is = (InputSource *) lParam;
\r
8764 if (is->lineByLine) {
\r
8765 /* Feed in lines one by one */
\r
8766 char *p = is->buf;
\r
8768 while (q < is->next) {
\r
8769 if (*q++ == '\n') {
\r
8770 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8775 /* Move any partial line to the start of the buffer */
\r
8777 while (p < is->next) {
\r
8782 if (is->error != NO_ERROR || is->count == 0) {
\r
8783 /* Notify backend of the error. Note: If there was a partial
\r
8784 line at the end, it is not flushed through. */
\r
8785 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8788 /* Feed in the whole chunk of input at once */
\r
8789 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8790 is->next = is->buf;
\r
8794 /*---------------------------------------------------------------------------*\
\r
8796 * Menu enables. Used when setting various modes.
\r
8798 \*---------------------------------------------------------------------------*/
\r
8806 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8808 while (enab->item > 0) {
\r
8809 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8814 Enables gnuEnables[] = {
\r
8815 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8816 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8817 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8818 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8819 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8820 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8822 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8823 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8824 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8828 Enables icsEnables[] = {
\r
8829 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8830 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8831 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8832 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8833 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8834 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8835 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8836 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8837 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8838 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8839 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8840 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8845 Enables zippyEnables[] = {
\r
8846 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8847 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8848 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8853 Enables ncpEnables[] = {
\r
8854 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8855 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8856 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8857 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8858 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8859 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8860 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8861 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8862 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8863 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8864 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8865 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8866 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8867 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8868 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8872 Enables trainingOnEnables[] = {
\r
8873 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8874 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8875 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8876 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8877 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8878 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8879 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8880 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8884 Enables trainingOffEnables[] = {
\r
8885 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8886 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8887 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8888 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8889 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8890 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8891 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8892 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8896 /* These modify either ncpEnables or gnuEnables */
\r
8897 Enables cmailEnables[] = {
\r
8898 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8899 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8900 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8901 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8902 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8903 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8904 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8908 Enables machineThinkingEnables[] = {
\r
8909 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8910 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8911 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8912 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8913 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8914 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8915 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8916 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8917 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8918 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8919 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8920 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8921 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8922 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8923 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8927 Enables userThinkingEnables[] = {
\r
8928 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8929 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8930 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8931 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8932 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8933 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8934 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8935 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8936 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8937 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8938 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8939 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8940 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8941 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8942 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8946 /*---------------------------------------------------------------------------*\
\r
8948 * Front-end interface functions exported by XBoard.
\r
8949 * Functions appear in same order as prototypes in frontend.h.
\r
8951 \*---------------------------------------------------------------------------*/
\r
8955 static UINT prevChecked = 0;
\r
8956 static int prevPausing = 0;
\r
8959 if (pausing != prevPausing) {
\r
8960 prevPausing = pausing;
\r
8961 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8962 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8963 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8966 switch (gameMode) {
\r
8967 case BeginningOfGame:
\r
8968 if (appData.icsActive)
\r
8969 nowChecked = IDM_IcsClient;
\r
8970 else if (appData.noChessProgram)
\r
8971 nowChecked = IDM_EditGame;
\r
8973 nowChecked = IDM_MachineBlack;
\r
8975 case MachinePlaysBlack:
\r
8976 nowChecked = IDM_MachineBlack;
\r
8978 case MachinePlaysWhite:
\r
8979 nowChecked = IDM_MachineWhite;
\r
8981 case TwoMachinesPlay:
\r
8982 nowChecked = IDM_TwoMachines;
\r
8985 nowChecked = IDM_AnalysisMode;
\r
8988 nowChecked = IDM_AnalyzeFile;
\r
8991 nowChecked = IDM_EditGame;
\r
8993 case PlayFromGameFile:
\r
8994 nowChecked = IDM_LoadGame;
\r
8996 case EditPosition:
\r
8997 nowChecked = IDM_EditPosition;
\r
9000 nowChecked = IDM_Training;
\r
9002 case IcsPlayingWhite:
\r
9003 case IcsPlayingBlack:
\r
9004 case IcsObserving:
\r
9006 nowChecked = IDM_IcsClient;
\r
9013 if (prevChecked != 0)
\r
9014 (void) CheckMenuItem(GetMenu(hwndMain),
\r
9015 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
9016 if (nowChecked != 0)
\r
9017 (void) CheckMenuItem(GetMenu(hwndMain),
\r
9018 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
9020 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
9021 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
9022 MF_BYCOMMAND|MF_ENABLED);
\r
9024 (void) EnableMenuItem(GetMenu(hwndMain),
\r
9025 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
9028 prevChecked = nowChecked;
\r
9030 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
9031 if (appData.icsActive) {
\r
9032 if (appData.icsEngineAnalyze) {
\r
9033 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9034 MF_BYCOMMAND|MF_CHECKED);
\r
9036 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9037 MF_BYCOMMAND|MF_UNCHECKED);
\r
9045 HMENU hmenu = GetMenu(hwndMain);
\r
9046 SetMenuEnables(hmenu, icsEnables);
\r
9047 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9048 MF_BYPOSITION|MF_ENABLED);
\r
9050 if (appData.zippyPlay) {
\r
9051 SetMenuEnables(hmenu, zippyEnables);
\r
9052 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9053 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9054 MF_BYCOMMAND|MF_ENABLED);
\r
9062 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9068 HMENU hmenu = GetMenu(hwndMain);
\r
9069 SetMenuEnables(hmenu, ncpEnables);
\r
9070 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9071 MF_BYPOSITION|MF_GRAYED);
\r
9072 DrawMenuBar(hwndMain);
\r
9078 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9082 SetTrainingModeOn()
\r
9085 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9086 for (i = 0; i < N_BUTTONS; i++) {
\r
9087 if (buttonDesc[i].hwnd != NULL)
\r
9088 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9093 VOID SetTrainingModeOff()
\r
9096 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9097 for (i = 0; i < N_BUTTONS; i++) {
\r
9098 if (buttonDesc[i].hwnd != NULL)
\r
9099 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9105 SetUserThinkingEnables()
\r
9107 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9111 SetMachineThinkingEnables()
\r
9113 HMENU hMenu = GetMenu(hwndMain);
\r
9114 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9116 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9118 if (gameMode == MachinePlaysBlack) {
\r
9119 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9120 } else if (gameMode == MachinePlaysWhite) {
\r
9121 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9122 } else if (gameMode == TwoMachinesPlay) {
\r
9123 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9129 DisplayTitle(char *str)
\r
9131 char title[MSG_SIZ], *host;
\r
9132 if (str[0] != NULLCHAR) {
\r
9133 strcpy(title, str);
\r
9134 } else if (appData.icsActive) {
\r
9135 if (appData.icsCommPort[0] != NULLCHAR)
\r
9138 host = appData.icsHost;
\r
9139 sprintf(title, "%s: %s", szTitle, host);
\r
9140 } else if (appData.noChessProgram) {
\r
9141 strcpy(title, szTitle);
\r
9143 strcpy(title, szTitle);
\r
9144 strcat(title, ": ");
\r
9145 strcat(title, first.tidy);
\r
9147 SetWindowText(hwndMain, title);
\r
9152 DisplayMessage(char *str1, char *str2)
\r
9156 int remain = MESSAGE_TEXT_MAX - 1;
\r
9159 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9160 messageText[0] = NULLCHAR;
\r
9162 len = strlen(str1);
\r
9163 if (len > remain) len = remain;
\r
9164 strncpy(messageText, str1, len);
\r
9165 messageText[len] = NULLCHAR;
\r
9168 if (*str2 && remain >= 2) {
\r
9170 strcat(messageText, " ");
\r
9173 len = strlen(str2);
\r
9174 if (len > remain) len = remain;
\r
9175 strncat(messageText, str2, len);
\r
9177 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9179 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9183 hdc = GetDC(hwndMain);
\r
9184 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9185 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9186 &messageRect, messageText, strlen(messageText), NULL);
\r
9187 (void) SelectObject(hdc, oldFont);
\r
9188 (void) ReleaseDC(hwndMain, hdc);
\r
9192 DisplayError(char *str, int error)
\r
9194 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9200 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9201 NULL, error, LANG_NEUTRAL,
\r
9202 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9204 sprintf(buf, "%s:\n%s", str, buf2);
\r
9206 ErrorMap *em = errmap;
\r
9207 while (em->err != 0 && em->err != error) em++;
\r
9208 if (em->err != 0) {
\r
9209 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9211 sprintf(buf, "%s:\nError code %d", str, error);
\r
9216 ErrorPopUp("Error", buf);
\r
9221 DisplayMoveError(char *str)
\r
9223 fromX = fromY = -1;
\r
9224 ClearHighlights();
\r
9225 DrawPosition(FALSE, NULL);
\r
9226 if (appData.popupMoveErrors) {
\r
9227 ErrorPopUp("Error", str);
\r
9229 DisplayMessage(str, "");
\r
9230 moveErrorMessageUp = TRUE;
\r
9235 DisplayFatalError(char *str, int error, int exitStatus)
\r
9237 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9239 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9242 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9243 NULL, error, LANG_NEUTRAL,
\r
9244 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9246 sprintf(buf, "%s:\n%s", str, buf2);
\r
9248 ErrorMap *em = errmap;
\r
9249 while (em->err != 0 && em->err != error) em++;
\r
9250 if (em->err != 0) {
\r
9251 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9253 sprintf(buf, "%s:\nError code %d", str, error);
\r
9258 if (appData.debugMode) {
\r
9259 fprintf(debugFP, "%s: %s\n", label, str);
\r
9261 if (appData.popupExitMessage) {
\r
9262 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9263 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9265 ExitEvent(exitStatus);
\r
9270 DisplayInformation(char *str)
\r
9272 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9277 DisplayNote(char *str)
\r
9279 ErrorPopUp("Note", str);
\r
9284 char *title, *question, *replyPrefix;
\r
9289 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9291 static QuestionParams *qp;
\r
9292 char reply[MSG_SIZ];
\r
9295 switch (message) {
\r
9296 case WM_INITDIALOG:
\r
9297 qp = (QuestionParams *) lParam;
\r
9298 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9299 SetWindowText(hDlg, qp->title);
\r
9300 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9301 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9305 switch (LOWORD(wParam)) {
\r
9307 strcpy(reply, qp->replyPrefix);
\r
9308 if (*reply) strcat(reply, " ");
\r
9309 len = strlen(reply);
\r
9310 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9311 strcat(reply, "\n");
\r
9312 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9313 EndDialog(hDlg, TRUE);
\r
9314 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9317 EndDialog(hDlg, FALSE);
\r
9328 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9330 QuestionParams qp;
\r
9334 qp.question = question;
\r
9335 qp.replyPrefix = replyPrefix;
\r
9337 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9338 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9339 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9340 FreeProcInstance(lpProc);
\r
9343 /* [AS] Pick FRC position */
\r
9344 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9346 static int * lpIndexFRC;
\r
9352 case WM_INITDIALOG:
\r
9353 lpIndexFRC = (int *) lParam;
\r
9355 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9357 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9358 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9359 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9360 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9365 switch( LOWORD(wParam) ) {
\r
9367 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9368 EndDialog( hDlg, 0 );
\r
9369 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9372 EndDialog( hDlg, 1 );
\r
9374 case IDC_NFG_Edit:
\r
9375 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9376 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9378 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9381 case IDC_NFG_Random:
\r
9382 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9383 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9396 int index = appData.defaultFrcPosition;
\r
9397 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9399 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9401 if( result == 0 ) {
\r
9402 appData.defaultFrcPosition = index;
\r
9408 /* [AS] Game list options */
\r
9414 static GLT_Item GLT_ItemInfo[] = {
\r
9415 { GLT_EVENT, "Event" },
\r
9416 { GLT_SITE, "Site" },
\r
9417 { GLT_DATE, "Date" },
\r
9418 { GLT_ROUND, "Round" },
\r
9419 { GLT_PLAYERS, "Players" },
\r
9420 { GLT_RESULT, "Result" },
\r
9421 { GLT_WHITE_ELO, "White Rating" },
\r
9422 { GLT_BLACK_ELO, "Black Rating" },
\r
9423 { GLT_TIME_CONTROL,"Time Control" },
\r
9424 { GLT_VARIANT, "Variant" },
\r
9425 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9426 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9430 const char * GLT_FindItem( char id )
\r
9432 const char * result = 0;
\r
9434 GLT_Item * list = GLT_ItemInfo;
\r
9436 while( list->id != 0 ) {
\r
9437 if( list->id == id ) {
\r
9438 result = list->name;
\r
9448 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9450 const char * name = GLT_FindItem( id );
\r
9453 if( index >= 0 ) {
\r
9454 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9457 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9462 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9466 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9469 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9473 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9475 pc = GLT_ALL_TAGS;
\r
9478 if( strchr( tags, *pc ) == 0 ) {
\r
9479 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9484 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9487 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9489 char result = '\0';
\r
9492 GLT_Item * list = GLT_ItemInfo;
\r
9494 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9495 while( list->id != 0 ) {
\r
9496 if( strcmp( list->name, name ) == 0 ) {
\r
9497 result = list->id;
\r
9508 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9510 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9511 int idx2 = idx1 + delta;
\r
9512 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9514 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9517 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9518 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9519 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9520 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9524 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9526 static char glt[64];
\r
9527 static char * lpUserGLT;
\r
9531 case WM_INITDIALOG:
\r
9532 lpUserGLT = (char *) lParam;
\r
9534 strcpy( glt, lpUserGLT );
\r
9536 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9538 /* Initialize list */
\r
9539 GLT_TagsToList( hDlg, glt );
\r
9541 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9546 switch( LOWORD(wParam) ) {
\r
9549 char * pc = lpUserGLT;
\r
9551 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9555 id = GLT_ListItemToTag( hDlg, idx );
\r
9559 } while( id != '\0' );
\r
9561 EndDialog( hDlg, 0 );
\r
9564 EndDialog( hDlg, 1 );
\r
9567 case IDC_GLT_Default:
\r
9568 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9569 GLT_TagsToList( hDlg, glt );
\r
9572 case IDC_GLT_Restore:
\r
9573 strcpy( glt, lpUserGLT );
\r
9574 GLT_TagsToList( hDlg, glt );
\r
9578 GLT_MoveSelection( hDlg, -1 );
\r
9581 case IDC_GLT_Down:
\r
9582 GLT_MoveSelection( hDlg, +1 );
\r
9592 int GameListOptions()
\r
9596 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9598 strcpy( glt, appData.gameListTags );
\r
9600 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9602 if( result == 0 ) {
\r
9603 /* [AS] Memory leak here! */
\r
9604 appData.gameListTags = strdup( glt );
\r
9612 DisplayIcsInteractionTitle(char *str)
\r
9614 char consoleTitle[MSG_SIZ];
\r
9616 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9617 SetWindowText(hwndConsole, consoleTitle);
\r
9621 DrawPosition(int fullRedraw, Board board)
\r
9623 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9630 fromX = fromY = -1;
\r
9631 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9632 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9633 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9634 dragInfo.lastpos = dragInfo.pos;
\r
9635 dragInfo.start.x = dragInfo.start.y = -1;
\r
9636 dragInfo.from = dragInfo.start;
\r
9638 DrawPosition(TRUE, NULL);
\r
9644 CommentPopUp(char *title, char *str)
\r
9646 HWND hwnd = GetActiveWindow();
\r
9647 EitherCommentPopUp(0, title, str, FALSE);
\r
9649 SetActiveWindow(hwnd);
\r
9653 CommentPopDown(void)
\r
9655 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9656 if (commentDialog) {
\r
9657 ShowWindow(commentDialog, SW_HIDE);
\r
9659 commentDialogUp = FALSE;
\r
9663 EditCommentPopUp(int index, char *title, char *str)
\r
9665 EitherCommentPopUp(index, title, str, TRUE);
\r
9672 MyPlaySound(&sounds[(int)SoundMove]);
\r
9675 VOID PlayIcsWinSound()
\r
9677 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9680 VOID PlayIcsLossSound()
\r
9682 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9685 VOID PlayIcsDrawSound()
\r
9687 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9690 VOID PlayIcsUnfinishedSound()
\r
9692 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9698 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9706 consoleEcho = TRUE;
\r
9707 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9708 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9709 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9718 consoleEcho = FALSE;
\r
9719 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9720 /* This works OK: set text and background both to the same color */
\r
9722 cf.crTextColor = COLOR_ECHOOFF;
\r
9723 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9724 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9727 /* No Raw()...? */
\r
9729 void Colorize(ColorClass cc, int continuation)
\r
9731 currentColorClass = cc;
\r
9732 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9733 consoleCF.crTextColor = textAttribs[cc].color;
\r
9734 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9735 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9741 static char buf[MSG_SIZ];
\r
9742 DWORD bufsiz = MSG_SIZ;
\r
9744 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9745 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9747 if (!GetUserName(buf, &bufsiz)) {
\r
9748 /*DisplayError("Error getting user name", GetLastError());*/
\r
9749 strcpy(buf, "User");
\r
9757 static char buf[MSG_SIZ];
\r
9758 DWORD bufsiz = MSG_SIZ;
\r
9760 if (!GetComputerName(buf, &bufsiz)) {
\r
9761 /*DisplayError("Error getting host name", GetLastError());*/
\r
9762 strcpy(buf, "Unknown");
\r
9769 ClockTimerRunning()
\r
9771 return clockTimerEvent != 0;
\r
9777 if (clockTimerEvent == 0) return FALSE;
\r
9778 KillTimer(hwndMain, clockTimerEvent);
\r
9779 clockTimerEvent = 0;
\r
9784 StartClockTimer(long millisec)
\r
9786 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9787 (UINT) millisec, NULL);
\r
9791 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9794 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9796 if(appData.noGUI) return;
\r
9797 hdc = GetDC(hwndMain);
\r
9798 if (!IsIconic(hwndMain)) {
\r
9799 DisplayAClock(hdc, timeRemaining, highlight,
\r
9800 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9802 if (highlight && iconCurrent == iconBlack) {
\r
9803 iconCurrent = iconWhite;
\r
9804 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9805 if (IsIconic(hwndMain)) {
\r
9806 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9809 (void) ReleaseDC(hwndMain, hdc);
\r
9811 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9815 DisplayBlackClock(long timeRemaining, int highlight)
\r
9818 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9820 if(appData.noGUI) return;
\r
9821 hdc = GetDC(hwndMain);
\r
9822 if (!IsIconic(hwndMain)) {
\r
9823 DisplayAClock(hdc, timeRemaining, highlight,
\r
9824 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9826 if (highlight && iconCurrent == iconWhite) {
\r
9827 iconCurrent = iconBlack;
\r
9828 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9829 if (IsIconic(hwndMain)) {
\r
9830 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9833 (void) ReleaseDC(hwndMain, hdc);
\r
9835 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9840 LoadGameTimerRunning()
\r
9842 return loadGameTimerEvent != 0;
\r
9846 StopLoadGameTimer()
\r
9848 if (loadGameTimerEvent == 0) return FALSE;
\r
9849 KillTimer(hwndMain, loadGameTimerEvent);
\r
9850 loadGameTimerEvent = 0;
\r
9855 StartLoadGameTimer(long millisec)
\r
9857 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9858 (UINT) millisec, NULL);
\r
9866 char fileTitle[MSG_SIZ];
\r
9868 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9869 f = OpenFileDialog(hwndMain, "a", defName,
\r
9870 appData.oldSaveStyle ? "gam" : "pgn",
\r
9872 "Save Game to File", NULL, fileTitle, NULL);
\r
9874 SaveGame(f, 0, "");
\r
9881 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9883 if (delayedTimerEvent != 0) {
\r
9884 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9885 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9887 KillTimer(hwndMain, delayedTimerEvent);
\r
9888 delayedTimerEvent = 0;
\r
9889 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9890 delayedTimerCallback();
\r
9892 delayedTimerCallback = cb;
\r
9893 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9894 (UINT) millisec, NULL);
\r
9897 DelayedEventCallback
\r
9900 if (delayedTimerEvent) {
\r
9901 return delayedTimerCallback;
\r
9908 CancelDelayedEvent()
\r
9910 if (delayedTimerEvent) {
\r
9911 KillTimer(hwndMain, delayedTimerEvent);
\r
9912 delayedTimerEvent = 0;
\r
9916 DWORD GetWin32Priority(int nice)
\r
9917 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9919 REALTIME_PRIORITY_CLASS 0x00000100
\r
9920 HIGH_PRIORITY_CLASS 0x00000080
\r
9921 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9922 NORMAL_PRIORITY_CLASS 0x00000020
\r
9923 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9924 IDLE_PRIORITY_CLASS 0x00000040
\r
9926 if (nice < -15) return 0x00000080;
\r
9927 if (nice < 0) return 0x00008000;
\r
9928 if (nice == 0) return 0x00000020;
\r
9929 if (nice < 15) return 0x00004000;
\r
9930 return 0x00000040;
\r
9933 /* Start a child process running the given program.
\r
9934 The process's standard output can be read from "from", and its
\r
9935 standard input can be written to "to".
\r
9936 Exit with fatal error if anything goes wrong.
\r
9937 Returns an opaque pointer that can be used to destroy the process
\r
9941 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9943 #define BUFSIZE 4096
\r
9945 HANDLE hChildStdinRd, hChildStdinWr,
\r
9946 hChildStdoutRd, hChildStdoutWr;
\r
9947 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9948 SECURITY_ATTRIBUTES saAttr;
\r
9950 PROCESS_INFORMATION piProcInfo;
\r
9951 STARTUPINFO siStartInfo;
\r
9953 char buf[MSG_SIZ];
\r
9956 if (appData.debugMode) {
\r
9957 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9962 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9963 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9964 saAttr.bInheritHandle = TRUE;
\r
9965 saAttr.lpSecurityDescriptor = NULL;
\r
9968 * The steps for redirecting child's STDOUT:
\r
9969 * 1. Create anonymous pipe to be STDOUT for child.
\r
9970 * 2. Create a noninheritable duplicate of read handle,
\r
9971 * and close the inheritable read handle.
\r
9974 /* Create a pipe for the child's STDOUT. */
\r
9975 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9976 return GetLastError();
\r
9979 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9980 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9981 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9982 FALSE, /* not inherited */
\r
9983 DUPLICATE_SAME_ACCESS);
\r
9985 return GetLastError();
\r
9987 CloseHandle(hChildStdoutRd);
\r
9990 * The steps for redirecting child's STDIN:
\r
9991 * 1. Create anonymous pipe to be STDIN for child.
\r
9992 * 2. Create a noninheritable duplicate of write handle,
\r
9993 * and close the inheritable write handle.
\r
9996 /* Create a pipe for the child's STDIN. */
\r
9997 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9998 return GetLastError();
\r
10001 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
10002 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
10003 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
10004 FALSE, /* not inherited */
\r
10005 DUPLICATE_SAME_ACCESS);
\r
10006 if (! fSuccess) {
\r
10007 return GetLastError();
\r
10009 CloseHandle(hChildStdinWr);
\r
10011 /* Arrange to (1) look in dir for the child .exe file, and
\r
10012 * (2) have dir be the child's working directory. Interpret
\r
10013 * dir relative to the directory WinBoard loaded from. */
\r
10014 GetCurrentDirectory(MSG_SIZ, buf);
\r
10015 SetCurrentDirectory(installDir);
\r
10016 SetCurrentDirectory(dir);
\r
10018 /* Now create the child process. */
\r
10020 siStartInfo.cb = sizeof(STARTUPINFO);
\r
10021 siStartInfo.lpReserved = NULL;
\r
10022 siStartInfo.lpDesktop = NULL;
\r
10023 siStartInfo.lpTitle = NULL;
\r
10024 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
10025 siStartInfo.cbReserved2 = 0;
\r
10026 siStartInfo.lpReserved2 = NULL;
\r
10027 siStartInfo.hStdInput = hChildStdinRd;
\r
10028 siStartInfo.hStdOutput = hChildStdoutWr;
\r
10029 siStartInfo.hStdError = hChildStdoutWr;
\r
10031 fSuccess = CreateProcess(NULL,
\r
10032 cmdLine, /* command line */
\r
10033 NULL, /* process security attributes */
\r
10034 NULL, /* primary thread security attrs */
\r
10035 TRUE, /* handles are inherited */
\r
10036 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
10037 NULL, /* use parent's environment */
\r
10039 &siStartInfo, /* STARTUPINFO pointer */
\r
10040 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
10042 err = GetLastError();
\r
10043 SetCurrentDirectory(buf); /* return to prev directory */
\r
10044 if (! fSuccess) {
\r
10048 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10049 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10050 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10053 /* Close the handles we don't need in the parent */
\r
10054 CloseHandle(piProcInfo.hThread);
\r
10055 CloseHandle(hChildStdinRd);
\r
10056 CloseHandle(hChildStdoutWr);
\r
10058 /* Prepare return value */
\r
10059 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10060 cp->kind = CPReal;
\r
10061 cp->hProcess = piProcInfo.hProcess;
\r
10062 cp->pid = piProcInfo.dwProcessId;
\r
10063 cp->hFrom = hChildStdoutRdDup;
\r
10064 cp->hTo = hChildStdinWrDup;
\r
10066 *pr = (void *) cp;
\r
10068 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10069 2000 where engines sometimes don't see the initial command(s)
\r
10070 from WinBoard and hang. I don't understand how that can happen,
\r
10071 but the Sleep is harmless, so I've put it in. Others have also
\r
10072 reported what may be the same problem, so hopefully this will fix
\r
10073 it for them too. */
\r
10081 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10083 ChildProc *cp; int result;
\r
10085 cp = (ChildProc *) pr;
\r
10086 if (cp == NULL) return;
\r
10088 switch (cp->kind) {
\r
10090 /* TerminateProcess is considered harmful, so... */
\r
10091 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10092 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10093 /* The following doesn't work because the chess program
\r
10094 doesn't "have the same console" as WinBoard. Maybe
\r
10095 we could arrange for this even though neither WinBoard
\r
10096 nor the chess program uses a console for stdio? */
\r
10097 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10099 /* [AS] Special termination modes for misbehaving programs... */
\r
10100 if( signal == 9 ) {
\r
10101 result = TerminateProcess( cp->hProcess, 0 );
\r
10103 if ( appData.debugMode) {
\r
10104 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10107 else if( signal == 10 ) {
\r
10108 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10110 if( dw != WAIT_OBJECT_0 ) {
\r
10111 result = TerminateProcess( cp->hProcess, 0 );
\r
10113 if ( appData.debugMode) {
\r
10114 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10120 CloseHandle(cp->hProcess);
\r
10124 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10128 closesocket(cp->sock);
\r
10133 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10134 closesocket(cp->sock);
\r
10135 closesocket(cp->sock2);
\r
10143 InterruptChildProcess(ProcRef pr)
\r
10147 cp = (ChildProc *) pr;
\r
10148 if (cp == NULL) return;
\r
10149 switch (cp->kind) {
\r
10151 /* The following doesn't work because the chess program
\r
10152 doesn't "have the same console" as WinBoard. Maybe
\r
10153 we could arrange for this even though neither WinBoard
\r
10154 nor the chess program uses a console for stdio */
\r
10155 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10160 /* Can't interrupt */
\r
10164 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10171 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10173 char cmdLine[MSG_SIZ];
\r
10175 if (port[0] == NULLCHAR) {
\r
10176 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10178 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10180 return StartChildProcess(cmdLine, "", pr);
\r
10184 /* Code to open TCP sockets */
\r
10187 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10192 struct sockaddr_in sa, mysa;
\r
10193 struct hostent FAR *hp;
\r
10194 unsigned short uport;
\r
10195 WORD wVersionRequested;
\r
10198 /* Initialize socket DLL */
\r
10199 wVersionRequested = MAKEWORD(1, 1);
\r
10200 err = WSAStartup(wVersionRequested, &wsaData);
\r
10201 if (err != 0) return err;
\r
10203 /* Make socket */
\r
10204 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10205 err = WSAGetLastError();
\r
10210 /* Bind local address using (mostly) don't-care values.
\r
10212 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10213 mysa.sin_family = AF_INET;
\r
10214 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10215 uport = (unsigned short) 0;
\r
10216 mysa.sin_port = htons(uport);
\r
10217 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10218 == SOCKET_ERROR) {
\r
10219 err = WSAGetLastError();
\r
10224 /* Resolve remote host name */
\r
10225 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10226 if (!(hp = gethostbyname(host))) {
\r
10227 unsigned int b0, b1, b2, b3;
\r
10229 err = WSAGetLastError();
\r
10231 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10232 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10233 hp->h_addrtype = AF_INET;
\r
10234 hp->h_length = 4;
\r
10235 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10236 hp->h_addr_list[0] = (char *) malloc(4);
\r
10237 hp->h_addr_list[0][0] = (char) b0;
\r
10238 hp->h_addr_list[0][1] = (char) b1;
\r
10239 hp->h_addr_list[0][2] = (char) b2;
\r
10240 hp->h_addr_list[0][3] = (char) b3;
\r
10246 sa.sin_family = hp->h_addrtype;
\r
10247 uport = (unsigned short) atoi(port);
\r
10248 sa.sin_port = htons(uport);
\r
10249 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10251 /* Make connection */
\r
10252 if (connect(s, (struct sockaddr *) &sa,
\r
10253 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10254 err = WSAGetLastError();
\r
10259 /* Prepare return value */
\r
10260 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10261 cp->kind = CPSock;
\r
10263 *pr = (ProcRef *) cp;
\r
10269 OpenCommPort(char *name, ProcRef *pr)
\r
10274 char fullname[MSG_SIZ];
\r
10276 if (*name != '\\')
\r
10277 sprintf(fullname, "\\\\.\\%s", name);
\r
10279 strcpy(fullname, name);
\r
10281 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10282 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10283 if (h == (HANDLE) -1) {
\r
10284 return GetLastError();
\r
10288 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10290 /* Accumulate characters until a 100ms pause, then parse */
\r
10291 ct.ReadIntervalTimeout = 100;
\r
10292 ct.ReadTotalTimeoutMultiplier = 0;
\r
10293 ct.ReadTotalTimeoutConstant = 0;
\r
10294 ct.WriteTotalTimeoutMultiplier = 0;
\r
10295 ct.WriteTotalTimeoutConstant = 0;
\r
10296 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10298 /* Prepare return value */
\r
10299 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10300 cp->kind = CPComm;
\r
10303 *pr = (ProcRef *) cp;
\r
10309 OpenLoopback(ProcRef *pr)
\r
10311 DisplayFatalError("Not implemented", 0, 1);
\r
10317 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10321 SOCKET s, s2, s3;
\r
10322 struct sockaddr_in sa, mysa;
\r
10323 struct hostent FAR *hp;
\r
10324 unsigned short uport;
\r
10325 WORD wVersionRequested;
\r
10328 char stderrPortStr[MSG_SIZ];
\r
10330 /* Initialize socket DLL */
\r
10331 wVersionRequested = MAKEWORD(1, 1);
\r
10332 err = WSAStartup(wVersionRequested, &wsaData);
\r
10333 if (err != 0) return err;
\r
10335 /* Resolve remote host name */
\r
10336 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10337 if (!(hp = gethostbyname(host))) {
\r
10338 unsigned int b0, b1, b2, b3;
\r
10340 err = WSAGetLastError();
\r
10342 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10343 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10344 hp->h_addrtype = AF_INET;
\r
10345 hp->h_length = 4;
\r
10346 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10347 hp->h_addr_list[0] = (char *) malloc(4);
\r
10348 hp->h_addr_list[0][0] = (char) b0;
\r
10349 hp->h_addr_list[0][1] = (char) b1;
\r
10350 hp->h_addr_list[0][2] = (char) b2;
\r
10351 hp->h_addr_list[0][3] = (char) b3;
\r
10357 sa.sin_family = hp->h_addrtype;
\r
10358 uport = (unsigned short) 514;
\r
10359 sa.sin_port = htons(uport);
\r
10360 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10362 /* Bind local socket to unused "privileged" port address
\r
10364 s = INVALID_SOCKET;
\r
10365 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10366 mysa.sin_family = AF_INET;
\r
10367 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10368 for (fromPort = 1023;; fromPort--) {
\r
10369 if (fromPort < 0) {
\r
10371 return WSAEADDRINUSE;
\r
10373 if (s == INVALID_SOCKET) {
\r
10374 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10375 err = WSAGetLastError();
\r
10380 uport = (unsigned short) fromPort;
\r
10381 mysa.sin_port = htons(uport);
\r
10382 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10383 == SOCKET_ERROR) {
\r
10384 err = WSAGetLastError();
\r
10385 if (err == WSAEADDRINUSE) continue;
\r
10389 if (connect(s, (struct sockaddr *) &sa,
\r
10390 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10391 err = WSAGetLastError();
\r
10392 if (err == WSAEADDRINUSE) {
\r
10403 /* Bind stderr local socket to unused "privileged" port address
\r
10405 s2 = INVALID_SOCKET;
\r
10406 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10407 mysa.sin_family = AF_INET;
\r
10408 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10409 for (fromPort = 1023;; fromPort--) {
\r
10410 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10411 if (fromPort < 0) {
\r
10412 (void) closesocket(s);
\r
10414 return WSAEADDRINUSE;
\r
10416 if (s2 == INVALID_SOCKET) {
\r
10417 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10418 err = WSAGetLastError();
\r
10424 uport = (unsigned short) fromPort;
\r
10425 mysa.sin_port = htons(uport);
\r
10426 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10427 == SOCKET_ERROR) {
\r
10428 err = WSAGetLastError();
\r
10429 if (err == WSAEADDRINUSE) continue;
\r
10430 (void) closesocket(s);
\r
10434 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10435 err = WSAGetLastError();
\r
10436 if (err == WSAEADDRINUSE) {
\r
10438 s2 = INVALID_SOCKET;
\r
10441 (void) closesocket(s);
\r
10442 (void) closesocket(s2);
\r
10448 prevStderrPort = fromPort; // remember port used
\r
10449 sprintf(stderrPortStr, "%d", fromPort);
\r
10451 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10452 err = WSAGetLastError();
\r
10453 (void) closesocket(s);
\r
10454 (void) closesocket(s2);
\r
10459 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10460 err = WSAGetLastError();
\r
10461 (void) closesocket(s);
\r
10462 (void) closesocket(s2);
\r
10466 if (*user == NULLCHAR) user = UserName();
\r
10467 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10468 err = WSAGetLastError();
\r
10469 (void) closesocket(s);
\r
10470 (void) closesocket(s2);
\r
10474 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10475 err = WSAGetLastError();
\r
10476 (void) closesocket(s);
\r
10477 (void) closesocket(s2);
\r
10482 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10483 err = WSAGetLastError();
\r
10484 (void) closesocket(s);
\r
10485 (void) closesocket(s2);
\r
10489 (void) closesocket(s2); /* Stop listening */
\r
10491 /* Prepare return value */
\r
10492 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10493 cp->kind = CPRcmd;
\r
10496 *pr = (ProcRef *) cp;
\r
10503 AddInputSource(ProcRef pr, int lineByLine,
\r
10504 InputCallback func, VOIDSTAR closure)
\r
10506 InputSource *is, *is2 = NULL;
\r
10507 ChildProc *cp = (ChildProc *) pr;
\r
10509 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10510 is->lineByLine = lineByLine;
\r
10512 is->closure = closure;
\r
10513 is->second = NULL;
\r
10514 is->next = is->buf;
\r
10515 if (pr == NoProc) {
\r
10516 is->kind = CPReal;
\r
10517 consoleInputSource = is;
\r
10519 is->kind = cp->kind;
\r
10521 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10522 we create all threads suspended so that the is->hThread variable can be
\r
10523 safely assigned, then let the threads start with ResumeThread.
\r
10525 switch (cp->kind) {
\r
10527 is->hFile = cp->hFrom;
\r
10528 cp->hFrom = NULL; /* now owned by InputThread */
\r
10530 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10531 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10535 is->hFile = cp->hFrom;
\r
10536 cp->hFrom = NULL; /* now owned by InputThread */
\r
10538 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10539 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10543 is->sock = cp->sock;
\r
10545 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10546 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10550 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10552 is->sock = cp->sock;
\r
10553 is->second = is2;
\r
10554 is2->sock = cp->sock2;
\r
10555 is2->second = is2;
\r
10557 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10558 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10560 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10561 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10565 if( is->hThread != NULL ) {
\r
10566 ResumeThread( is->hThread );
\r
10569 if( is2 != NULL && is2->hThread != NULL ) {
\r
10570 ResumeThread( is2->hThread );
\r
10574 return (InputSourceRef) is;
\r
10578 RemoveInputSource(InputSourceRef isr)
\r
10582 is = (InputSource *) isr;
\r
10583 is->hThread = NULL; /* tell thread to stop */
\r
10584 CloseHandle(is->hThread);
\r
10585 if (is->second != NULL) {
\r
10586 is->second->hThread = NULL;
\r
10587 CloseHandle(is->second->hThread);
\r
10593 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10596 int outCount = SOCKET_ERROR;
\r
10597 ChildProc *cp = (ChildProc *) pr;
\r
10598 static OVERLAPPED ovl;
\r
10600 if (pr == NoProc) {
\r
10601 ConsoleOutput(message, count, FALSE);
\r
10605 if (ovl.hEvent == NULL) {
\r
10606 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10608 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10610 switch (cp->kind) {
\r
10613 outCount = send(cp->sock, message, count, 0);
\r
10614 if (outCount == SOCKET_ERROR) {
\r
10615 *outError = WSAGetLastError();
\r
10617 *outError = NO_ERROR;
\r
10622 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10623 &dOutCount, NULL)) {
\r
10624 *outError = NO_ERROR;
\r
10625 outCount = (int) dOutCount;
\r
10627 *outError = GetLastError();
\r
10632 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10633 &dOutCount, &ovl);
\r
10634 if (*outError == NO_ERROR) {
\r
10635 outCount = (int) dOutCount;
\r
10643 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10646 /* Ignore delay, not implemented for WinBoard */
\r
10647 return OutputToProcess(pr, message, count, outError);
\r
10652 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10653 char *buf, int count, int error)
\r
10655 DisplayFatalError("Not implemented", 0, 1);
\r
10658 /* see wgamelist.c for Game List functions */
\r
10659 /* see wedittags.c for Edit Tags functions */
\r
10666 char buf[MSG_SIZ];
\r
10669 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10670 f = fopen(buf, "r");
\r
10672 ProcessICSInitScript(f);
\r
10680 StartAnalysisClock()
\r
10682 if (analysisTimerEvent) return;
\r
10683 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10684 (UINT) 2000, NULL);
\r
10688 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10690 static HANDLE hwndText;
\r
10692 static int sizeX, sizeY;
\r
10693 int newSizeX, newSizeY, flags;
\r
10696 switch (message) {
\r
10697 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10698 /* Initialize the dialog items */
\r
10699 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10700 SetWindowText(hDlg, analysisTitle);
\r
10701 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10702 /* Size and position the dialog */
\r
10703 if (!analysisDialog) {
\r
10704 analysisDialog = hDlg;
\r
10705 flags = SWP_NOZORDER;
\r
10706 GetClientRect(hDlg, &rect);
\r
10707 sizeX = rect.right;
\r
10708 sizeY = rect.bottom;
\r
10709 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10710 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10711 WINDOWPLACEMENT wp;
\r
10712 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10713 wp.length = sizeof(WINDOWPLACEMENT);
\r
10715 wp.showCmd = SW_SHOW;
\r
10716 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10717 wp.rcNormalPosition.left = analysisX;
\r
10718 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10719 wp.rcNormalPosition.top = analysisY;
\r
10720 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10721 SetWindowPlacement(hDlg, &wp);
\r
10723 GetClientRect(hDlg, &rect);
\r
10724 newSizeX = rect.right;
\r
10725 newSizeY = rect.bottom;
\r
10726 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10727 newSizeX, newSizeY);
\r
10728 sizeX = newSizeX;
\r
10729 sizeY = newSizeY;
\r
10734 case WM_COMMAND: /* message: received a command */
\r
10735 switch (LOWORD(wParam)) {
\r
10737 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10738 ExitAnalyzeMode();
\r
10750 newSizeX = LOWORD(lParam);
\r
10751 newSizeY = HIWORD(lParam);
\r
10752 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10753 sizeX = newSizeX;
\r
10754 sizeY = newSizeY;
\r
10757 case WM_GETMINMAXINFO:
\r
10758 /* Prevent resizing window too small */
\r
10759 mmi = (MINMAXINFO *) lParam;
\r
10760 mmi->ptMinTrackSize.x = 100;
\r
10761 mmi->ptMinTrackSize.y = 100;
\r
10768 AnalysisPopUp(char* title, char* str)
\r
10774 EngineOutputPopUp();
\r
10777 if (str == NULL) str = "";
\r
10778 p = (char *) malloc(2 * strlen(str) + 2);
\r
10781 if (*str == '\n') *q++ = '\r';
\r
10785 if (analysisText != NULL) free(analysisText);
\r
10786 analysisText = p;
\r
10788 if (analysisDialog) {
\r
10789 SetWindowText(analysisDialog, title);
\r
10790 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10791 ShowWindow(analysisDialog, SW_SHOW);
\r
10793 analysisTitle = title;
\r
10794 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10795 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10796 hwndMain, (DLGPROC)lpProc);
\r
10797 FreeProcInstance(lpProc);
\r
10799 analysisDialogUp = TRUE;
\r
10803 AnalysisPopDown()
\r
10805 if (analysisDialog) {
\r
10806 ShowWindow(analysisDialog, SW_HIDE);
\r
10808 analysisDialogUp = FALSE;
\r
10813 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10815 highlightInfo.sq[0].x = fromX;
\r
10816 highlightInfo.sq[0].y = fromY;
\r
10817 highlightInfo.sq[1].x = toX;
\r
10818 highlightInfo.sq[1].y = toY;
\r
10822 ClearHighlights()
\r
10824 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10825 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10829 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10831 premoveHighlightInfo.sq[0].x = fromX;
\r
10832 premoveHighlightInfo.sq[0].y = fromY;
\r
10833 premoveHighlightInfo.sq[1].x = toX;
\r
10834 premoveHighlightInfo.sq[1].y = toY;
\r
10838 ClearPremoveHighlights()
\r
10840 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10841 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10845 ShutDownFrontEnd()
\r
10847 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10848 DeleteClipboardTempFiles();
\r
10854 if (IsIconic(hwndMain))
\r
10855 ShowWindow(hwndMain, SW_RESTORE);
\r
10857 SetActiveWindow(hwndMain);
\r
10861 * Prototypes for animation support routines
\r
10863 static void ScreenSquare(int column, int row, POINT * pt);
\r
10864 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10865 POINT frames[], int * nFrames);
\r
10869 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10870 { // [HGM] atomic: animate blast wave
\r
10872 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10873 explodeInfo.fromX = fromX;
\r
10874 explodeInfo.fromY = fromY;
\r
10875 explodeInfo.toX = toX;
\r
10876 explodeInfo.toY = toY;
\r
10877 for(i=1; i<nFrames; i++) {
\r
10878 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10879 DrawPosition(FALSE, NULL);
\r
10880 Sleep(appData.animSpeed);
\r
10882 explodeInfo.radius = 0;
\r
10883 DrawPosition(TRUE, NULL);
\r
10886 #define kFactor 4
\r
10889 AnimateMove(board, fromX, fromY, toX, toY)
\r
10896 ChessSquare piece;
\r
10897 POINT start, finish, mid;
\r
10898 POINT frames[kFactor * 2 + 1];
\r
10901 if (!appData.animate) return;
\r
10902 if (doingSizing) return;
\r
10903 if (fromY < 0 || fromX < 0) return;
\r
10904 piece = board[fromY][fromX];
\r
10905 if (piece >= EmptySquare) return;
\r
10907 ScreenSquare(fromX, fromY, &start);
\r
10908 ScreenSquare(toX, toY, &finish);
\r
10910 /* All pieces except knights move in straight line */
\r
10911 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10912 mid.x = start.x + (finish.x - start.x) / 2;
\r
10913 mid.y = start.y + (finish.y - start.y) / 2;
\r
10915 /* Knight: make diagonal movement then straight */
\r
10916 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10917 mid.x = start.x + (finish.x - start.x) / 2;
\r
10918 mid.y = finish.y;
\r
10920 mid.x = finish.x;
\r
10921 mid.y = start.y + (finish.y - start.y) / 2;
\r
10925 /* Don't use as many frames for very short moves */
\r
10926 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10927 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10929 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10931 animInfo.from.x = fromX;
\r
10932 animInfo.from.y = fromY;
\r
10933 animInfo.to.x = toX;
\r
10934 animInfo.to.y = toY;
\r
10935 animInfo.lastpos = start;
\r
10936 animInfo.piece = piece;
\r
10937 for (n = 0; n < nFrames; n++) {
\r
10938 animInfo.pos = frames[n];
\r
10939 DrawPosition(FALSE, NULL);
\r
10940 animInfo.lastpos = animInfo.pos;
\r
10941 Sleep(appData.animSpeed);
\r
10943 animInfo.pos = finish;
\r
10944 DrawPosition(FALSE, NULL);
\r
10945 animInfo.piece = EmptySquare;
\r
10946 if(gameInfo.variant == VariantAtomic &&
\r
10947 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10948 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10951 /* Convert board position to corner of screen rect and color */
\r
10954 ScreenSquare(column, row, pt)
\r
10955 int column; int row; POINT * pt;
\r
10958 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10959 pt->y = lineGap + row * (squareSize + lineGap);
\r
10961 pt->x = lineGap + column * (squareSize + lineGap);
\r
10962 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10966 /* Generate a series of frame coords from start->mid->finish.
\r
10967 The movement rate doubles until the half way point is
\r
10968 reached, then halves back down to the final destination,
\r
10969 which gives a nice slow in/out effect. The algorithmn
\r
10970 may seem to generate too many intermediates for short
\r
10971 moves, but remember that the purpose is to attract the
\r
10972 viewers attention to the piece about to be moved and
\r
10973 then to where it ends up. Too few frames would be less
\r
10977 Tween(start, mid, finish, factor, frames, nFrames)
\r
10978 POINT * start; POINT * mid;
\r
10979 POINT * finish; int factor;
\r
10980 POINT frames[]; int * nFrames;
\r
10982 int n, fraction = 1, count = 0;
\r
10984 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10985 for (n = 0; n < factor; n++)
\r
10987 for (n = 0; n < factor; n++) {
\r
10988 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10989 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10991 fraction = fraction / 2;
\r
10995 frames[count] = *mid;
\r
10998 /* Slow out, stepping 1/2, then 1/4, ... */
\r
11000 for (n = 0; n < factor; n++) {
\r
11001 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
11002 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
11004 fraction = fraction * 2;
\r
11006 *nFrames = count;
\r
11010 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
11015 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
11016 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
11018 OutputDebugString( buf );
\r
11021 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
11023 EvalGraphSet( first, last, current, pvInfoList );
\r
11026 void SetProgramStats( FrontEndProgramStats * stats )
\r
11031 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
11032 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
11034 OutputDebugString( buf );
\r
11037 EngineOutputUpdate( stats );
\r