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
9648 SetActiveWindow(hwnd);
\r
9652 CommentPopDown(void)
\r
9654 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9655 if (commentDialog) {
\r
9656 ShowWindow(commentDialog, SW_HIDE);
\r
9658 commentDialogUp = FALSE;
\r
9662 EditCommentPopUp(int index, char *title, char *str)
\r
9664 EitherCommentPopUp(index, title, str, TRUE);
\r
9671 MyPlaySound(&sounds[(int)SoundMove]);
\r
9674 VOID PlayIcsWinSound()
\r
9676 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9679 VOID PlayIcsLossSound()
\r
9681 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9684 VOID PlayIcsDrawSound()
\r
9686 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9689 VOID PlayIcsUnfinishedSound()
\r
9691 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9697 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9705 consoleEcho = TRUE;
\r
9706 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9707 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9708 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9717 consoleEcho = FALSE;
\r
9718 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9719 /* This works OK: set text and background both to the same color */
\r
9721 cf.crTextColor = COLOR_ECHOOFF;
\r
9722 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9723 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9726 /* No Raw()...? */
\r
9728 void Colorize(ColorClass cc, int continuation)
\r
9730 currentColorClass = cc;
\r
9731 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9732 consoleCF.crTextColor = textAttribs[cc].color;
\r
9733 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9734 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9740 static char buf[MSG_SIZ];
\r
9741 DWORD bufsiz = MSG_SIZ;
\r
9743 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9744 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9746 if (!GetUserName(buf, &bufsiz)) {
\r
9747 /*DisplayError("Error getting user name", GetLastError());*/
\r
9748 strcpy(buf, "User");
\r
9756 static char buf[MSG_SIZ];
\r
9757 DWORD bufsiz = MSG_SIZ;
\r
9759 if (!GetComputerName(buf, &bufsiz)) {
\r
9760 /*DisplayError("Error getting host name", GetLastError());*/
\r
9761 strcpy(buf, "Unknown");
\r
9768 ClockTimerRunning()
\r
9770 return clockTimerEvent != 0;
\r
9776 if (clockTimerEvent == 0) return FALSE;
\r
9777 KillTimer(hwndMain, clockTimerEvent);
\r
9778 clockTimerEvent = 0;
\r
9783 StartClockTimer(long millisec)
\r
9785 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9786 (UINT) millisec, NULL);
\r
9790 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9793 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9795 if(appData.noGUI) return;
\r
9796 hdc = GetDC(hwndMain);
\r
9797 if (!IsIconic(hwndMain)) {
\r
9798 DisplayAClock(hdc, timeRemaining, highlight,
\r
9799 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9801 if (highlight && iconCurrent == iconBlack) {
\r
9802 iconCurrent = iconWhite;
\r
9803 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9804 if (IsIconic(hwndMain)) {
\r
9805 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9808 (void) ReleaseDC(hwndMain, hdc);
\r
9810 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9814 DisplayBlackClock(long timeRemaining, int highlight)
\r
9817 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9819 if(appData.noGUI) return;
\r
9820 hdc = GetDC(hwndMain);
\r
9821 if (!IsIconic(hwndMain)) {
\r
9822 DisplayAClock(hdc, timeRemaining, highlight,
\r
9823 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9825 if (highlight && iconCurrent == iconWhite) {
\r
9826 iconCurrent = iconBlack;
\r
9827 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9828 if (IsIconic(hwndMain)) {
\r
9829 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9832 (void) ReleaseDC(hwndMain, hdc);
\r
9834 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9839 LoadGameTimerRunning()
\r
9841 return loadGameTimerEvent != 0;
\r
9845 StopLoadGameTimer()
\r
9847 if (loadGameTimerEvent == 0) return FALSE;
\r
9848 KillTimer(hwndMain, loadGameTimerEvent);
\r
9849 loadGameTimerEvent = 0;
\r
9854 StartLoadGameTimer(long millisec)
\r
9856 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9857 (UINT) millisec, NULL);
\r
9865 char fileTitle[MSG_SIZ];
\r
9867 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9868 f = OpenFileDialog(hwndMain, "a", defName,
\r
9869 appData.oldSaveStyle ? "gam" : "pgn",
\r
9871 "Save Game to File", NULL, fileTitle, NULL);
\r
9873 SaveGame(f, 0, "");
\r
9880 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9882 if (delayedTimerEvent != 0) {
\r
9883 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9884 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9886 KillTimer(hwndMain, delayedTimerEvent);
\r
9887 delayedTimerEvent = 0;
\r
9888 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9889 delayedTimerCallback();
\r
9891 delayedTimerCallback = cb;
\r
9892 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9893 (UINT) millisec, NULL);
\r
9896 DelayedEventCallback
\r
9899 if (delayedTimerEvent) {
\r
9900 return delayedTimerCallback;
\r
9907 CancelDelayedEvent()
\r
9909 if (delayedTimerEvent) {
\r
9910 KillTimer(hwndMain, delayedTimerEvent);
\r
9911 delayedTimerEvent = 0;
\r
9915 DWORD GetWin32Priority(int nice)
\r
9916 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9918 REALTIME_PRIORITY_CLASS 0x00000100
\r
9919 HIGH_PRIORITY_CLASS 0x00000080
\r
9920 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9921 NORMAL_PRIORITY_CLASS 0x00000020
\r
9922 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9923 IDLE_PRIORITY_CLASS 0x00000040
\r
9925 if (nice < -15) return 0x00000080;
\r
9926 if (nice < 0) return 0x00008000;
\r
9927 if (nice == 0) return 0x00000020;
\r
9928 if (nice < 15) return 0x00004000;
\r
9929 return 0x00000040;
\r
9932 /* Start a child process running the given program.
\r
9933 The process's standard output can be read from "from", and its
\r
9934 standard input can be written to "to".
\r
9935 Exit with fatal error if anything goes wrong.
\r
9936 Returns an opaque pointer that can be used to destroy the process
\r
9940 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9942 #define BUFSIZE 4096
\r
9944 HANDLE hChildStdinRd, hChildStdinWr,
\r
9945 hChildStdoutRd, hChildStdoutWr;
\r
9946 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9947 SECURITY_ATTRIBUTES saAttr;
\r
9949 PROCESS_INFORMATION piProcInfo;
\r
9950 STARTUPINFO siStartInfo;
\r
9952 char buf[MSG_SIZ];
\r
9955 if (appData.debugMode) {
\r
9956 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9961 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9962 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9963 saAttr.bInheritHandle = TRUE;
\r
9964 saAttr.lpSecurityDescriptor = NULL;
\r
9967 * The steps for redirecting child's STDOUT:
\r
9968 * 1. Create anonymous pipe to be STDOUT for child.
\r
9969 * 2. Create a noninheritable duplicate of read handle,
\r
9970 * and close the inheritable read handle.
\r
9973 /* Create a pipe for the child's STDOUT. */
\r
9974 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9975 return GetLastError();
\r
9978 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9979 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9980 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9981 FALSE, /* not inherited */
\r
9982 DUPLICATE_SAME_ACCESS);
\r
9984 return GetLastError();
\r
9986 CloseHandle(hChildStdoutRd);
\r
9989 * The steps for redirecting child's STDIN:
\r
9990 * 1. Create anonymous pipe to be STDIN for child.
\r
9991 * 2. Create a noninheritable duplicate of write handle,
\r
9992 * and close the inheritable write handle.
\r
9995 /* Create a pipe for the child's STDIN. */
\r
9996 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9997 return GetLastError();
\r
10000 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
10001 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
10002 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
10003 FALSE, /* not inherited */
\r
10004 DUPLICATE_SAME_ACCESS);
\r
10005 if (! fSuccess) {
\r
10006 return GetLastError();
\r
10008 CloseHandle(hChildStdinWr);
\r
10010 /* Arrange to (1) look in dir for the child .exe file, and
\r
10011 * (2) have dir be the child's working directory. Interpret
\r
10012 * dir relative to the directory WinBoard loaded from. */
\r
10013 GetCurrentDirectory(MSG_SIZ, buf);
\r
10014 SetCurrentDirectory(installDir);
\r
10015 SetCurrentDirectory(dir);
\r
10017 /* Now create the child process. */
\r
10019 siStartInfo.cb = sizeof(STARTUPINFO);
\r
10020 siStartInfo.lpReserved = NULL;
\r
10021 siStartInfo.lpDesktop = NULL;
\r
10022 siStartInfo.lpTitle = NULL;
\r
10023 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
10024 siStartInfo.cbReserved2 = 0;
\r
10025 siStartInfo.lpReserved2 = NULL;
\r
10026 siStartInfo.hStdInput = hChildStdinRd;
\r
10027 siStartInfo.hStdOutput = hChildStdoutWr;
\r
10028 siStartInfo.hStdError = hChildStdoutWr;
\r
10030 fSuccess = CreateProcess(NULL,
\r
10031 cmdLine, /* command line */
\r
10032 NULL, /* process security attributes */
\r
10033 NULL, /* primary thread security attrs */
\r
10034 TRUE, /* handles are inherited */
\r
10035 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
10036 NULL, /* use parent's environment */
\r
10038 &siStartInfo, /* STARTUPINFO pointer */
\r
10039 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
10041 err = GetLastError();
\r
10042 SetCurrentDirectory(buf); /* return to prev directory */
\r
10043 if (! fSuccess) {
\r
10047 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10048 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10049 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10052 /* Close the handles we don't need in the parent */
\r
10053 CloseHandle(piProcInfo.hThread);
\r
10054 CloseHandle(hChildStdinRd);
\r
10055 CloseHandle(hChildStdoutWr);
\r
10057 /* Prepare return value */
\r
10058 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10059 cp->kind = CPReal;
\r
10060 cp->hProcess = piProcInfo.hProcess;
\r
10061 cp->pid = piProcInfo.dwProcessId;
\r
10062 cp->hFrom = hChildStdoutRdDup;
\r
10063 cp->hTo = hChildStdinWrDup;
\r
10065 *pr = (void *) cp;
\r
10067 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10068 2000 where engines sometimes don't see the initial command(s)
\r
10069 from WinBoard and hang. I don't understand how that can happen,
\r
10070 but the Sleep is harmless, so I've put it in. Others have also
\r
10071 reported what may be the same problem, so hopefully this will fix
\r
10072 it for them too. */
\r
10080 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10082 ChildProc *cp; int result;
\r
10084 cp = (ChildProc *) pr;
\r
10085 if (cp == NULL) return;
\r
10087 switch (cp->kind) {
\r
10089 /* TerminateProcess is considered harmful, so... */
\r
10090 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10091 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10092 /* The following doesn't work because the chess program
\r
10093 doesn't "have the same console" as WinBoard. Maybe
\r
10094 we could arrange for this even though neither WinBoard
\r
10095 nor the chess program uses a console for stdio? */
\r
10096 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10098 /* [AS] Special termination modes for misbehaving programs... */
\r
10099 if( signal == 9 ) {
\r
10100 result = TerminateProcess( cp->hProcess, 0 );
\r
10102 if ( appData.debugMode) {
\r
10103 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10106 else if( signal == 10 ) {
\r
10107 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10109 if( dw != WAIT_OBJECT_0 ) {
\r
10110 result = TerminateProcess( cp->hProcess, 0 );
\r
10112 if ( appData.debugMode) {
\r
10113 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10119 CloseHandle(cp->hProcess);
\r
10123 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10127 closesocket(cp->sock);
\r
10132 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10133 closesocket(cp->sock);
\r
10134 closesocket(cp->sock2);
\r
10142 InterruptChildProcess(ProcRef pr)
\r
10146 cp = (ChildProc *) pr;
\r
10147 if (cp == NULL) return;
\r
10148 switch (cp->kind) {
\r
10150 /* The following doesn't work because the chess program
\r
10151 doesn't "have the same console" as WinBoard. Maybe
\r
10152 we could arrange for this even though neither WinBoard
\r
10153 nor the chess program uses a console for stdio */
\r
10154 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10159 /* Can't interrupt */
\r
10163 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10170 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10172 char cmdLine[MSG_SIZ];
\r
10174 if (port[0] == NULLCHAR) {
\r
10175 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10177 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10179 return StartChildProcess(cmdLine, "", pr);
\r
10183 /* Code to open TCP sockets */
\r
10186 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10191 struct sockaddr_in sa, mysa;
\r
10192 struct hostent FAR *hp;
\r
10193 unsigned short uport;
\r
10194 WORD wVersionRequested;
\r
10197 /* Initialize socket DLL */
\r
10198 wVersionRequested = MAKEWORD(1, 1);
\r
10199 err = WSAStartup(wVersionRequested, &wsaData);
\r
10200 if (err != 0) return err;
\r
10202 /* Make socket */
\r
10203 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10204 err = WSAGetLastError();
\r
10209 /* Bind local address using (mostly) don't-care values.
\r
10211 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10212 mysa.sin_family = AF_INET;
\r
10213 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10214 uport = (unsigned short) 0;
\r
10215 mysa.sin_port = htons(uport);
\r
10216 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10217 == SOCKET_ERROR) {
\r
10218 err = WSAGetLastError();
\r
10223 /* Resolve remote host name */
\r
10224 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10225 if (!(hp = gethostbyname(host))) {
\r
10226 unsigned int b0, b1, b2, b3;
\r
10228 err = WSAGetLastError();
\r
10230 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10231 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10232 hp->h_addrtype = AF_INET;
\r
10233 hp->h_length = 4;
\r
10234 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10235 hp->h_addr_list[0] = (char *) malloc(4);
\r
10236 hp->h_addr_list[0][0] = (char) b0;
\r
10237 hp->h_addr_list[0][1] = (char) b1;
\r
10238 hp->h_addr_list[0][2] = (char) b2;
\r
10239 hp->h_addr_list[0][3] = (char) b3;
\r
10245 sa.sin_family = hp->h_addrtype;
\r
10246 uport = (unsigned short) atoi(port);
\r
10247 sa.sin_port = htons(uport);
\r
10248 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10250 /* Make connection */
\r
10251 if (connect(s, (struct sockaddr *) &sa,
\r
10252 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10253 err = WSAGetLastError();
\r
10258 /* Prepare return value */
\r
10259 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10260 cp->kind = CPSock;
\r
10262 *pr = (ProcRef *) cp;
\r
10268 OpenCommPort(char *name, ProcRef *pr)
\r
10273 char fullname[MSG_SIZ];
\r
10275 if (*name != '\\')
\r
10276 sprintf(fullname, "\\\\.\\%s", name);
\r
10278 strcpy(fullname, name);
\r
10280 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10281 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10282 if (h == (HANDLE) -1) {
\r
10283 return GetLastError();
\r
10287 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10289 /* Accumulate characters until a 100ms pause, then parse */
\r
10290 ct.ReadIntervalTimeout = 100;
\r
10291 ct.ReadTotalTimeoutMultiplier = 0;
\r
10292 ct.ReadTotalTimeoutConstant = 0;
\r
10293 ct.WriteTotalTimeoutMultiplier = 0;
\r
10294 ct.WriteTotalTimeoutConstant = 0;
\r
10295 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10297 /* Prepare return value */
\r
10298 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10299 cp->kind = CPComm;
\r
10302 *pr = (ProcRef *) cp;
\r
10308 OpenLoopback(ProcRef *pr)
\r
10310 DisplayFatalError("Not implemented", 0, 1);
\r
10316 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10320 SOCKET s, s2, s3;
\r
10321 struct sockaddr_in sa, mysa;
\r
10322 struct hostent FAR *hp;
\r
10323 unsigned short uport;
\r
10324 WORD wVersionRequested;
\r
10327 char stderrPortStr[MSG_SIZ];
\r
10329 /* Initialize socket DLL */
\r
10330 wVersionRequested = MAKEWORD(1, 1);
\r
10331 err = WSAStartup(wVersionRequested, &wsaData);
\r
10332 if (err != 0) return err;
\r
10334 /* Resolve remote host name */
\r
10335 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10336 if (!(hp = gethostbyname(host))) {
\r
10337 unsigned int b0, b1, b2, b3;
\r
10339 err = WSAGetLastError();
\r
10341 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10342 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10343 hp->h_addrtype = AF_INET;
\r
10344 hp->h_length = 4;
\r
10345 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10346 hp->h_addr_list[0] = (char *) malloc(4);
\r
10347 hp->h_addr_list[0][0] = (char) b0;
\r
10348 hp->h_addr_list[0][1] = (char) b1;
\r
10349 hp->h_addr_list[0][2] = (char) b2;
\r
10350 hp->h_addr_list[0][3] = (char) b3;
\r
10356 sa.sin_family = hp->h_addrtype;
\r
10357 uport = (unsigned short) 514;
\r
10358 sa.sin_port = htons(uport);
\r
10359 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10361 /* Bind local socket to unused "privileged" port address
\r
10363 s = INVALID_SOCKET;
\r
10364 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10365 mysa.sin_family = AF_INET;
\r
10366 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10367 for (fromPort = 1023;; fromPort--) {
\r
10368 if (fromPort < 0) {
\r
10370 return WSAEADDRINUSE;
\r
10372 if (s == INVALID_SOCKET) {
\r
10373 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10374 err = WSAGetLastError();
\r
10379 uport = (unsigned short) fromPort;
\r
10380 mysa.sin_port = htons(uport);
\r
10381 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10382 == SOCKET_ERROR) {
\r
10383 err = WSAGetLastError();
\r
10384 if (err == WSAEADDRINUSE) continue;
\r
10388 if (connect(s, (struct sockaddr *) &sa,
\r
10389 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10390 err = WSAGetLastError();
\r
10391 if (err == WSAEADDRINUSE) {
\r
10402 /* Bind stderr local socket to unused "privileged" port address
\r
10404 s2 = INVALID_SOCKET;
\r
10405 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10406 mysa.sin_family = AF_INET;
\r
10407 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10408 for (fromPort = 1023;; fromPort--) {
\r
10409 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10410 if (fromPort < 0) {
\r
10411 (void) closesocket(s);
\r
10413 return WSAEADDRINUSE;
\r
10415 if (s2 == INVALID_SOCKET) {
\r
10416 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10417 err = WSAGetLastError();
\r
10423 uport = (unsigned short) fromPort;
\r
10424 mysa.sin_port = htons(uport);
\r
10425 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10426 == SOCKET_ERROR) {
\r
10427 err = WSAGetLastError();
\r
10428 if (err == WSAEADDRINUSE) continue;
\r
10429 (void) closesocket(s);
\r
10433 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10434 err = WSAGetLastError();
\r
10435 if (err == WSAEADDRINUSE) {
\r
10437 s2 = INVALID_SOCKET;
\r
10440 (void) closesocket(s);
\r
10441 (void) closesocket(s2);
\r
10447 prevStderrPort = fromPort; // remember port used
\r
10448 sprintf(stderrPortStr, "%d", fromPort);
\r
10450 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10451 err = WSAGetLastError();
\r
10452 (void) closesocket(s);
\r
10453 (void) closesocket(s2);
\r
10458 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10459 err = WSAGetLastError();
\r
10460 (void) closesocket(s);
\r
10461 (void) closesocket(s2);
\r
10465 if (*user == NULLCHAR) user = UserName();
\r
10466 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10467 err = WSAGetLastError();
\r
10468 (void) closesocket(s);
\r
10469 (void) closesocket(s2);
\r
10473 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10474 err = WSAGetLastError();
\r
10475 (void) closesocket(s);
\r
10476 (void) closesocket(s2);
\r
10481 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10482 err = WSAGetLastError();
\r
10483 (void) closesocket(s);
\r
10484 (void) closesocket(s2);
\r
10488 (void) closesocket(s2); /* Stop listening */
\r
10490 /* Prepare return value */
\r
10491 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10492 cp->kind = CPRcmd;
\r
10495 *pr = (ProcRef *) cp;
\r
10502 AddInputSource(ProcRef pr, int lineByLine,
\r
10503 InputCallback func, VOIDSTAR closure)
\r
10505 InputSource *is, *is2 = NULL;
\r
10506 ChildProc *cp = (ChildProc *) pr;
\r
10508 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10509 is->lineByLine = lineByLine;
\r
10511 is->closure = closure;
\r
10512 is->second = NULL;
\r
10513 is->next = is->buf;
\r
10514 if (pr == NoProc) {
\r
10515 is->kind = CPReal;
\r
10516 consoleInputSource = is;
\r
10518 is->kind = cp->kind;
\r
10520 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10521 we create all threads suspended so that the is->hThread variable can be
\r
10522 safely assigned, then let the threads start with ResumeThread.
\r
10524 switch (cp->kind) {
\r
10526 is->hFile = cp->hFrom;
\r
10527 cp->hFrom = NULL; /* now owned by InputThread */
\r
10529 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10530 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10534 is->hFile = cp->hFrom;
\r
10535 cp->hFrom = NULL; /* now owned by InputThread */
\r
10537 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10538 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10542 is->sock = cp->sock;
\r
10544 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10545 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10549 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10551 is->sock = cp->sock;
\r
10552 is->second = is2;
\r
10553 is2->sock = cp->sock2;
\r
10554 is2->second = is2;
\r
10556 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10557 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10559 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10560 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10564 if( is->hThread != NULL ) {
\r
10565 ResumeThread( is->hThread );
\r
10568 if( is2 != NULL && is2->hThread != NULL ) {
\r
10569 ResumeThread( is2->hThread );
\r
10573 return (InputSourceRef) is;
\r
10577 RemoveInputSource(InputSourceRef isr)
\r
10581 is = (InputSource *) isr;
\r
10582 is->hThread = NULL; /* tell thread to stop */
\r
10583 CloseHandle(is->hThread);
\r
10584 if (is->second != NULL) {
\r
10585 is->second->hThread = NULL;
\r
10586 CloseHandle(is->second->hThread);
\r
10592 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10595 int outCount = SOCKET_ERROR;
\r
10596 ChildProc *cp = (ChildProc *) pr;
\r
10597 static OVERLAPPED ovl;
\r
10599 if (pr == NoProc) {
\r
10600 ConsoleOutput(message, count, FALSE);
\r
10604 if (ovl.hEvent == NULL) {
\r
10605 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10607 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10609 switch (cp->kind) {
\r
10612 outCount = send(cp->sock, message, count, 0);
\r
10613 if (outCount == SOCKET_ERROR) {
\r
10614 *outError = WSAGetLastError();
\r
10616 *outError = NO_ERROR;
\r
10621 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10622 &dOutCount, NULL)) {
\r
10623 *outError = NO_ERROR;
\r
10624 outCount = (int) dOutCount;
\r
10626 *outError = GetLastError();
\r
10631 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10632 &dOutCount, &ovl);
\r
10633 if (*outError == NO_ERROR) {
\r
10634 outCount = (int) dOutCount;
\r
10642 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10645 /* Ignore delay, not implemented for WinBoard */
\r
10646 return OutputToProcess(pr, message, count, outError);
\r
10651 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10652 char *buf, int count, int error)
\r
10654 DisplayFatalError("Not implemented", 0, 1);
\r
10657 /* see wgamelist.c for Game List functions */
\r
10658 /* see wedittags.c for Edit Tags functions */
\r
10665 char buf[MSG_SIZ];
\r
10668 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10669 f = fopen(buf, "r");
\r
10671 ProcessICSInitScript(f);
\r
10679 StartAnalysisClock()
\r
10681 if (analysisTimerEvent) return;
\r
10682 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10683 (UINT) 2000, NULL);
\r
10687 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10689 static HANDLE hwndText;
\r
10691 static int sizeX, sizeY;
\r
10692 int newSizeX, newSizeY, flags;
\r
10695 switch (message) {
\r
10696 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10697 /* Initialize the dialog items */
\r
10698 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10699 SetWindowText(hDlg, analysisTitle);
\r
10700 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10701 /* Size and position the dialog */
\r
10702 if (!analysisDialog) {
\r
10703 analysisDialog = hDlg;
\r
10704 flags = SWP_NOZORDER;
\r
10705 GetClientRect(hDlg, &rect);
\r
10706 sizeX = rect.right;
\r
10707 sizeY = rect.bottom;
\r
10708 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10709 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10710 WINDOWPLACEMENT wp;
\r
10711 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10712 wp.length = sizeof(WINDOWPLACEMENT);
\r
10714 wp.showCmd = SW_SHOW;
\r
10715 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10716 wp.rcNormalPosition.left = analysisX;
\r
10717 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10718 wp.rcNormalPosition.top = analysisY;
\r
10719 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10720 SetWindowPlacement(hDlg, &wp);
\r
10722 GetClientRect(hDlg, &rect);
\r
10723 newSizeX = rect.right;
\r
10724 newSizeY = rect.bottom;
\r
10725 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10726 newSizeX, newSizeY);
\r
10727 sizeX = newSizeX;
\r
10728 sizeY = newSizeY;
\r
10733 case WM_COMMAND: /* message: received a command */
\r
10734 switch (LOWORD(wParam)) {
\r
10736 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10737 ExitAnalyzeMode();
\r
10749 newSizeX = LOWORD(lParam);
\r
10750 newSizeY = HIWORD(lParam);
\r
10751 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10752 sizeX = newSizeX;
\r
10753 sizeY = newSizeY;
\r
10756 case WM_GETMINMAXINFO:
\r
10757 /* Prevent resizing window too small */
\r
10758 mmi = (MINMAXINFO *) lParam;
\r
10759 mmi->ptMinTrackSize.x = 100;
\r
10760 mmi->ptMinTrackSize.y = 100;
\r
10767 AnalysisPopUp(char* title, char* str)
\r
10773 EngineOutputPopUp();
\r
10776 if (str == NULL) str = "";
\r
10777 p = (char *) malloc(2 * strlen(str) + 2);
\r
10780 if (*str == '\n') *q++ = '\r';
\r
10784 if (analysisText != NULL) free(analysisText);
\r
10785 analysisText = p;
\r
10787 if (analysisDialog) {
\r
10788 SetWindowText(analysisDialog, title);
\r
10789 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10790 ShowWindow(analysisDialog, SW_SHOW);
\r
10792 analysisTitle = title;
\r
10793 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10794 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10795 hwndMain, (DLGPROC)lpProc);
\r
10796 FreeProcInstance(lpProc);
\r
10798 analysisDialogUp = TRUE;
\r
10802 AnalysisPopDown()
\r
10804 if (analysisDialog) {
\r
10805 ShowWindow(analysisDialog, SW_HIDE);
\r
10807 analysisDialogUp = FALSE;
\r
10812 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10814 highlightInfo.sq[0].x = fromX;
\r
10815 highlightInfo.sq[0].y = fromY;
\r
10816 highlightInfo.sq[1].x = toX;
\r
10817 highlightInfo.sq[1].y = toY;
\r
10821 ClearHighlights()
\r
10823 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10824 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10828 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10830 premoveHighlightInfo.sq[0].x = fromX;
\r
10831 premoveHighlightInfo.sq[0].y = fromY;
\r
10832 premoveHighlightInfo.sq[1].x = toX;
\r
10833 premoveHighlightInfo.sq[1].y = toY;
\r
10837 ClearPremoveHighlights()
\r
10839 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10840 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10844 ShutDownFrontEnd()
\r
10846 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10847 DeleteClipboardTempFiles();
\r
10853 if (IsIconic(hwndMain))
\r
10854 ShowWindow(hwndMain, SW_RESTORE);
\r
10856 SetActiveWindow(hwndMain);
\r
10860 * Prototypes for animation support routines
\r
10862 static void ScreenSquare(int column, int row, POINT * pt);
\r
10863 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10864 POINT frames[], int * nFrames);
\r
10868 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10869 { // [HGM] atomic: animate blast wave
\r
10871 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10872 explodeInfo.fromX = fromX;
\r
10873 explodeInfo.fromY = fromY;
\r
10874 explodeInfo.toX = toX;
\r
10875 explodeInfo.toY = toY;
\r
10876 for(i=1; i<nFrames; i++) {
\r
10877 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10878 DrawPosition(FALSE, NULL);
\r
10879 Sleep(appData.animSpeed);
\r
10881 explodeInfo.radius = 0;
\r
10882 DrawPosition(TRUE, NULL);
\r
10885 #define kFactor 4
\r
10888 AnimateMove(board, fromX, fromY, toX, toY)
\r
10895 ChessSquare piece;
\r
10896 POINT start, finish, mid;
\r
10897 POINT frames[kFactor * 2 + 1];
\r
10900 if (!appData.animate) return;
\r
10901 if (doingSizing) return;
\r
10902 if (fromY < 0 || fromX < 0) return;
\r
10903 piece = board[fromY][fromX];
\r
10904 if (piece >= EmptySquare) return;
\r
10906 ScreenSquare(fromX, fromY, &start);
\r
10907 ScreenSquare(toX, toY, &finish);
\r
10909 /* All pieces except knights move in straight line */
\r
10910 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10911 mid.x = start.x + (finish.x - start.x) / 2;
\r
10912 mid.y = start.y + (finish.y - start.y) / 2;
\r
10914 /* Knight: make diagonal movement then straight */
\r
10915 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10916 mid.x = start.x + (finish.x - start.x) / 2;
\r
10917 mid.y = finish.y;
\r
10919 mid.x = finish.x;
\r
10920 mid.y = start.y + (finish.y - start.y) / 2;
\r
10924 /* Don't use as many frames for very short moves */
\r
10925 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10926 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10928 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10930 animInfo.from.x = fromX;
\r
10931 animInfo.from.y = fromY;
\r
10932 animInfo.to.x = toX;
\r
10933 animInfo.to.y = toY;
\r
10934 animInfo.lastpos = start;
\r
10935 animInfo.piece = piece;
\r
10936 for (n = 0; n < nFrames; n++) {
\r
10937 animInfo.pos = frames[n];
\r
10938 DrawPosition(FALSE, NULL);
\r
10939 animInfo.lastpos = animInfo.pos;
\r
10940 Sleep(appData.animSpeed);
\r
10942 animInfo.pos = finish;
\r
10943 DrawPosition(FALSE, NULL);
\r
10944 animInfo.piece = EmptySquare;
\r
10945 if(gameInfo.variant == VariantAtomic &&
\r
10946 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10947 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10950 /* Convert board position to corner of screen rect and color */
\r
10953 ScreenSquare(column, row, pt)
\r
10954 int column; int row; POINT * pt;
\r
10957 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10958 pt->y = lineGap + row * (squareSize + lineGap);
\r
10960 pt->x = lineGap + column * (squareSize + lineGap);
\r
10961 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10965 /* Generate a series of frame coords from start->mid->finish.
\r
10966 The movement rate doubles until the half way point is
\r
10967 reached, then halves back down to the final destination,
\r
10968 which gives a nice slow in/out effect. The algorithmn
\r
10969 may seem to generate too many intermediates for short
\r
10970 moves, but remember that the purpose is to attract the
\r
10971 viewers attention to the piece about to be moved and
\r
10972 then to where it ends up. Too few frames would be less
\r
10976 Tween(start, mid, finish, factor, frames, nFrames)
\r
10977 POINT * start; POINT * mid;
\r
10978 POINT * finish; int factor;
\r
10979 POINT frames[]; int * nFrames;
\r
10981 int n, fraction = 1, count = 0;
\r
10983 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10984 for (n = 0; n < factor; n++)
\r
10986 for (n = 0; n < factor; n++) {
\r
10987 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10988 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10990 fraction = fraction / 2;
\r
10994 frames[count] = *mid;
\r
10997 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10999 for (n = 0; n < factor; n++) {
\r
11000 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
11001 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
11003 fraction = fraction * 2;
\r
11005 *nFrames = count;
\r
11009 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
11014 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
11015 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
11017 OutputDebugString( buf );
\r
11020 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
11022 EvalGraphSet( first, last, current, pvInfoList );
\r
11025 void SetProgramStats( FrontEndProgramStats * stats )
\r
11030 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
11031 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
11033 OutputDebugString( buf );
\r
11036 EngineOutputUpdate( stats );
\r