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
1344 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1345 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1346 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1347 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1348 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1349 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1350 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1351 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1352 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1353 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1354 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1355 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1356 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1358 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1359 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1360 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1361 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1362 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1363 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1364 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1366 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1367 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1368 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1369 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1370 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1371 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1372 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1373 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1374 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1375 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1376 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1377 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1378 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1379 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1380 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1381 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1382 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1383 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1384 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1386 /* [HGM] options for broadcasting and time odds */
\r
1387 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1388 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1389 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1390 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1391 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1392 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1393 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1394 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1395 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1396 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1397 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1399 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1400 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1401 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1402 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1403 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1404 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1405 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1406 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1407 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1408 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1409 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1410 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1411 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1412 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1413 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1414 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1415 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1416 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1417 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1418 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1419 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1420 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1421 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1422 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1423 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1424 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1425 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1426 /* [AS] Layout stuff */
\r
1427 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1428 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1429 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1430 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1431 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1433 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1434 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1435 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1436 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1437 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1439 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1440 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1441 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1442 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1443 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1445 { NULL, ArgNone, NULL, FALSE }
\r
1449 /* Kludge for indirection files on command line */
\r
1450 char* lastIndirectionFilename;
\r
1451 ArgDescriptor argDescriptorIndirection =
\r
1452 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1456 ExitArgError(char *msg, char *badArg)
\r
1458 char buf[MSG_SIZ];
\r
1460 sprintf(buf, "%s %s", msg, badArg);
\r
1461 DisplayFatalError(buf, 0, 2);
\r
1465 /* Command line font name parser. NULL name means do nothing.
\r
1466 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1467 For backward compatibility, syntax without the colon is also
\r
1468 accepted, but font names with digits in them won't work in that case.
\r
1471 ParseFontName(char *name, MyFontParams *mfp)
\r
1474 if (name == NULL) return;
\r
1476 q = strchr(p, ':');
\r
1478 if (q - p >= sizeof(mfp->faceName))
\r
1479 ExitArgError("Font name too long:", name);
\r
1480 memcpy(mfp->faceName, p, q - p);
\r
1481 mfp->faceName[q - p] = NULLCHAR;
\r
1484 q = mfp->faceName;
\r
1485 while (*p && !isdigit(*p)) {
\r
1487 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1488 ExitArgError("Font name too long:", name);
\r
1490 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1493 if (!*p) ExitArgError("Font point size missing:", name);
\r
1494 mfp->pointSize = (float) atof(p);
\r
1495 mfp->bold = (strchr(p, 'b') != NULL);
\r
1496 mfp->italic = (strchr(p, 'i') != NULL);
\r
1497 mfp->underline = (strchr(p, 'u') != NULL);
\r
1498 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1501 /* Color name parser.
\r
1502 X version accepts X color names, but this one
\r
1503 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1505 ParseColorName(char *name)
\r
1507 int red, green, blue, count;
\r
1508 char buf[MSG_SIZ];
\r
1510 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1512 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1513 &red, &green, &blue);
\r
1516 sprintf(buf, "Can't parse color name %s", name);
\r
1517 DisplayError(buf, 0);
\r
1518 return RGB(0, 0, 0);
\r
1520 return PALETTERGB(red, green, blue);
\r
1524 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1526 char *e = argValue;
\r
1530 if (*e == 'b') eff |= CFE_BOLD;
\r
1531 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1532 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1533 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1534 else if (*e == '#' || isdigit(*e)) break;
\r
1538 *color = ParseColorName(e);
\r
1543 ParseBoardSize(char *name)
\r
1545 BoardSize bs = SizeTiny;
\r
1546 while (sizeInfo[bs].name != NULL) {
\r
1547 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1550 ExitArgError("Unrecognized board size value", name);
\r
1551 return bs; /* not reached */
\r
1556 StringGet(void *getClosure)
\r
1558 char **p = (char **) getClosure;
\r
1563 FileGet(void *getClosure)
\r
1566 FILE* f = (FILE*) getClosure;
\r
1569 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1576 /* Parse settings file named "name". If file found, return the
\r
1577 full name in fullname and return TRUE; else return FALSE */
\r
1579 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1583 int ok; char buf[MSG_SIZ];
\r
1585 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1586 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1587 sprintf(buf, "%s.ini", name);
\r
1588 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1591 f = fopen(fullname, "r");
\r
1593 ParseArgs(FileGet, f);
\r
1602 ParseArgs(GetFunc get, void *cl)
\r
1604 char argName[ARG_MAX];
\r
1605 char argValue[ARG_MAX];
\r
1606 ArgDescriptor *ad;
\r
1615 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1616 if (ch == NULLCHAR) break;
\r
1618 /* Comment to end of line */
\r
1620 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1622 } else if (ch == '/' || ch == '-') {
\r
1625 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1626 ch != '\n' && ch != '\t') {
\r
1632 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1633 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1635 if (ad->argName == NULL)
\r
1636 ExitArgError("Unrecognized argument", argName);
\r
1638 } else if (ch == '@') {
\r
1639 /* Indirection file */
\r
1640 ad = &argDescriptorIndirection;
\r
1643 /* Positional argument */
\r
1644 ad = &argDescriptors[posarg++];
\r
1645 strcpy(argName, ad->argName);
\r
1648 if (ad->argType == ArgTrue) {
\r
1649 *(Boolean *) ad->argLoc = TRUE;
\r
1652 if (ad->argType == ArgFalse) {
\r
1653 *(Boolean *) ad->argLoc = FALSE;
\r
1657 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1658 if (ch == NULLCHAR || ch == '\n') {
\r
1659 ExitArgError("No value provided for argument", argName);
\r
1663 // Quoting with { }. No characters have to (or can) be escaped.
\r
1664 // Thus the string cannot contain a '}' character.
\r
1684 } else if (ch == '\'' || ch == '"') {
\r
1685 // Quoting with ' ' or " ", with \ as escape character.
\r
1686 // Inconvenient for long strings that may contain Windows filenames.
\r
1703 if (ch == start) {
\r
1712 if (ad->argType == ArgFilename
\r
1713 || ad->argType == ArgSettingsFilename) {
\r
1719 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1743 for (i = 0; i < 3; i++) {
\r
1744 if (ch >= '0' && ch <= '7') {
\r
1745 octval = octval*8 + (ch - '0');
\r
1752 *q++ = (char) octval;
\r
1763 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1770 switch (ad->argType) {
\r
1772 *(int *) ad->argLoc = atoi(argValue);
\r
1776 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1780 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1784 *(int *) ad->argLoc = atoi(argValue);
\r
1785 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1789 *(float *) ad->argLoc = (float) atof(argValue);
\r
1794 *(char **) ad->argLoc = strdup(argValue);
\r
1797 case ArgSettingsFilename:
\r
1799 char fullname[MSG_SIZ];
\r
1800 if (ParseSettingsFile(argValue, fullname)) {
\r
1801 if (ad->argLoc != NULL) {
\r
1802 *(char **) ad->argLoc = strdup(fullname);
\r
1805 if (ad->argLoc != NULL) {
\r
1807 ExitArgError("Failed to open indirection file", argValue);
\r
1814 switch (argValue[0]) {
\r
1817 *(Boolean *) ad->argLoc = TRUE;
\r
1821 *(Boolean *) ad->argLoc = FALSE;
\r
1824 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1830 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1833 case ArgAttribs: {
\r
1834 ColorClass cc = (ColorClass)ad->argLoc;
\r
1835 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1839 case ArgBoardSize:
\r
1840 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1844 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1847 case ArgCommSettings:
\r
1848 ParseCommSettings(argValue, &dcb);
\r
1852 ExitArgError("Unrecognized argument", argValue);
\r
1861 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1863 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1864 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1867 lf->lfEscapement = 0;
\r
1868 lf->lfOrientation = 0;
\r
1869 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1870 lf->lfItalic = mfp->italic;
\r
1871 lf->lfUnderline = mfp->underline;
\r
1872 lf->lfStrikeOut = mfp->strikeout;
\r
1873 lf->lfCharSet = DEFAULT_CHARSET;
\r
1874 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1875 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1876 lf->lfQuality = DEFAULT_QUALITY;
\r
1877 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1878 strcpy(lf->lfFaceName, mfp->faceName);
\r
1882 CreateFontInMF(MyFont *mf)
\r
1884 LFfromMFP(&mf->lf, &mf->mfp);
\r
1885 if (mf->hf) DeleteObject(mf->hf);
\r
1886 mf->hf = CreateFontIndirect(&mf->lf);
\r
1890 SetDefaultTextAttribs()
\r
1893 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1894 ParseAttribs(&textAttribs[cc].color,
\r
1895 &textAttribs[cc].effects,
\r
1896 defaultTextAttribs[cc]);
\r
1901 SetDefaultSounds()
\r
1905 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1906 textAttribs[cc].sound.name = strdup("");
\r
1907 textAttribs[cc].sound.data = NULL;
\r
1909 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1910 sounds[sc].name = strdup("");
\r
1911 sounds[sc].data = NULL;
\r
1913 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1921 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1922 MyLoadSound(&textAttribs[cc].sound);
\r
1924 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1925 MyLoadSound(&sounds[sc]);
\r
1930 InitAppData(LPSTR lpCmdLine)
\r
1933 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1936 programName = szAppName;
\r
1938 /* Initialize to defaults */
\r
1939 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1940 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1941 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1942 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1943 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1944 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1945 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1946 SetDefaultTextAttribs();
\r
1947 SetDefaultSounds();
\r
1948 appData.movesPerSession = MOVES_PER_SESSION;
\r
1949 appData.initString = INIT_STRING;
\r
1950 appData.secondInitString = INIT_STRING;
\r
1951 appData.firstComputerString = COMPUTER_STRING;
\r
1952 appData.secondComputerString = COMPUTER_STRING;
\r
1953 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1954 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1955 appData.firstPlaysBlack = FALSE;
\r
1956 appData.noChessProgram = FALSE;
\r
1957 chessProgram = FALSE;
\r
1958 appData.firstHost = FIRST_HOST;
\r
1959 appData.secondHost = SECOND_HOST;
\r
1960 appData.firstDirectory = FIRST_DIRECTORY;
\r
1961 appData.secondDirectory = SECOND_DIRECTORY;
\r
1962 appData.bitmapDirectory = "";
\r
1963 appData.remoteShell = REMOTE_SHELL;
\r
1964 appData.remoteUser = "";
\r
1965 appData.timeDelay = TIME_DELAY;
\r
1966 appData.timeControl = TIME_CONTROL;
\r
1967 appData.timeIncrement = TIME_INCREMENT;
\r
1968 appData.icsActive = FALSE;
\r
1969 appData.icsHost = "";
\r
1970 appData.icsPort = ICS_PORT;
\r
1971 appData.icsCommPort = ICS_COMM_PORT;
\r
1972 appData.icsLogon = ICS_LOGON;
\r
1973 appData.icsHelper = "";
\r
1974 appData.useTelnet = FALSE;
\r
1975 appData.telnetProgram = TELNET_PROGRAM;
\r
1976 appData.gateway = "";
\r
1977 appData.loadGameFile = "";
\r
1978 appData.loadGameIndex = 0;
\r
1979 appData.saveGameFile = "";
\r
1980 appData.autoSaveGames = FALSE;
\r
1981 appData.loadPositionFile = "";
\r
1982 appData.loadPositionIndex = 1;
\r
1983 appData.savePositionFile = "";
\r
1984 appData.matchMode = FALSE;
\r
1985 appData.matchGames = 0;
\r
1986 appData.monoMode = FALSE;
\r
1987 appData.debugMode = FALSE;
\r
1988 appData.clockMode = TRUE;
\r
1989 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1990 appData.Iconic = FALSE; /*unused*/
\r
1991 appData.searchTime = "";
\r
1992 appData.searchDepth = 0;
\r
1993 appData.showCoords = FALSE;
\r
1994 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1995 appData.autoCallFlag = FALSE;
\r
1996 appData.flipView = FALSE;
\r
1997 appData.autoFlipView = TRUE;
\r
1998 appData.cmailGameName = "";
\r
1999 appData.alwaysPromoteToQueen = FALSE;
\r
2000 appData.oldSaveStyle = FALSE;
\r
2001 appData.quietPlay = FALSE;
\r
2002 appData.showThinking = FALSE;
\r
2003 appData.ponderNextMove = TRUE;
\r
2004 appData.periodicUpdates = TRUE;
\r
2005 appData.popupExitMessage = TRUE;
\r
2006 appData.popupMoveErrors = FALSE;
\r
2007 appData.autoObserve = FALSE;
\r
2008 appData.autoComment = FALSE;
\r
2009 appData.animate = TRUE;
\r
2010 appData.animSpeed = 10;
\r
2011 appData.animateDragging = TRUE;
\r
2012 appData.highlightLastMove = TRUE;
\r
2013 appData.getMoveList = TRUE;
\r
2014 appData.testLegality = TRUE;
\r
2015 appData.premove = TRUE;
\r
2016 appData.premoveWhite = FALSE;
\r
2017 appData.premoveWhiteText = "";
\r
2018 appData.premoveBlack = FALSE;
\r
2019 appData.premoveBlackText = "";
\r
2020 appData.icsAlarm = TRUE;
\r
2021 appData.icsAlarmTime = 5000;
\r
2022 appData.autoRaiseBoard = TRUE;
\r
2023 appData.localLineEditing = TRUE;
\r
2024 appData.colorize = TRUE;
\r
2025 appData.reuseFirst = TRUE;
\r
2026 appData.reuseSecond = TRUE;
\r
2027 appData.blindfold = FALSE;
\r
2028 appData.icsEngineAnalyze = FALSE;
\r
2029 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2030 dcb.DCBlength = sizeof(DCB);
\r
2031 dcb.BaudRate = 9600;
\r
2032 dcb.fBinary = TRUE;
\r
2033 dcb.fParity = FALSE;
\r
2034 dcb.fOutxCtsFlow = FALSE;
\r
2035 dcb.fOutxDsrFlow = FALSE;
\r
2036 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2037 dcb.fDsrSensitivity = FALSE;
\r
2038 dcb.fTXContinueOnXoff = TRUE;
\r
2039 dcb.fOutX = FALSE;
\r
2041 dcb.fNull = FALSE;
\r
2042 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2043 dcb.fAbortOnError = FALSE;
\r
2045 dcb.Parity = SPACEPARITY;
\r
2046 dcb.StopBits = ONESTOPBIT;
\r
2047 settingsFileName = SETTINGS_FILE;
\r
2048 saveSettingsOnExit = TRUE;
\r
2049 boardX = CW_USEDEFAULT;
\r
2050 boardY = CW_USEDEFAULT;
\r
2051 analysisX = CW_USEDEFAULT;
\r
2052 analysisY = CW_USEDEFAULT;
\r
2053 analysisW = CW_USEDEFAULT;
\r
2054 analysisH = CW_USEDEFAULT;
\r
2055 commentX = CW_USEDEFAULT;
\r
2056 commentY = CW_USEDEFAULT;
\r
2057 commentW = CW_USEDEFAULT;
\r
2058 commentH = CW_USEDEFAULT;
\r
2059 editTagsX = CW_USEDEFAULT;
\r
2060 editTagsY = CW_USEDEFAULT;
\r
2061 editTagsW = CW_USEDEFAULT;
\r
2062 editTagsH = CW_USEDEFAULT;
\r
2063 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2064 icsNames = ICS_NAMES;
\r
2065 firstChessProgramNames = FCP_NAMES;
\r
2066 secondChessProgramNames = SCP_NAMES;
\r
2067 appData.initialMode = "";
\r
2068 appData.variant = "normal";
\r
2069 appData.firstProtocolVersion = PROTOVER;
\r
2070 appData.secondProtocolVersion = PROTOVER;
\r
2071 appData.showButtonBar = TRUE;
\r
2073 /* [AS] New properties (see comments in header file) */
\r
2074 appData.firstScoreIsAbsolute = FALSE;
\r
2075 appData.secondScoreIsAbsolute = FALSE;
\r
2076 appData.saveExtendedInfoInPGN = FALSE;
\r
2077 appData.hideThinkingFromHuman = FALSE;
\r
2078 appData.liteBackTextureFile = "";
\r
2079 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2080 appData.darkBackTextureFile = "";
\r
2081 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2082 appData.renderPiecesWithFont = "";
\r
2083 appData.fontToPieceTable = "";
\r
2084 appData.fontBackColorWhite = 0;
\r
2085 appData.fontForeColorWhite = 0;
\r
2086 appData.fontBackColorBlack = 0;
\r
2087 appData.fontForeColorBlack = 0;
\r
2088 appData.fontPieceSize = 80;
\r
2089 appData.overrideLineGap = 1;
\r
2090 appData.adjudicateLossThreshold = 0;
\r
2091 appData.delayBeforeQuit = 0;
\r
2092 appData.delayAfterQuit = 0;
\r
2093 appData.nameOfDebugFile = "winboard.debug";
\r
2094 appData.pgnEventHeader = "Computer Chess Game";
\r
2095 appData.defaultFrcPosition = -1;
\r
2096 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2097 appData.saveOutOfBookInfo = TRUE;
\r
2098 appData.showEvalInMoveHistory = TRUE;
\r
2099 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2100 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2101 appData.highlightMoveWithArrow = FALSE;
\r
2102 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2103 appData.useStickyWindows = TRUE;
\r
2104 appData.adjudicateDrawMoves = 0;
\r
2105 appData.autoDisplayComment = TRUE;
\r
2106 appData.autoDisplayTags = TRUE;
\r
2107 appData.firstIsUCI = FALSE;
\r
2108 appData.secondIsUCI = FALSE;
\r
2109 appData.firstHasOwnBookUCI = TRUE;
\r
2110 appData.secondHasOwnBookUCI = TRUE;
\r
2111 appData.polyglotDir = "";
\r
2112 appData.usePolyglotBook = FALSE;
\r
2113 appData.polyglotBook = "";
\r
2114 appData.defaultHashSize = 64;
\r
2115 appData.defaultCacheSizeEGTB = 4;
\r
2116 appData.defaultPathEGTB = "c:\\egtb";
\r
2117 appData.firstOptions = "";
\r
2118 appData.secondOptions = "";
\r
2120 InitWindowPlacement( &wpGameList );
\r
2121 InitWindowPlacement( &wpMoveHistory );
\r
2122 InitWindowPlacement( &wpEvalGraph );
\r
2123 InitWindowPlacement( &wpEngineOutput );
\r
2124 InitWindowPlacement( &wpConsole );
\r
2126 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2127 appData.NrFiles = -1;
\r
2128 appData.NrRanks = -1;
\r
2129 appData.holdingsSize = -1;
\r
2130 appData.testClaims = FALSE;
\r
2131 appData.checkMates = FALSE;
\r
2132 appData.materialDraws= FALSE;
\r
2133 appData.trivialDraws = FALSE;
\r
2134 appData.ruleMoves = 51;
\r
2135 appData.drawRepeats = 6;
\r
2136 appData.matchPause = 10000;
\r
2137 appData.alphaRank = FALSE;
\r
2138 appData.allWhite = FALSE;
\r
2139 appData.upsideDown = FALSE;
\r
2140 appData.serverPause = 15;
\r
2141 appData.serverMovesName = NULL;
\r
2142 appData.suppressLoadMoves = FALSE;
\r
2143 appData.firstTimeOdds = 1;
\r
2144 appData.secondTimeOdds = 1;
\r
2145 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2146 appData.secondAccumulateTC = 1;
\r
2147 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2148 appData.secondNPS = -1;
\r
2149 appData.engineComments = 1;
\r
2150 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2151 appData.egtFormats = "";
\r
2154 appData.zippyTalk = ZIPPY_TALK;
\r
2155 appData.zippyPlay = ZIPPY_PLAY;
\r
2156 appData.zippyLines = ZIPPY_LINES;
\r
2157 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2158 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2159 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2160 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2161 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2162 appData.zippyUseI = ZIPPY_USE_I;
\r
2163 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2164 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2165 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2166 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2167 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2168 appData.zippyAbort = ZIPPY_ABORT;
\r
2169 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2170 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2171 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2174 /* Point font array elements to structures and
\r
2175 parse default font names */
\r
2176 for (i=0; i<NUM_FONTS; i++) {
\r
2177 for (j=0; j<NUM_SIZES; j++) {
\r
2178 font[j][i] = &fontRec[j][i];
\r
2179 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2183 /* Parse default settings file if any */
\r
2184 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2185 settingsFileName = strdup(buf);
\r
2188 /* Parse command line */
\r
2189 ParseArgs(StringGet, &lpCmdLine);
\r
2191 /* [HGM] make sure board size is acceptable */
\r
2192 if(appData.NrFiles > BOARD_SIZE ||
\r
2193 appData.NrRanks > BOARD_SIZE )
\r
2194 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2196 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2197 * with options from the command line, we now make an even higher priority
\r
2198 * overrule by WB options attached to the engine command line. This so that
\r
2199 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2202 if(appData.firstChessProgram != NULL) {
\r
2203 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2204 static char *f = "first";
\r
2205 char buf[MSG_SIZ], *q = buf;
\r
2206 if(p != NULL) { // engine command line contains WinBoard options
\r
2207 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2208 ParseArgs(StringGet, &q);
\r
2209 p[-1] = 0; // cut them offengine command line
\r
2212 // now do same for second chess program
\r
2213 if(appData.secondChessProgram != NULL) {
\r
2214 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2215 static char *s = "second";
\r
2216 char buf[MSG_SIZ], *q = buf;
\r
2217 if(p != NULL) { // engine command line contains WinBoard options
\r
2218 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2219 ParseArgs(StringGet, &q);
\r
2220 p[-1] = 0; // cut them offengine command line
\r
2225 /* Propagate options that affect others */
\r
2226 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2227 if (appData.icsActive || appData.noChessProgram) {
\r
2228 chessProgram = FALSE; /* not local chess program mode */
\r
2231 /* Open startup dialog if needed */
\r
2232 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2233 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2234 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2235 *appData.secondChessProgram == NULLCHAR))) {
\r
2238 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2239 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2240 FreeProcInstance(lpProc);
\r
2243 /* Make sure save files land in the right (?) directory */
\r
2244 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2245 appData.saveGameFile = strdup(buf);
\r
2247 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2248 appData.savePositionFile = strdup(buf);
\r
2251 /* Finish initialization for fonts and sounds */
\r
2252 for (i=0; i<NUM_FONTS; i++) {
\r
2253 for (j=0; j<NUM_SIZES; j++) {
\r
2254 CreateFontInMF(font[j][i]);
\r
2257 /* xboard, and older WinBoards, controlled the move sound with the
\r
2258 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2259 always turn the option on (so that the backend will call us),
\r
2260 then let the user turn the sound off by setting it to silence if
\r
2261 desired. To accommodate old winboard.ini files saved by old
\r
2262 versions of WinBoard, we also turn off the sound if the option
\r
2263 was initially set to false. */
\r
2264 if (!appData.ringBellAfterMoves) {
\r
2265 sounds[(int)SoundMove].name = strdup("");
\r
2266 appData.ringBellAfterMoves = TRUE;
\r
2268 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2269 SetCurrentDirectory(installDir);
\r
2271 SetCurrentDirectory(currDir);
\r
2273 p = icsTextMenuString;
\r
2274 if (p[0] == '@') {
\r
2275 FILE* f = fopen(p + 1, "r");
\r
2277 DisplayFatalError(p + 1, errno, 2);
\r
2280 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2282 buf[i] = NULLCHAR;
\r
2285 ParseIcsTextMenu(strdup(p));
\r
2292 HMENU hmenu = GetMenu(hwndMain);
\r
2294 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2295 MF_BYCOMMAND|((appData.icsActive &&
\r
2296 *appData.icsCommPort != NULLCHAR) ?
\r
2297 MF_ENABLED : MF_GRAYED));
\r
2298 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2299 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2300 MF_CHECKED : MF_UNCHECKED));
\r
2305 SaveSettings(char* name)
\r
2308 ArgDescriptor *ad;
\r
2309 WINDOWPLACEMENT wp;
\r
2310 char dir[MSG_SIZ];
\r
2312 if (!hwndMain) return;
\r
2314 GetCurrentDirectory(MSG_SIZ, dir);
\r
2315 SetCurrentDirectory(installDir);
\r
2316 f = fopen(name, "w");
\r
2317 SetCurrentDirectory(dir);
\r
2319 DisplayError(name, errno);
\r
2322 fprintf(f, ";\n");
\r
2323 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2324 fprintf(f, ";\n");
\r
2325 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2326 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2327 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2328 fprintf(f, ";\n");
\r
2330 wp.length = sizeof(WINDOWPLACEMENT);
\r
2331 GetWindowPlacement(hwndMain, &wp);
\r
2332 boardX = wp.rcNormalPosition.left;
\r
2333 boardY = wp.rcNormalPosition.top;
\r
2335 if (hwndConsole) {
\r
2336 GetWindowPlacement(hwndConsole, &wp);
\r
2337 wpConsole.x = wp.rcNormalPosition.left;
\r
2338 wpConsole.y = wp.rcNormalPosition.top;
\r
2339 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2340 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2343 if (analysisDialog) {
\r
2344 GetWindowPlacement(analysisDialog, &wp);
\r
2345 analysisX = wp.rcNormalPosition.left;
\r
2346 analysisY = wp.rcNormalPosition.top;
\r
2347 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2348 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2351 if (commentDialog) {
\r
2352 GetWindowPlacement(commentDialog, &wp);
\r
2353 commentX = wp.rcNormalPosition.left;
\r
2354 commentY = wp.rcNormalPosition.top;
\r
2355 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2356 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2359 if (editTagsDialog) {
\r
2360 GetWindowPlacement(editTagsDialog, &wp);
\r
2361 editTagsX = wp.rcNormalPosition.left;
\r
2362 editTagsY = wp.rcNormalPosition.top;
\r
2363 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2364 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2367 if (gameListDialog) {
\r
2368 GetWindowPlacement(gameListDialog, &wp);
\r
2369 wpGameList.x = wp.rcNormalPosition.left;
\r
2370 wpGameList.y = wp.rcNormalPosition.top;
\r
2371 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2372 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2375 /* [AS] Move history */
\r
2376 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2378 if( moveHistoryDialog ) {
\r
2379 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2380 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2381 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2382 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2383 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2386 /* [AS] Eval graph */
\r
2387 wpEvalGraph.visible = EvalGraphIsUp();
\r
2389 if( evalGraphDialog ) {
\r
2390 GetWindowPlacement(evalGraphDialog, &wp);
\r
2391 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2392 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2393 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2394 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2397 /* [AS] Engine output */
\r
2398 wpEngineOutput.visible = EngineOutputIsUp();
\r
2400 if( engineOutputDialog ) {
\r
2401 GetWindowPlacement(engineOutputDialog, &wp);
\r
2402 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2403 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2404 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2405 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2408 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2409 if (!ad->save) continue;
\r
2410 switch (ad->argType) {
\r
2413 char *p = *(char **)ad->argLoc;
\r
2414 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2415 /* Quote multiline values or \-containing values
\r
2416 with { } if possible */
\r
2417 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2419 /* Else quote with " " */
\r
2420 fprintf(f, "/%s=\"", ad->argName);
\r
2422 if (*p == '\n') fprintf(f, "\n");
\r
2423 else if (*p == '\r') fprintf(f, "\\r");
\r
2424 else if (*p == '\t') fprintf(f, "\\t");
\r
2425 else if (*p == '\b') fprintf(f, "\\b");
\r
2426 else if (*p == '\f') fprintf(f, "\\f");
\r
2427 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2428 else if (*p == '\"') fprintf(f, "\\\"");
\r
2429 else if (*p == '\\') fprintf(f, "\\\\");
\r
2433 fprintf(f, "\"\n");
\r
2439 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2442 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2445 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2448 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2451 fprintf(f, "/%s=%s\n", ad->argName,
\r
2452 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2455 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2458 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2462 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2463 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2464 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2469 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2470 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2471 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2472 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2473 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2474 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2475 (ta->effects) ? " " : "",
\r
2476 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2480 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2481 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2483 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2486 case ArgBoardSize:
\r
2487 fprintf(f, "/%s=%s\n", ad->argName,
\r
2488 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2493 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2494 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2495 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2496 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2497 ad->argName, mfp->faceName, mfp->pointSize,
\r
2498 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2499 mfp->bold ? "b" : "",
\r
2500 mfp->italic ? "i" : "",
\r
2501 mfp->underline ? "u" : "",
\r
2502 mfp->strikeout ? "s" : "");
\r
2506 case ArgCommSettings:
\r
2507 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2509 case ArgSettingsFilename: ;
\r
2517 /*---------------------------------------------------------------------------*\
\r
2519 * GDI board drawing routines
\r
2521 \*---------------------------------------------------------------------------*/
\r
2523 /* [AS] Draw square using background texture */
\r
2524 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2529 return; /* Should never happen! */
\r
2532 SetGraphicsMode( dst, GM_ADVANCED );
\r
2539 /* X reflection */
\r
2544 x.eDx = (FLOAT) dw + dx - 1;
\r
2547 SetWorldTransform( dst, &x );
\r
2550 /* Y reflection */
\r
2556 x.eDy = (FLOAT) dh + dy - 1;
\r
2558 SetWorldTransform( dst, &x );
\r
2566 x.eDx = (FLOAT) dx;
\r
2567 x.eDy = (FLOAT) dy;
\r
2570 SetWorldTransform( dst, &x );
\r
2574 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2582 SetWorldTransform( dst, &x );
\r
2584 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2587 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2589 PM_WP = (int) WhitePawn,
\r
2590 PM_WN = (int) WhiteKnight,
\r
2591 PM_WB = (int) WhiteBishop,
\r
2592 PM_WR = (int) WhiteRook,
\r
2593 PM_WQ = (int) WhiteQueen,
\r
2594 PM_WF = (int) WhiteFerz,
\r
2595 PM_WW = (int) WhiteWazir,
\r
2596 PM_WE = (int) WhiteAlfil,
\r
2597 PM_WM = (int) WhiteMan,
\r
2598 PM_WO = (int) WhiteCannon,
\r
2599 PM_WU = (int) WhiteUnicorn,
\r
2600 PM_WH = (int) WhiteNightrider,
\r
2601 PM_WA = (int) WhiteAngel,
\r
2602 PM_WC = (int) WhiteMarshall,
\r
2603 PM_WAB = (int) WhiteCardinal,
\r
2604 PM_WD = (int) WhiteDragon,
\r
2605 PM_WL = (int) WhiteLance,
\r
2606 PM_WS = (int) WhiteCobra,
\r
2607 PM_WV = (int) WhiteFalcon,
\r
2608 PM_WSG = (int) WhiteSilver,
\r
2609 PM_WG = (int) WhiteGrasshopper,
\r
2610 PM_WK = (int) WhiteKing,
\r
2611 PM_BP = (int) BlackPawn,
\r
2612 PM_BN = (int) BlackKnight,
\r
2613 PM_BB = (int) BlackBishop,
\r
2614 PM_BR = (int) BlackRook,
\r
2615 PM_BQ = (int) BlackQueen,
\r
2616 PM_BF = (int) BlackFerz,
\r
2617 PM_BW = (int) BlackWazir,
\r
2618 PM_BE = (int) BlackAlfil,
\r
2619 PM_BM = (int) BlackMan,
\r
2620 PM_BO = (int) BlackCannon,
\r
2621 PM_BU = (int) BlackUnicorn,
\r
2622 PM_BH = (int) BlackNightrider,
\r
2623 PM_BA = (int) BlackAngel,
\r
2624 PM_BC = (int) BlackMarshall,
\r
2625 PM_BG = (int) BlackGrasshopper,
\r
2626 PM_BAB = (int) BlackCardinal,
\r
2627 PM_BD = (int) BlackDragon,
\r
2628 PM_BL = (int) BlackLance,
\r
2629 PM_BS = (int) BlackCobra,
\r
2630 PM_BV = (int) BlackFalcon,
\r
2631 PM_BSG = (int) BlackSilver,
\r
2632 PM_BK = (int) BlackKing
\r
2635 static HFONT hPieceFont = NULL;
\r
2636 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2637 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2638 static int fontBitmapSquareSize = 0;
\r
2639 static char pieceToFontChar[(int) EmptySquare] =
\r
2640 { 'p', 'n', 'b', 'r', 'q',
\r
2641 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2642 'k', 'o', 'm', 'v', 't', 'w',
\r
2643 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2646 extern BOOL SetCharTable( char *table, const char * map );
\r
2647 /* [HGM] moved to backend.c */
\r
2649 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2652 BYTE r1 = GetRValue( color );
\r
2653 BYTE g1 = GetGValue( color );
\r
2654 BYTE b1 = GetBValue( color );
\r
2660 /* Create a uniform background first */
\r
2661 hbrush = CreateSolidBrush( color );
\r
2662 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2663 FillRect( hdc, &rc, hbrush );
\r
2664 DeleteObject( hbrush );
\r
2667 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2668 int steps = squareSize / 2;
\r
2671 for( i=0; i<steps; i++ ) {
\r
2672 BYTE r = r1 - (r1-r2) * i / steps;
\r
2673 BYTE g = g1 - (g1-g2) * i / steps;
\r
2674 BYTE b = b1 - (b1-b2) * i / steps;
\r
2676 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2677 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2678 FillRect( hdc, &rc, hbrush );
\r
2679 DeleteObject(hbrush);
\r
2682 else if( mode == 2 ) {
\r
2683 /* Diagonal gradient, good more or less for every piece */
\r
2684 POINT triangle[3];
\r
2685 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2686 HBRUSH hbrush_old;
\r
2687 int steps = squareSize;
\r
2690 triangle[0].x = squareSize - steps;
\r
2691 triangle[0].y = squareSize;
\r
2692 triangle[1].x = squareSize;
\r
2693 triangle[1].y = squareSize;
\r
2694 triangle[2].x = squareSize;
\r
2695 triangle[2].y = squareSize - steps;
\r
2697 for( i=0; i<steps; i++ ) {
\r
2698 BYTE r = r1 - (r1-r2) * i / steps;
\r
2699 BYTE g = g1 - (g1-g2) * i / steps;
\r
2700 BYTE b = b1 - (b1-b2) * i / steps;
\r
2702 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2703 hbrush_old = SelectObject( hdc, hbrush );
\r
2704 Polygon( hdc, triangle, 3 );
\r
2705 SelectObject( hdc, hbrush_old );
\r
2706 DeleteObject(hbrush);
\r
2711 SelectObject( hdc, hpen );
\r
2716 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2717 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2718 piece: follow the steps as explained below.
\r
2720 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2724 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2728 int backColor = whitePieceColor;
\r
2729 int foreColor = blackPieceColor;
\r
2731 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2732 backColor = appData.fontBackColorWhite;
\r
2733 foreColor = appData.fontForeColorWhite;
\r
2735 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2736 backColor = appData.fontBackColorBlack;
\r
2737 foreColor = appData.fontForeColorBlack;
\r
2741 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2743 hbm_old = SelectObject( hdc, hbm );
\r
2747 rc.right = squareSize;
\r
2748 rc.bottom = squareSize;
\r
2750 /* Step 1: background is now black */
\r
2751 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2753 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2755 pt.x = (squareSize - sz.cx) / 2;
\r
2756 pt.y = (squareSize - sz.cy) / 2;
\r
2758 SetBkMode( hdc, TRANSPARENT );
\r
2759 SetTextColor( hdc, chroma );
\r
2760 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2761 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2763 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2764 /* Step 3: the area outside the piece is filled with white */
\r
2765 // FloodFill( hdc, 0, 0, chroma );
\r
2766 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2767 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2768 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2769 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2770 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2772 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2773 but if the start point is not inside the piece we're lost!
\r
2774 There should be a better way to do this... if we could create a region or path
\r
2775 from the fill operation we would be fine for example.
\r
2777 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2778 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2780 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2781 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2782 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2784 SelectObject( dc2, bm2 );
\r
2785 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2786 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2787 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2788 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2789 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2792 DeleteObject( bm2 );
\r
2795 SetTextColor( hdc, 0 );
\r
2797 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2798 draw the piece again in black for safety.
\r
2800 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2802 SelectObject( hdc, hbm_old );
\r
2804 if( hPieceMask[index] != NULL ) {
\r
2805 DeleteObject( hPieceMask[index] );
\r
2808 hPieceMask[index] = hbm;
\r
2811 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2813 SelectObject( hdc, hbm );
\r
2816 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2817 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2818 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2820 SelectObject( dc1, hPieceMask[index] );
\r
2821 SelectObject( dc2, bm2 );
\r
2822 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2823 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2826 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2827 the piece background and deletes (makes transparent) the rest.
\r
2828 Thanks to that mask, we are free to paint the background with the greates
\r
2829 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2830 We use this, to make gradients and give the pieces a "roundish" look.
\r
2832 SetPieceBackground( hdc, backColor, 2 );
\r
2833 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2837 DeleteObject( bm2 );
\r
2840 SetTextColor( hdc, foreColor );
\r
2841 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2843 SelectObject( hdc, hbm_old );
\r
2845 if( hPieceFace[index] != NULL ) {
\r
2846 DeleteObject( hPieceFace[index] );
\r
2849 hPieceFace[index] = hbm;
\r
2852 static int TranslatePieceToFontPiece( int piece )
\r
2882 case BlackMarshall:
\r
2886 case BlackNightrider:
\r
2892 case BlackUnicorn:
\r
2896 case BlackGrasshopper:
\r
2908 case BlackCardinal:
\r
2915 case WhiteMarshall:
\r
2919 case WhiteNightrider:
\r
2925 case WhiteUnicorn:
\r
2929 case WhiteGrasshopper:
\r
2941 case WhiteCardinal:
\r
2950 void CreatePiecesFromFont()
\r
2953 HDC hdc_window = NULL;
\r
2959 if( fontBitmapSquareSize < 0 ) {
\r
2960 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2964 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2965 fontBitmapSquareSize = -1;
\r
2969 if( fontBitmapSquareSize != squareSize ) {
\r
2970 hdc_window = GetDC( hwndMain );
\r
2971 hdc = CreateCompatibleDC( hdc_window );
\r
2973 if( hPieceFont != NULL ) {
\r
2974 DeleteObject( hPieceFont );
\r
2977 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2978 hPieceMask[i] = NULL;
\r
2979 hPieceFace[i] = NULL;
\r
2985 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2986 fontHeight = appData.fontPieceSize;
\r
2989 fontHeight = (fontHeight * squareSize) / 100;
\r
2991 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2993 lf.lfEscapement = 0;
\r
2994 lf.lfOrientation = 0;
\r
2995 lf.lfWeight = FW_NORMAL;
\r
2997 lf.lfUnderline = 0;
\r
2998 lf.lfStrikeOut = 0;
\r
2999 lf.lfCharSet = DEFAULT_CHARSET;
\r
3000 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
3001 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
3002 lf.lfQuality = PROOF_QUALITY;
\r
3003 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
3004 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3005 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3007 hPieceFont = CreateFontIndirect( &lf );
\r
3009 if( hPieceFont == NULL ) {
\r
3010 fontBitmapSquareSize = -2;
\r
3013 /* Setup font-to-piece character table */
\r
3014 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3015 /* No (or wrong) global settings, try to detect the font */
\r
3016 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3018 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3020 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3021 /* DiagramTT* family */
\r
3022 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3024 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3025 /* Fairy symbols */
\r
3026 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3028 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3029 /* Good Companion (Some characters get warped as literal :-( */
\r
3030 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3031 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3032 SetCharTable(pieceToFontChar, s);
\r
3035 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3036 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3040 /* Create bitmaps */
\r
3041 hfont_old = SelectObject( hdc, hPieceFont );
\r
3043 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3048 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3050 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3051 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3056 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3063 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3064 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3065 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3066 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3067 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3068 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3069 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3070 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3071 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3072 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3073 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3074 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3075 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3076 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3077 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3078 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3079 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3080 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3081 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3082 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3083 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3084 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3085 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3086 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3087 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3089 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3090 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3091 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3093 SelectObject( hdc, hfont_old );
\r
3095 fontBitmapSquareSize = squareSize;
\r
3099 if( hdc != NULL ) {
\r
3103 if( hdc_window != NULL ) {
\r
3104 ReleaseDC( hwndMain, hdc_window );
\r
3109 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3113 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3114 if (gameInfo.event &&
\r
3115 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3116 strcmp(name, "k80s") == 0) {
\r
3117 strcpy(name, "tim");
\r
3119 return LoadBitmap(hinst, name);
\r
3123 /* Insert a color into the program's logical palette
\r
3124 structure. This code assumes the given color is
\r
3125 the result of the RGB or PALETTERGB macro, and it
\r
3126 knows how those macros work (which is documented).
\r
3129 InsertInPalette(COLORREF color)
\r
3131 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3133 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3134 DisplayFatalError("Too many colors", 0, 1);
\r
3135 pLogPal->palNumEntries--;
\r
3139 pe->peFlags = (char) 0;
\r
3140 pe->peRed = (char) (0xFF & color);
\r
3141 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3142 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3148 InitDrawingColors()
\r
3150 if (pLogPal == NULL) {
\r
3151 /* Allocate enough memory for a logical palette with
\r
3152 * PALETTESIZE entries and set the size and version fields
\r
3153 * of the logical palette structure.
\r
3155 pLogPal = (NPLOGPALETTE)
\r
3156 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3157 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3158 pLogPal->palVersion = 0x300;
\r
3160 pLogPal->palNumEntries = 0;
\r
3162 InsertInPalette(lightSquareColor);
\r
3163 InsertInPalette(darkSquareColor);
\r
3164 InsertInPalette(whitePieceColor);
\r
3165 InsertInPalette(blackPieceColor);
\r
3166 InsertInPalette(highlightSquareColor);
\r
3167 InsertInPalette(premoveHighlightColor);
\r
3169 /* create a logical color palette according the information
\r
3170 * in the LOGPALETTE structure.
\r
3172 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3174 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3175 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3176 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3177 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3178 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3179 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3180 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3181 /* [AS] Force rendering of the font-based pieces */
\r
3182 if( fontBitmapSquareSize > 0 ) {
\r
3183 fontBitmapSquareSize = 0;
\r
3189 BoardWidth(int boardSize, int n)
\r
3190 { /* [HGM] argument n added to allow different width and height */
\r
3191 int lineGap = sizeInfo[boardSize].lineGap;
\r
3193 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3194 lineGap = appData.overrideLineGap;
\r
3197 return (n + 1) * lineGap +
\r
3198 n * sizeInfo[boardSize].squareSize;
\r
3201 /* Respond to board resize by dragging edge */
\r
3203 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3205 BoardSize newSize = NUM_SIZES - 1;
\r
3206 static int recurse = 0;
\r
3207 if (IsIconic(hwndMain)) return;
\r
3208 if (recurse > 0) return;
\r
3210 while (newSize > 0) {
\r
3211 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3212 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3213 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3216 boardSize = newSize;
\r
3217 InitDrawingSizes(boardSize, flags);
\r
3224 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3226 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3227 ChessSquare piece;
\r
3228 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3230 SIZE clockSize, messageSize;
\r
3232 char buf[MSG_SIZ];
\r
3234 HMENU hmenu = GetMenu(hwndMain);
\r
3235 RECT crect, wrect, oldRect;
\r
3237 LOGBRUSH logbrush;
\r
3239 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3240 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3242 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3243 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3245 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3246 oldRect.top = boardY;
\r
3247 oldRect.right = boardX + winWidth;
\r
3248 oldRect.bottom = boardY + winHeight;
\r
3250 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3251 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3252 squareSize = sizeInfo[boardSize].squareSize;
\r
3253 lineGap = sizeInfo[boardSize].lineGap;
\r
3254 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3256 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3257 lineGap = appData.overrideLineGap;
\r
3260 if (tinyLayout != oldTinyLayout) {
\r
3261 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3263 style &= ~WS_SYSMENU;
\r
3264 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3265 "&Minimize\tCtrl+F4");
\r
3267 style |= WS_SYSMENU;
\r
3268 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3270 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3272 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3273 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3274 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3276 DrawMenuBar(hwndMain);
\r
3279 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3280 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3282 /* Get text area sizes */
\r
3283 hdc = GetDC(hwndMain);
\r
3284 if (appData.clockMode) {
\r
3285 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3287 sprintf(buf, "White");
\r
3289 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3290 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3291 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3292 str = "We only care about the height here";
\r
3293 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3294 SelectObject(hdc, oldFont);
\r
3295 ReleaseDC(hwndMain, hdc);
\r
3297 /* Compute where everything goes */
\r
3298 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3299 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3300 logoHeight = 2*clockSize.cy;
\r
3301 leftLogoRect.left = OUTER_MARGIN;
\r
3302 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3303 leftLogoRect.top = OUTER_MARGIN;
\r
3304 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3306 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3307 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3308 rightLogoRect.top = OUTER_MARGIN;
\r
3309 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3312 whiteRect.left = leftLogoRect.right;
\r
3313 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3314 whiteRect.top = OUTER_MARGIN;
\r
3315 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3317 blackRect.right = rightLogoRect.left;
\r
3318 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3319 blackRect.top = whiteRect.top;
\r
3320 blackRect.bottom = whiteRect.bottom;
\r
3322 whiteRect.left = OUTER_MARGIN;
\r
3323 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3324 whiteRect.top = OUTER_MARGIN;
\r
3325 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3327 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3328 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3329 blackRect.top = whiteRect.top;
\r
3330 blackRect.bottom = whiteRect.bottom;
\r
3333 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3334 if (appData.showButtonBar) {
\r
3335 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3336 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3338 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3340 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3341 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3343 boardRect.left = OUTER_MARGIN;
\r
3344 boardRect.right = boardRect.left + boardWidth;
\r
3345 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3346 boardRect.bottom = boardRect.top + boardHeight;
\r
3348 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3349 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3350 oldBoardSize = boardSize;
\r
3351 oldTinyLayout = tinyLayout;
\r
3352 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3353 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3354 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3355 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3356 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3357 winHeight = winH; // without disturbing window attachments
\r
3358 GetWindowRect(hwndMain, &wrect);
\r
3359 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3360 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3362 // [HGM] placement: let attached windows follow size change.
\r
3363 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3364 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3365 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3366 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3367 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3369 /* compensate if menu bar wrapped */
\r
3370 GetClientRect(hwndMain, &crect);
\r
3371 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3372 winHeight += offby;
\r
3374 case WMSZ_TOPLEFT:
\r
3375 SetWindowPos(hwndMain, NULL,
\r
3376 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3377 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3380 case WMSZ_TOPRIGHT:
\r
3382 SetWindowPos(hwndMain, NULL,
\r
3383 wrect.left, wrect.bottom - winHeight,
\r
3384 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3387 case WMSZ_BOTTOMLEFT:
\r
3389 SetWindowPos(hwndMain, NULL,
\r
3390 wrect.right - winWidth, wrect.top,
\r
3391 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3394 case WMSZ_BOTTOMRIGHT:
\r
3398 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3399 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3404 for (i = 0; i < N_BUTTONS; i++) {
\r
3405 if (buttonDesc[i].hwnd != NULL) {
\r
3406 DestroyWindow(buttonDesc[i].hwnd);
\r
3407 buttonDesc[i].hwnd = NULL;
\r
3409 if (appData.showButtonBar) {
\r
3410 buttonDesc[i].hwnd =
\r
3411 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3412 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3413 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3414 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3415 (HMENU) buttonDesc[i].id,
\r
3416 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3418 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3419 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3420 MAKELPARAM(FALSE, 0));
\r
3422 if (buttonDesc[i].id == IDM_Pause)
\r
3423 hwndPause = buttonDesc[i].hwnd;
\r
3424 buttonDesc[i].wndproc = (WNDPROC)
\r
3425 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3428 if (gridPen != NULL) DeleteObject(gridPen);
\r
3429 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3430 if (premovePen != NULL) DeleteObject(premovePen);
\r
3431 if (lineGap != 0) {
\r
3432 logbrush.lbStyle = BS_SOLID;
\r
3433 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3435 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3436 lineGap, &logbrush, 0, NULL);
\r
3437 logbrush.lbColor = highlightSquareColor;
\r
3439 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3440 lineGap, &logbrush, 0, NULL);
\r
3442 logbrush.lbColor = premoveHighlightColor;
\r
3444 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3445 lineGap, &logbrush, 0, NULL);
\r
3447 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3448 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3449 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3450 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3451 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3452 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3453 BOARD_WIDTH * (squareSize + lineGap);
\r
3454 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3456 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3457 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3458 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3459 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3460 lineGap / 2 + (i * (squareSize + lineGap));
\r
3461 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3462 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3463 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3467 /* [HGM] Licensing requirement */
\r
3469 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3472 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3474 GothicPopUp( "", VariantNormal);
\r
3477 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3479 /* Load piece bitmaps for this board size */
\r
3480 for (i=0; i<=2; i++) {
\r
3481 for (piece = WhitePawn;
\r
3482 (int) piece < (int) BlackPawn;
\r
3483 piece = (ChessSquare) ((int) piece + 1)) {
\r
3484 if (pieceBitmap[i][piece] != NULL)
\r
3485 DeleteObject(pieceBitmap[i][piece]);
\r
3489 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3490 // Orthodox Chess pieces
\r
3491 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3492 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3493 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3494 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3495 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3496 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3497 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3498 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3499 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3500 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3501 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3502 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3503 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3504 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3505 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3506 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3507 // in Shogi, Hijack the unused Queen for Lance
\r
3508 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3509 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3510 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3512 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3513 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3514 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3517 if(squareSize <= 72 && squareSize >= 33) {
\r
3518 /* A & C are available in most sizes now */
\r
3519 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3520 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3521 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3522 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3523 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3524 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3525 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3526 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3527 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3528 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3529 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3530 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3531 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3532 } else { // Smirf-like
\r
3533 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3534 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3535 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3537 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3538 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3539 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3540 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3541 } else { // WinBoard standard
\r
3542 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3543 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3544 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3549 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3550 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3551 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3552 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3553 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3554 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3555 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3556 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3557 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3558 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3559 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3560 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3561 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3562 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3563 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3564 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3565 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3566 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3567 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3568 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3569 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3570 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3571 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3572 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3573 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3574 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3575 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3576 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3577 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3578 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3579 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3581 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3582 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3583 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3584 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3585 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3586 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3587 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3588 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3589 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3590 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3591 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3592 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3593 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3595 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3596 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3597 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3598 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3599 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3600 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3601 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3602 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3603 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3604 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3605 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3606 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3609 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3610 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3611 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3612 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3613 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3614 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3615 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3616 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3617 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3618 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3619 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3620 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3621 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3622 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3623 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3627 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3628 /* special Shogi support in this size */
\r
3629 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3630 for (piece = WhitePawn;
\r
3631 (int) piece < (int) BlackPawn;
\r
3632 piece = (ChessSquare) ((int) piece + 1)) {
\r
3633 if (pieceBitmap[i][piece] != NULL)
\r
3634 DeleteObject(pieceBitmap[i][piece]);
\r
3637 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3638 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3639 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3640 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3641 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3642 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3643 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3644 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3645 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3646 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3647 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3648 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3649 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3650 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3651 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3652 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3653 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3654 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3655 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3656 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3657 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3658 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3659 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3660 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3661 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3662 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3663 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3664 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3665 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3666 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3667 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3668 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3669 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3670 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3671 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3672 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3673 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3674 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3675 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3676 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3677 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3678 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3684 PieceBitmap(ChessSquare p, int kind)
\r
3686 if ((int) p >= (int) BlackPawn)
\r
3687 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3689 return pieceBitmap[kind][(int) p];
\r
3692 /***************************************************************/
\r
3694 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3695 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3697 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3698 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3702 SquareToPos(int row, int column, int * x, int * y)
\r
3705 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3706 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3708 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3709 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3714 DrawCoordsOnDC(HDC hdc)
\r
3716 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
3717 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
3718 char str[2] = { NULLCHAR, NULLCHAR };
\r
3719 int oldMode, oldAlign, x, y, start, i;
\r
3723 if (!appData.showCoords)
\r
3726 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3728 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3729 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3730 oldAlign = GetTextAlign(hdc);
\r
3731 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3733 y = boardRect.top + lineGap;
\r
3734 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3736 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3737 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3738 str[0] = files[start + i];
\r
3739 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3740 y += squareSize + lineGap;
\r
3743 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3745 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3746 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3747 str[0] = ranks[start + i];
\r
3748 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3749 x += squareSize + lineGap;
\r
3752 SelectObject(hdc, oldBrush);
\r
3753 SetBkMode(hdc, oldMode);
\r
3754 SetTextAlign(hdc, oldAlign);
\r
3755 SelectObject(hdc, oldFont);
\r
3759 DrawGridOnDC(HDC hdc)
\r
3763 if (lineGap != 0) {
\r
3764 oldPen = SelectObject(hdc, gridPen);
\r
3765 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3766 SelectObject(hdc, oldPen);
\r
3770 #define HIGHLIGHT_PEN 0
\r
3771 #define PREMOVE_PEN 1
\r
3774 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3777 HPEN oldPen, hPen;
\r
3778 if (lineGap == 0) return;
\r
3780 x1 = boardRect.left +
\r
3781 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3782 y1 = boardRect.top +
\r
3783 lineGap/2 + y * (squareSize + lineGap);
\r
3785 x1 = boardRect.left +
\r
3786 lineGap/2 + x * (squareSize + lineGap);
\r
3787 y1 = boardRect.top +
\r
3788 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3790 hPen = pen ? premovePen : highlightPen;
\r
3791 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3792 MoveToEx(hdc, x1, y1, NULL);
\r
3793 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3794 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3795 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3796 LineTo(hdc, x1, y1);
\r
3797 SelectObject(hdc, oldPen);
\r
3801 DrawHighlightsOnDC(HDC hdc)
\r
3804 for (i=0; i<2; i++) {
\r
3805 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3806 DrawHighlightOnDC(hdc, TRUE,
\r
3807 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3810 for (i=0; i<2; i++) {
\r
3811 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3812 premoveHighlightInfo.sq[i].y >= 0) {
\r
3813 DrawHighlightOnDC(hdc, TRUE,
\r
3814 premoveHighlightInfo.sq[i].x,
\r
3815 premoveHighlightInfo.sq[i].y,
\r
3821 /* Note: sqcolor is used only in monoMode */
\r
3822 /* Note that this code is largely duplicated in woptions.c,
\r
3823 function DrawSampleSquare, so that needs to be updated too */
\r
3825 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3827 HBITMAP oldBitmap;
\r
3831 if (appData.blindfold) return;
\r
3833 /* [AS] Use font-based pieces if needed */
\r
3834 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3835 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3836 CreatePiecesFromFont();
\r
3838 if( fontBitmapSquareSize == squareSize ) {
\r
3839 int index = TranslatePieceToFontPiece(piece);
\r
3841 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3845 squareSize, squareSize,
\r
3850 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3854 squareSize, squareSize,
\r
3863 if (appData.monoMode) {
\r
3864 SelectObject(tmphdc, PieceBitmap(piece,
\r
3865 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3866 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3867 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3869 tmpSize = squareSize;
\r
3871 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3872 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3873 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3874 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3875 x += (squareSize - minorSize)>>1;
\r
3876 y += squareSize - minorSize - 2;
\r
3877 tmpSize = minorSize;
\r
3879 if (color || appData.allWhite ) {
\r
3880 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3882 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3883 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3884 if(appData.upsideDown && color==flipView)
\r
3885 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3887 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3889 /* Use black piece color for outline of white pieces */
\r
3890 /* Not sure this looks really good (though xboard does it).
\r
3891 Maybe better to have another selectable color, default black */
\r
3892 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3893 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3894 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3896 /* Use black for outline of white pieces */
\r
3897 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3898 if(appData.upsideDown && color==flipView)
\r
3899 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3901 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3905 /* Use white piece color for details of black pieces */
\r
3906 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3907 WHITE_PIECE ones aren't always the right shape. */
\r
3908 /* Not sure this looks really good (though xboard does it).
\r
3909 Maybe better to have another selectable color, default medium gray? */
\r
3910 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3911 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3912 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3913 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3914 SelectObject(hdc, blackPieceBrush);
\r
3915 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3917 /* Use square color for details of black pieces */
\r
3918 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3919 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3920 if(appData.upsideDown && !flipView)
\r
3921 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3923 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3926 SelectObject(hdc, oldBrush);
\r
3927 SelectObject(tmphdc, oldBitmap);
\r
3931 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3932 int GetBackTextureMode( int algo )
\r
3934 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3938 case BACK_TEXTURE_MODE_PLAIN:
\r
3939 result = 1; /* Always use identity map */
\r
3941 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3942 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3950 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3951 to handle redraws cleanly (as random numbers would always be different).
\r
3953 VOID RebuildTextureSquareInfo()
\r
3963 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3965 if( liteBackTexture != NULL ) {
\r
3966 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3967 lite_w = bi.bmWidth;
\r
3968 lite_h = bi.bmHeight;
\r
3972 if( darkBackTexture != NULL ) {
\r
3973 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3974 dark_w = bi.bmWidth;
\r
3975 dark_h = bi.bmHeight;
\r
3979 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3980 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3981 if( (col + row) & 1 ) {
\r
3983 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3984 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3985 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3986 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3991 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3992 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3993 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3994 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
4001 /* [AS] Arrow highlighting support */
\r
4003 static int A_WIDTH = 5; /* Width of arrow body */
\r
4005 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
4006 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
4008 static double Sqr( double x )
\r
4013 static int Round( double x )
\r
4015 return (int) (x + 0.5);
\r
4018 /* Draw an arrow between two points using current settings */
\r
4019 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
4022 double dx, dy, j, k, x, y;
\r
4024 if( d_x == s_x ) {
\r
4025 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4027 arrow[0].x = s_x + A_WIDTH;
\r
4030 arrow[1].x = s_x + A_WIDTH;
\r
4031 arrow[1].y = d_y - h;
\r
4033 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4034 arrow[2].y = d_y - h;
\r
4039 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4040 arrow[4].y = d_y - h;
\r
4042 arrow[5].x = s_x - A_WIDTH;
\r
4043 arrow[5].y = d_y - h;
\r
4045 arrow[6].x = s_x - A_WIDTH;
\r
4048 else if( d_y == s_y ) {
\r
4049 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4052 arrow[0].y = s_y + A_WIDTH;
\r
4054 arrow[1].x = d_x - w;
\r
4055 arrow[1].y = s_y + A_WIDTH;
\r
4057 arrow[2].x = d_x - w;
\r
4058 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4063 arrow[4].x = d_x - w;
\r
4064 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4066 arrow[5].x = d_x - w;
\r
4067 arrow[5].y = s_y - A_WIDTH;
\r
4070 arrow[6].y = s_y - A_WIDTH;
\r
4073 /* [AS] Needed a lot of paper for this! :-) */
\r
4074 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4075 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4077 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4079 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4084 arrow[0].x = Round(x - j);
\r
4085 arrow[0].y = Round(y + j*dx);
\r
4087 arrow[1].x = Round(x + j);
\r
4088 arrow[1].y = Round(y - j*dx);
\r
4091 x = (double) d_x - k;
\r
4092 y = (double) d_y - k*dy;
\r
4095 x = (double) d_x + k;
\r
4096 y = (double) d_y + k*dy;
\r
4099 arrow[2].x = Round(x + j);
\r
4100 arrow[2].y = Round(y - j*dx);
\r
4102 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4103 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4108 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4109 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4111 arrow[6].x = Round(x - j);
\r
4112 arrow[6].y = Round(y + j*dx);
\r
4115 Polygon( hdc, arrow, 7 );
\r
4118 /* [AS] Draw an arrow between two squares */
\r
4119 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4121 int s_x, s_y, d_x, d_y;
\r
4128 if( s_col == d_col && s_row == d_row ) {
\r
4132 /* Get source and destination points */
\r
4133 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4134 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4137 d_y += squareSize / 4;
\r
4139 else if( d_y < s_y ) {
\r
4140 d_y += 3 * squareSize / 4;
\r
4143 d_y += squareSize / 2;
\r
4147 d_x += squareSize / 4;
\r
4149 else if( d_x < s_x ) {
\r
4150 d_x += 3 * squareSize / 4;
\r
4153 d_x += squareSize / 2;
\r
4156 s_x += squareSize / 2;
\r
4157 s_y += squareSize / 2;
\r
4159 /* Adjust width */
\r
4160 A_WIDTH = squareSize / 14;
\r
4163 stLB.lbStyle = BS_SOLID;
\r
4164 stLB.lbColor = appData.highlightArrowColor;
\r
4167 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4168 holdpen = SelectObject( hdc, hpen );
\r
4169 hbrush = CreateBrushIndirect( &stLB );
\r
4170 holdbrush = SelectObject( hdc, hbrush );
\r
4172 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4174 SelectObject( hdc, holdpen );
\r
4175 SelectObject( hdc, holdbrush );
\r
4176 DeleteObject( hpen );
\r
4177 DeleteObject( hbrush );
\r
4180 BOOL HasHighlightInfo()
\r
4182 BOOL result = FALSE;
\r
4184 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4185 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4193 BOOL IsDrawArrowEnabled()
\r
4195 BOOL result = FALSE;
\r
4197 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4204 VOID DrawArrowHighlight( HDC hdc )
\r
4206 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4207 DrawArrowBetweenSquares( hdc,
\r
4208 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4209 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4213 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4215 HRGN result = NULL;
\r
4217 if( HasHighlightInfo() ) {
\r
4218 int x1, y1, x2, y2;
\r
4219 int sx, sy, dx, dy;
\r
4221 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4222 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4224 sx = MIN( x1, x2 );
\r
4225 sy = MIN( y1, y2 );
\r
4226 dx = MAX( x1, x2 ) + squareSize;
\r
4227 dy = MAX( y1, y2 ) + squareSize;
\r
4229 result = CreateRectRgn( sx, sy, dx, dy );
\r
4236 Warning: this function modifies the behavior of several other functions.
\r
4238 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4239 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4240 repaint is scattered all over the place, which is not good for features such as
\r
4241 "arrow highlighting" that require a full repaint of the board.
\r
4243 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4244 user interaction, when speed is not so important) but especially to avoid errors
\r
4245 in the displayed graphics.
\r
4247 In such patched places, I always try refer to this function so there is a single
\r
4248 place to maintain knowledge.
\r
4250 To restore the original behavior, just return FALSE unconditionally.
\r
4252 BOOL IsFullRepaintPreferrable()
\r
4254 BOOL result = FALSE;
\r
4256 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4257 /* Arrow may appear on the board */
\r
4265 This function is called by DrawPosition to know whether a full repaint must
\r
4268 Only DrawPosition may directly call this function, which makes use of
\r
4269 some state information. Other function should call DrawPosition specifying
\r
4270 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4272 BOOL DrawPositionNeedsFullRepaint()
\r
4274 BOOL result = FALSE;
\r
4277 Probably a slightly better policy would be to trigger a full repaint
\r
4278 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4279 but animation is fast enough that it's difficult to notice.
\r
4281 if( animInfo.piece == EmptySquare ) {
\r
4282 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4291 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4293 int row, column, x, y, square_color, piece_color;
\r
4294 ChessSquare piece;
\r
4296 HDC texture_hdc = NULL;
\r
4298 /* [AS] Initialize background textures if needed */
\r
4299 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4300 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4301 if( backTextureSquareSize != squareSize
\r
4302 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4303 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4304 backTextureSquareSize = squareSize;
\r
4305 RebuildTextureSquareInfo();
\r
4308 texture_hdc = CreateCompatibleDC( hdc );
\r
4311 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4312 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4314 SquareToPos(row, column, &x, &y);
\r
4316 piece = board[row][column];
\r
4318 square_color = ((column + row) % 2) == 1;
\r
4319 if( gameInfo.variant == VariantXiangqi ) {
\r
4320 square_color = !InPalace(row, column);
\r
4321 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4322 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4324 piece_color = (int) piece < (int) BlackPawn;
\r
4327 /* [HGM] holdings file: light square or black */
\r
4328 if(column == BOARD_LEFT-2) {
\r
4329 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4332 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4336 if(column == BOARD_RGHT + 1 ) {
\r
4337 if( row < gameInfo.holdingsSize )
\r
4340 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4344 if(column == BOARD_LEFT-1 ) /* left align */
\r
4345 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4346 else if( column == BOARD_RGHT) /* right align */
\r
4347 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4349 if (appData.monoMode) {
\r
4350 if (piece == EmptySquare) {
\r
4351 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4352 square_color ? WHITENESS : BLACKNESS);
\r
4354 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4357 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4358 /* [AS] Draw the square using a texture bitmap */
\r
4359 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4360 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4361 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4364 squareSize, squareSize,
\r
4367 backTextureSquareInfo[r][c].mode,
\r
4368 backTextureSquareInfo[r][c].x,
\r
4369 backTextureSquareInfo[r][c].y );
\r
4371 SelectObject( texture_hdc, hbm );
\r
4373 if (piece != EmptySquare) {
\r
4374 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4378 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4380 oldBrush = SelectObject(hdc, brush );
\r
4381 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4382 SelectObject(hdc, oldBrush);
\r
4383 if (piece != EmptySquare)
\r
4384 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4389 if( texture_hdc != NULL ) {
\r
4390 DeleteDC( texture_hdc );
\r
4394 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4395 void fputDW(FILE *f, int x)
\r
4397 fputc(x & 255, f);
\r
4398 fputc(x>>8 & 255, f);
\r
4399 fputc(x>>16 & 255, f);
\r
4400 fputc(x>>24 & 255, f);
\r
4403 #define MAX_CLIPS 200 /* more than enough */
\r
4406 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4408 // HBITMAP bufferBitmap;
\r
4413 int w = 100, h = 50;
\r
4415 if(logo == NULL) return;
\r
4416 // GetClientRect(hwndMain, &Rect);
\r
4417 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4418 // Rect.bottom-Rect.top+1);
\r
4419 tmphdc = CreateCompatibleDC(hdc);
\r
4420 hbm = SelectObject(tmphdc, logo);
\r
4421 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4425 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4426 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4427 SelectObject(tmphdc, hbm);
\r
4432 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4434 static Board lastReq, lastDrawn;
\r
4435 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4436 static int lastDrawnFlipView = 0;
\r
4437 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4438 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4441 HBITMAP bufferBitmap;
\r
4442 HBITMAP oldBitmap;
\r
4444 HRGN clips[MAX_CLIPS];
\r
4445 ChessSquare dragged_piece = EmptySquare;
\r
4447 /* I'm undecided on this - this function figures out whether a full
\r
4448 * repaint is necessary on its own, so there's no real reason to have the
\r
4449 * caller tell it that. I think this can safely be set to FALSE - but
\r
4450 * if we trust the callers not to request full repaints unnessesarily, then
\r
4451 * we could skip some clipping work. In other words, only request a full
\r
4452 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4453 * gamestart and similar) --Hawk
\r
4455 Boolean fullrepaint = repaint;
\r
4457 if( DrawPositionNeedsFullRepaint() ) {
\r
4458 fullrepaint = TRUE;
\r
4462 if( fullrepaint ) {
\r
4463 static int repaint_count = 0;
\r
4467 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4468 OutputDebugString( buf );
\r
4472 if (board == NULL) {
\r
4473 if (!lastReqValid) {
\r
4478 CopyBoard(lastReq, board);
\r
4482 if (doingSizing) {
\r
4486 if (IsIconic(hwndMain)) {
\r
4490 if (hdc == NULL) {
\r
4491 hdc = GetDC(hwndMain);
\r
4492 if (!appData.monoMode) {
\r
4493 SelectPalette(hdc, hPal, FALSE);
\r
4494 RealizePalette(hdc);
\r
4498 releaseDC = FALSE;
\r
4502 fprintf(debugFP, "*******************************\n"
\r
4504 "dragInfo.from (%d,%d)\n"
\r
4505 "dragInfo.start (%d,%d)\n"
\r
4506 "dragInfo.pos (%d,%d)\n"
\r
4507 "dragInfo.lastpos (%d,%d)\n",
\r
4508 repaint ? "TRUE" : "FALSE",
\r
4509 dragInfo.from.x, dragInfo.from.y,
\r
4510 dragInfo.start.x, dragInfo.start.y,
\r
4511 dragInfo.pos.x, dragInfo.pos.y,
\r
4512 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4513 fprintf(debugFP, "prev: ");
\r
4514 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4515 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4516 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4519 fprintf(debugFP, "\n");
\r
4520 fprintf(debugFP, "board: ");
\r
4521 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4522 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4523 fprintf(debugFP, "%d ", board[row][column]);
\r
4526 fprintf(debugFP, "\n");
\r
4530 /* Create some work-DCs */
\r
4531 hdcmem = CreateCompatibleDC(hdc);
\r
4532 tmphdc = CreateCompatibleDC(hdc);
\r
4534 /* If dragging is in progress, we temporarely remove the piece */
\r
4535 /* [HGM] or temporarily decrease count if stacked */
\r
4536 /* !! Moved to before board compare !! */
\r
4537 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4538 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4539 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4540 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4541 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4543 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4544 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4545 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4547 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4550 /* Figure out which squares need updating by comparing the
\r
4551 * newest board with the last drawn board and checking if
\r
4552 * flipping has changed.
\r
4554 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4555 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4556 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4557 if (lastDrawn[row][column] != board[row][column]) {
\r
4558 SquareToPos(row, column, &x, &y);
\r
4559 clips[num_clips++] =
\r
4560 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4564 for (i=0; i<2; i++) {
\r
4565 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4566 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4567 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4568 lastDrawnHighlight.sq[i].y >= 0) {
\r
4569 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4570 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4571 clips[num_clips++] =
\r
4572 CreateRectRgn(x - lineGap, y - lineGap,
\r
4573 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4575 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4576 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4577 clips[num_clips++] =
\r
4578 CreateRectRgn(x - lineGap, y - lineGap,
\r
4579 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4583 for (i=0; i<2; i++) {
\r
4584 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4585 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4586 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4587 lastDrawnPremove.sq[i].y >= 0) {
\r
4588 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4589 lastDrawnPremove.sq[i].x, &x, &y);
\r
4590 clips[num_clips++] =
\r
4591 CreateRectRgn(x - lineGap, y - lineGap,
\r
4592 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4594 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4595 premoveHighlightInfo.sq[i].y >= 0) {
\r
4596 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4597 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4598 clips[num_clips++] =
\r
4599 CreateRectRgn(x - lineGap, y - lineGap,
\r
4600 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4605 fullrepaint = TRUE;
\r
4608 /* Create a buffer bitmap - this is the actual bitmap
\r
4609 * being written to. When all the work is done, we can
\r
4610 * copy it to the real DC (the screen). This avoids
\r
4611 * the problems with flickering.
\r
4613 GetClientRect(hwndMain, &Rect);
\r
4614 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4615 Rect.bottom-Rect.top+1);
\r
4616 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4617 if (!appData.monoMode) {
\r
4618 SelectPalette(hdcmem, hPal, FALSE);
\r
4621 /* Create clips for dragging */
\r
4622 if (!fullrepaint) {
\r
4623 if (dragInfo.from.x >= 0) {
\r
4624 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4625 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4627 if (dragInfo.start.x >= 0) {
\r
4628 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4629 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4631 if (dragInfo.pos.x >= 0) {
\r
4632 x = dragInfo.pos.x - squareSize / 2;
\r
4633 y = dragInfo.pos.y - squareSize / 2;
\r
4634 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4636 if (dragInfo.lastpos.x >= 0) {
\r
4637 x = dragInfo.lastpos.x - squareSize / 2;
\r
4638 y = dragInfo.lastpos.y - squareSize / 2;
\r
4639 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4643 /* Are we animating a move?
\r
4645 * - remove the piece from the board (temporarely)
\r
4646 * - calculate the clipping region
\r
4648 if (!fullrepaint) {
\r
4649 if (animInfo.piece != EmptySquare) {
\r
4650 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4651 x = boardRect.left + animInfo.lastpos.x;
\r
4652 y = boardRect.top + animInfo.lastpos.y;
\r
4653 x2 = boardRect.left + animInfo.pos.x;
\r
4654 y2 = boardRect.top + animInfo.pos.y;
\r
4655 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4656 /* Slight kludge. The real problem is that after AnimateMove is
\r
4657 done, the position on the screen does not match lastDrawn.
\r
4658 This currently causes trouble only on e.p. captures in
\r
4659 atomic, where the piece moves to an empty square and then
\r
4660 explodes. The old and new positions both had an empty square
\r
4661 at the destination, but animation has drawn a piece there and
\r
4662 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4663 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4667 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4668 if (num_clips == 0)
\r
4669 fullrepaint = TRUE;
\r
4671 /* Set clipping on the memory DC */
\r
4672 if (!fullrepaint) {
\r
4673 SelectClipRgn(hdcmem, clips[0]);
\r
4674 for (x = 1; x < num_clips; x++) {
\r
4675 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4676 abort(); // this should never ever happen!
\r
4680 /* Do all the drawing to the memory DC */
\r
4681 if(explodeInfo.radius) { // [HGM] atomic
\r
4683 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4684 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4685 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4686 x += squareSize/2;
\r
4687 y += squareSize/2;
\r
4688 if(!fullrepaint) {
\r
4689 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4690 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4692 DrawGridOnDC(hdcmem);
\r
4693 DrawHighlightsOnDC(hdcmem);
\r
4694 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4695 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4696 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4697 SelectObject(hdcmem, oldBrush);
\r
4699 DrawGridOnDC(hdcmem);
\r
4700 DrawHighlightsOnDC(hdcmem);
\r
4701 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4704 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4705 if(appData.autoLogo) {
\r
4707 switch(gameMode) { // pick logos based on game mode
\r
4708 case IcsObserving:
\r
4709 whiteLogo = second.programLogo; // ICS logo
\r
4710 blackLogo = second.programLogo;
\r
4713 case IcsPlayingWhite:
\r
4714 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4715 blackLogo = second.programLogo; // ICS logo
\r
4717 case IcsPlayingBlack:
\r
4718 whiteLogo = second.programLogo; // ICS logo
\r
4719 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4721 case TwoMachinesPlay:
\r
4722 if(first.twoMachinesColor[0] == 'b') {
\r
4723 whiteLogo = second.programLogo;
\r
4724 blackLogo = first.programLogo;
\r
4727 case MachinePlaysWhite:
\r
4728 blackLogo = userLogo;
\r
4730 case MachinePlaysBlack:
\r
4731 whiteLogo = userLogo;
\r
4732 blackLogo = first.programLogo;
\r
4735 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4736 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4739 if( appData.highlightMoveWithArrow ) {
\r
4740 DrawArrowHighlight(hdcmem);
\r
4743 DrawCoordsOnDC(hdcmem);
\r
4745 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4746 /* to make sure lastDrawn contains what is actually drawn */
\r
4748 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4749 if (dragged_piece != EmptySquare) {
\r
4750 /* [HGM] or restack */
\r
4751 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4752 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4754 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4755 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4756 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4757 x = dragInfo.pos.x - squareSize / 2;
\r
4758 y = dragInfo.pos.y - squareSize / 2;
\r
4759 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4760 ((int) dragged_piece < (int) BlackPawn),
\r
4761 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4764 /* Put the animated piece back into place and draw it */
\r
4765 if (animInfo.piece != EmptySquare) {
\r
4766 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4767 x = boardRect.left + animInfo.pos.x;
\r
4768 y = boardRect.top + animInfo.pos.y;
\r
4769 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4770 ((int) animInfo.piece < (int) BlackPawn),
\r
4771 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4774 /* Release the bufferBitmap by selecting in the old bitmap
\r
4775 * and delete the memory DC
\r
4777 SelectObject(hdcmem, oldBitmap);
\r
4780 /* Set clipping on the target DC */
\r
4781 if (!fullrepaint) {
\r
4782 SelectClipRgn(hdc, clips[0]);
\r
4783 for (x = 1; x < num_clips; x++) {
\r
4784 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4785 abort(); // this should never ever happen!
\r
4789 /* Copy the new bitmap onto the screen in one go.
\r
4790 * This way we avoid any flickering
\r
4792 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4793 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4794 boardRect.right - boardRect.left,
\r
4795 boardRect.bottom - boardRect.top,
\r
4796 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4797 if(saveDiagFlag) {
\r
4798 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4799 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4801 GetObject(bufferBitmap, sizeof(b), &b);
\r
4802 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4803 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4804 bih.biWidth = b.bmWidth;
\r
4805 bih.biHeight = b.bmHeight;
\r
4807 bih.biBitCount = b.bmBitsPixel;
\r
4808 bih.biCompression = 0;
\r
4809 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4810 bih.biXPelsPerMeter = 0;
\r
4811 bih.biYPelsPerMeter = 0;
\r
4812 bih.biClrUsed = 0;
\r
4813 bih.biClrImportant = 0;
\r
4814 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4815 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4816 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4817 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4820 wb = b.bmWidthBytes;
\r
4822 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4823 int k = ((int*) pData)[i];
\r
4824 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4825 if(j >= 16) break;
\r
4827 if(j >= nrColors) nrColors = j+1;
\r
4829 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4831 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4832 for(w=0; w<(wb>>2); w+=2) {
\r
4833 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4834 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4835 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4836 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4837 pData[p++] = m | j<<4;
\r
4839 while(p&3) pData[p++] = 0;
\r
4842 wb = ((wb+31)>>5)<<2;
\r
4844 // write BITMAPFILEHEADER
\r
4845 fprintf(diagFile, "BM");
\r
4846 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4847 fputDW(diagFile, 0);
\r
4848 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4849 // write BITMAPINFOHEADER
\r
4850 fputDW(diagFile, 40);
\r
4851 fputDW(diagFile, b.bmWidth);
\r
4852 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4853 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4854 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4855 fputDW(diagFile, 0);
\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 // write color table
\r
4863 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4864 // write bitmap data
\r
4865 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4866 fputc(pData[i], diagFile);
\r
4871 SelectObject(tmphdc, oldBitmap);
\r
4873 /* Massive cleanup */
\r
4874 for (x = 0; x < num_clips; x++)
\r
4875 DeleteObject(clips[x]);
\r
4878 DeleteObject(bufferBitmap);
\r
4881 ReleaseDC(hwndMain, hdc);
\r
4883 if (lastDrawnFlipView != flipView) {
\r
4885 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4887 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4890 /* CopyBoard(lastDrawn, board);*/
\r
4891 lastDrawnHighlight = highlightInfo;
\r
4892 lastDrawnPremove = premoveHighlightInfo;
\r
4893 lastDrawnFlipView = flipView;
\r
4894 lastDrawnValid = 1;
\r
4897 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4902 saveDiagFlag = 1; diagFile = f;
\r
4903 HDCDrawPosition(NULL, TRUE, NULL);
\r
4907 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4914 /*---------------------------------------------------------------------------*\
\r
4915 | CLIENT PAINT PROCEDURE
\r
4916 | This is the main event-handler for the WM_PAINT message.
\r
4918 \*---------------------------------------------------------------------------*/
\r
4920 PaintProc(HWND hwnd)
\r
4926 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4927 if (IsIconic(hwnd)) {
\r
4928 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4930 if (!appData.monoMode) {
\r
4931 SelectPalette(hdc, hPal, FALSE);
\r
4932 RealizePalette(hdc);
\r
4934 HDCDrawPosition(hdc, 1, NULL);
\r
4936 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4937 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4938 ETO_CLIPPED|ETO_OPAQUE,
\r
4939 &messageRect, messageText, strlen(messageText), NULL);
\r
4940 SelectObject(hdc, oldFont);
\r
4941 DisplayBothClocks();
\r
4943 EndPaint(hwnd,&ps);
\r
4951 * If the user selects on a border boundary, return -1; if off the board,
\r
4952 * return -2. Otherwise map the event coordinate to the square.
\r
4953 * The offset boardRect.left or boardRect.top must already have been
\r
4954 * subtracted from x.
\r
4957 EventToSquare(int x)
\r
4964 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4966 x /= (squareSize + lineGap);
\r
4967 if (x >= BOARD_SIZE)
\r
4978 DropEnable dropEnables[] = {
\r
4979 { 'P', DP_Pawn, "Pawn" },
\r
4980 { 'N', DP_Knight, "Knight" },
\r
4981 { 'B', DP_Bishop, "Bishop" },
\r
4982 { 'R', DP_Rook, "Rook" },
\r
4983 { 'Q', DP_Queen, "Queen" },
\r
4987 SetupDropMenu(HMENU hmenu)
\r
4989 int i, count, enable;
\r
4991 extern char white_holding[], black_holding[];
\r
4992 char item[MSG_SIZ];
\r
4994 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4995 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4996 dropEnables[i].piece);
\r
4998 while (p && *p++ == dropEnables[i].piece) count++;
\r
4999 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
5000 enable = count > 0 || !appData.testLegality
\r
5001 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
5002 && !appData.icsActive);
\r
5003 ModifyMenu(hmenu, dropEnables[i].command,
\r
5004 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
5005 dropEnables[i].command, item);
\r
5009 /* Event handler for mouse messages */
\r
5011 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5015 static int recursive = 0;
\r
5017 // BOOLEAN needsRedraw = FALSE;
\r
5018 BOOLEAN saveAnimate;
\r
5019 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
5020 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
5021 ChessMove moveType;
\r
5024 if (message == WM_MBUTTONUP) {
\r
5025 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5026 to the middle button: we simulate pressing the left button too!
\r
5028 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5029 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5035 pt.x = LOWORD(lParam);
\r
5036 pt.y = HIWORD(lParam);
\r
5037 x = EventToSquare(pt.x - boardRect.left);
\r
5038 y = EventToSquare(pt.y - boardRect.top);
\r
5039 if (!flipView && y >= 0) {
\r
5040 y = BOARD_HEIGHT - 1 - y;
\r
5042 if (flipView && x >= 0) {
\r
5043 x = BOARD_WIDTH - 1 - x;
\r
5046 switch (message) {
\r
5047 case WM_LBUTTONDOWN:
\r
5048 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5049 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5050 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5051 if(gameInfo.holdingsWidth &&
\r
5052 (WhiteOnMove(currentMove)
\r
5053 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5054 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5055 // click in right holdings, for determining promotion piece
\r
5056 ChessSquare p = boards[currentMove][y][x];
\r
5057 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5058 if(p != EmptySquare) {
\r
5059 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5060 fromX = fromY = -1;
\r
5064 DrawPosition(FALSE, boards[currentMove]);
\r
5068 sameAgain = FALSE;
\r
5070 /* Downclick vertically off board; check if on clock */
\r
5071 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5072 if (gameMode == EditPosition) {
\r
5073 SetWhiteToPlayEvent();
\r
5074 } else if (gameMode == IcsPlayingBlack ||
\r
5075 gameMode == MachinePlaysWhite) {
\r
5077 } else if (gameMode == EditGame) {
\r
5078 AdjustClock(flipClock, -1);
\r
5080 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5081 if (gameMode == EditPosition) {
\r
5082 SetBlackToPlayEvent();
\r
5083 } else if (gameMode == IcsPlayingWhite ||
\r
5084 gameMode == MachinePlaysBlack) {
\r
5086 } else if (gameMode == EditGame) {
\r
5087 AdjustClock(!flipClock, -1);
\r
5090 if (!appData.highlightLastMove) {
\r
5091 ClearHighlights();
\r
5092 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5094 fromX = fromY = -1;
\r
5095 dragInfo.start.x = dragInfo.start.y = -1;
\r
5096 dragInfo.from = dragInfo.start;
\r
5098 } else if (x < 0 || y < 0
\r
5099 /* [HGM] block clicks between board and holdings */
\r
5100 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5101 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5102 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5103 /* EditPosition, empty square, or different color piece;
\r
5104 click-click move is possible */
\r
5107 } else if (fromX == x && fromY == y) {
\r
5108 /* Downclick on same square again */
\r
5109 ClearHighlights();
\r
5110 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5111 sameAgain = TRUE;
\r
5112 } else if (fromX != -1 &&
\r
5113 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5115 /* Downclick on different square. */
\r
5116 /* [HGM] if on holdings file, should count as new first click ! */
\r
5117 /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5120 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5121 to make sure move is legal before showing promotion popup */
\r
5122 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5123 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5124 fromX = fromY = -1;
\r
5125 ClearHighlights();
\r
5126 DrawPosition(FALSE, boards[currentMove]);
\r
5129 if(moveType != ImpossibleMove) {
\r
5130 if(moveType == IllegalMove) {
\r
5133 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5134 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5135 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5136 appData.alwaysPromoteToQueen)) {
\r
5137 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5138 if (!appData.highlightLastMove) {
\r
5139 ClearHighlights();
\r
5140 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5143 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5144 SetHighlights(fromX, fromY, toX, toY);
\r
5145 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5146 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5147 If promotion to Q is legal, all are legal! */
\r
5148 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5149 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5150 // kludge to temporarily execute move on display, without promoting yet
\r
5151 promotionChoice = TRUE;
\r
5152 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5153 boards[currentMove][toY][toX] = p;
\r
5154 DrawPosition(FALSE, boards[currentMove]);
\r
5155 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5156 boards[currentMove][toY][toX] = q;
\r
5158 PromotionPopup(hwnd);
\r
5159 } else { /* not a promotion */
\r
5160 if (appData.animate || appData.highlightLastMove) {
\r
5161 SetHighlights(fromX, fromY, toX, toY);
\r
5163 ClearHighlights();
\r
5165 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5166 if (appData.animate && !appData.highlightLastMove) {
\r
5167 ClearHighlights();
\r
5168 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5171 fromX = fromY = -1;
\r
5175 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5176 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5177 } else ClearHighlights();
\r
5178 fromX = fromY = -1;
\r
5179 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5181 /* First downclick, or restart on a square with same color piece */
\r
5182 if (!frozen && OKToStartUserMove(x, y)) {
\r
5185 dragInfo.lastpos = pt;
\r
5186 dragInfo.from.x = fromX;
\r
5187 dragInfo.from.y = fromY;
\r
5188 dragInfo.start = dragInfo.from;
\r
5189 SetCapture(hwndMain);
\r
5191 fromX = fromY = -1;
\r
5192 dragInfo.start.x = dragInfo.start.y = -1;
\r
5193 dragInfo.from = dragInfo.start;
\r
5194 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5198 case WM_LBUTTONUP:
\r
5200 if (fromX == -1) break;
\r
5201 if (x == fromX && y == fromY) {
\r
5202 dragInfo.from.x = dragInfo.from.y = -1;
\r
5203 /* Upclick on same square */
\r
5205 /* Clicked same square twice: abort click-click move */
\r
5206 fromX = fromY = -1;
\r
5208 ClearPremoveHighlights();
\r
5210 /* First square clicked: start click-click move */
\r
5211 SetHighlights(fromX, fromY, -1, -1);
\r
5213 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5214 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5215 /* Errant click; ignore */
\r
5218 /* Finish drag move. */
\r
5219 if (appData.debugMode) {
\r
5220 fprintf(debugFP, "release\n");
\r
5222 dragInfo.from.x = dragInfo.from.y = -1;
\r
5225 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5226 appData.animate = appData.animate && !appData.animateDragging;
\r
5227 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5228 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5229 fromX = fromY = -1;
\r
5230 ClearHighlights();
\r
5231 DrawPosition(FALSE, boards[currentMove]);
\r
5232 appData.animate = saveAnimate;
\r
5235 if(moveType != ImpossibleMove) {
\r
5236 /* [HGM] use move type to determine if move is promotion.
\r
5237 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5238 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5239 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5240 appData.alwaysPromoteToQueen))
\r
5241 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5243 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5244 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5245 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5246 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5247 // kludge to temporarily execute move on display, wthout promotng yet
\r
5248 promotionChoice = TRUE;
\r
5249 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5250 boards[currentMove][toY][toX] = p;
\r
5251 DrawPosition(FALSE, boards[currentMove]);
\r
5252 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5253 boards[currentMove][toY][toX] = q;
\r
5254 appData.animate = saveAnimate;
\r
5257 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5259 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5260 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5261 moveType == WhiteCapturesEnPassant ||
\r
5262 moveType == BlackCapturesEnPassant ) )
\r
5263 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5264 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5267 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5268 appData.animate = saveAnimate;
\r
5269 fromX = fromY = -1;
\r
5270 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5271 ClearHighlights();
\r
5273 if (appData.animate || appData.animateDragging ||
\r
5274 appData.highlightDragging || gotPremove) {
\r
5275 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5278 dragInfo.start.x = dragInfo.start.y = -1;
\r
5279 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5282 case WM_MOUSEMOVE:
\r
5283 if ((appData.animateDragging || appData.highlightDragging)
\r
5284 && (wParam & MK_LBUTTON)
\r
5285 && dragInfo.from.x >= 0)
\r
5287 BOOL full_repaint = FALSE;
\r
5289 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5290 if (appData.animateDragging) {
\r
5291 dragInfo.pos = pt;
\r
5293 if (appData.highlightDragging) {
\r
5294 SetHighlights(fromX, fromY, x, y);
\r
5295 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5296 full_repaint = TRUE;
\r
5300 DrawPosition( full_repaint, NULL);
\r
5302 dragInfo.lastpos = dragInfo.pos;
\r
5306 case WM_MOUSEWHEEL: // [DM]
\r
5307 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5308 /* Mouse Wheel is being rolled forward
\r
5309 * Play moves forward
\r
5311 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5312 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5313 /* Mouse Wheel is being rolled backward
\r
5314 * Play moves backward
\r
5316 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5317 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5321 case WM_MBUTTONDOWN:
\r
5322 case WM_RBUTTONDOWN:
\r
5325 fromX = fromY = -1;
\r
5326 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5327 dragInfo.start.x = dragInfo.start.y = -1;
\r
5328 dragInfo.from = dragInfo.start;
\r
5329 dragInfo.lastpos = dragInfo.pos;
\r
5330 if (appData.highlightDragging) {
\r
5331 ClearHighlights();
\r
5334 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5335 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5336 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5337 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5338 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5341 DrawPosition(TRUE, NULL);
\r
5343 switch (gameMode) {
\r
5344 case EditPosition:
\r
5345 case IcsExamining:
\r
5346 if (x < 0 || y < 0) break;
\r
5349 if (message == WM_MBUTTONDOWN) {
\r
5350 buttonCount = 3; /* even if system didn't think so */
\r
5351 if (wParam & MK_SHIFT)
\r
5352 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5354 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5355 } else { /* message == WM_RBUTTONDOWN */
\r
5357 if (buttonCount == 3) {
\r
5358 if (wParam & MK_SHIFT)
\r
5359 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5361 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5363 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5366 /* Just have one menu, on the right button. Windows users don't
\r
5367 think to try the middle one, and sometimes other software steals
\r
5368 it, or it doesn't really exist. */
\r
5369 if(gameInfo.variant != VariantShogi)
\r
5370 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5372 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5376 case IcsPlayingWhite:
\r
5377 case IcsPlayingBlack:
\r
5379 case MachinePlaysWhite:
\r
5380 case MachinePlaysBlack:
\r
5381 if (appData.testLegality &&
\r
5382 gameInfo.variant != VariantBughouse &&
\r
5383 gameInfo.variant != VariantCrazyhouse) break;
\r
5384 if (x < 0 || y < 0) break;
\r
5387 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5388 SetupDropMenu(hmenu);
\r
5389 MenuPopup(hwnd, pt, hmenu, -1);
\r
5400 /* Preprocess messages for buttons in main window */
\r
5402 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5404 int id = GetWindowLong(hwnd, GWL_ID);
\r
5407 for (i=0; i<N_BUTTONS; i++) {
\r
5408 if (buttonDesc[i].id == id) break;
\r
5410 if (i == N_BUTTONS) return 0;
\r
5411 switch (message) {
\r
5416 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5417 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5424 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5427 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5428 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5429 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5430 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5432 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5434 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5435 PopUpMoveDialog((char)wParam);
\r
5441 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5444 /* Process messages for Promotion dialog box */
\r
5446 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5450 switch (message) {
\r
5451 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5452 /* Center the dialog over the application window */
\r
5453 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5454 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5455 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5456 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5457 SW_SHOW : SW_HIDE);
\r
5458 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5459 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5460 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5461 PieceToChar(WhiteAngel) != '~') ||
\r
5462 (PieceToChar(BlackAngel) >= 'A' &&
\r
5463 PieceToChar(BlackAngel) != '~') ) ?
\r
5464 SW_SHOW : SW_HIDE);
\r
5465 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5466 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5467 PieceToChar(WhiteMarshall) != '~') ||
\r
5468 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5469 PieceToChar(BlackMarshall) != '~') ) ?
\r
5470 SW_SHOW : SW_HIDE);
\r
5471 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5472 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5473 gameInfo.variant != VariantShogi ?
\r
5474 SW_SHOW : SW_HIDE);
\r
5475 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5476 gameInfo.variant != VariantShogi ?
\r
5477 SW_SHOW : SW_HIDE);
\r
5478 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5479 gameInfo.variant == VariantShogi ?
\r
5480 SW_SHOW : SW_HIDE);
\r
5481 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5482 gameInfo.variant == VariantShogi ?
\r
5483 SW_SHOW : SW_HIDE);
\r
5484 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5485 gameInfo.variant == VariantSuper ?
\r
5486 SW_SHOW : SW_HIDE);
\r
5489 case WM_COMMAND: /* message: received a command */
\r
5490 switch (LOWORD(wParam)) {
\r
5492 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5493 ClearHighlights();
\r
5494 DrawPosition(FALSE, NULL);
\r
5497 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5500 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5503 promoChar = PieceToChar(BlackRook);
\r
5506 promoChar = PieceToChar(BlackBishop);
\r
5508 case PB_Chancellor:
\r
5509 promoChar = PieceToChar(BlackMarshall);
\r
5511 case PB_Archbishop:
\r
5512 promoChar = PieceToChar(BlackAngel);
\r
5515 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5520 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5521 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5522 only show the popup when we are already sure the move is valid or
\r
5523 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5524 will figure out it is a promotion from the promoChar. */
\r
5525 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5526 if (!appData.highlightLastMove) {
\r
5527 ClearHighlights();
\r
5528 DrawPosition(FALSE, NULL);
\r
5535 /* Pop up promotion dialog */
\r
5537 PromotionPopup(HWND hwnd)
\r
5541 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5542 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5543 hwnd, (DLGPROC)lpProc);
\r
5544 FreeProcInstance(lpProc);
\r
5547 /* Toggle ShowThinking */
\r
5549 ToggleShowThinking()
\r
5551 appData.showThinking = !appData.showThinking;
\r
5552 ShowThinkingEvent();
\r
5556 LoadGameDialog(HWND hwnd, char* title)
\r
5560 char fileTitle[MSG_SIZ];
\r
5561 f = OpenFileDialog(hwnd, "rb", "",
\r
5562 appData.oldSaveStyle ? "gam" : "pgn",
\r
5564 title, &number, fileTitle, NULL);
\r
5566 cmailMsgLoaded = FALSE;
\r
5567 if (number == 0) {
\r
5568 int error = GameListBuild(f);
\r
5570 DisplayError("Cannot build game list", error);
\r
5571 } else if (!ListEmpty(&gameList) &&
\r
5572 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5573 GameListPopUp(f, fileTitle);
\r
5576 GameListDestroy();
\r
5579 LoadGame(f, number, fileTitle, FALSE);
\r
5584 ChangedConsoleFont()
\r
5587 CHARRANGE tmpsel, sel;
\r
5588 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5589 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5590 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5593 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5594 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5595 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5596 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5597 * size. This was undocumented in the version of MSVC++ that I had
\r
5598 * when I wrote the code, but is apparently documented now.
\r
5600 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5601 cfmt.bCharSet = f->lf.lfCharSet;
\r
5602 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5603 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5604 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5605 /* Why are the following seemingly needed too? */
\r
5606 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5607 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5608 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5610 tmpsel.cpMax = -1; /*999999?*/
\r
5611 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5612 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5613 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5614 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5616 paraf.cbSize = sizeof(paraf);
\r
5617 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5618 paraf.dxStartIndent = 0;
\r
5619 paraf.dxOffset = WRAP_INDENT;
\r
5620 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5621 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5624 /*---------------------------------------------------------------------------*\
\r
5626 * Window Proc for main window
\r
5628 \*---------------------------------------------------------------------------*/
\r
5630 /* Process messages for main window, etc. */
\r
5632 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5635 int wmId, wmEvent;
\r
5639 char fileTitle[MSG_SIZ];
\r
5640 char buf[MSG_SIZ];
\r
5641 static SnapData sd;
\r
5643 switch (message) {
\r
5645 case WM_PAINT: /* message: repaint portion of window */
\r
5649 case WM_ERASEBKGND:
\r
5650 if (IsIconic(hwnd)) {
\r
5651 /* Cheat; change the message */
\r
5652 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5654 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5658 case WM_LBUTTONDOWN:
\r
5659 case WM_MBUTTONDOWN:
\r
5660 case WM_RBUTTONDOWN:
\r
5661 case WM_LBUTTONUP:
\r
5662 case WM_MBUTTONUP:
\r
5663 case WM_RBUTTONUP:
\r
5664 case WM_MOUSEMOVE:
\r
5665 case WM_MOUSEWHEEL:
\r
5666 MouseEvent(hwnd, message, wParam, lParam);
\r
5669 JAWS_KB_NAVIGATION
\r
5673 JAWS_ALT_INTERCEPT
\r
5675 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5676 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5677 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5678 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5680 SendMessage(h, message, wParam, lParam);
\r
5681 } else if(lParam != KF_REPEAT) {
\r
5682 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5683 PopUpMoveDialog((char)wParam);
\r
5684 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5685 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5690 case WM_PALETTECHANGED:
\r
5691 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5693 HDC hdc = GetDC(hwndMain);
\r
5694 SelectPalette(hdc, hPal, TRUE);
\r
5695 nnew = RealizePalette(hdc);
\r
5697 paletteChanged = TRUE;
\r
5699 UpdateColors(hdc);
\r
5701 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5704 ReleaseDC(hwnd, hdc);
\r
5708 case WM_QUERYNEWPALETTE:
\r
5709 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5711 HDC hdc = GetDC(hwndMain);
\r
5712 paletteChanged = FALSE;
\r
5713 SelectPalette(hdc, hPal, FALSE);
\r
5714 nnew = RealizePalette(hdc);
\r
5716 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5718 ReleaseDC(hwnd, hdc);
\r
5723 case WM_COMMAND: /* message: command from application menu */
\r
5724 wmId = LOWORD(wParam);
\r
5725 wmEvent = HIWORD(wParam);
\r
5730 AnalysisPopDown();
\r
5731 SAY("new game enter a move to play against the computer with white");
\r
5734 case IDM_NewGameFRC:
\r
5735 if( NewGameFRC() == 0 ) {
\r
5737 AnalysisPopDown();
\r
5741 case IDM_NewVariant:
\r
5742 NewVariantPopup(hwnd);
\r
5745 case IDM_LoadGame:
\r
5746 LoadGameDialog(hwnd, "Load Game from File");
\r
5749 case IDM_LoadNextGame:
\r
5753 case IDM_LoadPrevGame:
\r
5757 case IDM_ReloadGame:
\r
5761 case IDM_LoadPosition:
\r
5762 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5763 Reset(FALSE, TRUE);
\r
5766 f = OpenFileDialog(hwnd, "rb", "",
\r
5767 appData.oldSaveStyle ? "pos" : "fen",
\r
5769 "Load Position from File", &number, fileTitle, NULL);
\r
5771 LoadPosition(f, number, fileTitle);
\r
5775 case IDM_LoadNextPosition:
\r
5776 ReloadPosition(1);
\r
5779 case IDM_LoadPrevPosition:
\r
5780 ReloadPosition(-1);
\r
5783 case IDM_ReloadPosition:
\r
5784 ReloadPosition(0);
\r
5787 case IDM_SaveGame:
\r
5788 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5789 f = OpenFileDialog(hwnd, "a", defName,
\r
5790 appData.oldSaveStyle ? "gam" : "pgn",
\r
5792 "Save Game to File", NULL, fileTitle, NULL);
\r
5794 SaveGame(f, 0, "");
\r
5798 case IDM_SavePosition:
\r
5799 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5800 f = OpenFileDialog(hwnd, "a", defName,
\r
5801 appData.oldSaveStyle ? "pos" : "fen",
\r
5803 "Save Position to File", NULL, fileTitle, NULL);
\r
5805 SavePosition(f, 0, "");
\r
5809 case IDM_SaveDiagram:
\r
5810 defName = "diagram";
\r
5811 f = OpenFileDialog(hwnd, "wb", defName,
\r
5814 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5820 case IDM_CopyGame:
\r
5821 CopyGameToClipboard();
\r
5824 case IDM_PasteGame:
\r
5825 PasteGameFromClipboard();
\r
5828 case IDM_CopyGameListToClipboard:
\r
5829 CopyGameListToClipboard();
\r
5832 /* [AS] Autodetect FEN or PGN data */
\r
5833 case IDM_PasteAny:
\r
5834 PasteGameOrFENFromClipboard();
\r
5837 /* [AS] Move history */
\r
5838 case IDM_ShowMoveHistory:
\r
5839 if( MoveHistoryIsUp() ) {
\r
5840 MoveHistoryPopDown();
\r
5843 MoveHistoryPopUp();
\r
5847 /* [AS] Eval graph */
\r
5848 case IDM_ShowEvalGraph:
\r
5849 if( EvalGraphIsUp() ) {
\r
5850 EvalGraphPopDown();
\r
5854 SetFocus(hwndMain);
\r
5858 /* [AS] Engine output */
\r
5859 case IDM_ShowEngineOutput:
\r
5860 if( EngineOutputIsUp() ) {
\r
5861 EngineOutputPopDown();
\r
5864 EngineOutputPopUp();
\r
5868 /* [AS] User adjudication */
\r
5869 case IDM_UserAdjudication_White:
\r
5870 UserAdjudicationEvent( +1 );
\r
5873 case IDM_UserAdjudication_Black:
\r
5874 UserAdjudicationEvent( -1 );
\r
5877 case IDM_UserAdjudication_Draw:
\r
5878 UserAdjudicationEvent( 0 );
\r
5881 /* [AS] Game list options dialog */
\r
5882 case IDM_GameListOptions:
\r
5883 GameListOptions();
\r
5890 case IDM_CopyPosition:
\r
5891 CopyFENToClipboard();
\r
5894 case IDM_PastePosition:
\r
5895 PasteFENFromClipboard();
\r
5898 case IDM_MailMove:
\r
5902 case IDM_ReloadCMailMsg:
\r
5903 Reset(TRUE, TRUE);
\r
5904 ReloadCmailMsgEvent(FALSE);
\r
5907 case IDM_Minimize:
\r
5908 ShowWindow(hwnd, SW_MINIMIZE);
\r
5915 case IDM_MachineWhite:
\r
5916 MachineWhiteEvent();
\r
5918 * refresh the tags dialog only if it's visible
\r
5920 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5922 tags = PGNTags(&gameInfo);
\r
5923 TagsPopUp(tags, CmailMsg());
\r
5926 SAY("computer starts playing white");
\r
5929 case IDM_MachineBlack:
\r
5930 MachineBlackEvent();
\r
5932 * refresh the tags dialog only if it's visible
\r
5934 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5936 tags = PGNTags(&gameInfo);
\r
5937 TagsPopUp(tags, CmailMsg());
\r
5940 SAY("computer starts playing black");
\r
5943 case IDM_TwoMachines:
\r
5944 TwoMachinesEvent();
\r
5946 * refresh the tags dialog only if it's visible
\r
5948 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5950 tags = PGNTags(&gameInfo);
\r
5951 TagsPopUp(tags, CmailMsg());
\r
5954 SAY("programs start playing each other");
\r
5957 case IDM_AnalysisMode:
\r
5958 if (!first.analysisSupport) {
\r
5959 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5960 DisplayError(buf, 0);
\r
5962 SAY("analyzing current position");
\r
5963 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5964 if (appData.icsActive) {
\r
5965 if (gameMode != IcsObserving) {
\r
5966 sprintf(buf, "You are not observing a game");
\r
5967 DisplayError(buf, 0);
\r
5968 /* secure check */
\r
5969 if (appData.icsEngineAnalyze) {
\r
5970 if (appData.debugMode)
\r
5971 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5972 ExitAnalyzeMode();
\r
5978 /* if enable, user want disable icsEngineAnalyze */
\r
5979 if (appData.icsEngineAnalyze) {
\r
5980 ExitAnalyzeMode();
\r
5984 appData.icsEngineAnalyze = TRUE;
\r
5985 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5988 if (!appData.showThinking) ToggleShowThinking();
\r
5989 AnalyzeModeEvent();
\r
5993 case IDM_AnalyzeFile:
\r
5994 if (!first.analysisSupport) {
\r
5995 char buf[MSG_SIZ];
\r
5996 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5997 DisplayError(buf, 0);
\r
5999 if (!appData.showThinking) ToggleShowThinking();
\r
6000 AnalyzeFileEvent();
\r
6001 LoadGameDialog(hwnd, "Analyze Game from File");
\r
6002 AnalysisPeriodicEvent(1);
\r
6006 case IDM_IcsClient:
\r
6010 case IDM_EditGame:
\r
6015 case IDM_EditPosition:
\r
6016 EditPositionEvent();
\r
6017 SAY("to set up a position type a FEN");
\r
6020 case IDM_Training:
\r
6024 case IDM_ShowGameList:
\r
6025 ShowGameListProc();
\r
6028 case IDM_EditTags:
\r
6032 case IDM_EditComment:
\r
6033 if (commentDialogUp && editComment) {
\r
6036 EditCommentEvent();
\r
6056 case IDM_CallFlag:
\r
6076 case IDM_StopObserving:
\r
6077 StopObservingEvent();
\r
6080 case IDM_StopExamining:
\r
6081 StopExaminingEvent();
\r
6084 case IDM_TypeInMove:
\r
6085 PopUpMoveDialog('\000');
\r
6088 case IDM_TypeInName:
\r
6089 PopUpNameDialog('\000');
\r
6092 case IDM_Backward:
\r
6094 SetFocus(hwndMain);
\r
6101 SetFocus(hwndMain);
\r
6106 SetFocus(hwndMain);
\r
6111 SetFocus(hwndMain);
\r
6118 case IDM_TruncateGame:
\r
6119 TruncateGameEvent();
\r
6126 case IDM_RetractMove:
\r
6127 RetractMoveEvent();
\r
6130 case IDM_FlipView:
\r
6131 flipView = !flipView;
\r
6132 DrawPosition(FALSE, NULL);
\r
6135 case IDM_FlipClock:
\r
6136 flipClock = !flipClock;
\r
6137 DisplayBothClocks();
\r
6138 DrawPosition(FALSE, NULL);
\r
6141 case IDM_MuteSounds:
\r
6142 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
6143 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
6144 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
6147 case IDM_GeneralOptions:
\r
6148 GeneralOptionsPopup(hwnd);
\r
6149 DrawPosition(TRUE, NULL);
\r
6152 case IDM_BoardOptions:
\r
6153 BoardOptionsPopup(hwnd);
\r
6156 case IDM_EnginePlayOptions:
\r
6157 EnginePlayOptionsPopup(hwnd);
\r
6160 case IDM_Engine1Options:
\r
6161 EngineOptionsPopup(hwnd, &first);
\r
6164 case IDM_Engine2Options:
\r
6165 EngineOptionsPopup(hwnd, &second);
\r
6168 case IDM_OptionsUCI:
\r
6169 UciOptionsPopup(hwnd);
\r
6172 case IDM_IcsOptions:
\r
6173 IcsOptionsPopup(hwnd);
\r
6177 FontsOptionsPopup(hwnd);
\r
6181 SoundOptionsPopup(hwnd);
\r
6184 case IDM_CommPort:
\r
6185 CommPortOptionsPopup(hwnd);
\r
6188 case IDM_LoadOptions:
\r
6189 LoadOptionsPopup(hwnd);
\r
6192 case IDM_SaveOptions:
\r
6193 SaveOptionsPopup(hwnd);
\r
6196 case IDM_TimeControl:
\r
6197 TimeControlOptionsPopup(hwnd);
\r
6200 case IDM_SaveSettings:
\r
6201 SaveSettings(settingsFileName);
\r
6204 case IDM_SaveSettingsOnExit:
\r
6205 saveSettingsOnExit = !saveSettingsOnExit;
\r
6206 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6207 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6208 MF_CHECKED : MF_UNCHECKED));
\r
6219 case IDM_AboutGame:
\r
6224 appData.debugMode = !appData.debugMode;
\r
6225 if (appData.debugMode) {
\r
6226 char dir[MSG_SIZ];
\r
6227 GetCurrentDirectory(MSG_SIZ, dir);
\r
6228 SetCurrentDirectory(installDir);
\r
6229 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6230 SetCurrentDirectory(dir);
\r
6231 setbuf(debugFP, NULL);
\r
6238 case IDM_HELPCONTENTS:
\r
6239 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6240 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6241 MessageBox (GetFocus(),
\r
6242 "Unable to activate help",
\r
6243 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6247 case IDM_HELPSEARCH:
\r
6248 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6249 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6250 MessageBox (GetFocus(),
\r
6251 "Unable to activate help",
\r
6252 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6256 case IDM_HELPHELP:
\r
6257 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6258 MessageBox (GetFocus(),
\r
6259 "Unable to activate help",
\r
6260 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6265 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6267 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6268 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6269 FreeProcInstance(lpProc);
\r
6272 case IDM_DirectCommand1:
\r
6273 AskQuestionEvent("Direct Command",
\r
6274 "Send to chess program:", "", "1");
\r
6276 case IDM_DirectCommand2:
\r
6277 AskQuestionEvent("Direct Command",
\r
6278 "Send to second chess program:", "", "2");
\r
6281 case EP_WhitePawn:
\r
6282 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6283 fromX = fromY = -1;
\r
6286 case EP_WhiteKnight:
\r
6287 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6288 fromX = fromY = -1;
\r
6291 case EP_WhiteBishop:
\r
6292 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6293 fromX = fromY = -1;
\r
6296 case EP_WhiteRook:
\r
6297 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6298 fromX = fromY = -1;
\r
6301 case EP_WhiteQueen:
\r
6302 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6303 fromX = fromY = -1;
\r
6306 case EP_WhiteFerz:
\r
6307 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6308 fromX = fromY = -1;
\r
6311 case EP_WhiteWazir:
\r
6312 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6313 fromX = fromY = -1;
\r
6316 case EP_WhiteAlfil:
\r
6317 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6318 fromX = fromY = -1;
\r
6321 case EP_WhiteCannon:
\r
6322 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6323 fromX = fromY = -1;
\r
6326 case EP_WhiteCardinal:
\r
6327 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6328 fromX = fromY = -1;
\r
6331 case EP_WhiteMarshall:
\r
6332 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6333 fromX = fromY = -1;
\r
6336 case EP_WhiteKing:
\r
6337 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6338 fromX = fromY = -1;
\r
6341 case EP_BlackPawn:
\r
6342 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6343 fromX = fromY = -1;
\r
6346 case EP_BlackKnight:
\r
6347 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6348 fromX = fromY = -1;
\r
6351 case EP_BlackBishop:
\r
6352 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6353 fromX = fromY = -1;
\r
6356 case EP_BlackRook:
\r
6357 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6358 fromX = fromY = -1;
\r
6361 case EP_BlackQueen:
\r
6362 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6363 fromX = fromY = -1;
\r
6366 case EP_BlackFerz:
\r
6367 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6368 fromX = fromY = -1;
\r
6371 case EP_BlackWazir:
\r
6372 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6373 fromX = fromY = -1;
\r
6376 case EP_BlackAlfil:
\r
6377 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6378 fromX = fromY = -1;
\r
6381 case EP_BlackCannon:
\r
6382 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6383 fromX = fromY = -1;
\r
6386 case EP_BlackCardinal:
\r
6387 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6388 fromX = fromY = -1;
\r
6391 case EP_BlackMarshall:
\r
6392 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6393 fromX = fromY = -1;
\r
6396 case EP_BlackKing:
\r
6397 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6398 fromX = fromY = -1;
\r
6401 case EP_EmptySquare:
\r
6402 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6403 fromX = fromY = -1;
\r
6406 case EP_ClearBoard:
\r
6407 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6408 fromX = fromY = -1;
\r
6412 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6413 fromX = fromY = -1;
\r
6417 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6418 fromX = fromY = -1;
\r
6422 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6423 fromX = fromY = -1;
\r
6427 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6428 fromX = fromY = -1;
\r
6432 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6433 fromX = fromY = -1;
\r
6437 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6438 fromX = fromY = -1;
\r
6442 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6443 fromX = fromY = -1;
\r
6447 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6448 fromX = fromY = -1;
\r
6452 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6453 fromX = fromY = -1;
\r
6457 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6463 case CLOCK_TIMER_ID:
\r
6464 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6465 clockTimerEvent = 0;
\r
6466 DecrementClocks(); /* call into back end */
\r
6468 case LOAD_GAME_TIMER_ID:
\r
6469 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6470 loadGameTimerEvent = 0;
\r
6471 AutoPlayGameLoop(); /* call into back end */
\r
6473 case ANALYSIS_TIMER_ID:
\r
6474 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6475 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6476 AnalysisPeriodicEvent(0);
\r
6478 KillTimer(hwnd, analysisTimerEvent);
\r
6479 analysisTimerEvent = 0;
\r
6482 case DELAYED_TIMER_ID:
\r
6483 KillTimer(hwnd, delayedTimerEvent);
\r
6484 delayedTimerEvent = 0;
\r
6485 delayedTimerCallback();
\r
6490 case WM_USER_Input:
\r
6491 InputEvent(hwnd, message, wParam, lParam);
\r
6494 /* [AS] Also move "attached" child windows */
\r
6495 case WM_WINDOWPOSCHANGING:
\r
6497 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6498 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6500 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6501 /* Window is moving */
\r
6504 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6505 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6506 rcMain.right = boardX + winWidth;
\r
6507 rcMain.top = boardY;
\r
6508 rcMain.bottom = boardY + winHeight;
\r
6510 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6511 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6512 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6513 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6514 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6521 /* [AS] Snapping */
\r
6522 case WM_ENTERSIZEMOVE:
\r
6523 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6524 if (hwnd == hwndMain) {
\r
6525 doingSizing = TRUE;
\r
6528 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6532 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6533 if (hwnd == hwndMain) {
\r
6534 lastSizing = wParam;
\r
6539 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6540 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6542 case WM_EXITSIZEMOVE:
\r
6543 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6544 if (hwnd == hwndMain) {
\r
6546 doingSizing = FALSE;
\r
6547 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6548 GetClientRect(hwnd, &client);
\r
6549 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6551 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6553 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6556 case WM_DESTROY: /* message: window being destroyed */
\r
6557 PostQuitMessage(0);
\r
6561 if (hwnd == hwndMain) {
\r
6566 default: /* Passes it on if unprocessed */
\r
6567 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6572 /*---------------------------------------------------------------------------*\
\r
6574 * Misc utility routines
\r
6576 \*---------------------------------------------------------------------------*/
\r
6579 * Decent random number generator, at least not as bad as Windows
\r
6580 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6582 unsigned int randstate;
\r
6587 randstate = randstate * 1664525 + 1013904223;
\r
6588 return (int) randstate & 0x7fffffff;
\r
6592 mysrandom(unsigned int seed)
\r
6599 * returns TRUE if user selects a different color, FALSE otherwise
\r
6603 ChangeColor(HWND hwnd, COLORREF *which)
\r
6605 static BOOL firstTime = TRUE;
\r
6606 static DWORD customColors[16];
\r
6608 COLORREF newcolor;
\r
6613 /* Make initial colors in use available as custom colors */
\r
6614 /* Should we put the compiled-in defaults here instead? */
\r
6616 customColors[i++] = lightSquareColor & 0xffffff;
\r
6617 customColors[i++] = darkSquareColor & 0xffffff;
\r
6618 customColors[i++] = whitePieceColor & 0xffffff;
\r
6619 customColors[i++] = blackPieceColor & 0xffffff;
\r
6620 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6621 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6623 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6624 customColors[i++] = textAttribs[ccl].color;
\r
6626 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6627 firstTime = FALSE;
\r
6630 cc.lStructSize = sizeof(cc);
\r
6631 cc.hwndOwner = hwnd;
\r
6632 cc.hInstance = NULL;
\r
6633 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6634 cc.lpCustColors = (LPDWORD) customColors;
\r
6635 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6637 if (!ChooseColor(&cc)) return FALSE;
\r
6639 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6640 if (newcolor == *which) return FALSE;
\r
6641 *which = newcolor;
\r
6645 InitDrawingColors();
\r
6646 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6651 MyLoadSound(MySound *ms)
\r
6657 if (ms->data) free(ms->data);
\r
6660 switch (ms->name[0]) {
\r
6666 /* System sound from Control Panel. Don't preload here. */
\r
6670 if (ms->name[1] == NULLCHAR) {
\r
6671 /* "!" alone = silence */
\r
6674 /* Builtin wave resource. Error if not found. */
\r
6675 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6676 if (h == NULL) break;
\r
6677 ms->data = (void *)LoadResource(hInst, h);
\r
6678 if (h == NULL) break;
\r
6683 /* .wav file. Error if not found. */
\r
6684 f = fopen(ms->name, "rb");
\r
6685 if (f == NULL) break;
\r
6686 if (fstat(fileno(f), &st) < 0) break;
\r
6687 ms->data = malloc(st.st_size);
\r
6688 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6694 char buf[MSG_SIZ];
\r
6695 sprintf(buf, "Error loading sound %s", ms->name);
\r
6696 DisplayError(buf, GetLastError());
\r
6702 MyPlaySound(MySound *ms)
\r
6704 BOOLEAN ok = FALSE;
\r
6706 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6707 switch (ms->name[0]) {
\r
6709 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6714 /* System sound from Control Panel (deprecated feature).
\r
6715 "$" alone or an unset sound name gets default beep (still in use). */
\r
6716 if (ms->name[1]) {
\r
6717 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6719 if (!ok) ok = MessageBeep(MB_OK);
\r
6722 /* Builtin wave resource, or "!" alone for silence */
\r
6723 if (ms->name[1]) {
\r
6724 if (ms->data == NULL) return FALSE;
\r
6725 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6731 /* .wav file. Error if not found. */
\r
6732 if (ms->data == NULL) return FALSE;
\r
6733 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6736 /* Don't print an error: this can happen innocently if the sound driver
\r
6737 is busy; for instance, if another instance of WinBoard is playing
\r
6738 a sound at about the same time. */
\r
6741 char buf[MSG_SIZ];
\r
6742 sprintf(buf, "Error playing sound %s", ms->name);
\r
6743 DisplayError(buf, GetLastError());
\r
6751 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6754 OPENFILENAME *ofn;
\r
6755 static UINT *number; /* gross that this is static */
\r
6757 switch (message) {
\r
6758 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6759 /* Center the dialog over the application window */
\r
6760 ofn = (OPENFILENAME *) lParam;
\r
6761 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6762 number = (UINT *) ofn->lCustData;
\r
6763 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6767 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6768 return FALSE; /* Allow for further processing */
\r
6771 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6772 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6774 return FALSE; /* Allow for further processing */
\r
6780 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6782 static UINT *number;
\r
6783 OPENFILENAME *ofname;
\r
6786 case WM_INITDIALOG:
\r
6787 ofname = (OPENFILENAME *)lParam;
\r
6788 number = (UINT *)(ofname->lCustData);
\r
6791 ofnot = (OFNOTIFY *)lParam;
\r
6792 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6793 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6802 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6803 char *nameFilt, char *dlgTitle, UINT *number,
\r
6804 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6806 OPENFILENAME openFileName;
\r
6807 char buf1[MSG_SIZ];
\r
6810 if (fileName == NULL) fileName = buf1;
\r
6811 if (defName == NULL) {
\r
6812 strcpy(fileName, "*.");
\r
6813 strcat(fileName, defExt);
\r
6815 strcpy(fileName, defName);
\r
6817 if (fileTitle) strcpy(fileTitle, "");
\r
6818 if (number) *number = 0;
\r
6820 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6821 openFileName.hwndOwner = hwnd;
\r
6822 openFileName.hInstance = (HANDLE) hInst;
\r
6823 openFileName.lpstrFilter = nameFilt;
\r
6824 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6825 openFileName.nMaxCustFilter = 0L;
\r
6826 openFileName.nFilterIndex = 1L;
\r
6827 openFileName.lpstrFile = fileName;
\r
6828 openFileName.nMaxFile = MSG_SIZ;
\r
6829 openFileName.lpstrFileTitle = fileTitle;
\r
6830 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6831 openFileName.lpstrInitialDir = NULL;
\r
6832 openFileName.lpstrTitle = dlgTitle;
\r
6833 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6834 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6835 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6836 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6837 openFileName.nFileOffset = 0;
\r
6838 openFileName.nFileExtension = 0;
\r
6839 openFileName.lpstrDefExt = defExt;
\r
6840 openFileName.lCustData = (LONG) number;
\r
6841 openFileName.lpfnHook = oldDialog ?
\r
6842 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6843 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6845 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6846 GetOpenFileName(&openFileName)) {
\r
6847 /* open the file */
\r
6848 f = fopen(openFileName.lpstrFile, write);
\r
6850 MessageBox(hwnd, "File open failed", NULL,
\r
6851 MB_OK|MB_ICONEXCLAMATION);
\r
6855 int err = CommDlgExtendedError();
\r
6856 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6865 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6867 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6870 * Get the first pop-up menu in the menu template. This is the
\r
6871 * menu that TrackPopupMenu displays.
\r
6873 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6875 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6878 * TrackPopup uses screen coordinates, so convert the
\r
6879 * coordinates of the mouse click to screen coordinates.
\r
6881 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6883 /* Draw and track the floating pop-up menu. */
\r
6884 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6885 pt.x, pt.y, 0, hwnd, NULL);
\r
6887 /* Destroy the menu.*/
\r
6888 DestroyMenu(hmenu);
\r
6893 int sizeX, sizeY, newSizeX, newSizeY;
\r
6895 } ResizeEditPlusButtonsClosure;
\r
6898 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6900 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6904 if (hChild == cl->hText) return TRUE;
\r
6905 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6906 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6907 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6908 ScreenToClient(cl->hDlg, &pt);
\r
6909 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6910 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6914 /* Resize a dialog that has a (rich) edit field filling most of
\r
6915 the top, with a row of buttons below */
\r
6917 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6920 int newTextHeight, newTextWidth;
\r
6921 ResizeEditPlusButtonsClosure cl;
\r
6923 /*if (IsIconic(hDlg)) return;*/
\r
6924 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6926 cl.hdwp = BeginDeferWindowPos(8);
\r
6928 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6929 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6930 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6931 if (newTextHeight < 0) {
\r
6932 newSizeY += -newTextHeight;
\r
6933 newTextHeight = 0;
\r
6935 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6936 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6942 cl.newSizeX = newSizeX;
\r
6943 cl.newSizeY = newSizeY;
\r
6944 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6946 EndDeferWindowPos(cl.hdwp);
\r
6949 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6951 RECT rChild, rParent;
\r
6952 int wChild, hChild, wParent, hParent;
\r
6953 int wScreen, hScreen, xNew, yNew;
\r
6956 /* Get the Height and Width of the child window */
\r
6957 GetWindowRect (hwndChild, &rChild);
\r
6958 wChild = rChild.right - rChild.left;
\r
6959 hChild = rChild.bottom - rChild.top;
\r
6961 /* Get the Height and Width of the parent window */
\r
6962 GetWindowRect (hwndParent, &rParent);
\r
6963 wParent = rParent.right - rParent.left;
\r
6964 hParent = rParent.bottom - rParent.top;
\r
6966 /* Get the display limits */
\r
6967 hdc = GetDC (hwndChild);
\r
6968 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6969 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6970 ReleaseDC(hwndChild, hdc);
\r
6972 /* Calculate new X position, then adjust for screen */
\r
6973 xNew = rParent.left + ((wParent - wChild) /2);
\r
6976 } else if ((xNew+wChild) > wScreen) {
\r
6977 xNew = wScreen - wChild;
\r
6980 /* Calculate new Y position, then adjust for screen */
\r
6982 yNew = rParent.top + ((hParent - hChild) /2);
\r
6985 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6990 } else if ((yNew+hChild) > hScreen) {
\r
6991 yNew = hScreen - hChild;
\r
6994 /* Set it, and return */
\r
6995 return SetWindowPos (hwndChild, NULL,
\r
6996 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6999 /* Center one window over another */
\r
7000 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
7002 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
7005 /*---------------------------------------------------------------------------*\
\r
7007 * Startup Dialog functions
\r
7009 \*---------------------------------------------------------------------------*/
\r
7011 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
7013 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7015 while (*cd != NULL) {
\r
7016 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
7022 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
7024 char buf1[ARG_MAX];
\r
7027 if (str[0] == '@') {
\r
7028 FILE* f = fopen(str + 1, "r");
\r
7030 DisplayFatalError(str + 1, errno, 2);
\r
7033 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
7035 buf1[len] = NULLCHAR;
\r
7039 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7042 char buf[MSG_SIZ];
\r
7043 char *end = strchr(str, '\n');
\r
7044 if (end == NULL) return;
\r
7045 memcpy(buf, str, end - str);
\r
7046 buf[end - str] = NULLCHAR;
\r
7047 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7053 SetStartupDialogEnables(HWND hDlg)
\r
7055 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7056 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7057 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7058 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7059 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7060 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7061 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7062 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7063 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7064 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7065 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7066 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7067 IsDlgButtonChecked(hDlg, OPT_View));
\r
7071 QuoteForFilename(char *filename)
\r
7073 int dquote, space;
\r
7074 dquote = strchr(filename, '"') != NULL;
\r
7075 space = strchr(filename, ' ') != NULL;
\r
7076 if (dquote || space) {
\r
7088 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7090 char buf[MSG_SIZ];
\r
7093 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7094 q = QuoteForFilename(nthcp);
\r
7095 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7096 if (*nthdir != NULLCHAR) {
\r
7097 q = QuoteForFilename(nthdir);
\r
7098 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7100 if (*nthcp == NULLCHAR) {
\r
7101 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7102 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7103 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7104 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7109 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7111 char buf[MSG_SIZ];
\r
7115 switch (message) {
\r
7116 case WM_INITDIALOG:
\r
7117 /* Center the dialog */
\r
7118 CenterWindow (hDlg, GetDesktopWindow());
\r
7119 /* Initialize the dialog items */
\r
7120 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7121 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7122 firstChessProgramNames);
\r
7123 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7124 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7125 secondChessProgramNames);
\r
7126 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7127 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7128 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7129 if (*appData.icsHelper != NULLCHAR) {
\r
7130 char *q = QuoteForFilename(appData.icsHelper);
\r
7131 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7133 if (*appData.icsHost == NULLCHAR) {
\r
7134 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7135 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7136 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7137 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7138 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7141 if (appData.icsActive) {
\r
7142 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7144 else if (appData.noChessProgram) {
\r
7145 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7148 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7151 SetStartupDialogEnables(hDlg);
\r
7155 switch (LOWORD(wParam)) {
\r
7157 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7158 strcpy(buf, "/fcp=");
\r
7159 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7161 ParseArgs(StringGet, &p);
\r
7162 strcpy(buf, "/scp=");
\r
7163 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7165 ParseArgs(StringGet, &p);
\r
7166 appData.noChessProgram = FALSE;
\r
7167 appData.icsActive = FALSE;
\r
7168 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7169 strcpy(buf, "/ics /icshost=");
\r
7170 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7172 ParseArgs(StringGet, &p);
\r
7173 if (appData.zippyPlay) {
\r
7174 strcpy(buf, "/fcp=");
\r
7175 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7177 ParseArgs(StringGet, &p);
\r
7179 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7180 appData.noChessProgram = TRUE;
\r
7181 appData.icsActive = FALSE;
\r
7183 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7184 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7187 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7188 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7190 ParseArgs(StringGet, &p);
\r
7192 EndDialog(hDlg, TRUE);
\r
7199 case IDM_HELPCONTENTS:
\r
7200 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7201 MessageBox (GetFocus(),
\r
7202 "Unable to activate help",
\r
7203 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7208 SetStartupDialogEnables(hDlg);
\r
7216 /*---------------------------------------------------------------------------*\
\r
7218 * About box dialog functions
\r
7220 \*---------------------------------------------------------------------------*/
\r
7222 /* Process messages for "About" dialog box */
\r
7224 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7226 switch (message) {
\r
7227 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7228 /* Center the dialog over the application window */
\r
7229 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7230 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7234 case WM_COMMAND: /* message: received a command */
\r
7235 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7236 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7237 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7245 /*---------------------------------------------------------------------------*\
\r
7247 * Comment Dialog functions
\r
7249 \*---------------------------------------------------------------------------*/
\r
7252 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7254 static HANDLE hwndText = NULL;
\r
7255 int len, newSizeX, newSizeY, flags;
\r
7256 static int sizeX, sizeY;
\r
7261 switch (message) {
\r
7262 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7263 /* Initialize the dialog items */
\r
7264 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7265 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7266 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7267 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7268 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7269 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7270 SetWindowText(hDlg, commentTitle);
\r
7271 if (editComment) {
\r
7272 SetFocus(hwndText);
\r
7274 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7276 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7277 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7278 MAKELPARAM(FALSE, 0));
\r
7279 /* Size and position the dialog */
\r
7280 if (!commentDialog) {
\r
7281 commentDialog = hDlg;
\r
7282 flags = SWP_NOZORDER;
\r
7283 GetClientRect(hDlg, &rect);
\r
7284 sizeX = rect.right;
\r
7285 sizeY = rect.bottom;
\r
7286 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7287 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7288 WINDOWPLACEMENT wp;
\r
7289 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7290 wp.length = sizeof(WINDOWPLACEMENT);
\r
7292 wp.showCmd = SW_SHOW;
\r
7293 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7294 wp.rcNormalPosition.left = commentX;
\r
7295 wp.rcNormalPosition.right = commentX + commentW;
\r
7296 wp.rcNormalPosition.top = commentY;
\r
7297 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7298 SetWindowPlacement(hDlg, &wp);
\r
7300 GetClientRect(hDlg, &rect);
\r
7301 newSizeX = rect.right;
\r
7302 newSizeY = rect.bottom;
\r
7303 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7304 newSizeX, newSizeY);
\r
7311 case WM_COMMAND: /* message: received a command */
\r
7312 switch (LOWORD(wParam)) {
\r
7314 if (editComment) {
\r
7316 /* Read changed options from the dialog box */
\r
7317 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7318 len = GetWindowTextLength(hwndText);
\r
7319 str = (char *) malloc(len + 1);
\r
7320 GetWindowText(hwndText, str, len + 1);
\r
7329 ReplaceComment(commentIndex, str);
\r
7336 case OPT_CancelComment:
\r
7340 case OPT_ClearComment:
\r
7341 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7344 case OPT_EditComment:
\r
7345 EditCommentEvent();
\r
7354 newSizeX = LOWORD(lParam);
\r
7355 newSizeY = HIWORD(lParam);
\r
7356 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7361 case WM_GETMINMAXINFO:
\r
7362 /* Prevent resizing window too small */
\r
7363 mmi = (MINMAXINFO *) lParam;
\r
7364 mmi->ptMinTrackSize.x = 100;
\r
7365 mmi->ptMinTrackSize.y = 100;
\r
7372 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7377 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7379 if (str == NULL) str = "";
\r
7380 p = (char *) malloc(2 * strlen(str) + 2);
\r
7383 if (*str == '\n') *q++ = '\r';
\r
7387 if (commentText != NULL) free(commentText);
\r
7389 commentIndex = index;
\r
7390 commentTitle = title;
\r
7392 editComment = edit;
\r
7394 if (commentDialog) {
\r
7395 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7396 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7398 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7399 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7400 hwndMain, (DLGPROC)lpProc);
\r
7401 FreeProcInstance(lpProc);
\r
7403 commentDialogUp = TRUE;
\r
7407 /*---------------------------------------------------------------------------*\
\r
7409 * Type-in move dialog functions
\r
7411 \*---------------------------------------------------------------------------*/
\r
7414 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7416 char move[MSG_SIZ];
\r
7418 ChessMove moveType;
\r
7419 int fromX, fromY, toX, toY;
\r
7422 switch (message) {
\r
7423 case WM_INITDIALOG:
\r
7424 move[0] = (char) lParam;
\r
7425 move[1] = NULLCHAR;
\r
7426 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7427 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7428 SetWindowText(hInput, move);
\r
7430 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7434 switch (LOWORD(wParam)) {
\r
7436 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7437 { int n; Board board;
\r
7439 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7440 EditPositionPasteFEN(move);
\r
7441 EndDialog(hDlg, TRUE);
\r
7444 // [HGM] movenum: allow move number to be typed in any mode
\r
7445 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7446 currentMove = 2*n-1;
\r
7447 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7448 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7449 EndDialog(hDlg, TRUE);
\r
7450 DrawPosition(TRUE, boards[currentMove]);
\r
7451 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7452 else DisplayMessage("", "");
\r
7456 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7457 gameMode != Training) {
\r
7458 DisplayMoveError("Displayed move is not current");
\r
7460 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7461 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7462 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7463 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7464 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7465 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7466 if (gameMode != Training)
\r
7467 forwardMostMove = currentMove;
\r
7468 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7470 DisplayMoveError("Could not parse move");
\r
7473 EndDialog(hDlg, TRUE);
\r
7476 EndDialog(hDlg, FALSE);
\r
7487 PopUpMoveDialog(char firstchar)
\r
7491 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7492 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7493 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7494 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7495 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7496 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7497 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7498 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7499 gameMode == Training) {
\r
7500 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7501 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7502 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7503 FreeProcInstance(lpProc);
\r
7507 /*---------------------------------------------------------------------------*\
\r
7509 * Type-in name dialog functions
\r
7511 \*---------------------------------------------------------------------------*/
\r
7514 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7516 char move[MSG_SIZ];
\r
7519 switch (message) {
\r
7520 case WM_INITDIALOG:
\r
7521 move[0] = (char) lParam;
\r
7522 move[1] = NULLCHAR;
\r
7523 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7524 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7525 SetWindowText(hInput, move);
\r
7527 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7531 switch (LOWORD(wParam)) {
\r
7533 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7534 appData.userName = strdup(move);
\r
7537 EndDialog(hDlg, TRUE);
\r
7540 EndDialog(hDlg, FALSE);
\r
7551 PopUpNameDialog(char firstchar)
\r
7555 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7556 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7557 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7558 FreeProcInstance(lpProc);
\r
7561 /*---------------------------------------------------------------------------*\
\r
7565 \*---------------------------------------------------------------------------*/
\r
7567 /* Nonmodal error box */
\r
7568 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7569 WPARAM wParam, LPARAM lParam);
\r
7572 ErrorPopUp(char *title, char *content)
\r
7576 BOOLEAN modal = hwndMain == NULL;
\r
7594 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7595 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7598 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7600 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7601 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7602 hwndMain, (DLGPROC)lpProc);
\r
7603 FreeProcInstance(lpProc);
\r
7610 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7611 if (errorDialog == NULL) return;
\r
7612 DestroyWindow(errorDialog);
\r
7613 errorDialog = NULL;
\r
7617 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7622 switch (message) {
\r
7623 case WM_INITDIALOG:
\r
7624 GetWindowRect(hDlg, &rChild);
\r
7627 SetWindowPos(hDlg, NULL, rChild.left,
\r
7628 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7629 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7633 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7634 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7635 and it doesn't work when you resize the dialog.
\r
7636 For now, just give it a default position.
\r
7638 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7640 errorDialog = hDlg;
\r
7641 SetWindowText(hDlg, errorTitle);
\r
7642 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7643 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7647 switch (LOWORD(wParam)) {
\r
7650 if (errorDialog == hDlg) errorDialog = NULL;
\r
7651 DestroyWindow(hDlg);
\r
7663 HWND gothicDialog = NULL;
\r
7666 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7670 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7672 switch (message) {
\r
7673 case WM_INITDIALOG:
\r
7674 GetWindowRect(hDlg, &rChild);
\r
7676 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7680 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7681 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7682 and it doesn't work when you resize the dialog.
\r
7683 For now, just give it a default position.
\r
7685 gothicDialog = hDlg;
\r
7686 SetWindowText(hDlg, errorTitle);
\r
7687 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7688 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7692 switch (LOWORD(wParam)) {
\r
7695 if (errorDialog == hDlg) errorDialog = NULL;
\r
7696 DestroyWindow(hDlg);
\r
7708 GothicPopUp(char *title, VariantClass variant)
\r
7711 static char *lastTitle;
\r
7713 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7714 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7716 if(lastTitle != title && gothicDialog != NULL) {
\r
7717 DestroyWindow(gothicDialog);
\r
7718 gothicDialog = NULL;
\r
7720 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7721 title = lastTitle;
\r
7722 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7723 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7724 hwndMain, (DLGPROC)lpProc);
\r
7725 FreeProcInstance(lpProc);
\r
7730 /*---------------------------------------------------------------------------*\
\r
7732 * Ics Interaction console functions
\r
7734 \*---------------------------------------------------------------------------*/
\r
7736 #define HISTORY_SIZE 64
\r
7737 static char *history[HISTORY_SIZE];
\r
7738 int histIn = 0, histP = 0;
\r
7741 SaveInHistory(char *cmd)
\r
7743 if (history[histIn] != NULL) {
\r
7744 free(history[histIn]);
\r
7745 history[histIn] = NULL;
\r
7747 if (*cmd == NULLCHAR) return;
\r
7748 history[histIn] = StrSave(cmd);
\r
7749 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7750 if (history[histIn] != NULL) {
\r
7751 free(history[histIn]);
\r
7752 history[histIn] = NULL;
\r
7758 PrevInHistory(char *cmd)
\r
7761 if (histP == histIn) {
\r
7762 if (history[histIn] != NULL) free(history[histIn]);
\r
7763 history[histIn] = StrSave(cmd);
\r
7765 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7766 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7768 return history[histP];
\r
7774 if (histP == histIn) return NULL;
\r
7775 histP = (histP + 1) % HISTORY_SIZE;
\r
7776 return history[histP];
\r
7783 BOOLEAN immediate;
\r
7784 } IcsTextMenuEntry;
\r
7785 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7786 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7789 ParseIcsTextMenu(char *icsTextMenuString)
\r
7792 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7793 char *p = icsTextMenuString;
\r
7794 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7797 if (e->command != NULL) {
\r
7799 e->command = NULL;
\r
7803 e = icsTextMenuEntry;
\r
7804 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7805 if (*p == ';' || *p == '\n') {
\r
7806 e->item = strdup("-");
\r
7807 e->command = NULL;
\r
7809 } else if (*p == '-') {
\r
7810 e->item = strdup("-");
\r
7811 e->command = NULL;
\r
7815 char *q, *r, *s, *t;
\r
7817 q = strchr(p, ',');
\r
7818 if (q == NULL) break;
\r
7820 r = strchr(q + 1, ',');
\r
7821 if (r == NULL) break;
\r
7823 s = strchr(r + 1, ',');
\r
7824 if (s == NULL) break;
\r
7827 t = strchr(s + 1, c);
\r
7830 t = strchr(s + 1, c);
\r
7832 if (t != NULL) *t = NULLCHAR;
\r
7833 e->item = strdup(p);
\r
7834 e->command = strdup(q + 1);
\r
7835 e->getname = *(r + 1) != '0';
\r
7836 e->immediate = *(s + 1) != '0';
\r
7840 if (t == NULL) break;
\r
7849 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7853 hmenu = LoadMenu(hInst, "TextMenu");
\r
7854 h = GetSubMenu(hmenu, 0);
\r
7856 if (strcmp(e->item, "-") == 0) {
\r
7857 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7859 if (e->item[0] == '|') {
\r
7860 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7861 IDM_CommandX + i, &e->item[1]);
\r
7863 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7872 WNDPROC consoleTextWindowProc;
\r
7875 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7877 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7878 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7882 SetWindowText(hInput, command);
\r
7884 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7886 sel.cpMin = 999999;
\r
7887 sel.cpMax = 999999;
\r
7888 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7893 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7894 if (sel.cpMin == sel.cpMax) {
\r
7895 /* Expand to surrounding word */
\r
7898 tr.chrg.cpMax = sel.cpMin;
\r
7899 tr.chrg.cpMin = --sel.cpMin;
\r
7900 if (sel.cpMin < 0) break;
\r
7901 tr.lpstrText = name;
\r
7902 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7903 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7907 tr.chrg.cpMin = sel.cpMax;
\r
7908 tr.chrg.cpMax = ++sel.cpMax;
\r
7909 tr.lpstrText = name;
\r
7910 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7911 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7914 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7915 MessageBeep(MB_ICONEXCLAMATION);
\r
7919 tr.lpstrText = name;
\r
7920 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7922 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7923 MessageBeep(MB_ICONEXCLAMATION);
\r
7926 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7929 sprintf(buf, "%s %s", command, name);
\r
7930 SetWindowText(hInput, buf);
\r
7931 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7933 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7934 SetWindowText(hInput, buf);
\r
7935 sel.cpMin = 999999;
\r
7936 sel.cpMax = 999999;
\r
7937 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7943 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7948 switch (message) {
\r
7950 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7953 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7956 sel.cpMin = 999999;
\r
7957 sel.cpMax = 999999;
\r
7958 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7959 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7964 if(wParam != '\022') {
\r
7965 if (wParam == '\t') {
\r
7966 if (GetKeyState(VK_SHIFT) < 0) {
\r
7968 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7969 if (buttonDesc[0].hwnd) {
\r
7970 SetFocus(buttonDesc[0].hwnd);
\r
7972 SetFocus(hwndMain);
\r
7976 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7979 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7980 JAWS_DELETE( SetFocus(hInput); )
\r
7981 SendMessage(hInput, message, wParam, lParam);
\r
7984 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7985 case WM_RBUTTONUP:
\r
7986 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7987 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7988 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7991 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7992 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7993 if (sel.cpMin == sel.cpMax) {
\r
7994 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7995 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7997 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7998 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8000 pt.x = LOWORD(lParam);
\r
8001 pt.y = HIWORD(lParam);
\r
8002 MenuPopup(hwnd, pt, hmenu, -1);
\r
8006 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8008 return SendMessage(hInput, message, wParam, lParam);
\r
8009 case WM_MBUTTONDOWN:
\r
8010 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8011 case WM_RBUTTONDOWN:
\r
8012 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
8013 /* Move selection here if it was empty */
\r
8015 pt.x = LOWORD(lParam);
\r
8016 pt.y = HIWORD(lParam);
\r
8017 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8018 if (sel.cpMin == sel.cpMax) {
\r
8019 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
8020 sel.cpMax = sel.cpMin;
\r
8021 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8023 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
8027 switch (LOWORD(wParam)) {
\r
8028 case IDM_QuickPaste:
\r
8030 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8031 if (sel.cpMin == sel.cpMax) {
\r
8032 MessageBeep(MB_ICONEXCLAMATION);
\r
8035 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8036 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8037 SendMessage(hInput, WM_PASTE, 0, 0);
\r
8042 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8045 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8048 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8052 int i = LOWORD(wParam) - IDM_CommandX;
\r
8053 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8054 icsTextMenuEntry[i].command != NULL) {
\r
8055 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8056 icsTextMenuEntry[i].getname,
\r
8057 icsTextMenuEntry[i].immediate);
\r
8065 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8068 WNDPROC consoleInputWindowProc;
\r
8071 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8073 char buf[MSG_SIZ];
\r
8075 static BOOL sendNextChar = FALSE;
\r
8076 static BOOL quoteNextChar = FALSE;
\r
8077 InputSource *is = consoleInputSource;
\r
8081 switch (message) {
\r
8083 if (!appData.localLineEditing || sendNextChar) {
\r
8084 is->buf[0] = (CHAR) wParam;
\r
8086 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8087 sendNextChar = FALSE;
\r
8090 if (quoteNextChar) {
\r
8091 buf[0] = (char) wParam;
\r
8092 buf[1] = NULLCHAR;
\r
8093 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8094 quoteNextChar = FALSE;
\r
8098 case '\r': /* Enter key */
\r
8099 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8100 if (consoleEcho) SaveInHistory(is->buf);
\r
8101 is->buf[is->count++] = '\n';
\r
8102 is->buf[is->count] = NULLCHAR;
\r
8103 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8104 if (consoleEcho) {
\r
8105 ConsoleOutput(is->buf, is->count, TRUE);
\r
8106 } else if (appData.localLineEditing) {
\r
8107 ConsoleOutput("\n", 1, TRUE);
\r
8110 case '\033': /* Escape key */
\r
8111 SetWindowText(hwnd, "");
\r
8112 cf.cbSize = sizeof(CHARFORMAT);
\r
8113 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8114 if (consoleEcho) {
\r
8115 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8117 cf.crTextColor = COLOR_ECHOOFF;
\r
8119 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8120 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8122 case '\t': /* Tab key */
\r
8123 if (GetKeyState(VK_SHIFT) < 0) {
\r
8125 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8128 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8129 if (buttonDesc[0].hwnd) {
\r
8130 SetFocus(buttonDesc[0].hwnd);
\r
8132 SetFocus(hwndMain);
\r
8136 case '\023': /* Ctrl+S */
\r
8137 sendNextChar = TRUE;
\r
8139 case '\021': /* Ctrl+Q */
\r
8140 quoteNextChar = TRUE;
\r
8150 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8151 p = PrevInHistory(buf);
\r
8153 SetWindowText(hwnd, p);
\r
8154 sel.cpMin = 999999;
\r
8155 sel.cpMax = 999999;
\r
8156 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8161 p = NextInHistory();
\r
8163 SetWindowText(hwnd, p);
\r
8164 sel.cpMin = 999999;
\r
8165 sel.cpMax = 999999;
\r
8166 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8172 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8176 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8180 case WM_MBUTTONDOWN:
\r
8181 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8182 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8184 case WM_RBUTTONUP:
\r
8185 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8186 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8187 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8191 hmenu = LoadMenu(hInst, "InputMenu");
\r
8192 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8193 if (sel.cpMin == sel.cpMax) {
\r
8194 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8195 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8197 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8198 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8200 pt.x = LOWORD(lParam);
\r
8201 pt.y = HIWORD(lParam);
\r
8202 MenuPopup(hwnd, pt, hmenu, -1);
\r
8206 switch (LOWORD(wParam)) {
\r
8208 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8210 case IDM_SelectAll:
\r
8212 sel.cpMax = -1; /*999999?*/
\r
8213 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8216 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8219 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8222 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8227 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8230 #define CO_MAX 100000
\r
8231 #define CO_TRIM 1000
\r
8234 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8236 static SnapData sd;
\r
8237 static HWND hText, hInput /*, hFocus*/;
\r
8238 // InputSource *is = consoleInputSource;
\r
8240 static int sizeX, sizeY;
\r
8241 int newSizeX, newSizeY;
\r
8244 switch (message) {
\r
8245 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8246 hwndConsole = hDlg;
\r
8247 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8248 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8250 consoleTextWindowProc = (WNDPROC)
\r
8251 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8252 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8253 consoleInputWindowProc = (WNDPROC)
\r
8254 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8255 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8256 Colorize(ColorNormal, TRUE);
\r
8257 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8258 ChangedConsoleFont();
\r
8259 GetClientRect(hDlg, &rect);
\r
8260 sizeX = rect.right;
\r
8261 sizeY = rect.bottom;
\r
8262 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8263 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8264 WINDOWPLACEMENT wp;
\r
8265 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8266 wp.length = sizeof(WINDOWPLACEMENT);
\r
8268 wp.showCmd = SW_SHOW;
\r
8269 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8270 wp.rcNormalPosition.left = wpConsole.x;
\r
8271 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8272 wp.rcNormalPosition.top = wpConsole.y;
\r
8273 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8274 SetWindowPlacement(hDlg, &wp);
\r
8277 // [HGM] Chessknight's change 2004-07-13
\r
8278 else { /* Determine Defaults */
\r
8279 WINDOWPLACEMENT wp;
\r
8280 wpConsole.x = winWidth + 1;
\r
8281 wpConsole.y = boardY;
\r
8282 wpConsole.width = screenWidth - winWidth;
\r
8283 wpConsole.height = winHeight;
\r
8284 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8285 wp.length = sizeof(WINDOWPLACEMENT);
\r
8287 wp.showCmd = SW_SHOW;
\r
8288 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8289 wp.rcNormalPosition.left = wpConsole.x;
\r
8290 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8291 wp.rcNormalPosition.top = wpConsole.y;
\r
8292 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8293 SetWindowPlacement(hDlg, &wp);
\r
8308 if (IsIconic(hDlg)) break;
\r
8309 newSizeX = LOWORD(lParam);
\r
8310 newSizeY = HIWORD(lParam);
\r
8311 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8312 RECT rectText, rectInput;
\r
8314 int newTextHeight, newTextWidth;
\r
8315 GetWindowRect(hText, &rectText);
\r
8316 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8317 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8318 if (newTextHeight < 0) {
\r
8319 newSizeY += -newTextHeight;
\r
8320 newTextHeight = 0;
\r
8322 SetWindowPos(hText, NULL, 0, 0,
\r
8323 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8324 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8325 pt.x = rectInput.left;
\r
8326 pt.y = rectInput.top + newSizeY - sizeY;
\r
8327 ScreenToClient(hDlg, &pt);
\r
8328 SetWindowPos(hInput, NULL,
\r
8329 pt.x, pt.y, /* needs client coords */
\r
8330 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8331 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8337 case WM_GETMINMAXINFO:
\r
8338 /* Prevent resizing window too small */
\r
8339 mmi = (MINMAXINFO *) lParam;
\r
8340 mmi->ptMinTrackSize.x = 100;
\r
8341 mmi->ptMinTrackSize.y = 100;
\r
8344 /* [AS] Snapping */
\r
8345 case WM_ENTERSIZEMOVE:
\r
8346 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8349 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8352 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8354 case WM_EXITSIZEMOVE:
\r
8355 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8358 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8366 if (hwndConsole) return;
\r
8367 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8368 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8373 ConsoleOutput(char* data, int length, int forceVisible)
\r
8378 char buf[CO_MAX+1];
\r
8381 static int delayLF = 0;
\r
8382 CHARRANGE savesel, sel;
\r
8384 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8392 while (length--) {
\r
8400 } else if (*p == '\007') {
\r
8401 MyPlaySound(&sounds[(int)SoundBell]);
\r
8408 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8409 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8410 /* Save current selection */
\r
8411 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8412 exlen = GetWindowTextLength(hText);
\r
8413 /* Find out whether current end of text is visible */
\r
8414 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8415 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8416 /* Trim existing text if it's too long */
\r
8417 if (exlen + (q - buf) > CO_MAX) {
\r
8418 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8421 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8422 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8424 savesel.cpMin -= trim;
\r
8425 savesel.cpMax -= trim;
\r
8426 if (exlen < 0) exlen = 0;
\r
8427 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8428 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8430 /* Append the new text */
\r
8431 sel.cpMin = exlen;
\r
8432 sel.cpMax = exlen;
\r
8433 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8434 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8435 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8436 if (forceVisible || exlen == 0 ||
\r
8437 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8438 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8439 /* Scroll to make new end of text visible if old end of text
\r
8440 was visible or new text is an echo of user typein */
\r
8441 sel.cpMin = 9999999;
\r
8442 sel.cpMax = 9999999;
\r
8443 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8444 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8445 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8446 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8448 if (savesel.cpMax == exlen || forceVisible) {
\r
8449 /* Move insert point to new end of text if it was at the old
\r
8450 end of text or if the new text is an echo of user typein */
\r
8451 sel.cpMin = 9999999;
\r
8452 sel.cpMax = 9999999;
\r
8453 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8455 /* Restore previous selection */
\r
8456 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8458 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8465 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8469 COLORREF oldFg, oldBg;
\r
8473 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8475 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8476 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8477 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8480 rect.right = x + squareSize;
\r
8482 rect.bottom = y + squareSize;
\r
8485 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8486 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8487 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8488 &rect, str, strlen(str), NULL);
\r
8490 (void) SetTextColor(hdc, oldFg);
\r
8491 (void) SetBkColor(hdc, oldBg);
\r
8492 (void) SelectObject(hdc, oldFont);
\r
8496 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8497 RECT *rect, char *color, char *flagFell)
\r
8501 COLORREF oldFg, oldBg;
\r
8504 if (appData.clockMode) {
\r
8506 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8508 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8515 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8516 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8518 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8519 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8521 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8525 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8526 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8527 rect, str, strlen(str), NULL);
\r
8528 if(logoHeight > 0 && appData.clockMode) {
\r
8530 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8531 r.top = rect->top + logoHeight/2;
\r
8532 r.left = rect->left;
\r
8533 r.right = rect->right;
\r
8534 r.bottom = rect->bottom;
\r
8535 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8536 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8537 &r, str, strlen(str), NULL);
\r
8539 (void) SetTextColor(hdc, oldFg);
\r
8540 (void) SetBkColor(hdc, oldBg);
\r
8541 (void) SelectObject(hdc, oldFont);
\r
8546 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8552 if( count <= 0 ) {
\r
8553 if (appData.debugMode) {
\r
8554 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8557 return ERROR_INVALID_USER_BUFFER;
\r
8560 ResetEvent(ovl->hEvent);
\r
8561 ovl->Offset = ovl->OffsetHigh = 0;
\r
8562 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8566 err = GetLastError();
\r
8567 if (err == ERROR_IO_PENDING) {
\r
8568 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8572 err = GetLastError();
\r
8579 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8584 ResetEvent(ovl->hEvent);
\r
8585 ovl->Offset = ovl->OffsetHigh = 0;
\r
8586 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8590 err = GetLastError();
\r
8591 if (err == ERROR_IO_PENDING) {
\r
8592 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8596 err = GetLastError();
\r
8602 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8603 void CheckForInputBufferFull( InputSource * is )
\r
8605 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8606 /* Look for end of line */
\r
8607 char * p = is->buf;
\r
8609 while( p < is->next && *p != '\n' ) {
\r
8613 if( p >= is->next ) {
\r
8614 if (appData.debugMode) {
\r
8615 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8618 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8619 is->count = (DWORD) -1;
\r
8620 is->next = is->buf;
\r
8626 InputThread(LPVOID arg)
\r
8631 is = (InputSource *) arg;
\r
8632 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8633 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8634 while (is->hThread != NULL) {
\r
8635 is->error = DoReadFile(is->hFile, is->next,
\r
8636 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8637 &is->count, &ovl);
\r
8638 if (is->error == NO_ERROR) {
\r
8639 is->next += is->count;
\r
8641 if (is->error == ERROR_BROKEN_PIPE) {
\r
8642 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8645 is->count = (DWORD) -1;
\r
8646 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8651 CheckForInputBufferFull( is );
\r
8653 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8655 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8657 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8660 CloseHandle(ovl.hEvent);
\r
8661 CloseHandle(is->hFile);
\r
8663 if (appData.debugMode) {
\r
8664 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8671 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8673 NonOvlInputThread(LPVOID arg)
\r
8680 is = (InputSource *) arg;
\r
8681 while (is->hThread != NULL) {
\r
8682 is->error = ReadFile(is->hFile, is->next,
\r
8683 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8684 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8685 if (is->error == NO_ERROR) {
\r
8686 /* Change CRLF to LF */
\r
8687 if (is->next > is->buf) {
\r
8689 i = is->count + 1;
\r
8697 if (prev == '\r' && *p == '\n') {
\r
8709 if (is->error == ERROR_BROKEN_PIPE) {
\r
8710 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8713 is->count = (DWORD) -1;
\r
8717 CheckForInputBufferFull( is );
\r
8719 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8721 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8723 if (is->count < 0) break; /* Quit on error */
\r
8725 CloseHandle(is->hFile);
\r
8730 SocketInputThread(LPVOID arg)
\r
8734 is = (InputSource *) arg;
\r
8735 while (is->hThread != NULL) {
\r
8736 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8737 if ((int)is->count == SOCKET_ERROR) {
\r
8738 is->count = (DWORD) -1;
\r
8739 is->error = WSAGetLastError();
\r
8741 is->error = NO_ERROR;
\r
8742 is->next += is->count;
\r
8743 if (is->count == 0 && is->second == is) {
\r
8744 /* End of file on stderr; quit with no message */
\r
8748 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8750 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8752 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8758 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8762 is = (InputSource *) lParam;
\r
8763 if (is->lineByLine) {
\r
8764 /* Feed in lines one by one */
\r
8765 char *p = is->buf;
\r
8767 while (q < is->next) {
\r
8768 if (*q++ == '\n') {
\r
8769 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8774 /* Move any partial line to the start of the buffer */
\r
8776 while (p < is->next) {
\r
8781 if (is->error != NO_ERROR || is->count == 0) {
\r
8782 /* Notify backend of the error. Note: If there was a partial
\r
8783 line at the end, it is not flushed through. */
\r
8784 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8787 /* Feed in the whole chunk of input at once */
\r
8788 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8789 is->next = is->buf;
\r
8793 /*---------------------------------------------------------------------------*\
\r
8795 * Menu enables. Used when setting various modes.
\r
8797 \*---------------------------------------------------------------------------*/
\r
8805 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8807 while (enab->item > 0) {
\r
8808 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8813 Enables gnuEnables[] = {
\r
8814 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8815 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8816 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8817 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8818 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8819 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8820 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8822 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8823 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8827 Enables icsEnables[] = {
\r
8828 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8829 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8830 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8831 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8832 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8833 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8834 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8835 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8836 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8837 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8838 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8839 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8844 Enables zippyEnables[] = {
\r
8845 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8846 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8847 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8852 Enables ncpEnables[] = {
\r
8853 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8854 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8855 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8856 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8857 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8858 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8859 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8860 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8861 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8862 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8863 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8864 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8865 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8866 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8867 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8871 Enables trainingOnEnables[] = {
\r
8872 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8873 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8874 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8875 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8876 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8877 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8878 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8879 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8883 Enables trainingOffEnables[] = {
\r
8884 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8885 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8886 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8887 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8888 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8889 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8890 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8891 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8895 /* These modify either ncpEnables or gnuEnables */
\r
8896 Enables cmailEnables[] = {
\r
8897 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8898 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8899 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8900 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8901 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8902 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8903 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8907 Enables machineThinkingEnables[] = {
\r
8908 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8909 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8910 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8911 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8912 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8913 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8914 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8915 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8916 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8917 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8918 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8919 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8920 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8921 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8922 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8926 Enables userThinkingEnables[] = {
\r
8927 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8928 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8929 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8930 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8931 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8932 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8933 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8934 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8935 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8936 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8937 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8938 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8939 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8940 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8941 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8945 /*---------------------------------------------------------------------------*\
\r
8947 * Front-end interface functions exported by XBoard.
\r
8948 * Functions appear in same order as prototypes in frontend.h.
\r
8950 \*---------------------------------------------------------------------------*/
\r
8954 static UINT prevChecked = 0;
\r
8955 static int prevPausing = 0;
\r
8958 if (pausing != prevPausing) {
\r
8959 prevPausing = pausing;
\r
8960 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8961 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8962 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8965 switch (gameMode) {
\r
8966 case BeginningOfGame:
\r
8967 if (appData.icsActive)
\r
8968 nowChecked = IDM_IcsClient;
\r
8969 else if (appData.noChessProgram)
\r
8970 nowChecked = IDM_EditGame;
\r
8972 nowChecked = IDM_MachineBlack;
\r
8974 case MachinePlaysBlack:
\r
8975 nowChecked = IDM_MachineBlack;
\r
8977 case MachinePlaysWhite:
\r
8978 nowChecked = IDM_MachineWhite;
\r
8980 case TwoMachinesPlay:
\r
8981 nowChecked = IDM_TwoMachines;
\r
8984 nowChecked = IDM_AnalysisMode;
\r
8987 nowChecked = IDM_AnalyzeFile;
\r
8990 nowChecked = IDM_EditGame;
\r
8992 case PlayFromGameFile:
\r
8993 nowChecked = IDM_LoadGame;
\r
8995 case EditPosition:
\r
8996 nowChecked = IDM_EditPosition;
\r
8999 nowChecked = IDM_Training;
\r
9001 case IcsPlayingWhite:
\r
9002 case IcsPlayingBlack:
\r
9003 case IcsObserving:
\r
9005 nowChecked = IDM_IcsClient;
\r
9012 if (prevChecked != 0)
\r
9013 (void) CheckMenuItem(GetMenu(hwndMain),
\r
9014 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
9015 if (nowChecked != 0)
\r
9016 (void) CheckMenuItem(GetMenu(hwndMain),
\r
9017 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
9019 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
9020 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
9021 MF_BYCOMMAND|MF_ENABLED);
\r
9023 (void) EnableMenuItem(GetMenu(hwndMain),
\r
9024 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
9027 prevChecked = nowChecked;
\r
9029 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
9030 if (appData.icsActive) {
\r
9031 if (appData.icsEngineAnalyze) {
\r
9032 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9033 MF_BYCOMMAND|MF_CHECKED);
\r
9035 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9036 MF_BYCOMMAND|MF_UNCHECKED);
\r
9044 HMENU hmenu = GetMenu(hwndMain);
\r
9045 SetMenuEnables(hmenu, icsEnables);
\r
9046 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9047 MF_BYPOSITION|MF_ENABLED);
\r
9049 if (appData.zippyPlay) {
\r
9050 SetMenuEnables(hmenu, zippyEnables);
\r
9051 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9052 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9053 MF_BYCOMMAND|MF_ENABLED);
\r
9061 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9067 HMENU hmenu = GetMenu(hwndMain);
\r
9068 SetMenuEnables(hmenu, ncpEnables);
\r
9069 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9070 MF_BYPOSITION|MF_GRAYED);
\r
9071 DrawMenuBar(hwndMain);
\r
9077 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9081 SetTrainingModeOn()
\r
9084 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9085 for (i = 0; i < N_BUTTONS; i++) {
\r
9086 if (buttonDesc[i].hwnd != NULL)
\r
9087 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9092 VOID SetTrainingModeOff()
\r
9095 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9096 for (i = 0; i < N_BUTTONS; i++) {
\r
9097 if (buttonDesc[i].hwnd != NULL)
\r
9098 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9104 SetUserThinkingEnables()
\r
9106 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9110 SetMachineThinkingEnables()
\r
9112 HMENU hMenu = GetMenu(hwndMain);
\r
9113 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9115 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9117 if (gameMode == MachinePlaysBlack) {
\r
9118 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9119 } else if (gameMode == MachinePlaysWhite) {
\r
9120 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9121 } else if (gameMode == TwoMachinesPlay) {
\r
9122 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9128 DisplayTitle(char *str)
\r
9130 char title[MSG_SIZ], *host;
\r
9131 if (str[0] != NULLCHAR) {
\r
9132 strcpy(title, str);
\r
9133 } else if (appData.icsActive) {
\r
9134 if (appData.icsCommPort[0] != NULLCHAR)
\r
9137 host = appData.icsHost;
\r
9138 sprintf(title, "%s: %s", szTitle, host);
\r
9139 } else if (appData.noChessProgram) {
\r
9140 strcpy(title, szTitle);
\r
9142 strcpy(title, szTitle);
\r
9143 strcat(title, ": ");
\r
9144 strcat(title, first.tidy);
\r
9146 SetWindowText(hwndMain, title);
\r
9151 DisplayMessage(char *str1, char *str2)
\r
9155 int remain = MESSAGE_TEXT_MAX - 1;
\r
9158 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9159 messageText[0] = NULLCHAR;
\r
9161 len = strlen(str1);
\r
9162 if (len > remain) len = remain;
\r
9163 strncpy(messageText, str1, len);
\r
9164 messageText[len] = NULLCHAR;
\r
9167 if (*str2 && remain >= 2) {
\r
9169 strcat(messageText, " ");
\r
9172 len = strlen(str2);
\r
9173 if (len > remain) len = remain;
\r
9174 strncat(messageText, str2, len);
\r
9176 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9178 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9182 hdc = GetDC(hwndMain);
\r
9183 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9184 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9185 &messageRect, messageText, strlen(messageText), NULL);
\r
9186 (void) SelectObject(hdc, oldFont);
\r
9187 (void) ReleaseDC(hwndMain, hdc);
\r
9191 DisplayError(char *str, int error)
\r
9193 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9199 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9200 NULL, error, LANG_NEUTRAL,
\r
9201 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9203 sprintf(buf, "%s:\n%s", str, buf2);
\r
9205 ErrorMap *em = errmap;
\r
9206 while (em->err != 0 && em->err != error) em++;
\r
9207 if (em->err != 0) {
\r
9208 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9210 sprintf(buf, "%s:\nError code %d", str, error);
\r
9215 ErrorPopUp("Error", buf);
\r
9220 DisplayMoveError(char *str)
\r
9222 fromX = fromY = -1;
\r
9223 ClearHighlights();
\r
9224 DrawPosition(FALSE, NULL);
\r
9225 if (appData.popupMoveErrors) {
\r
9226 ErrorPopUp("Error", str);
\r
9228 DisplayMessage(str, "");
\r
9229 moveErrorMessageUp = TRUE;
\r
9234 DisplayFatalError(char *str, int error, int exitStatus)
\r
9236 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9238 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9241 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9242 NULL, error, LANG_NEUTRAL,
\r
9243 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9245 sprintf(buf, "%s:\n%s", str, buf2);
\r
9247 ErrorMap *em = errmap;
\r
9248 while (em->err != 0 && em->err != error) em++;
\r
9249 if (em->err != 0) {
\r
9250 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9252 sprintf(buf, "%s:\nError code %d", str, error);
\r
9257 if (appData.debugMode) {
\r
9258 fprintf(debugFP, "%s: %s\n", label, str);
\r
9260 if (appData.popupExitMessage) {
\r
9261 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9262 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9264 ExitEvent(exitStatus);
\r
9269 DisplayInformation(char *str)
\r
9271 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9276 DisplayNote(char *str)
\r
9278 ErrorPopUp("Note", str);
\r
9283 char *title, *question, *replyPrefix;
\r
9288 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9290 static QuestionParams *qp;
\r
9291 char reply[MSG_SIZ];
\r
9294 switch (message) {
\r
9295 case WM_INITDIALOG:
\r
9296 qp = (QuestionParams *) lParam;
\r
9297 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9298 SetWindowText(hDlg, qp->title);
\r
9299 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9300 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9304 switch (LOWORD(wParam)) {
\r
9306 strcpy(reply, qp->replyPrefix);
\r
9307 if (*reply) strcat(reply, " ");
\r
9308 len = strlen(reply);
\r
9309 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9310 strcat(reply, "\n");
\r
9311 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9312 EndDialog(hDlg, TRUE);
\r
9313 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9316 EndDialog(hDlg, FALSE);
\r
9327 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9329 QuestionParams qp;
\r
9333 qp.question = question;
\r
9334 qp.replyPrefix = replyPrefix;
\r
9336 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9337 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9338 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9339 FreeProcInstance(lpProc);
\r
9342 /* [AS] Pick FRC position */
\r
9343 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9345 static int * lpIndexFRC;
\r
9351 case WM_INITDIALOG:
\r
9352 lpIndexFRC = (int *) lParam;
\r
9354 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9356 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9357 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9358 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9359 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9364 switch( LOWORD(wParam) ) {
\r
9366 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9367 EndDialog( hDlg, 0 );
\r
9368 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9371 EndDialog( hDlg, 1 );
\r
9373 case IDC_NFG_Edit:
\r
9374 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9375 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9377 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9380 case IDC_NFG_Random:
\r
9381 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9382 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9395 int index = appData.defaultFrcPosition;
\r
9396 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9398 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9400 if( result == 0 ) {
\r
9401 appData.defaultFrcPosition = index;
\r
9407 /* [AS] Game list options */
\r
9413 static GLT_Item GLT_ItemInfo[] = {
\r
9414 { GLT_EVENT, "Event" },
\r
9415 { GLT_SITE, "Site" },
\r
9416 { GLT_DATE, "Date" },
\r
9417 { GLT_ROUND, "Round" },
\r
9418 { GLT_PLAYERS, "Players" },
\r
9419 { GLT_RESULT, "Result" },
\r
9420 { GLT_WHITE_ELO, "White Rating" },
\r
9421 { GLT_BLACK_ELO, "Black Rating" },
\r
9422 { GLT_TIME_CONTROL,"Time Control" },
\r
9423 { GLT_VARIANT, "Variant" },
\r
9424 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9425 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9429 const char * GLT_FindItem( char id )
\r
9431 const char * result = 0;
\r
9433 GLT_Item * list = GLT_ItemInfo;
\r
9435 while( list->id != 0 ) {
\r
9436 if( list->id == id ) {
\r
9437 result = list->name;
\r
9447 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9449 const char * name = GLT_FindItem( id );
\r
9452 if( index >= 0 ) {
\r
9453 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9456 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9461 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9465 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9468 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9472 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9474 pc = GLT_ALL_TAGS;
\r
9477 if( strchr( tags, *pc ) == 0 ) {
\r
9478 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9483 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9486 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9488 char result = '\0';
\r
9491 GLT_Item * list = GLT_ItemInfo;
\r
9493 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9494 while( list->id != 0 ) {
\r
9495 if( strcmp( list->name, name ) == 0 ) {
\r
9496 result = list->id;
\r
9507 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9509 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9510 int idx2 = idx1 + delta;
\r
9511 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9513 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9516 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9517 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9518 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9519 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9523 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9525 static char glt[64];
\r
9526 static char * lpUserGLT;
\r
9530 case WM_INITDIALOG:
\r
9531 lpUserGLT = (char *) lParam;
\r
9533 strcpy( glt, lpUserGLT );
\r
9535 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9537 /* Initialize list */
\r
9538 GLT_TagsToList( hDlg, glt );
\r
9540 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9545 switch( LOWORD(wParam) ) {
\r
9548 char * pc = lpUserGLT;
\r
9550 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9554 id = GLT_ListItemToTag( hDlg, idx );
\r
9558 } while( id != '\0' );
\r
9560 EndDialog( hDlg, 0 );
\r
9563 EndDialog( hDlg, 1 );
\r
9566 case IDC_GLT_Default:
\r
9567 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9568 GLT_TagsToList( hDlg, glt );
\r
9571 case IDC_GLT_Restore:
\r
9572 strcpy( glt, lpUserGLT );
\r
9573 GLT_TagsToList( hDlg, glt );
\r
9577 GLT_MoveSelection( hDlg, -1 );
\r
9580 case IDC_GLT_Down:
\r
9581 GLT_MoveSelection( hDlg, +1 );
\r
9591 int GameListOptions()
\r
9595 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9597 strcpy( glt, appData.gameListTags );
\r
9599 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9601 if( result == 0 ) {
\r
9602 /* [AS] Memory leak here! */
\r
9603 appData.gameListTags = strdup( glt );
\r
9611 DisplayIcsInteractionTitle(char *str)
\r
9613 char consoleTitle[MSG_SIZ];
\r
9615 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9616 SetWindowText(hwndConsole, consoleTitle);
\r
9620 DrawPosition(int fullRedraw, Board board)
\r
9622 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9629 fromX = fromY = -1;
\r
9630 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9631 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9632 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9633 dragInfo.lastpos = dragInfo.pos;
\r
9634 dragInfo.start.x = dragInfo.start.y = -1;
\r
9635 dragInfo.from = dragInfo.start;
\r
9637 DrawPosition(TRUE, NULL);
\r
9643 CommentPopUp(char *title, char *str)
\r
9645 HWND hwnd = GetActiveWindow();
\r
9646 EitherCommentPopUp(0, title, str, FALSE);
\r
9647 SetActiveWindow(hwnd);
\r
9651 CommentPopDown(void)
\r
9653 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9654 if (commentDialog) {
\r
9655 ShowWindow(commentDialog, SW_HIDE);
\r
9657 commentDialogUp = FALSE;
\r
9661 EditCommentPopUp(int index, char *title, char *str)
\r
9663 EitherCommentPopUp(index, title, str, TRUE);
\r
9670 MyPlaySound(&sounds[(int)SoundMove]);
\r
9673 VOID PlayIcsWinSound()
\r
9675 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9678 VOID PlayIcsLossSound()
\r
9680 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9683 VOID PlayIcsDrawSound()
\r
9685 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9688 VOID PlayIcsUnfinishedSound()
\r
9690 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9696 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9704 consoleEcho = TRUE;
\r
9705 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9706 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9707 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9716 consoleEcho = FALSE;
\r
9717 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9718 /* This works OK: set text and background both to the same color */
\r
9720 cf.crTextColor = COLOR_ECHOOFF;
\r
9721 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9722 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9725 /* No Raw()...? */
\r
9727 void Colorize(ColorClass cc, int continuation)
\r
9729 currentColorClass = cc;
\r
9730 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9731 consoleCF.crTextColor = textAttribs[cc].color;
\r
9732 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9733 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9739 static char buf[MSG_SIZ];
\r
9740 DWORD bufsiz = MSG_SIZ;
\r
9742 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9743 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9745 if (!GetUserName(buf, &bufsiz)) {
\r
9746 /*DisplayError("Error getting user name", GetLastError());*/
\r
9747 strcpy(buf, "User");
\r
9755 static char buf[MSG_SIZ];
\r
9756 DWORD bufsiz = MSG_SIZ;
\r
9758 if (!GetComputerName(buf, &bufsiz)) {
\r
9759 /*DisplayError("Error getting host name", GetLastError());*/
\r
9760 strcpy(buf, "Unknown");
\r
9767 ClockTimerRunning()
\r
9769 return clockTimerEvent != 0;
\r
9775 if (clockTimerEvent == 0) return FALSE;
\r
9776 KillTimer(hwndMain, clockTimerEvent);
\r
9777 clockTimerEvent = 0;
\r
9782 StartClockTimer(long millisec)
\r
9784 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9785 (UINT) millisec, NULL);
\r
9789 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9792 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9794 if(appData.noGUI) return;
\r
9795 hdc = GetDC(hwndMain);
\r
9796 if (!IsIconic(hwndMain)) {
\r
9797 DisplayAClock(hdc, timeRemaining, highlight,
\r
9798 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9800 if (highlight && iconCurrent == iconBlack) {
\r
9801 iconCurrent = iconWhite;
\r
9802 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9803 if (IsIconic(hwndMain)) {
\r
9804 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9807 (void) ReleaseDC(hwndMain, hdc);
\r
9809 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9813 DisplayBlackClock(long timeRemaining, int highlight)
\r
9816 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9818 if(appData.noGUI) return;
\r
9819 hdc = GetDC(hwndMain);
\r
9820 if (!IsIconic(hwndMain)) {
\r
9821 DisplayAClock(hdc, timeRemaining, highlight,
\r
9822 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9824 if (highlight && iconCurrent == iconWhite) {
\r
9825 iconCurrent = iconBlack;
\r
9826 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9827 if (IsIconic(hwndMain)) {
\r
9828 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9831 (void) ReleaseDC(hwndMain, hdc);
\r
9833 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9838 LoadGameTimerRunning()
\r
9840 return loadGameTimerEvent != 0;
\r
9844 StopLoadGameTimer()
\r
9846 if (loadGameTimerEvent == 0) return FALSE;
\r
9847 KillTimer(hwndMain, loadGameTimerEvent);
\r
9848 loadGameTimerEvent = 0;
\r
9853 StartLoadGameTimer(long millisec)
\r
9855 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9856 (UINT) millisec, NULL);
\r
9864 char fileTitle[MSG_SIZ];
\r
9866 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9867 f = OpenFileDialog(hwndMain, "a", defName,
\r
9868 appData.oldSaveStyle ? "gam" : "pgn",
\r
9870 "Save Game to File", NULL, fileTitle, NULL);
\r
9872 SaveGame(f, 0, "");
\r
9879 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9881 if (delayedTimerEvent != 0) {
\r
9882 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9883 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9885 KillTimer(hwndMain, delayedTimerEvent);
\r
9886 delayedTimerEvent = 0;
\r
9887 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9888 delayedTimerCallback();
\r
9890 delayedTimerCallback = cb;
\r
9891 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9892 (UINT) millisec, NULL);
\r
9895 DelayedEventCallback
\r
9898 if (delayedTimerEvent) {
\r
9899 return delayedTimerCallback;
\r
9906 CancelDelayedEvent()
\r
9908 if (delayedTimerEvent) {
\r
9909 KillTimer(hwndMain, delayedTimerEvent);
\r
9910 delayedTimerEvent = 0;
\r
9914 DWORD GetWin32Priority(int nice)
\r
9915 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9917 REALTIME_PRIORITY_CLASS 0x00000100
\r
9918 HIGH_PRIORITY_CLASS 0x00000080
\r
9919 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9920 NORMAL_PRIORITY_CLASS 0x00000020
\r
9921 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9922 IDLE_PRIORITY_CLASS 0x00000040
\r
9924 if (nice < -15) return 0x00000080;
\r
9925 if (nice < 0) return 0x00008000;
\r
9926 if (nice == 0) return 0x00000020;
\r
9927 if (nice < 15) return 0x00004000;
\r
9928 return 0x00000040;
\r
9931 /* Start a child process running the given program.
\r
9932 The process's standard output can be read from "from", and its
\r
9933 standard input can be written to "to".
\r
9934 Exit with fatal error if anything goes wrong.
\r
9935 Returns an opaque pointer that can be used to destroy the process
\r
9939 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9941 #define BUFSIZE 4096
\r
9943 HANDLE hChildStdinRd, hChildStdinWr,
\r
9944 hChildStdoutRd, hChildStdoutWr;
\r
9945 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9946 SECURITY_ATTRIBUTES saAttr;
\r
9948 PROCESS_INFORMATION piProcInfo;
\r
9949 STARTUPINFO siStartInfo;
\r
9951 char buf[MSG_SIZ];
\r
9954 if (appData.debugMode) {
\r
9955 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9960 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9961 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9962 saAttr.bInheritHandle = TRUE;
\r
9963 saAttr.lpSecurityDescriptor = NULL;
\r
9966 * The steps for redirecting child's STDOUT:
\r
9967 * 1. Create anonymous pipe to be STDOUT for child.
\r
9968 * 2. Create a noninheritable duplicate of read handle,
\r
9969 * and close the inheritable read handle.
\r
9972 /* Create a pipe for the child's STDOUT. */
\r
9973 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9974 return GetLastError();
\r
9977 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9978 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9979 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9980 FALSE, /* not inherited */
\r
9981 DUPLICATE_SAME_ACCESS);
\r
9983 return GetLastError();
\r
9985 CloseHandle(hChildStdoutRd);
\r
9988 * The steps for redirecting child's STDIN:
\r
9989 * 1. Create anonymous pipe to be STDIN for child.
\r
9990 * 2. Create a noninheritable duplicate of write handle,
\r
9991 * and close the inheritable write handle.
\r
9994 /* Create a pipe for the child's STDIN. */
\r
9995 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9996 return GetLastError();
\r
9999 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
10000 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
10001 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
10002 FALSE, /* not inherited */
\r
10003 DUPLICATE_SAME_ACCESS);
\r
10004 if (! fSuccess) {
\r
10005 return GetLastError();
\r
10007 CloseHandle(hChildStdinWr);
\r
10009 /* Arrange to (1) look in dir for the child .exe file, and
\r
10010 * (2) have dir be the child's working directory. Interpret
\r
10011 * dir relative to the directory WinBoard loaded from. */
\r
10012 GetCurrentDirectory(MSG_SIZ, buf);
\r
10013 SetCurrentDirectory(installDir);
\r
10014 SetCurrentDirectory(dir);
\r
10016 /* Now create the child process. */
\r
10018 siStartInfo.cb = sizeof(STARTUPINFO);
\r
10019 siStartInfo.lpReserved = NULL;
\r
10020 siStartInfo.lpDesktop = NULL;
\r
10021 siStartInfo.lpTitle = NULL;
\r
10022 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
10023 siStartInfo.cbReserved2 = 0;
\r
10024 siStartInfo.lpReserved2 = NULL;
\r
10025 siStartInfo.hStdInput = hChildStdinRd;
\r
10026 siStartInfo.hStdOutput = hChildStdoutWr;
\r
10027 siStartInfo.hStdError = hChildStdoutWr;
\r
10029 fSuccess = CreateProcess(NULL,
\r
10030 cmdLine, /* command line */
\r
10031 NULL, /* process security attributes */
\r
10032 NULL, /* primary thread security attrs */
\r
10033 TRUE, /* handles are inherited */
\r
10034 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
10035 NULL, /* use parent's environment */
\r
10037 &siStartInfo, /* STARTUPINFO pointer */
\r
10038 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
10040 err = GetLastError();
\r
10041 SetCurrentDirectory(buf); /* return to prev directory */
\r
10042 if (! fSuccess) {
\r
10046 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10047 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10048 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10051 /* Close the handles we don't need in the parent */
\r
10052 CloseHandle(piProcInfo.hThread);
\r
10053 CloseHandle(hChildStdinRd);
\r
10054 CloseHandle(hChildStdoutWr);
\r
10056 /* Prepare return value */
\r
10057 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10058 cp->kind = CPReal;
\r
10059 cp->hProcess = piProcInfo.hProcess;
\r
10060 cp->pid = piProcInfo.dwProcessId;
\r
10061 cp->hFrom = hChildStdoutRdDup;
\r
10062 cp->hTo = hChildStdinWrDup;
\r
10064 *pr = (void *) cp;
\r
10066 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10067 2000 where engines sometimes don't see the initial command(s)
\r
10068 from WinBoard and hang. I don't understand how that can happen,
\r
10069 but the Sleep is harmless, so I've put it in. Others have also
\r
10070 reported what may be the same problem, so hopefully this will fix
\r
10071 it for them too. */
\r
10079 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10081 ChildProc *cp; int result;
\r
10083 cp = (ChildProc *) pr;
\r
10084 if (cp == NULL) return;
\r
10086 switch (cp->kind) {
\r
10088 /* TerminateProcess is considered harmful, so... */
\r
10089 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10090 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10091 /* The following doesn't work because the chess program
\r
10092 doesn't "have the same console" as WinBoard. Maybe
\r
10093 we could arrange for this even though neither WinBoard
\r
10094 nor the chess program uses a console for stdio? */
\r
10095 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10097 /* [AS] Special termination modes for misbehaving programs... */
\r
10098 if( signal == 9 ) {
\r
10099 result = TerminateProcess( cp->hProcess, 0 );
\r
10101 if ( appData.debugMode) {
\r
10102 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10105 else if( signal == 10 ) {
\r
10106 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10108 if( dw != WAIT_OBJECT_0 ) {
\r
10109 result = TerminateProcess( cp->hProcess, 0 );
\r
10111 if ( appData.debugMode) {
\r
10112 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10118 CloseHandle(cp->hProcess);
\r
10122 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10126 closesocket(cp->sock);
\r
10131 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10132 closesocket(cp->sock);
\r
10133 closesocket(cp->sock2);
\r
10141 InterruptChildProcess(ProcRef pr)
\r
10145 cp = (ChildProc *) pr;
\r
10146 if (cp == NULL) return;
\r
10147 switch (cp->kind) {
\r
10149 /* The following doesn't work because the chess program
\r
10150 doesn't "have the same console" as WinBoard. Maybe
\r
10151 we could arrange for this even though neither WinBoard
\r
10152 nor the chess program uses a console for stdio */
\r
10153 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10158 /* Can't interrupt */
\r
10162 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10169 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10171 char cmdLine[MSG_SIZ];
\r
10173 if (port[0] == NULLCHAR) {
\r
10174 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10176 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10178 return StartChildProcess(cmdLine, "", pr);
\r
10182 /* Code to open TCP sockets */
\r
10185 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10190 struct sockaddr_in sa, mysa;
\r
10191 struct hostent FAR *hp;
\r
10192 unsigned short uport;
\r
10193 WORD wVersionRequested;
\r
10196 /* Initialize socket DLL */
\r
10197 wVersionRequested = MAKEWORD(1, 1);
\r
10198 err = WSAStartup(wVersionRequested, &wsaData);
\r
10199 if (err != 0) return err;
\r
10201 /* Make socket */
\r
10202 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10203 err = WSAGetLastError();
\r
10208 /* Bind local address using (mostly) don't-care values.
\r
10210 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10211 mysa.sin_family = AF_INET;
\r
10212 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10213 uport = (unsigned short) 0;
\r
10214 mysa.sin_port = htons(uport);
\r
10215 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10216 == SOCKET_ERROR) {
\r
10217 err = WSAGetLastError();
\r
10222 /* Resolve remote host name */
\r
10223 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10224 if (!(hp = gethostbyname(host))) {
\r
10225 unsigned int b0, b1, b2, b3;
\r
10227 err = WSAGetLastError();
\r
10229 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10230 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10231 hp->h_addrtype = AF_INET;
\r
10232 hp->h_length = 4;
\r
10233 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10234 hp->h_addr_list[0] = (char *) malloc(4);
\r
10235 hp->h_addr_list[0][0] = (char) b0;
\r
10236 hp->h_addr_list[0][1] = (char) b1;
\r
10237 hp->h_addr_list[0][2] = (char) b2;
\r
10238 hp->h_addr_list[0][3] = (char) b3;
\r
10244 sa.sin_family = hp->h_addrtype;
\r
10245 uport = (unsigned short) atoi(port);
\r
10246 sa.sin_port = htons(uport);
\r
10247 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10249 /* Make connection */
\r
10250 if (connect(s, (struct sockaddr *) &sa,
\r
10251 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10252 err = WSAGetLastError();
\r
10257 /* Prepare return value */
\r
10258 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10259 cp->kind = CPSock;
\r
10261 *pr = (ProcRef *) cp;
\r
10267 OpenCommPort(char *name, ProcRef *pr)
\r
10272 char fullname[MSG_SIZ];
\r
10274 if (*name != '\\')
\r
10275 sprintf(fullname, "\\\\.\\%s", name);
\r
10277 strcpy(fullname, name);
\r
10279 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10280 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10281 if (h == (HANDLE) -1) {
\r
10282 return GetLastError();
\r
10286 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10288 /* Accumulate characters until a 100ms pause, then parse */
\r
10289 ct.ReadIntervalTimeout = 100;
\r
10290 ct.ReadTotalTimeoutMultiplier = 0;
\r
10291 ct.ReadTotalTimeoutConstant = 0;
\r
10292 ct.WriteTotalTimeoutMultiplier = 0;
\r
10293 ct.WriteTotalTimeoutConstant = 0;
\r
10294 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10296 /* Prepare return value */
\r
10297 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10298 cp->kind = CPComm;
\r
10301 *pr = (ProcRef *) cp;
\r
10307 OpenLoopback(ProcRef *pr)
\r
10309 DisplayFatalError("Not implemented", 0, 1);
\r
10315 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10319 SOCKET s, s2, s3;
\r
10320 struct sockaddr_in sa, mysa;
\r
10321 struct hostent FAR *hp;
\r
10322 unsigned short uport;
\r
10323 WORD wVersionRequested;
\r
10326 char stderrPortStr[MSG_SIZ];
\r
10328 /* Initialize socket DLL */
\r
10329 wVersionRequested = MAKEWORD(1, 1);
\r
10330 err = WSAStartup(wVersionRequested, &wsaData);
\r
10331 if (err != 0) return err;
\r
10333 /* Resolve remote host name */
\r
10334 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10335 if (!(hp = gethostbyname(host))) {
\r
10336 unsigned int b0, b1, b2, b3;
\r
10338 err = WSAGetLastError();
\r
10340 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10341 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10342 hp->h_addrtype = AF_INET;
\r
10343 hp->h_length = 4;
\r
10344 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10345 hp->h_addr_list[0] = (char *) malloc(4);
\r
10346 hp->h_addr_list[0][0] = (char) b0;
\r
10347 hp->h_addr_list[0][1] = (char) b1;
\r
10348 hp->h_addr_list[0][2] = (char) b2;
\r
10349 hp->h_addr_list[0][3] = (char) b3;
\r
10355 sa.sin_family = hp->h_addrtype;
\r
10356 uport = (unsigned short) 514;
\r
10357 sa.sin_port = htons(uport);
\r
10358 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10360 /* Bind local socket to unused "privileged" port address
\r
10362 s = INVALID_SOCKET;
\r
10363 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10364 mysa.sin_family = AF_INET;
\r
10365 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10366 for (fromPort = 1023;; fromPort--) {
\r
10367 if (fromPort < 0) {
\r
10369 return WSAEADDRINUSE;
\r
10371 if (s == INVALID_SOCKET) {
\r
10372 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10373 err = WSAGetLastError();
\r
10378 uport = (unsigned short) fromPort;
\r
10379 mysa.sin_port = htons(uport);
\r
10380 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10381 == SOCKET_ERROR) {
\r
10382 err = WSAGetLastError();
\r
10383 if (err == WSAEADDRINUSE) continue;
\r
10387 if (connect(s, (struct sockaddr *) &sa,
\r
10388 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10389 err = WSAGetLastError();
\r
10390 if (err == WSAEADDRINUSE) {
\r
10401 /* Bind stderr local socket to unused "privileged" port address
\r
10403 s2 = INVALID_SOCKET;
\r
10404 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10405 mysa.sin_family = AF_INET;
\r
10406 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10407 for (fromPort = 1023;; fromPort--) {
\r
10408 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10409 if (fromPort < 0) {
\r
10410 (void) closesocket(s);
\r
10412 return WSAEADDRINUSE;
\r
10414 if (s2 == INVALID_SOCKET) {
\r
10415 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10416 err = WSAGetLastError();
\r
10422 uport = (unsigned short) fromPort;
\r
10423 mysa.sin_port = htons(uport);
\r
10424 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10425 == SOCKET_ERROR) {
\r
10426 err = WSAGetLastError();
\r
10427 if (err == WSAEADDRINUSE) continue;
\r
10428 (void) closesocket(s);
\r
10432 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10433 err = WSAGetLastError();
\r
10434 if (err == WSAEADDRINUSE) {
\r
10436 s2 = INVALID_SOCKET;
\r
10439 (void) closesocket(s);
\r
10440 (void) closesocket(s2);
\r
10446 prevStderrPort = fromPort; // remember port used
\r
10447 sprintf(stderrPortStr, "%d", fromPort);
\r
10449 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10450 err = WSAGetLastError();
\r
10451 (void) closesocket(s);
\r
10452 (void) closesocket(s2);
\r
10457 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10458 err = WSAGetLastError();
\r
10459 (void) closesocket(s);
\r
10460 (void) closesocket(s2);
\r
10464 if (*user == NULLCHAR) user = UserName();
\r
10465 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10466 err = WSAGetLastError();
\r
10467 (void) closesocket(s);
\r
10468 (void) closesocket(s2);
\r
10472 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10473 err = WSAGetLastError();
\r
10474 (void) closesocket(s);
\r
10475 (void) closesocket(s2);
\r
10480 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10481 err = WSAGetLastError();
\r
10482 (void) closesocket(s);
\r
10483 (void) closesocket(s2);
\r
10487 (void) closesocket(s2); /* Stop listening */
\r
10489 /* Prepare return value */
\r
10490 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10491 cp->kind = CPRcmd;
\r
10494 *pr = (ProcRef *) cp;
\r
10501 AddInputSource(ProcRef pr, int lineByLine,
\r
10502 InputCallback func, VOIDSTAR closure)
\r
10504 InputSource *is, *is2 = NULL;
\r
10505 ChildProc *cp = (ChildProc *) pr;
\r
10507 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10508 is->lineByLine = lineByLine;
\r
10510 is->closure = closure;
\r
10511 is->second = NULL;
\r
10512 is->next = is->buf;
\r
10513 if (pr == NoProc) {
\r
10514 is->kind = CPReal;
\r
10515 consoleInputSource = is;
\r
10517 is->kind = cp->kind;
\r
10519 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10520 we create all threads suspended so that the is->hThread variable can be
\r
10521 safely assigned, then let the threads start with ResumeThread.
\r
10523 switch (cp->kind) {
\r
10525 is->hFile = cp->hFrom;
\r
10526 cp->hFrom = NULL; /* now owned by InputThread */
\r
10528 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10529 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10533 is->hFile = cp->hFrom;
\r
10534 cp->hFrom = NULL; /* now owned by InputThread */
\r
10536 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10537 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10541 is->sock = cp->sock;
\r
10543 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10544 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10548 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10550 is->sock = cp->sock;
\r
10551 is->second = is2;
\r
10552 is2->sock = cp->sock2;
\r
10553 is2->second = is2;
\r
10555 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10556 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10558 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10559 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10563 if( is->hThread != NULL ) {
\r
10564 ResumeThread( is->hThread );
\r
10567 if( is2 != NULL && is2->hThread != NULL ) {
\r
10568 ResumeThread( is2->hThread );
\r
10572 return (InputSourceRef) is;
\r
10576 RemoveInputSource(InputSourceRef isr)
\r
10580 is = (InputSource *) isr;
\r
10581 is->hThread = NULL; /* tell thread to stop */
\r
10582 CloseHandle(is->hThread);
\r
10583 if (is->second != NULL) {
\r
10584 is->second->hThread = NULL;
\r
10585 CloseHandle(is->second->hThread);
\r
10591 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10594 int outCount = SOCKET_ERROR;
\r
10595 ChildProc *cp = (ChildProc *) pr;
\r
10596 static OVERLAPPED ovl;
\r
10598 if (pr == NoProc) {
\r
10599 ConsoleOutput(message, count, FALSE);
\r
10603 if (ovl.hEvent == NULL) {
\r
10604 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10606 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10608 switch (cp->kind) {
\r
10611 outCount = send(cp->sock, message, count, 0);
\r
10612 if (outCount == SOCKET_ERROR) {
\r
10613 *outError = WSAGetLastError();
\r
10615 *outError = NO_ERROR;
\r
10620 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10621 &dOutCount, NULL)) {
\r
10622 *outError = NO_ERROR;
\r
10623 outCount = (int) dOutCount;
\r
10625 *outError = GetLastError();
\r
10630 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10631 &dOutCount, &ovl);
\r
10632 if (*outError == NO_ERROR) {
\r
10633 outCount = (int) dOutCount;
\r
10641 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10644 /* Ignore delay, not implemented for WinBoard */
\r
10645 return OutputToProcess(pr, message, count, outError);
\r
10650 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10651 char *buf, int count, int error)
\r
10653 DisplayFatalError("Not implemented", 0, 1);
\r
10656 /* see wgamelist.c for Game List functions */
\r
10657 /* see wedittags.c for Edit Tags functions */
\r
10664 char buf[MSG_SIZ];
\r
10667 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10668 f = fopen(buf, "r");
\r
10670 ProcessICSInitScript(f);
\r
10678 StartAnalysisClock()
\r
10680 if (analysisTimerEvent) return;
\r
10681 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10682 (UINT) 2000, NULL);
\r
10686 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10688 static HANDLE hwndText;
\r
10690 static int sizeX, sizeY;
\r
10691 int newSizeX, newSizeY, flags;
\r
10694 switch (message) {
\r
10695 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10696 /* Initialize the dialog items */
\r
10697 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10698 SetWindowText(hDlg, analysisTitle);
\r
10699 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10700 /* Size and position the dialog */
\r
10701 if (!analysisDialog) {
\r
10702 analysisDialog = hDlg;
\r
10703 flags = SWP_NOZORDER;
\r
10704 GetClientRect(hDlg, &rect);
\r
10705 sizeX = rect.right;
\r
10706 sizeY = rect.bottom;
\r
10707 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10708 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10709 WINDOWPLACEMENT wp;
\r
10710 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10711 wp.length = sizeof(WINDOWPLACEMENT);
\r
10713 wp.showCmd = SW_SHOW;
\r
10714 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10715 wp.rcNormalPosition.left = analysisX;
\r
10716 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10717 wp.rcNormalPosition.top = analysisY;
\r
10718 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10719 SetWindowPlacement(hDlg, &wp);
\r
10721 GetClientRect(hDlg, &rect);
\r
10722 newSizeX = rect.right;
\r
10723 newSizeY = rect.bottom;
\r
10724 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10725 newSizeX, newSizeY);
\r
10726 sizeX = newSizeX;
\r
10727 sizeY = newSizeY;
\r
10732 case WM_COMMAND: /* message: received a command */
\r
10733 switch (LOWORD(wParam)) {
\r
10735 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10736 ExitAnalyzeMode();
\r
10748 newSizeX = LOWORD(lParam);
\r
10749 newSizeY = HIWORD(lParam);
\r
10750 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10751 sizeX = newSizeX;
\r
10752 sizeY = newSizeY;
\r
10755 case WM_GETMINMAXINFO:
\r
10756 /* Prevent resizing window too small */
\r
10757 mmi = (MINMAXINFO *) lParam;
\r
10758 mmi->ptMinTrackSize.x = 100;
\r
10759 mmi->ptMinTrackSize.y = 100;
\r
10766 AnalysisPopUp(char* title, char* str)
\r
10772 EngineOutputPopUp();
\r
10775 if (str == NULL) str = "";
\r
10776 p = (char *) malloc(2 * strlen(str) + 2);
\r
10779 if (*str == '\n') *q++ = '\r';
\r
10783 if (analysisText != NULL) free(analysisText);
\r
10784 analysisText = p;
\r
10786 if (analysisDialog) {
\r
10787 SetWindowText(analysisDialog, title);
\r
10788 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10789 ShowWindow(analysisDialog, SW_SHOW);
\r
10791 analysisTitle = title;
\r
10792 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10793 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10794 hwndMain, (DLGPROC)lpProc);
\r
10795 FreeProcInstance(lpProc);
\r
10797 analysisDialogUp = TRUE;
\r
10801 AnalysisPopDown()
\r
10803 if (analysisDialog) {
\r
10804 ShowWindow(analysisDialog, SW_HIDE);
\r
10806 analysisDialogUp = FALSE;
\r
10811 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10813 highlightInfo.sq[0].x = fromX;
\r
10814 highlightInfo.sq[0].y = fromY;
\r
10815 highlightInfo.sq[1].x = toX;
\r
10816 highlightInfo.sq[1].y = toY;
\r
10820 ClearHighlights()
\r
10822 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10823 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10827 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10829 premoveHighlightInfo.sq[0].x = fromX;
\r
10830 premoveHighlightInfo.sq[0].y = fromY;
\r
10831 premoveHighlightInfo.sq[1].x = toX;
\r
10832 premoveHighlightInfo.sq[1].y = toY;
\r
10836 ClearPremoveHighlights()
\r
10838 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10839 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10843 ShutDownFrontEnd()
\r
10845 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10846 DeleteClipboardTempFiles();
\r
10852 if (IsIconic(hwndMain))
\r
10853 ShowWindow(hwndMain, SW_RESTORE);
\r
10855 SetActiveWindow(hwndMain);
\r
10859 * Prototypes for animation support routines
\r
10861 static void ScreenSquare(int column, int row, POINT * pt);
\r
10862 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10863 POINT frames[], int * nFrames);
\r
10867 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10868 { // [HGM] atomic: animate blast wave
\r
10870 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10871 explodeInfo.fromX = fromX;
\r
10872 explodeInfo.fromY = fromY;
\r
10873 explodeInfo.toX = toX;
\r
10874 explodeInfo.toY = toY;
\r
10875 for(i=1; i<nFrames; i++) {
\r
10876 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10877 DrawPosition(FALSE, NULL);
\r
10878 Sleep(appData.animSpeed);
\r
10880 explodeInfo.radius = 0;
\r
10881 DrawPosition(TRUE, NULL);
\r
10884 #define kFactor 4
\r
10887 AnimateMove(board, fromX, fromY, toX, toY)
\r
10894 ChessSquare piece;
\r
10895 POINT start, finish, mid;
\r
10896 POINT frames[kFactor * 2 + 1];
\r
10899 if (!appData.animate) return;
\r
10900 if (doingSizing) return;
\r
10901 if (fromY < 0 || fromX < 0) return;
\r
10902 piece = board[fromY][fromX];
\r
10903 if (piece >= EmptySquare) return;
\r
10905 ScreenSquare(fromX, fromY, &start);
\r
10906 ScreenSquare(toX, toY, &finish);
\r
10908 /* All pieces except knights move in straight line */
\r
10909 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10910 mid.x = start.x + (finish.x - start.x) / 2;
\r
10911 mid.y = start.y + (finish.y - start.y) / 2;
\r
10913 /* Knight: make diagonal movement then straight */
\r
10914 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10915 mid.x = start.x + (finish.x - start.x) / 2;
\r
10916 mid.y = finish.y;
\r
10918 mid.x = finish.x;
\r
10919 mid.y = start.y + (finish.y - start.y) / 2;
\r
10923 /* Don't use as many frames for very short moves */
\r
10924 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10925 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10927 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10929 animInfo.from.x = fromX;
\r
10930 animInfo.from.y = fromY;
\r
10931 animInfo.to.x = toX;
\r
10932 animInfo.to.y = toY;
\r
10933 animInfo.lastpos = start;
\r
10934 animInfo.piece = piece;
\r
10935 for (n = 0; n < nFrames; n++) {
\r
10936 animInfo.pos = frames[n];
\r
10937 DrawPosition(FALSE, NULL);
\r
10938 animInfo.lastpos = animInfo.pos;
\r
10939 Sleep(appData.animSpeed);
\r
10941 animInfo.pos = finish;
\r
10942 DrawPosition(FALSE, NULL);
\r
10943 animInfo.piece = EmptySquare;
\r
10944 if(gameInfo.variant == VariantAtomic &&
\r
10945 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10946 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10949 /* Convert board position to corner of screen rect and color */
\r
10952 ScreenSquare(column, row, pt)
\r
10953 int column; int row; POINT * pt;
\r
10956 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10957 pt->y = lineGap + row * (squareSize + lineGap);
\r
10959 pt->x = lineGap + column * (squareSize + lineGap);
\r
10960 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10964 /* Generate a series of frame coords from start->mid->finish.
\r
10965 The movement rate doubles until the half way point is
\r
10966 reached, then halves back down to the final destination,
\r
10967 which gives a nice slow in/out effect. The algorithmn
\r
10968 may seem to generate too many intermediates for short
\r
10969 moves, but remember that the purpose is to attract the
\r
10970 viewers attention to the piece about to be moved and
\r
10971 then to where it ends up. Too few frames would be less
\r
10975 Tween(start, mid, finish, factor, frames, nFrames)
\r
10976 POINT * start; POINT * mid;
\r
10977 POINT * finish; int factor;
\r
10978 POINT frames[]; int * nFrames;
\r
10980 int n, fraction = 1, count = 0;
\r
10982 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10983 for (n = 0; n < factor; n++)
\r
10985 for (n = 0; n < factor; n++) {
\r
10986 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10987 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10989 fraction = fraction / 2;
\r
10993 frames[count] = *mid;
\r
10996 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10998 for (n = 0; n < factor; n++) {
\r
10999 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
11000 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
11002 fraction = fraction * 2;
\r
11004 *nFrames = count;
\r
11008 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
11013 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
11014 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
11016 OutputDebugString( buf );
\r
11019 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
11021 EvalGraphSet( first, last, current, pvInfoList );
\r
11024 void SetProgramStats( FrontEndProgramStats * stats )
\r
11029 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
11030 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
11032 OutputDebugString( buf );
\r
11035 EngineOutputUpdate( stats );
\r