2 * WinBoard.c -- Windows NT front end to XBoard
\r
3 * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
\r
5 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
6 * Massachusetts. Enhancements Copyright
\r
7 * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software
\r
10 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
11 * which was written and is copyrighted by Wayne Christopher.
\r
13 * The following terms apply to Digital Equipment Corporation's copyright
\r
14 * interest in XBoard:
\r
15 * ------------------------------------------------------------------------
\r
16 * All Rights Reserved
\r
18 * Permission to use, copy, modify, and distribute this software and its
\r
19 * documentation for any purpose and without fee is hereby granted,
\r
20 * provided that the above copyright notice appear in all copies and that
\r
21 * both that copyright notice and this permission notice appear in
\r
22 * supporting documentation, and that the name of Digital not be
\r
23 * used in advertising or publicity pertaining to distribution of the
\r
24 * software without specific, written prior permission.
\r
26 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
27 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
28 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
29 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
30 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
31 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
33 * ------------------------------------------------------------------------
\r
35 * The following terms apply to the enhanced version of XBoard
\r
36 * distributed by the Free Software Foundation:
\r
37 * ------------------------------------------------------------------------
\r
39 * GNU XBoard is free software: you can redistribute it and/or modify
\r
40 * it under the terms of the GNU General Public License as published by
\r
41 * the Free Software Foundation, either version 3 of the License, or (at
\r
42 * your option) any later version.
\r
44 * GNU XBoard is distributed in the hope that it will be useful, but
\r
45 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
46 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
47 * General Public License for more details.
\r
49 * You should have received a copy of the GNU General Public License
\r
50 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
52 *------------------------------------------------------------------------
\r
53 ** See the file ChangeLog for a revision history. */
\r
57 #include <windows.h>
\r
58 #include <winuser.h>
\r
59 #include <winsock.h>
\r
60 #include <commctrl.h>
\r
66 #include <sys/stat.h>
\r
69 #include <commdlg.h>
\r
71 #include <richedit.h>
\r
72 #include <mmsystem.h>
\r
81 #include "winboard.h"
\r
82 #include "frontend.h"
\r
83 #include "backend.h"
\r
85 #include "wclipbrd.h"
\r
86 #include "wgamelist.h"
\r
87 #include "wedittags.h"
\r
88 #include "woptions.h"
\r
89 #include "wsockerr.h"
\r
90 #include "defaults.h"
\r
94 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
97 void mysrandom(unsigned int seed);
\r
99 extern int whiteFlag, blackFlag;
\r
100 Boolean flipClock = FALSE;
\r
102 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
103 VOID NewVariantPopup(HWND hwnd);
\r
104 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
105 /*char*/int promoChar));
\r
106 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
109 ChessSquare piece;
\r
110 POINT pos; /* window coordinates of current pos */
\r
111 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
112 POINT from; /* board coordinates of the piece's orig pos */
\r
113 POINT to; /* board coordinates of the piece's new pos */
\r
116 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
119 POINT start; /* window coordinates of start pos */
\r
120 POINT pos; /* window coordinates of current pos */
\r
121 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
122 POINT from; /* board coordinates of the piece's orig pos */
\r
125 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
128 POINT sq[2]; /* board coordinates of from, to squares */
\r
131 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
132 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
134 typedef struct { // [HGM] atomic
\r
135 int fromX, fromY, toX, toY, radius;
\r
138 static ExplodeInfo explodeInfo;
\r
140 /* Window class names */
\r
141 char szAppName[] = "WinBoard";
\r
142 char szConsoleName[] = "WBConsole";
\r
144 /* Title bar text */
\r
145 char szTitle[] = "WinBoard";
\r
146 char szConsoleTitle[] = "ICS Interaction";
\r
149 char *settingsFileName;
\r
150 BOOLEAN saveSettingsOnExit;
\r
151 char installDir[MSG_SIZ];
\r
153 BoardSize boardSize;
\r
154 BOOLEAN chessProgram;
\r
155 static int boardX, boardY;
\r
156 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
157 static int squareSize, lineGap, minorSize;
\r
158 static int winWidth, winHeight, winW, winH;
\r
159 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
160 static int logoHeight = 0;
\r
161 static char messageText[MESSAGE_TEXT_MAX];
\r
162 static int clockTimerEvent = 0;
\r
163 static int loadGameTimerEvent = 0;
\r
164 static int analysisTimerEvent = 0;
\r
165 static DelayedEventCallback delayedTimerCallback;
\r
166 static int delayedTimerEvent = 0;
\r
167 static int buttonCount = 2;
\r
168 char *icsTextMenuString;
\r
170 char *firstChessProgramNames;
\r
171 char *secondChessProgramNames;
\r
173 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
175 #define PALETTESIZE 256
\r
177 HINSTANCE hInst; /* current instance */
\r
178 HWND hwndMain = NULL; /* root window*/
\r
179 HWND hwndConsole = NULL;
\r
180 BOOLEAN alwaysOnTop = FALSE;
\r
182 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
183 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
185 ColorClass currentColorClass;
\r
187 HWND hCommPort = NULL; /* currently open comm port */
\r
188 static HWND hwndPause; /* pause button */
\r
189 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
190 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
191 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
192 explodeBrush, /* [HGM] atomic */
\r
193 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
194 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
195 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
196 static HPEN gridPen = NULL;
\r
197 static HPEN highlightPen = NULL;
\r
198 static HPEN premovePen = NULL;
\r
199 static NPLOGPALETTE pLogPal;
\r
200 static BOOL paletteChanged = FALSE;
\r
201 static HICON iconWhite, iconBlack, iconCurrent;
\r
202 static int doingSizing = FALSE;
\r
203 static int lastSizing = 0;
\r
204 static int prevStderrPort;
\r
205 static HBITMAP userLogo;
\r
207 /* [AS] Support for background textures */
\r
208 #define BACK_TEXTURE_MODE_DISABLED 0
\r
209 #define BACK_TEXTURE_MODE_PLAIN 1
\r
210 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
212 static HBITMAP liteBackTexture = NULL;
\r
213 static HBITMAP darkBackTexture = NULL;
\r
214 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
215 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
216 static int backTextureSquareSize = 0;
\r
217 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
219 #if __GNUC__ && !defined(_winmajor)
\r
220 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
222 #define oldDialog (_winmajor < 4)
\r
225 char *defaultTextAttribs[] =
\r
227 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
228 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
238 int cliWidth, cliHeight;
\r
241 SizeInfo sizeInfo[] =
\r
243 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
244 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
245 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
246 { "petite", 33, 1, 1, 1, 0, 0 },
\r
247 { "slim", 37, 2, 1, 0, 0, 0 },
\r
248 { "small", 40, 2, 1, 0, 0, 0 },
\r
249 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
250 { "middling", 49, 2, 0, 0, 0, 0 },
\r
251 { "average", 54, 2, 0, 0, 0, 0 },
\r
252 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
253 { "medium", 64, 3, 0, 0, 0, 0 },
\r
254 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
255 { "large", 80, 3, 0, 0, 0, 0 },
\r
256 { "big", 87, 3, 0, 0, 0, 0 },
\r
257 { "huge", 95, 3, 0, 0, 0, 0 },
\r
258 { "giant", 108, 3, 0, 0, 0, 0 },
\r
259 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
260 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
261 { NULL, 0, 0, 0, 0, 0, 0 }
\r
264 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
265 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
267 { 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
268 { 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
269 { 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
270 { 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
271 { 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
272 { 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
273 { 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
274 { 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
275 { 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
276 { 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
277 { 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
278 { 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
279 { 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
280 { 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
281 { 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
282 { 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
283 { 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
284 { 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
287 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
296 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
297 #define N_BUTTONS 5
\r
299 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
301 {"<<", IDM_ToStart, NULL, NULL},
\r
302 {"<", IDM_Backward, NULL, NULL},
\r
303 {"P", IDM_Pause, NULL, NULL},
\r
304 {">", IDM_Forward, NULL, NULL},
\r
305 {">>", IDM_ToEnd, NULL, NULL},
\r
308 int tinyLayout = 0, smallLayout = 0;
\r
309 #define MENU_BAR_ITEMS 6
\r
310 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
311 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
312 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
316 MySound sounds[(int)NSoundClasses];
\r
317 MyTextAttribs textAttribs[(int)NColorClasses];
\r
319 MyColorizeAttribs colorizeAttribs[] = {
\r
320 { (COLORREF)0, 0, "Shout Text" },
\r
321 { (COLORREF)0, 0, "SShout/CShout" },
\r
322 { (COLORREF)0, 0, "Channel 1 Text" },
\r
323 { (COLORREF)0, 0, "Channel Text" },
\r
324 { (COLORREF)0, 0, "Kibitz Text" },
\r
325 { (COLORREF)0, 0, "Tell Text" },
\r
326 { (COLORREF)0, 0, "Challenge Text" },
\r
327 { (COLORREF)0, 0, "Request Text" },
\r
328 { (COLORREF)0, 0, "Seek Text" },
\r
329 { (COLORREF)0, 0, "Normal Text" },
\r
330 { (COLORREF)0, 0, "None" }
\r
335 static char *commentTitle;
\r
336 static char *commentText;
\r
337 static int commentIndex;
\r
338 static Boolean editComment = FALSE;
\r
339 HWND commentDialog = NULL;
\r
340 BOOLEAN commentDialogUp = FALSE;
\r
341 static int commentX, commentY, commentH, commentW;
\r
343 static char *analysisTitle;
\r
344 static char *analysisText;
\r
345 HWND analysisDialog = NULL;
\r
346 BOOLEAN analysisDialogUp = FALSE;
\r
347 static int analysisX, analysisY, analysisH, analysisW;
\r
349 char errorTitle[MSG_SIZ];
\r
350 char errorMessage[2*MSG_SIZ];
\r
351 HWND errorDialog = NULL;
\r
352 BOOLEAN moveErrorMessageUp = FALSE;
\r
353 BOOLEAN consoleEcho = TRUE;
\r
354 CHARFORMAT consoleCF;
\r
355 COLORREF consoleBackgroundColor;
\r
357 char *programVersion;
\r
363 typedef int CPKind;
\r
372 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
375 #define INPUT_SOURCE_BUF_SIZE 4096
\r
377 typedef struct _InputSource {
\r
384 char buf[INPUT_SOURCE_BUF_SIZE];
\r
388 InputCallback func;
\r
389 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
393 InputSource *consoleInputSource;
\r
398 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
399 VOID ConsoleCreate();
\r
401 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
402 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
403 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
404 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
406 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
407 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
408 void ParseIcsTextMenu(char *icsTextMenuString);
\r
409 VOID PopUpMoveDialog(char firstchar);
\r
410 VOID PopUpNameDialog(char firstchar);
\r
411 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
415 int GameListOptions();
\r
417 HWND moveHistoryDialog = NULL;
\r
418 BOOLEAN moveHistoryDialogUp = FALSE;
\r
420 WindowPlacement wpMoveHistory;
\r
422 HWND evalGraphDialog = NULL;
\r
423 BOOLEAN evalGraphDialogUp = FALSE;
\r
425 WindowPlacement wpEvalGraph;
\r
427 HWND engineOutputDialog = NULL;
\r
428 BOOLEAN engineOutputDialogUp = FALSE;
\r
430 WindowPlacement wpEngineOutput;
\r
431 WindowPlacement wpGameList;
\r
432 WindowPlacement wpConsole;
\r
434 VOID MoveHistoryPopUp();
\r
435 VOID MoveHistoryPopDown();
\r
436 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
437 BOOL MoveHistoryIsUp();
\r
439 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
440 VOID EvalGraphPopUp();
\r
441 VOID EvalGraphPopDown();
\r
442 BOOL EvalGraphIsUp();
\r
444 VOID EngineOutputPopUp();
\r
445 VOID EngineOutputPopDown();
\r
446 BOOL EngineOutputIsUp();
\r
447 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
449 VOID GothicPopUp(char *title, VariantClass variant);
\r
451 * Setting "frozen" should disable all user input other than deleting
\r
452 * the window. We do this while engines are initializing themselves.
\r
454 static int frozen = 0;
\r
455 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
461 if (frozen) return;
\r
463 hmenu = GetMenu(hwndMain);
\r
464 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
465 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
467 DrawMenuBar(hwndMain);
\r
470 /* Undo a FreezeUI */
\r
476 if (!frozen) return;
\r
478 hmenu = GetMenu(hwndMain);
\r
479 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
480 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
482 DrawMenuBar(hwndMain);
\r
485 /*---------------------------------------------------------------------------*\
\r
489 \*---------------------------------------------------------------------------*/
\r
492 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
493 LPSTR lpCmdLine, int nCmdShow)
\r
496 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
497 // INITCOMMONCONTROLSEX ex;
\r
501 LoadLibrary("RICHED32.DLL");
\r
502 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
504 if (!InitApplication(hInstance)) {
\r
507 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
511 // InitCommonControlsEx(&ex);
\r
512 InitCommonControls();
\r
514 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
515 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
516 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
518 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
520 while (GetMessage(&msg, /* message structure */
\r
521 NULL, /* handle of window receiving the message */
\r
522 0, /* lowest message to examine */
\r
523 0)) /* highest message to examine */
\r
525 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
526 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
527 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
528 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
529 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
530 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
531 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
532 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
533 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
534 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
535 TranslateMessage(&msg); /* Translates virtual key codes */
\r
536 DispatchMessage(&msg); /* Dispatches message to window */
\r
541 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
544 /*---------------------------------------------------------------------------*\
\r
546 * Initialization functions
\r
548 \*---------------------------------------------------------------------------*/
\r
552 { // update user logo if necessary
\r
553 static char oldUserName[MSG_SIZ], *curName;
\r
555 if(appData.autoLogo) {
\r
556 curName = UserName();
\r
557 if(strcmp(curName, oldUserName)) {
\r
558 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
559 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
560 strcpy(oldUserName, curName);
\r
566 InitApplication(HINSTANCE hInstance)
\r
570 /* Fill in window class structure with parameters that describe the */
\r
573 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
574 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
575 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
576 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
577 wc.hInstance = hInstance; /* Owner of this class */
\r
578 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
579 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
580 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
581 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
582 wc.lpszClassName = szAppName; /* Name to register as */
\r
584 /* Register the window class and return success/failure code. */
\r
585 if (!RegisterClass(&wc)) return FALSE;
\r
587 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
588 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
590 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
591 wc.hInstance = hInstance;
\r
592 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
593 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
594 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
595 wc.lpszMenuName = NULL;
\r
596 wc.lpszClassName = szConsoleName;
\r
598 if (!RegisterClass(&wc)) return FALSE;
\r
603 /* Set by InitInstance, used by EnsureOnScreen */
\r
604 int screenHeight, screenWidth;
\r
607 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
609 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
610 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
611 if (*x > screenWidth - 32) *x = 0;
\r
612 if (*y > screenHeight - 32) *y = 0;
\r
613 if (*x < minX) *x = minX;
\r
614 if (*y < minY) *y = minY;
\r
618 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
620 HWND hwnd; /* Main window handle. */
\r
622 WINDOWPLACEMENT wp;
\r
625 hInst = hInstance; /* Store instance handle in our global variable */
\r
627 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
628 *filepart = NULLCHAR;
\r
630 GetCurrentDirectory(MSG_SIZ, installDir);
\r
632 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
633 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
634 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
635 if (appData.debugMode) {
\r
636 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
637 setbuf(debugFP, NULL);
\r
642 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
643 // InitEngineUCI( installDir, &second );
\r
645 /* Create a main window for this application instance. */
\r
646 hwnd = CreateWindow(szAppName, szTitle,
\r
647 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
648 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
649 NULL, NULL, hInstance, NULL);
\r
652 /* If window could not be created, return "failure" */
\r
657 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
658 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
659 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
661 if (first.programLogo == NULL && appData.debugMode) {
\r
662 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
664 } else if(appData.autoLogo) {
\r
665 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
667 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
668 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
672 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
673 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
675 if (second.programLogo == NULL && appData.debugMode) {
\r
676 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
678 } else if(appData.autoLogo) {
\r
680 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
681 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
682 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
684 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
685 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
686 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
692 iconWhite = LoadIcon(hInstance, "icon_white");
\r
693 iconBlack = LoadIcon(hInstance, "icon_black");
\r
694 iconCurrent = iconWhite;
\r
695 InitDrawingColors();
\r
696 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
697 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
698 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
699 /* Compute window size for each board size, and use the largest
\r
700 size that fits on this screen as the default. */
\r
701 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
702 if (boardSize == (BoardSize)-1 &&
\r
703 winH <= screenHeight
\r
704 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
705 && winW <= screenWidth) {
\r
706 boardSize = (BoardSize)ibs;
\r
710 InitDrawingSizes(boardSize, 0);
\r
712 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
714 /* [AS] Load textures if specified */
\r
715 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
717 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
718 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
719 liteBackTextureMode = appData.liteBackTextureMode;
\r
721 if (liteBackTexture == NULL && appData.debugMode) {
\r
722 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
726 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
727 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
728 darkBackTextureMode = appData.darkBackTextureMode;
\r
730 if (darkBackTexture == NULL && appData.debugMode) {
\r
731 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
735 mysrandom( (unsigned) time(NULL) );
\r
737 /* [AS] Restore layout */
\r
738 if( wpMoveHistory.visible ) {
\r
739 MoveHistoryPopUp();
\r
742 if( wpEvalGraph.visible ) {
\r
746 if( wpEngineOutput.visible ) {
\r
747 EngineOutputPopUp();
\r
752 /* Make the window visible; update its client area; and return "success" */
\r
753 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
754 wp.length = sizeof(WINDOWPLACEMENT);
\r
756 wp.showCmd = nCmdShow;
\r
757 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
758 wp.rcNormalPosition.left = boardX;
\r
759 wp.rcNormalPosition.right = boardX + winWidth;
\r
760 wp.rcNormalPosition.top = boardY;
\r
761 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
762 SetWindowPlacement(hwndMain, &wp);
\r
764 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
765 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
769 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
770 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
772 ShowWindow(hwndConsole, nCmdShow);
\r
774 UpdateWindow(hwnd);
\r
782 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
783 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
784 ArgSettingsFilename,
\r
785 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
793 String *pString; // ArgString
\r
794 int *pInt; // ArgInt
\r
795 float *pFloat; // ArgFloat
\r
796 Boolean *pBoolean; // ArgBoolean
\r
797 COLORREF *pColor; // ArgColor
\r
798 ColorClass cc; // ArgAttribs
\r
799 String *pFilename; // ArgFilename
\r
800 BoardSize *pBoardSize; // ArgBoardSize
\r
801 int whichFont; // ArgFont
\r
802 DCB *pDCB; // ArgCommSettings
\r
803 String *pFilename; // ArgSettingsFilename
\r
811 ArgDescriptor argDescriptors[] = {
\r
812 /* positional arguments */
\r
813 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
814 { "", ArgNone, NULL },
\r
815 /* keyword arguments */
\r
816 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
817 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
818 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
819 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
820 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
821 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
822 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
823 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
824 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
825 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
826 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
827 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
828 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
829 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
830 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
831 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
832 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
833 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
835 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
837 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
839 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
840 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
842 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
843 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
844 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
845 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
846 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
847 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
848 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
849 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
850 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
851 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
852 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
853 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
854 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
855 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
856 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
857 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
858 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
859 /*!!bitmapDirectory?*/
\r
860 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
861 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
862 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
863 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
864 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
865 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
866 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
867 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
868 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
869 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
870 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
871 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
872 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
873 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
874 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
875 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
876 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
877 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
878 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
879 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
880 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
881 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
882 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
883 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
884 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
885 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
886 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
887 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
888 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
889 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
890 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
891 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
892 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
893 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
894 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
895 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
896 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
897 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
898 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
899 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
900 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
901 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
902 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
903 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
904 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
905 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
906 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
907 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
908 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
909 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
910 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
911 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
912 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
913 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
914 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
915 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
916 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
917 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
918 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
919 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
920 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
921 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
922 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
923 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
924 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
925 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
926 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
927 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
928 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
929 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
930 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
931 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
932 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
933 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
934 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
935 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
936 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
937 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
938 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
939 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
940 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
941 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
942 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
943 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
944 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
945 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
946 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
947 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
948 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
949 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
950 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
951 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
952 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
953 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
954 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
955 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
956 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
957 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
958 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
959 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
960 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
961 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
962 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
963 TRUE }, /* must come after all fonts */
\r
964 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
965 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
966 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
967 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
968 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
969 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
970 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
971 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
972 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
973 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
974 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
975 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
976 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
977 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
978 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
979 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
980 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
981 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
982 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
983 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
984 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
985 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
986 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
987 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
988 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
989 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
990 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
991 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
992 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
993 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
994 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
996 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
997 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
999 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1000 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1001 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1002 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1003 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1004 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1005 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1006 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1007 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1008 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1009 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1010 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1011 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1012 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1013 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1014 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1015 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1016 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1017 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1018 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1019 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1020 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1021 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1022 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1023 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1024 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1025 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1026 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1027 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1028 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1029 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1030 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1031 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1032 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1033 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1034 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1035 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1036 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1037 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1038 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1039 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1040 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1041 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1042 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1043 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1044 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1045 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1046 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1047 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1048 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1049 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1050 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1051 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1052 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1053 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1054 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1055 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1056 { "highlightLastMove", ArgBoolean,
\r
1057 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1058 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1059 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1060 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1061 { "highlightDragging", ArgBoolean,
\r
1062 (LPVOID) &appData.highlightDragging, TRUE },
\r
1063 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1064 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1065 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1066 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1067 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1068 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1069 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1070 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1071 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1072 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1073 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1074 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1075 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1076 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1077 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1078 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1079 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1080 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1081 { "soundShout", ArgFilename,
\r
1082 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1083 { "soundSShout", ArgFilename,
\r
1084 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1085 { "soundChannel1", ArgFilename,
\r
1086 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1087 { "soundChannel", ArgFilename,
\r
1088 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1089 { "soundKibitz", ArgFilename,
\r
1090 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1091 { "soundTell", ArgFilename,
\r
1092 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1093 { "soundChallenge", ArgFilename,
\r
1094 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1095 { "soundRequest", ArgFilename,
\r
1096 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1097 { "soundSeek", ArgFilename,
\r
1098 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1099 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1100 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1101 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1102 { "soundIcsLoss", ArgFilename,
\r
1103 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1104 { "soundIcsDraw", ArgFilename,
\r
1105 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1106 { "soundIcsUnfinished", ArgFilename,
\r
1107 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1108 { "soundIcsAlarm", ArgFilename,
\r
1109 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1110 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1111 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1112 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1113 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1114 { "reuseChessPrograms", ArgBoolean,
\r
1115 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1116 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1117 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1118 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1119 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1120 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1121 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1122 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1123 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1124 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1125 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1126 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1127 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1128 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1129 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1130 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1132 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1134 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1135 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1136 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1137 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1138 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1139 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1140 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1141 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1142 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1143 /* [AS] New features */
\r
1144 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1145 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1146 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1147 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1148 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1149 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1150 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1151 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1152 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1153 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1154 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1155 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1156 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1157 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1158 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1159 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1160 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1161 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1162 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1163 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1164 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1165 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1166 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1167 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1168 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1169 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1170 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1171 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1172 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1173 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1174 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1175 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1176 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1177 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1178 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1179 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1180 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1181 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1182 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1183 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1184 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1185 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1186 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1187 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1188 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1189 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1190 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1191 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1192 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1193 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1195 /* [HGM] board-size, adjudication and misc. options */
\r
1196 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1197 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1198 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1199 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1200 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1201 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1202 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1203 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1204 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1205 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1206 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1207 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1208 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1209 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1210 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1211 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1212 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1213 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1214 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1215 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1216 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1217 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1218 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1219 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1220 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1221 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1222 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1223 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1224 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1225 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1226 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1229 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1230 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1231 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1232 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1233 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1234 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1235 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1236 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1237 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1238 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1239 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1240 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1241 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1243 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1244 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1245 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1246 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1247 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1248 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1249 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1251 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1252 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1253 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1254 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1255 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1256 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1257 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1258 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1259 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1260 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1261 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1262 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1263 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1264 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1265 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1266 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1267 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1268 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1269 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1271 /* [HGM] options for broadcasting and time odds */
\r
1272 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1273 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1274 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1275 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1276 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1277 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1278 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1279 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1280 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1281 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1282 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1284 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1285 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1286 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1287 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1288 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1289 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1290 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1291 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1292 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1293 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1294 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1295 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1296 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1297 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1298 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1299 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1300 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1301 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1302 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1303 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1304 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1305 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1306 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1307 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1308 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1309 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1310 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1311 /* [AS] Layout stuff */
\r
1312 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1313 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1314 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1315 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1316 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1318 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1319 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1320 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1321 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1322 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1324 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1325 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1326 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1327 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1328 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1330 { NULL, ArgNone, NULL, FALSE }
\r
1334 /* Kludge for indirection files on command line */
\r
1335 char* lastIndirectionFilename;
\r
1336 ArgDescriptor argDescriptorIndirection =
\r
1337 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1341 ExitArgError(char *msg, char *badArg)
\r
1343 char buf[MSG_SIZ];
\r
1345 sprintf(buf, "%s %s", msg, badArg);
\r
1346 DisplayFatalError(buf, 0, 2);
\r
1350 /* Command line font name parser. NULL name means do nothing.
\r
1351 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1352 For backward compatibility, syntax without the colon is also
\r
1353 accepted, but font names with digits in them won't work in that case.
\r
1356 ParseFontName(char *name, MyFontParams *mfp)
\r
1359 if (name == NULL) return;
\r
1361 q = strchr(p, ':');
\r
1363 if (q - p >= sizeof(mfp->faceName))
\r
1364 ExitArgError("Font name too long:", name);
\r
1365 memcpy(mfp->faceName, p, q - p);
\r
1366 mfp->faceName[q - p] = NULLCHAR;
\r
1369 q = mfp->faceName;
\r
1370 while (*p && !isdigit(*p)) {
\r
1372 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1373 ExitArgError("Font name too long:", name);
\r
1375 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1378 if (!*p) ExitArgError("Font point size missing:", name);
\r
1379 mfp->pointSize = (float) atof(p);
\r
1380 mfp->bold = (strchr(p, 'b') != NULL);
\r
1381 mfp->italic = (strchr(p, 'i') != NULL);
\r
1382 mfp->underline = (strchr(p, 'u') != NULL);
\r
1383 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1386 /* Color name parser.
\r
1387 X version accepts X color names, but this one
\r
1388 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1390 ParseColorName(char *name)
\r
1392 int red, green, blue, count;
\r
1393 char buf[MSG_SIZ];
\r
1395 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1397 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1398 &red, &green, &blue);
\r
1401 sprintf(buf, "Can't parse color name %s", name);
\r
1402 DisplayError(buf, 0);
\r
1403 return RGB(0, 0, 0);
\r
1405 return PALETTERGB(red, green, blue);
\r
1409 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1411 char *e = argValue;
\r
1415 if (*e == 'b') eff |= CFE_BOLD;
\r
1416 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1417 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1418 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1419 else if (*e == '#' || isdigit(*e)) break;
\r
1423 *color = ParseColorName(e);
\r
1428 ParseBoardSize(char *name)
\r
1430 BoardSize bs = SizeTiny;
\r
1431 while (sizeInfo[bs].name != NULL) {
\r
1432 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1435 ExitArgError("Unrecognized board size value", name);
\r
1436 return bs; /* not reached */
\r
1441 StringGet(void *getClosure)
\r
1443 char **p = (char **) getClosure;
\r
1448 FileGet(void *getClosure)
\r
1451 FILE* f = (FILE*) getClosure;
\r
1454 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1461 /* Parse settings file named "name". If file found, return the
\r
1462 full name in fullname and return TRUE; else return FALSE */
\r
1464 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1468 int ok; char buf[MSG_SIZ];
\r
1470 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1471 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1472 sprintf(buf, "%s.ini", name);
\r
1473 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1476 f = fopen(fullname, "r");
\r
1478 ParseArgs(FileGet, f);
\r
1487 ParseArgs(GetFunc get, void *cl)
\r
1489 char argName[ARG_MAX];
\r
1490 char argValue[ARG_MAX];
\r
1491 ArgDescriptor *ad;
\r
1500 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1501 if (ch == NULLCHAR) break;
\r
1503 /* Comment to end of line */
\r
1505 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1507 } else if (ch == '/' || ch == '-') {
\r
1510 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1511 ch != '\n' && ch != '\t') {
\r
1517 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1518 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1520 if (ad->argName == NULL)
\r
1521 ExitArgError("Unrecognized argument", argName);
\r
1523 } else if (ch == '@') {
\r
1524 /* Indirection file */
\r
1525 ad = &argDescriptorIndirection;
\r
1528 /* Positional argument */
\r
1529 ad = &argDescriptors[posarg++];
\r
1530 strcpy(argName, ad->argName);
\r
1533 if (ad->argType == ArgTrue) {
\r
1534 *(Boolean *) ad->argLoc = TRUE;
\r
1537 if (ad->argType == ArgFalse) {
\r
1538 *(Boolean *) ad->argLoc = FALSE;
\r
1542 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1543 if (ch == NULLCHAR || ch == '\n') {
\r
1544 ExitArgError("No value provided for argument", argName);
\r
1548 // Quoting with { }. No characters have to (or can) be escaped.
\r
1549 // Thus the string cannot contain a '}' character.
\r
1569 } else if (ch == '\'' || ch == '"') {
\r
1570 // Quoting with ' ' or " ", with \ as escape character.
\r
1571 // Inconvenient for long strings that may contain Windows filenames.
\r
1588 if (ch == start) {
\r
1597 if (ad->argType == ArgFilename
\r
1598 || ad->argType == ArgSettingsFilename) {
\r
1604 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1628 for (i = 0; i < 3; i++) {
\r
1629 if (ch >= '0' && ch <= '7') {
\r
1630 octval = octval*8 + (ch - '0');
\r
1637 *q++ = (char) octval;
\r
1648 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1655 switch (ad->argType) {
\r
1657 *(int *) ad->argLoc = atoi(argValue);
\r
1661 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1665 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1669 *(int *) ad->argLoc = atoi(argValue);
\r
1670 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1674 *(float *) ad->argLoc = (float) atof(argValue);
\r
1679 *(char **) ad->argLoc = strdup(argValue);
\r
1682 case ArgSettingsFilename:
\r
1684 char fullname[MSG_SIZ];
\r
1685 if (ParseSettingsFile(argValue, fullname)) {
\r
1686 if (ad->argLoc != NULL) {
\r
1687 *(char **) ad->argLoc = strdup(fullname);
\r
1690 if (ad->argLoc != NULL) {
\r
1692 ExitArgError("Failed to open indirection file", argValue);
\r
1699 switch (argValue[0]) {
\r
1702 *(Boolean *) ad->argLoc = TRUE;
\r
1706 *(Boolean *) ad->argLoc = FALSE;
\r
1709 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1715 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1718 case ArgAttribs: {
\r
1719 ColorClass cc = (ColorClass)ad->argLoc;
\r
1720 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1724 case ArgBoardSize:
\r
1725 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1729 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1732 case ArgCommSettings:
\r
1733 ParseCommSettings(argValue, &dcb);
\r
1737 ExitArgError("Unrecognized argument", argValue);
\r
1746 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1748 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1749 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1752 lf->lfEscapement = 0;
\r
1753 lf->lfOrientation = 0;
\r
1754 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1755 lf->lfItalic = mfp->italic;
\r
1756 lf->lfUnderline = mfp->underline;
\r
1757 lf->lfStrikeOut = mfp->strikeout;
\r
1758 lf->lfCharSet = DEFAULT_CHARSET;
\r
1759 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1760 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1761 lf->lfQuality = DEFAULT_QUALITY;
\r
1762 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1763 strcpy(lf->lfFaceName, mfp->faceName);
\r
1767 CreateFontInMF(MyFont *mf)
\r
1769 LFfromMFP(&mf->lf, &mf->mfp);
\r
1770 if (mf->hf) DeleteObject(mf->hf);
\r
1771 mf->hf = CreateFontIndirect(&mf->lf);
\r
1775 SetDefaultTextAttribs()
\r
1778 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1779 ParseAttribs(&textAttribs[cc].color,
\r
1780 &textAttribs[cc].effects,
\r
1781 defaultTextAttribs[cc]);
\r
1786 SetDefaultSounds()
\r
1790 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1791 textAttribs[cc].sound.name = strdup("");
\r
1792 textAttribs[cc].sound.data = NULL;
\r
1794 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1795 sounds[sc].name = strdup("");
\r
1796 sounds[sc].data = NULL;
\r
1798 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1806 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1807 MyLoadSound(&textAttribs[cc].sound);
\r
1809 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1810 MyLoadSound(&sounds[sc]);
\r
1815 InitAppData(LPSTR lpCmdLine)
\r
1818 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1821 programName = szAppName;
\r
1823 /* Initialize to defaults */
\r
1824 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1825 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1826 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1827 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1828 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1829 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1830 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1831 SetDefaultTextAttribs();
\r
1832 SetDefaultSounds();
\r
1833 appData.movesPerSession = MOVES_PER_SESSION;
\r
1834 appData.initString = INIT_STRING;
\r
1835 appData.secondInitString = INIT_STRING;
\r
1836 appData.firstComputerString = COMPUTER_STRING;
\r
1837 appData.secondComputerString = COMPUTER_STRING;
\r
1838 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1839 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1840 appData.firstPlaysBlack = FALSE;
\r
1841 appData.noChessProgram = FALSE;
\r
1842 chessProgram = FALSE;
\r
1843 appData.firstHost = FIRST_HOST;
\r
1844 appData.secondHost = SECOND_HOST;
\r
1845 appData.firstDirectory = FIRST_DIRECTORY;
\r
1846 appData.secondDirectory = SECOND_DIRECTORY;
\r
1847 appData.bitmapDirectory = "";
\r
1848 appData.remoteShell = REMOTE_SHELL;
\r
1849 appData.remoteUser = "";
\r
1850 appData.timeDelay = TIME_DELAY;
\r
1851 appData.timeControl = TIME_CONTROL;
\r
1852 appData.timeIncrement = TIME_INCREMENT;
\r
1853 appData.icsActive = FALSE;
\r
1854 appData.icsHost = "";
\r
1855 appData.icsPort = ICS_PORT;
\r
1856 appData.icsCommPort = ICS_COMM_PORT;
\r
1857 appData.icsLogon = ICS_LOGON;
\r
1858 appData.icsHelper = "";
\r
1859 appData.useTelnet = FALSE;
\r
1860 appData.telnetProgram = TELNET_PROGRAM;
\r
1861 appData.gateway = "";
\r
1862 appData.loadGameFile = "";
\r
1863 appData.loadGameIndex = 0;
\r
1864 appData.saveGameFile = "";
\r
1865 appData.autoSaveGames = FALSE;
\r
1866 appData.loadPositionFile = "";
\r
1867 appData.loadPositionIndex = 1;
\r
1868 appData.savePositionFile = "";
\r
1869 appData.matchMode = FALSE;
\r
1870 appData.matchGames = 0;
\r
1871 appData.monoMode = FALSE;
\r
1872 appData.debugMode = FALSE;
\r
1873 appData.clockMode = TRUE;
\r
1874 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1875 appData.Iconic = FALSE; /*unused*/
\r
1876 appData.searchTime = "";
\r
1877 appData.searchDepth = 0;
\r
1878 appData.showCoords = FALSE;
\r
1879 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1880 appData.autoCallFlag = FALSE;
\r
1881 appData.flipView = FALSE;
\r
1882 appData.autoFlipView = TRUE;
\r
1883 appData.cmailGameName = "";
\r
1884 appData.alwaysPromoteToQueen = FALSE;
\r
1885 appData.oldSaveStyle = FALSE;
\r
1886 appData.quietPlay = FALSE;
\r
1887 appData.showThinking = FALSE;
\r
1888 appData.ponderNextMove = TRUE;
\r
1889 appData.periodicUpdates = TRUE;
\r
1890 appData.popupExitMessage = TRUE;
\r
1891 appData.popupMoveErrors = FALSE;
\r
1892 appData.autoObserve = FALSE;
\r
1893 appData.autoComment = FALSE;
\r
1894 appData.animate = TRUE;
\r
1895 appData.animSpeed = 10;
\r
1896 appData.animateDragging = TRUE;
\r
1897 appData.highlightLastMove = TRUE;
\r
1898 appData.getMoveList = TRUE;
\r
1899 appData.testLegality = TRUE;
\r
1900 appData.premove = TRUE;
\r
1901 appData.premoveWhite = FALSE;
\r
1902 appData.premoveWhiteText = "";
\r
1903 appData.premoveBlack = FALSE;
\r
1904 appData.premoveBlackText = "";
\r
1905 appData.icsAlarm = TRUE;
\r
1906 appData.icsAlarmTime = 5000;
\r
1907 appData.autoRaiseBoard = TRUE;
\r
1908 appData.localLineEditing = TRUE;
\r
1909 appData.colorize = TRUE;
\r
1910 appData.reuseFirst = TRUE;
\r
1911 appData.reuseSecond = TRUE;
\r
1912 appData.blindfold = FALSE;
\r
1913 appData.icsEngineAnalyze = FALSE;
\r
1914 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1915 dcb.DCBlength = sizeof(DCB);
\r
1916 dcb.BaudRate = 9600;
\r
1917 dcb.fBinary = TRUE;
\r
1918 dcb.fParity = FALSE;
\r
1919 dcb.fOutxCtsFlow = FALSE;
\r
1920 dcb.fOutxDsrFlow = FALSE;
\r
1921 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1922 dcb.fDsrSensitivity = FALSE;
\r
1923 dcb.fTXContinueOnXoff = TRUE;
\r
1924 dcb.fOutX = FALSE;
\r
1926 dcb.fNull = FALSE;
\r
1927 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1928 dcb.fAbortOnError = FALSE;
\r
1930 dcb.Parity = SPACEPARITY;
\r
1931 dcb.StopBits = ONESTOPBIT;
\r
1932 settingsFileName = SETTINGS_FILE;
\r
1933 saveSettingsOnExit = TRUE;
\r
1934 boardX = CW_USEDEFAULT;
\r
1935 boardY = CW_USEDEFAULT;
\r
1936 analysisX = CW_USEDEFAULT;
\r
1937 analysisY = CW_USEDEFAULT;
\r
1938 analysisW = CW_USEDEFAULT;
\r
1939 analysisH = CW_USEDEFAULT;
\r
1940 commentX = CW_USEDEFAULT;
\r
1941 commentY = CW_USEDEFAULT;
\r
1942 commentW = CW_USEDEFAULT;
\r
1943 commentH = CW_USEDEFAULT;
\r
1944 editTagsX = CW_USEDEFAULT;
\r
1945 editTagsY = CW_USEDEFAULT;
\r
1946 editTagsW = CW_USEDEFAULT;
\r
1947 editTagsH = CW_USEDEFAULT;
\r
1948 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1949 icsNames = ICS_NAMES;
\r
1950 firstChessProgramNames = FCP_NAMES;
\r
1951 secondChessProgramNames = SCP_NAMES;
\r
1952 appData.initialMode = "";
\r
1953 appData.variant = "normal";
\r
1954 appData.firstProtocolVersion = PROTOVER;
\r
1955 appData.secondProtocolVersion = PROTOVER;
\r
1956 appData.showButtonBar = TRUE;
\r
1958 /* [AS] New properties (see comments in header file) */
\r
1959 appData.firstScoreIsAbsolute = FALSE;
\r
1960 appData.secondScoreIsAbsolute = FALSE;
\r
1961 appData.saveExtendedInfoInPGN = FALSE;
\r
1962 appData.hideThinkingFromHuman = FALSE;
\r
1963 appData.liteBackTextureFile = "";
\r
1964 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1965 appData.darkBackTextureFile = "";
\r
1966 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1967 appData.renderPiecesWithFont = "";
\r
1968 appData.fontToPieceTable = "";
\r
1969 appData.fontBackColorWhite = 0;
\r
1970 appData.fontForeColorWhite = 0;
\r
1971 appData.fontBackColorBlack = 0;
\r
1972 appData.fontForeColorBlack = 0;
\r
1973 appData.fontPieceSize = 80;
\r
1974 appData.overrideLineGap = 1;
\r
1975 appData.adjudicateLossThreshold = 0;
\r
1976 appData.delayBeforeQuit = 0;
\r
1977 appData.delayAfterQuit = 0;
\r
1978 appData.nameOfDebugFile = "winboard.debug";
\r
1979 appData.pgnEventHeader = "Computer Chess Game";
\r
1980 appData.defaultFrcPosition = -1;
\r
1981 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1982 appData.saveOutOfBookInfo = TRUE;
\r
1983 appData.showEvalInMoveHistory = TRUE;
\r
1984 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1985 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1986 appData.highlightMoveWithArrow = FALSE;
\r
1987 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1988 appData.useStickyWindows = TRUE;
\r
1989 appData.adjudicateDrawMoves = 0;
\r
1990 appData.autoDisplayComment = TRUE;
\r
1991 appData.autoDisplayTags = TRUE;
\r
1992 appData.firstIsUCI = FALSE;
\r
1993 appData.secondIsUCI = FALSE;
\r
1994 appData.firstHasOwnBookUCI = TRUE;
\r
1995 appData.secondHasOwnBookUCI = TRUE;
\r
1996 appData.polyglotDir = "";
\r
1997 appData.usePolyglotBook = FALSE;
\r
1998 appData.polyglotBook = "";
\r
1999 appData.defaultHashSize = 64;
\r
2000 appData.defaultCacheSizeEGTB = 4;
\r
2001 appData.defaultPathEGTB = "c:\\egtb";
\r
2002 appData.firstOptions = "";
\r
2003 appData.secondOptions = "";
\r
2005 InitWindowPlacement( &wpGameList );
\r
2006 InitWindowPlacement( &wpMoveHistory );
\r
2007 InitWindowPlacement( &wpEvalGraph );
\r
2008 InitWindowPlacement( &wpEngineOutput );
\r
2009 InitWindowPlacement( &wpConsole );
\r
2011 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2012 appData.NrFiles = -1;
\r
2013 appData.NrRanks = -1;
\r
2014 appData.holdingsSize = -1;
\r
2015 appData.testClaims = FALSE;
\r
2016 appData.checkMates = FALSE;
\r
2017 appData.materialDraws= FALSE;
\r
2018 appData.trivialDraws = FALSE;
\r
2019 appData.ruleMoves = 51;
\r
2020 appData.drawRepeats = 6;
\r
2021 appData.matchPause = 10000;
\r
2022 appData.alphaRank = FALSE;
\r
2023 appData.allWhite = FALSE;
\r
2024 appData.upsideDown = FALSE;
\r
2025 appData.serverPause = 15;
\r
2026 appData.serverMovesName = NULL;
\r
2027 appData.suppressLoadMoves = FALSE;
\r
2028 appData.firstTimeOdds = 1;
\r
2029 appData.secondTimeOdds = 1;
\r
2030 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2031 appData.secondAccumulateTC = 1;
\r
2032 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2033 appData.secondNPS = -1;
\r
2034 appData.engineComments = 1;
\r
2035 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2036 appData.egtFormats = "";
\r
2039 appData.zippyTalk = ZIPPY_TALK;
\r
2040 appData.zippyPlay = ZIPPY_PLAY;
\r
2041 appData.zippyLines = ZIPPY_LINES;
\r
2042 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2043 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2044 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2045 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2046 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2047 appData.zippyUseI = ZIPPY_USE_I;
\r
2048 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2049 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2050 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2051 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2052 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2053 appData.zippyAbort = ZIPPY_ABORT;
\r
2054 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2055 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2056 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2059 /* Point font array elements to structures and
\r
2060 parse default font names */
\r
2061 for (i=0; i<NUM_FONTS; i++) {
\r
2062 for (j=0; j<NUM_SIZES; j++) {
\r
2063 font[j][i] = &fontRec[j][i];
\r
2064 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2068 /* Parse default settings file if any */
\r
2069 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2070 settingsFileName = strdup(buf);
\r
2073 /* Parse command line */
\r
2074 ParseArgs(StringGet, &lpCmdLine);
\r
2076 /* [HGM] make sure board size is acceptable */
\r
2077 if(appData.NrFiles > BOARD_SIZE ||
\r
2078 appData.NrRanks > BOARD_SIZE )
\r
2079 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2081 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2082 * with options from the command line, we now make an even higher priority
\r
2083 * overrule by WB options attached to the engine command line. This so that
\r
2084 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2087 if(appData.firstChessProgram != NULL) {
\r
2088 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2089 static char *f = "first";
\r
2090 char buf[MSG_SIZ], *q = buf;
\r
2091 if(p != NULL) { // engine command line contains WinBoard options
\r
2092 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2093 ParseArgs(StringGet, &q);
\r
2094 p[-1] = 0; // cut them offengine command line
\r
2097 // now do same for second chess program
\r
2098 if(appData.secondChessProgram != NULL) {
\r
2099 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2100 static char *s = "second";
\r
2101 char buf[MSG_SIZ], *q = buf;
\r
2102 if(p != NULL) { // engine command line contains WinBoard options
\r
2103 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2104 ParseArgs(StringGet, &q);
\r
2105 p[-1] = 0; // cut them offengine command line
\r
2110 /* Propagate options that affect others */
\r
2111 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2112 if (appData.icsActive || appData.noChessProgram) {
\r
2113 chessProgram = FALSE; /* not local chess program mode */
\r
2116 /* Open startup dialog if needed */
\r
2117 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2118 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2119 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2120 *appData.secondChessProgram == NULLCHAR))) {
\r
2123 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2124 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2125 FreeProcInstance(lpProc);
\r
2128 /* Make sure save files land in the right (?) directory */
\r
2129 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2130 appData.saveGameFile = strdup(buf);
\r
2132 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2133 appData.savePositionFile = strdup(buf);
\r
2136 /* Finish initialization for fonts and sounds */
\r
2137 for (i=0; i<NUM_FONTS; i++) {
\r
2138 for (j=0; j<NUM_SIZES; j++) {
\r
2139 CreateFontInMF(font[j][i]);
\r
2142 /* xboard, and older WinBoards, controlled the move sound with the
\r
2143 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2144 always turn the option on (so that the backend will call us),
\r
2145 then let the user turn the sound off by setting it to silence if
\r
2146 desired. To accommodate old winboard.ini files saved by old
\r
2147 versions of WinBoard, we also turn off the sound if the option
\r
2148 was initially set to false. */
\r
2149 if (!appData.ringBellAfterMoves) {
\r
2150 sounds[(int)SoundMove].name = strdup("");
\r
2151 appData.ringBellAfterMoves = TRUE;
\r
2153 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2154 SetCurrentDirectory(installDir);
\r
2156 SetCurrentDirectory(currDir);
\r
2158 p = icsTextMenuString;
\r
2159 if (p[0] == '@') {
\r
2160 FILE* f = fopen(p + 1, "r");
\r
2162 DisplayFatalError(p + 1, errno, 2);
\r
2165 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2167 buf[i] = NULLCHAR;
\r
2170 ParseIcsTextMenu(strdup(p));
\r
2177 HMENU hmenu = GetMenu(hwndMain);
\r
2179 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2180 MF_BYCOMMAND|((appData.icsActive &&
\r
2181 *appData.icsCommPort != NULLCHAR) ?
\r
2182 MF_ENABLED : MF_GRAYED));
\r
2183 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2184 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2185 MF_CHECKED : MF_UNCHECKED));
\r
2190 SaveSettings(char* name)
\r
2193 ArgDescriptor *ad;
\r
2194 WINDOWPLACEMENT wp;
\r
2195 char dir[MSG_SIZ];
\r
2197 if (!hwndMain) return;
\r
2199 GetCurrentDirectory(MSG_SIZ, dir);
\r
2200 SetCurrentDirectory(installDir);
\r
2201 f = fopen(name, "w");
\r
2202 SetCurrentDirectory(dir);
\r
2204 DisplayError(name, errno);
\r
2207 fprintf(f, ";\n");
\r
2208 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2209 fprintf(f, ";\n");
\r
2210 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2211 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2212 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2213 fprintf(f, ";\n");
\r
2215 wp.length = sizeof(WINDOWPLACEMENT);
\r
2216 GetWindowPlacement(hwndMain, &wp);
\r
2217 boardX = wp.rcNormalPosition.left;
\r
2218 boardY = wp.rcNormalPosition.top;
\r
2220 if (hwndConsole) {
\r
2221 GetWindowPlacement(hwndConsole, &wp);
\r
2222 wpConsole.x = wp.rcNormalPosition.left;
\r
2223 wpConsole.y = wp.rcNormalPosition.top;
\r
2224 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2225 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2228 if (analysisDialog) {
\r
2229 GetWindowPlacement(analysisDialog, &wp);
\r
2230 analysisX = wp.rcNormalPosition.left;
\r
2231 analysisY = wp.rcNormalPosition.top;
\r
2232 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2233 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2236 if (commentDialog) {
\r
2237 GetWindowPlacement(commentDialog, &wp);
\r
2238 commentX = wp.rcNormalPosition.left;
\r
2239 commentY = wp.rcNormalPosition.top;
\r
2240 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2241 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2244 if (editTagsDialog) {
\r
2245 GetWindowPlacement(editTagsDialog, &wp);
\r
2246 editTagsX = wp.rcNormalPosition.left;
\r
2247 editTagsY = wp.rcNormalPosition.top;
\r
2248 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2249 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2252 if (gameListDialog) {
\r
2253 GetWindowPlacement(gameListDialog, &wp);
\r
2254 wpGameList.x = wp.rcNormalPosition.left;
\r
2255 wpGameList.y = wp.rcNormalPosition.top;
\r
2256 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2257 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2260 /* [AS] Move history */
\r
2261 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2263 if( moveHistoryDialog ) {
\r
2264 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2265 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2266 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2267 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2268 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2271 /* [AS] Eval graph */
\r
2272 wpEvalGraph.visible = EvalGraphIsUp();
\r
2274 if( evalGraphDialog ) {
\r
2275 GetWindowPlacement(evalGraphDialog, &wp);
\r
2276 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2277 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2278 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2279 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2282 /* [AS] Engine output */
\r
2283 wpEngineOutput.visible = EngineOutputIsUp();
\r
2285 if( engineOutputDialog ) {
\r
2286 GetWindowPlacement(engineOutputDialog, &wp);
\r
2287 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2288 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2289 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2290 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2293 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2294 if (!ad->save) continue;
\r
2295 switch (ad->argType) {
\r
2298 char *p = *(char **)ad->argLoc;
\r
2299 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2300 /* Quote multiline values or \-containing values
\r
2301 with { } if possible */
\r
2302 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2304 /* Else quote with " " */
\r
2305 fprintf(f, "/%s=\"", ad->argName);
\r
2307 if (*p == '\n') fprintf(f, "\n");
\r
2308 else if (*p == '\r') fprintf(f, "\\r");
\r
2309 else if (*p == '\t') fprintf(f, "\\t");
\r
2310 else if (*p == '\b') fprintf(f, "\\b");
\r
2311 else if (*p == '\f') fprintf(f, "\\f");
\r
2312 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2313 else if (*p == '\"') fprintf(f, "\\\"");
\r
2314 else if (*p == '\\') fprintf(f, "\\\\");
\r
2318 fprintf(f, "\"\n");
\r
2324 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2327 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2330 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2333 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2336 fprintf(f, "/%s=%s\n", ad->argName,
\r
2337 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2340 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2343 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2347 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2348 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2349 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2354 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2355 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2356 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2357 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2358 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2359 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2360 (ta->effects) ? " " : "",
\r
2361 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2365 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2366 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2368 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2371 case ArgBoardSize:
\r
2372 fprintf(f, "/%s=%s\n", ad->argName,
\r
2373 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2378 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2379 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2380 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2381 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2382 ad->argName, mfp->faceName, mfp->pointSize,
\r
2383 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2384 mfp->bold ? "b" : "",
\r
2385 mfp->italic ? "i" : "",
\r
2386 mfp->underline ? "u" : "",
\r
2387 mfp->strikeout ? "s" : "");
\r
2391 case ArgCommSettings:
\r
2392 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2394 case ArgSettingsFilename: ;
\r
2402 /*---------------------------------------------------------------------------*\
\r
2404 * GDI board drawing routines
\r
2406 \*---------------------------------------------------------------------------*/
\r
2408 /* [AS] Draw square using background texture */
\r
2409 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2414 return; /* Should never happen! */
\r
2417 SetGraphicsMode( dst, GM_ADVANCED );
\r
2424 /* X reflection */
\r
2429 x.eDx = (FLOAT) dw + dx - 1;
\r
2432 SetWorldTransform( dst, &x );
\r
2435 /* Y reflection */
\r
2441 x.eDy = (FLOAT) dh + dy - 1;
\r
2443 SetWorldTransform( dst, &x );
\r
2451 x.eDx = (FLOAT) dx;
\r
2452 x.eDy = (FLOAT) dy;
\r
2455 SetWorldTransform( dst, &x );
\r
2459 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2467 SetWorldTransform( dst, &x );
\r
2469 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2472 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2474 PM_WP = (int) WhitePawn,
\r
2475 PM_WN = (int) WhiteKnight,
\r
2476 PM_WB = (int) WhiteBishop,
\r
2477 PM_WR = (int) WhiteRook,
\r
2478 PM_WQ = (int) WhiteQueen,
\r
2479 PM_WF = (int) WhiteFerz,
\r
2480 PM_WW = (int) WhiteWazir,
\r
2481 PM_WE = (int) WhiteAlfil,
\r
2482 PM_WM = (int) WhiteMan,
\r
2483 PM_WO = (int) WhiteCannon,
\r
2484 PM_WU = (int) WhiteUnicorn,
\r
2485 PM_WH = (int) WhiteNightrider,
\r
2486 PM_WA = (int) WhiteAngel,
\r
2487 PM_WC = (int) WhiteMarshall,
\r
2488 PM_WAB = (int) WhiteCardinal,
\r
2489 PM_WD = (int) WhiteDragon,
\r
2490 PM_WL = (int) WhiteLance,
\r
2491 PM_WS = (int) WhiteCobra,
\r
2492 PM_WV = (int) WhiteFalcon,
\r
2493 PM_WSG = (int) WhiteSilver,
\r
2494 PM_WG = (int) WhiteGrasshopper,
\r
2495 PM_WK = (int) WhiteKing,
\r
2496 PM_BP = (int) BlackPawn,
\r
2497 PM_BN = (int) BlackKnight,
\r
2498 PM_BB = (int) BlackBishop,
\r
2499 PM_BR = (int) BlackRook,
\r
2500 PM_BQ = (int) BlackQueen,
\r
2501 PM_BF = (int) BlackFerz,
\r
2502 PM_BW = (int) BlackWazir,
\r
2503 PM_BE = (int) BlackAlfil,
\r
2504 PM_BM = (int) BlackMan,
\r
2505 PM_BO = (int) BlackCannon,
\r
2506 PM_BU = (int) BlackUnicorn,
\r
2507 PM_BH = (int) BlackNightrider,
\r
2508 PM_BA = (int) BlackAngel,
\r
2509 PM_BC = (int) BlackMarshall,
\r
2510 PM_BG = (int) BlackGrasshopper,
\r
2511 PM_BAB = (int) BlackCardinal,
\r
2512 PM_BD = (int) BlackDragon,
\r
2513 PM_BL = (int) BlackLance,
\r
2514 PM_BS = (int) BlackCobra,
\r
2515 PM_BV = (int) BlackFalcon,
\r
2516 PM_BSG = (int) BlackSilver,
\r
2517 PM_BK = (int) BlackKing
\r
2520 static HFONT hPieceFont = NULL;
\r
2521 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2522 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2523 static int fontBitmapSquareSize = 0;
\r
2524 static char pieceToFontChar[(int) EmptySquare] =
\r
2525 { 'p', 'n', 'b', 'r', 'q',
\r
2526 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2527 'k', 'o', 'm', 'v', 't', 'w',
\r
2528 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2531 extern BOOL SetCharTable( char *table, const char * map );
\r
2532 /* [HGM] moved to backend.c */
\r
2534 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2537 BYTE r1 = GetRValue( color );
\r
2538 BYTE g1 = GetGValue( color );
\r
2539 BYTE b1 = GetBValue( color );
\r
2545 /* Create a uniform background first */
\r
2546 hbrush = CreateSolidBrush( color );
\r
2547 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2548 FillRect( hdc, &rc, hbrush );
\r
2549 DeleteObject( hbrush );
\r
2552 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2553 int steps = squareSize / 2;
\r
2556 for( i=0; i<steps; i++ ) {
\r
2557 BYTE r = r1 - (r1-r2) * i / steps;
\r
2558 BYTE g = g1 - (g1-g2) * i / steps;
\r
2559 BYTE b = b1 - (b1-b2) * i / steps;
\r
2561 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2562 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2563 FillRect( hdc, &rc, hbrush );
\r
2564 DeleteObject(hbrush);
\r
2567 else if( mode == 2 ) {
\r
2568 /* Diagonal gradient, good more or less for every piece */
\r
2569 POINT triangle[3];
\r
2570 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2571 HBRUSH hbrush_old;
\r
2572 int steps = squareSize;
\r
2575 triangle[0].x = squareSize - steps;
\r
2576 triangle[0].y = squareSize;
\r
2577 triangle[1].x = squareSize;
\r
2578 triangle[1].y = squareSize;
\r
2579 triangle[2].x = squareSize;
\r
2580 triangle[2].y = squareSize - steps;
\r
2582 for( i=0; i<steps; i++ ) {
\r
2583 BYTE r = r1 - (r1-r2) * i / steps;
\r
2584 BYTE g = g1 - (g1-g2) * i / steps;
\r
2585 BYTE b = b1 - (b1-b2) * i / steps;
\r
2587 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2588 hbrush_old = SelectObject( hdc, hbrush );
\r
2589 Polygon( hdc, triangle, 3 );
\r
2590 SelectObject( hdc, hbrush_old );
\r
2591 DeleteObject(hbrush);
\r
2596 SelectObject( hdc, hpen );
\r
2601 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2602 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2603 piece: follow the steps as explained below.
\r
2605 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2609 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2613 int backColor = whitePieceColor;
\r
2614 int foreColor = blackPieceColor;
\r
2616 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2617 backColor = appData.fontBackColorWhite;
\r
2618 foreColor = appData.fontForeColorWhite;
\r
2620 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2621 backColor = appData.fontBackColorBlack;
\r
2622 foreColor = appData.fontForeColorBlack;
\r
2626 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2628 hbm_old = SelectObject( hdc, hbm );
\r
2632 rc.right = squareSize;
\r
2633 rc.bottom = squareSize;
\r
2635 /* Step 1: background is now black */
\r
2636 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2638 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2640 pt.x = (squareSize - sz.cx) / 2;
\r
2641 pt.y = (squareSize - sz.cy) / 2;
\r
2643 SetBkMode( hdc, TRANSPARENT );
\r
2644 SetTextColor( hdc, chroma );
\r
2645 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2646 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2648 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2649 /* Step 3: the area outside the piece is filled with white */
\r
2650 // FloodFill( hdc, 0, 0, chroma );
\r
2651 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2652 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2653 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2654 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2655 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2657 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2658 but if the start point is not inside the piece we're lost!
\r
2659 There should be a better way to do this... if we could create a region or path
\r
2660 from the fill operation we would be fine for example.
\r
2662 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2663 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2665 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2666 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2667 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2669 SelectObject( dc2, bm2 );
\r
2670 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2671 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2672 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2673 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2674 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2677 DeleteObject( bm2 );
\r
2680 SetTextColor( hdc, 0 );
\r
2682 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2683 draw the piece again in black for safety.
\r
2685 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2687 SelectObject( hdc, hbm_old );
\r
2689 if( hPieceMask[index] != NULL ) {
\r
2690 DeleteObject( hPieceMask[index] );
\r
2693 hPieceMask[index] = hbm;
\r
2696 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2698 SelectObject( hdc, hbm );
\r
2701 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2702 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2703 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2705 SelectObject( dc1, hPieceMask[index] );
\r
2706 SelectObject( dc2, bm2 );
\r
2707 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2708 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2711 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2712 the piece background and deletes (makes transparent) the rest.
\r
2713 Thanks to that mask, we are free to paint the background with the greates
\r
2714 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2715 We use this, to make gradients and give the pieces a "roundish" look.
\r
2717 SetPieceBackground( hdc, backColor, 2 );
\r
2718 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2722 DeleteObject( bm2 );
\r
2725 SetTextColor( hdc, foreColor );
\r
2726 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2728 SelectObject( hdc, hbm_old );
\r
2730 if( hPieceFace[index] != NULL ) {
\r
2731 DeleteObject( hPieceFace[index] );
\r
2734 hPieceFace[index] = hbm;
\r
2737 static int TranslatePieceToFontPiece( int piece )
\r
2767 case BlackMarshall:
\r
2771 case BlackNightrider:
\r
2777 case BlackUnicorn:
\r
2781 case BlackGrasshopper:
\r
2793 case BlackCardinal:
\r
2800 case WhiteMarshall:
\r
2804 case WhiteNightrider:
\r
2810 case WhiteUnicorn:
\r
2814 case WhiteGrasshopper:
\r
2826 case WhiteCardinal:
\r
2835 void CreatePiecesFromFont()
\r
2838 HDC hdc_window = NULL;
\r
2844 if( fontBitmapSquareSize < 0 ) {
\r
2845 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2849 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2850 fontBitmapSquareSize = -1;
\r
2854 if( fontBitmapSquareSize != squareSize ) {
\r
2855 hdc_window = GetDC( hwndMain );
\r
2856 hdc = CreateCompatibleDC( hdc_window );
\r
2858 if( hPieceFont != NULL ) {
\r
2859 DeleteObject( hPieceFont );
\r
2862 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2863 hPieceMask[i] = NULL;
\r
2864 hPieceFace[i] = NULL;
\r
2870 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2871 fontHeight = appData.fontPieceSize;
\r
2874 fontHeight = (fontHeight * squareSize) / 100;
\r
2876 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2878 lf.lfEscapement = 0;
\r
2879 lf.lfOrientation = 0;
\r
2880 lf.lfWeight = FW_NORMAL;
\r
2882 lf.lfUnderline = 0;
\r
2883 lf.lfStrikeOut = 0;
\r
2884 lf.lfCharSet = DEFAULT_CHARSET;
\r
2885 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2886 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2887 lf.lfQuality = PROOF_QUALITY;
\r
2888 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2889 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2890 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2892 hPieceFont = CreateFontIndirect( &lf );
\r
2894 if( hPieceFont == NULL ) {
\r
2895 fontBitmapSquareSize = -2;
\r
2898 /* Setup font-to-piece character table */
\r
2899 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2900 /* No (or wrong) global settings, try to detect the font */
\r
2901 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2903 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2905 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2906 /* DiagramTT* family */
\r
2907 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2909 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2910 /* Fairy symbols */
\r
2911 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2913 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2914 /* Good Companion (Some characters get warped as literal :-( */
\r
2915 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2916 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2917 SetCharTable(pieceToFontChar, s);
\r
2920 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2921 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2925 /* Create bitmaps */
\r
2926 hfont_old = SelectObject( hdc, hPieceFont );
\r
2928 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2929 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2930 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2931 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2932 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2933 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2934 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2935 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2936 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2937 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2938 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2939 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2941 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2942 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2943 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2944 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2945 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2946 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2947 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2948 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2949 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2950 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2951 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
2952 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
2953 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
2954 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
2955 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
2956 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
2957 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2958 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2959 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2960 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2961 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2962 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2963 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2964 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2965 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2966 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2967 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
2968 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
2969 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
2970 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
2971 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
2972 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
2974 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2975 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2976 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2978 SelectObject( hdc, hfont_old );
\r
2980 fontBitmapSquareSize = squareSize;
\r
2984 if( hdc != NULL ) {
\r
2988 if( hdc_window != NULL ) {
\r
2989 ReleaseDC( hwndMain, hdc_window );
\r
2994 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2998 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2999 if (gameInfo.event &&
\r
3000 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3001 strcmp(name, "k80s") == 0) {
\r
3002 strcpy(name, "tim");
\r
3004 return LoadBitmap(hinst, name);
\r
3008 /* Insert a color into the program's logical palette
\r
3009 structure. This code assumes the given color is
\r
3010 the result of the RGB or PALETTERGB macro, and it
\r
3011 knows how those macros work (which is documented).
\r
3014 InsertInPalette(COLORREF color)
\r
3016 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3018 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3019 DisplayFatalError("Too many colors", 0, 1);
\r
3020 pLogPal->palNumEntries--;
\r
3024 pe->peFlags = (char) 0;
\r
3025 pe->peRed = (char) (0xFF & color);
\r
3026 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3027 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3033 InitDrawingColors()
\r
3035 if (pLogPal == NULL) {
\r
3036 /* Allocate enough memory for a logical palette with
\r
3037 * PALETTESIZE entries and set the size and version fields
\r
3038 * of the logical palette structure.
\r
3040 pLogPal = (NPLOGPALETTE)
\r
3041 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3042 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3043 pLogPal->palVersion = 0x300;
\r
3045 pLogPal->palNumEntries = 0;
\r
3047 InsertInPalette(lightSquareColor);
\r
3048 InsertInPalette(darkSquareColor);
\r
3049 InsertInPalette(whitePieceColor);
\r
3050 InsertInPalette(blackPieceColor);
\r
3051 InsertInPalette(highlightSquareColor);
\r
3052 InsertInPalette(premoveHighlightColor);
\r
3054 /* create a logical color palette according the information
\r
3055 * in the LOGPALETTE structure.
\r
3057 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3059 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3060 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3061 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3062 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3063 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3064 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3065 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3066 /* [AS] Force rendering of the font-based pieces */
\r
3067 if( fontBitmapSquareSize > 0 ) {
\r
3068 fontBitmapSquareSize = 0;
\r
3074 BoardWidth(int boardSize, int n)
\r
3075 { /* [HGM] argument n added to allow different width and height */
\r
3076 int lineGap = sizeInfo[boardSize].lineGap;
\r
3078 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3079 lineGap = appData.overrideLineGap;
\r
3082 return (n + 1) * lineGap +
\r
3083 n * sizeInfo[boardSize].squareSize;
\r
3086 /* Respond to board resize by dragging edge */
\r
3088 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3090 BoardSize newSize = NUM_SIZES - 1;
\r
3091 static int recurse = 0;
\r
3092 if (IsIconic(hwndMain)) return;
\r
3093 if (recurse > 0) return;
\r
3095 while (newSize > 0) {
\r
3096 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3097 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3098 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3101 boardSize = newSize;
\r
3102 InitDrawingSizes(boardSize, flags);
\r
3109 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3111 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3112 ChessSquare piece;
\r
3113 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3115 SIZE clockSize, messageSize;
\r
3117 char buf[MSG_SIZ];
\r
3119 HMENU hmenu = GetMenu(hwndMain);
\r
3120 RECT crect, wrect, oldRect;
\r
3122 LOGBRUSH logbrush;
\r
3124 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3125 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3127 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3128 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3130 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3131 oldRect.top = boardY;
\r
3132 oldRect.right = boardX + winWidth;
\r
3133 oldRect.bottom = boardY + winHeight;
\r
3135 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3136 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3137 squareSize = sizeInfo[boardSize].squareSize;
\r
3138 lineGap = sizeInfo[boardSize].lineGap;
\r
3139 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3141 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3142 lineGap = appData.overrideLineGap;
\r
3145 if (tinyLayout != oldTinyLayout) {
\r
3146 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3148 style &= ~WS_SYSMENU;
\r
3149 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3150 "&Minimize\tCtrl+F4");
\r
3152 style |= WS_SYSMENU;
\r
3153 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3155 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3157 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3158 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3159 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3161 DrawMenuBar(hwndMain);
\r
3164 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3165 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3167 /* Get text area sizes */
\r
3168 hdc = GetDC(hwndMain);
\r
3169 if (appData.clockMode) {
\r
3170 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3172 sprintf(buf, "White");
\r
3174 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3175 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3176 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3177 str = "We only care about the height here";
\r
3178 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3179 SelectObject(hdc, oldFont);
\r
3180 ReleaseDC(hwndMain, hdc);
\r
3182 /* Compute where everything goes */
\r
3183 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3184 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3185 logoHeight = 2*clockSize.cy;
\r
3186 leftLogoRect.left = OUTER_MARGIN;
\r
3187 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3188 leftLogoRect.top = OUTER_MARGIN;
\r
3189 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3191 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3192 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3193 rightLogoRect.top = OUTER_MARGIN;
\r
3194 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3197 whiteRect.left = leftLogoRect.right;
\r
3198 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3199 whiteRect.top = OUTER_MARGIN;
\r
3200 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3202 blackRect.right = rightLogoRect.left;
\r
3203 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3204 blackRect.top = whiteRect.top;
\r
3205 blackRect.bottom = whiteRect.bottom;
\r
3207 whiteRect.left = OUTER_MARGIN;
\r
3208 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3209 whiteRect.top = OUTER_MARGIN;
\r
3210 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3212 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3213 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3214 blackRect.top = whiteRect.top;
\r
3215 blackRect.bottom = whiteRect.bottom;
\r
3218 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3219 if (appData.showButtonBar) {
\r
3220 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3221 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3223 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3225 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3226 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3228 boardRect.left = OUTER_MARGIN;
\r
3229 boardRect.right = boardRect.left + boardWidth;
\r
3230 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3231 boardRect.bottom = boardRect.top + boardHeight;
\r
3233 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3234 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3235 oldBoardSize = boardSize;
\r
3236 oldTinyLayout = tinyLayout;
\r
3237 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3238 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3239 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3240 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3241 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3242 winHeight = winH; // without disturbing window attachments
\r
3243 GetWindowRect(hwndMain, &wrect);
\r
3244 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3245 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3247 // [HGM] placement: let attached windows follow size change.
\r
3248 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3249 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3250 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3251 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3252 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3254 /* compensate if menu bar wrapped */
\r
3255 GetClientRect(hwndMain, &crect);
\r
3256 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3257 winHeight += offby;
\r
3259 case WMSZ_TOPLEFT:
\r
3260 SetWindowPos(hwndMain, NULL,
\r
3261 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3262 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3265 case WMSZ_TOPRIGHT:
\r
3267 SetWindowPos(hwndMain, NULL,
\r
3268 wrect.left, wrect.bottom - winHeight,
\r
3269 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3272 case WMSZ_BOTTOMLEFT:
\r
3274 SetWindowPos(hwndMain, NULL,
\r
3275 wrect.right - winWidth, wrect.top,
\r
3276 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3279 case WMSZ_BOTTOMRIGHT:
\r
3283 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3284 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3289 for (i = 0; i < N_BUTTONS; i++) {
\r
3290 if (buttonDesc[i].hwnd != NULL) {
\r
3291 DestroyWindow(buttonDesc[i].hwnd);
\r
3292 buttonDesc[i].hwnd = NULL;
\r
3294 if (appData.showButtonBar) {
\r
3295 buttonDesc[i].hwnd =
\r
3296 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3297 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3298 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3299 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3300 (HMENU) buttonDesc[i].id,
\r
3301 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3303 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3304 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3305 MAKELPARAM(FALSE, 0));
\r
3307 if (buttonDesc[i].id == IDM_Pause)
\r
3308 hwndPause = buttonDesc[i].hwnd;
\r
3309 buttonDesc[i].wndproc = (WNDPROC)
\r
3310 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3313 if (gridPen != NULL) DeleteObject(gridPen);
\r
3314 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3315 if (premovePen != NULL) DeleteObject(premovePen);
\r
3316 if (lineGap != 0) {
\r
3317 logbrush.lbStyle = BS_SOLID;
\r
3318 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3320 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3321 lineGap, &logbrush, 0, NULL);
\r
3322 logbrush.lbColor = highlightSquareColor;
\r
3324 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3325 lineGap, &logbrush, 0, NULL);
\r
3327 logbrush.lbColor = premoveHighlightColor;
\r
3329 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3330 lineGap, &logbrush, 0, NULL);
\r
3332 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3333 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3334 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3335 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3336 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3337 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3338 BOARD_WIDTH * (squareSize + lineGap);
\r
3339 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3341 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3342 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3343 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3344 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3345 lineGap / 2 + (i * (squareSize + lineGap));
\r
3346 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3347 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3348 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3352 /* [HGM] Licensing requirement */
\r
3354 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3357 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3359 GothicPopUp( "", VariantNormal);
\r
3362 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3364 /* Load piece bitmaps for this board size */
\r
3365 for (i=0; i<=2; i++) {
\r
3366 for (piece = WhitePawn;
\r
3367 (int) piece < (int) BlackPawn;
\r
3368 piece = (ChessSquare) ((int) piece + 1)) {
\r
3369 if (pieceBitmap[i][piece] != NULL)
\r
3370 DeleteObject(pieceBitmap[i][piece]);
\r
3374 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3375 // Orthodox Chess pieces
\r
3376 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3377 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3378 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3379 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3380 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3381 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3382 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3383 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3384 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3385 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3386 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3387 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3388 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3389 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3390 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3391 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3392 // in Shogi, Hijack the unused Queen for Lance
\r
3393 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3394 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3395 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3397 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3398 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3399 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3402 if(squareSize <= 72 && squareSize >= 33) {
\r
3403 /* A & C are available in most sizes now */
\r
3404 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3405 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3406 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3407 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3408 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3409 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3410 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3411 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3412 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3413 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3414 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3415 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3416 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3417 } else { // Smirf-like
\r
3418 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3419 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3420 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3422 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3423 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3424 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3425 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3426 } else { // WinBoard standard
\r
3427 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3428 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3429 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3434 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3435 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3436 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3437 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3438 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3439 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3440 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3441 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3442 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3443 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3444 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3445 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3446 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3447 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3448 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3449 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3450 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3451 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3452 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3453 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3454 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3455 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3456 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3457 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3458 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3459 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3460 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3461 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3462 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3463 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3464 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3466 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3467 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3468 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3469 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3470 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3471 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3472 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3473 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3474 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3475 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3476 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3477 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3478 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3480 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3481 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3482 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3483 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3484 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3485 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3486 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3487 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3488 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3489 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3490 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3491 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3494 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3495 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3496 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3497 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3498 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3499 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3500 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3501 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3502 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3503 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3504 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3505 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3506 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3507 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3508 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3512 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3513 /* special Shogi support in this size */
\r
3514 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3515 for (piece = WhitePawn;
\r
3516 (int) piece < (int) BlackPawn;
\r
3517 piece = (ChessSquare) ((int) piece + 1)) {
\r
3518 if (pieceBitmap[i][piece] != NULL)
\r
3519 DeleteObject(pieceBitmap[i][piece]);
\r
3522 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3523 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3524 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3525 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3526 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3527 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3528 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3529 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3530 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3531 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3532 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3533 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3534 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3535 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3536 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3537 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3538 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3539 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3540 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3541 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3542 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3543 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3544 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3545 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3546 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3547 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3548 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3549 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3550 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3551 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3552 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3553 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3554 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3555 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3556 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3557 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3558 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3559 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3560 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3561 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3562 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3563 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3569 PieceBitmap(ChessSquare p, int kind)
\r
3571 if ((int) p >= (int) BlackPawn)
\r
3572 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3574 return pieceBitmap[kind][(int) p];
\r
3577 /***************************************************************/
\r
3579 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3580 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3582 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3583 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3587 SquareToPos(int row, int column, int * x, int * y)
\r
3590 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3591 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3593 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3594 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3599 DrawCoordsOnDC(HDC hdc)
\r
3601 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
3602 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
3603 char str[2] = { NULLCHAR, NULLCHAR };
\r
3604 int oldMode, oldAlign, x, y, start, i;
\r
3608 if (!appData.showCoords)
\r
3611 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3613 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3614 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3615 oldAlign = GetTextAlign(hdc);
\r
3616 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3618 y = boardRect.top + lineGap;
\r
3619 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3621 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3622 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3623 str[0] = files[start + i];
\r
3624 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3625 y += squareSize + lineGap;
\r
3628 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3630 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3631 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3632 str[0] = ranks[start + i];
\r
3633 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3634 x += squareSize + lineGap;
\r
3637 SelectObject(hdc, oldBrush);
\r
3638 SetBkMode(hdc, oldMode);
\r
3639 SetTextAlign(hdc, oldAlign);
\r
3640 SelectObject(hdc, oldFont);
\r
3644 DrawGridOnDC(HDC hdc)
\r
3648 if (lineGap != 0) {
\r
3649 oldPen = SelectObject(hdc, gridPen);
\r
3650 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3651 SelectObject(hdc, oldPen);
\r
3655 #define HIGHLIGHT_PEN 0
\r
3656 #define PREMOVE_PEN 1
\r
3659 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3662 HPEN oldPen, hPen;
\r
3663 if (lineGap == 0) return;
\r
3665 x1 = boardRect.left +
\r
3666 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3667 y1 = boardRect.top +
\r
3668 lineGap/2 + y * (squareSize + lineGap);
\r
3670 x1 = boardRect.left +
\r
3671 lineGap/2 + x * (squareSize + lineGap);
\r
3672 y1 = boardRect.top +
\r
3673 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3675 hPen = pen ? premovePen : highlightPen;
\r
3676 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3677 MoveToEx(hdc, x1, y1, NULL);
\r
3678 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3679 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3680 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3681 LineTo(hdc, x1, y1);
\r
3682 SelectObject(hdc, oldPen);
\r
3686 DrawHighlightsOnDC(HDC hdc)
\r
3689 for (i=0; i<2; i++) {
\r
3690 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3691 DrawHighlightOnDC(hdc, TRUE,
\r
3692 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3695 for (i=0; i<2; i++) {
\r
3696 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3697 premoveHighlightInfo.sq[i].y >= 0) {
\r
3698 DrawHighlightOnDC(hdc, TRUE,
\r
3699 premoveHighlightInfo.sq[i].x,
\r
3700 premoveHighlightInfo.sq[i].y,
\r
3706 /* Note: sqcolor is used only in monoMode */
\r
3707 /* Note that this code is largely duplicated in woptions.c,
\r
3708 function DrawSampleSquare, so that needs to be updated too */
\r
3710 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3712 HBITMAP oldBitmap;
\r
3716 if (appData.blindfold) return;
\r
3718 /* [AS] Use font-based pieces if needed */
\r
3719 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3720 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3721 CreatePiecesFromFont();
\r
3723 if( fontBitmapSquareSize == squareSize ) {
\r
3724 int index = TranslatePieceToFontPiece(piece);
\r
3726 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3730 squareSize, squareSize,
\r
3735 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3739 squareSize, squareSize,
\r
3748 if (appData.monoMode) {
\r
3749 SelectObject(tmphdc, PieceBitmap(piece,
\r
3750 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3751 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3752 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3754 tmpSize = squareSize;
\r
3756 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3757 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3758 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3759 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3760 x += (squareSize - minorSize)>>1;
\r
3761 y += squareSize - minorSize - 2;
\r
3762 tmpSize = minorSize;
\r
3764 if (color || appData.allWhite ) {
\r
3765 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3767 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3768 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3769 if(appData.upsideDown && color==flipView)
\r
3770 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3772 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3774 /* Use black piece color for outline of white pieces */
\r
3775 /* Not sure this looks really good (though xboard does it).
\r
3776 Maybe better to have another selectable color, default black */
\r
3777 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3778 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3779 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3781 /* Use black for outline of white pieces */
\r
3782 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3783 if(appData.upsideDown && color==flipView)
\r
3784 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3786 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3790 /* Use white piece color for details of black pieces */
\r
3791 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3792 WHITE_PIECE ones aren't always the right shape. */
\r
3793 /* Not sure this looks really good (though xboard does it).
\r
3794 Maybe better to have another selectable color, default medium gray? */
\r
3795 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3796 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3797 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3798 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3799 SelectObject(hdc, blackPieceBrush);
\r
3800 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3802 /* Use square color for details of black pieces */
\r
3803 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3804 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3805 if(appData.upsideDown && !flipView)
\r
3806 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3808 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3811 SelectObject(hdc, oldBrush);
\r
3812 SelectObject(tmphdc, oldBitmap);
\r
3816 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3817 int GetBackTextureMode( int algo )
\r
3819 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3823 case BACK_TEXTURE_MODE_PLAIN:
\r
3824 result = 1; /* Always use identity map */
\r
3826 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3827 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3835 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3836 to handle redraws cleanly (as random numbers would always be different).
\r
3838 VOID RebuildTextureSquareInfo()
\r
3848 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3850 if( liteBackTexture != NULL ) {
\r
3851 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3852 lite_w = bi.bmWidth;
\r
3853 lite_h = bi.bmHeight;
\r
3857 if( darkBackTexture != NULL ) {
\r
3858 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3859 dark_w = bi.bmWidth;
\r
3860 dark_h = bi.bmHeight;
\r
3864 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3865 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3866 if( (col + row) & 1 ) {
\r
3868 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3869 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3870 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3871 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3876 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3877 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3878 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3879 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3886 /* [AS] Arrow highlighting support */
\r
3888 static int A_WIDTH = 5; /* Width of arrow body */
\r
3890 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3891 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3893 static double Sqr( double x )
\r
3898 static int Round( double x )
\r
3900 return (int) (x + 0.5);
\r
3903 /* Draw an arrow between two points using current settings */
\r
3904 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3907 double dx, dy, j, k, x, y;
\r
3909 if( d_x == s_x ) {
\r
3910 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3912 arrow[0].x = s_x + A_WIDTH;
\r
3915 arrow[1].x = s_x + A_WIDTH;
\r
3916 arrow[1].y = d_y - h;
\r
3918 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3919 arrow[2].y = d_y - h;
\r
3924 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3925 arrow[4].y = d_y - h;
\r
3927 arrow[5].x = s_x - A_WIDTH;
\r
3928 arrow[5].y = d_y - h;
\r
3930 arrow[6].x = s_x - A_WIDTH;
\r
3933 else if( d_y == s_y ) {
\r
3934 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3937 arrow[0].y = s_y + A_WIDTH;
\r
3939 arrow[1].x = d_x - w;
\r
3940 arrow[1].y = s_y + A_WIDTH;
\r
3942 arrow[2].x = d_x - w;
\r
3943 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3948 arrow[4].x = d_x - w;
\r
3949 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3951 arrow[5].x = d_x - w;
\r
3952 arrow[5].y = s_y - A_WIDTH;
\r
3955 arrow[6].y = s_y - A_WIDTH;
\r
3958 /* [AS] Needed a lot of paper for this! :-) */
\r
3959 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3960 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3962 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3964 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3969 arrow[0].x = Round(x - j);
\r
3970 arrow[0].y = Round(y + j*dx);
\r
3972 arrow[1].x = Round(x + j);
\r
3973 arrow[1].y = Round(y - j*dx);
\r
3976 x = (double) d_x - k;
\r
3977 y = (double) d_y - k*dy;
\r
3980 x = (double) d_x + k;
\r
3981 y = (double) d_y + k*dy;
\r
3984 arrow[2].x = Round(x + j);
\r
3985 arrow[2].y = Round(y - j*dx);
\r
3987 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3988 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3993 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3994 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3996 arrow[6].x = Round(x - j);
\r
3997 arrow[6].y = Round(y + j*dx);
\r
4000 Polygon( hdc, arrow, 7 );
\r
4003 /* [AS] Draw an arrow between two squares */
\r
4004 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4006 int s_x, s_y, d_x, d_y;
\r
4013 if( s_col == d_col && s_row == d_row ) {
\r
4017 /* Get source and destination points */
\r
4018 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4019 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4022 d_y += squareSize / 4;
\r
4024 else if( d_y < s_y ) {
\r
4025 d_y += 3 * squareSize / 4;
\r
4028 d_y += squareSize / 2;
\r
4032 d_x += squareSize / 4;
\r
4034 else if( d_x < s_x ) {
\r
4035 d_x += 3 * squareSize / 4;
\r
4038 d_x += squareSize / 2;
\r
4041 s_x += squareSize / 2;
\r
4042 s_y += squareSize / 2;
\r
4044 /* Adjust width */
\r
4045 A_WIDTH = squareSize / 14;
\r
4048 stLB.lbStyle = BS_SOLID;
\r
4049 stLB.lbColor = appData.highlightArrowColor;
\r
4052 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4053 holdpen = SelectObject( hdc, hpen );
\r
4054 hbrush = CreateBrushIndirect( &stLB );
\r
4055 holdbrush = SelectObject( hdc, hbrush );
\r
4057 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4059 SelectObject( hdc, holdpen );
\r
4060 SelectObject( hdc, holdbrush );
\r
4061 DeleteObject( hpen );
\r
4062 DeleteObject( hbrush );
\r
4065 BOOL HasHighlightInfo()
\r
4067 BOOL result = FALSE;
\r
4069 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4070 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4078 BOOL IsDrawArrowEnabled()
\r
4080 BOOL result = FALSE;
\r
4082 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4089 VOID DrawArrowHighlight( HDC hdc )
\r
4091 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4092 DrawArrowBetweenSquares( hdc,
\r
4093 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4094 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4098 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4100 HRGN result = NULL;
\r
4102 if( HasHighlightInfo() ) {
\r
4103 int x1, y1, x2, y2;
\r
4104 int sx, sy, dx, dy;
\r
4106 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4107 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4109 sx = MIN( x1, x2 );
\r
4110 sy = MIN( y1, y2 );
\r
4111 dx = MAX( x1, x2 ) + squareSize;
\r
4112 dy = MAX( y1, y2 ) + squareSize;
\r
4114 result = CreateRectRgn( sx, sy, dx, dy );
\r
4121 Warning: this function modifies the behavior of several other functions.
\r
4123 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4124 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4125 repaint is scattered all over the place, which is not good for features such as
\r
4126 "arrow highlighting" that require a full repaint of the board.
\r
4128 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4129 user interaction, when speed is not so important) but especially to avoid errors
\r
4130 in the displayed graphics.
\r
4132 In such patched places, I always try refer to this function so there is a single
\r
4133 place to maintain knowledge.
\r
4135 To restore the original behavior, just return FALSE unconditionally.
\r
4137 BOOL IsFullRepaintPreferrable()
\r
4139 BOOL result = FALSE;
\r
4141 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4142 /* Arrow may appear on the board */
\r
4150 This function is called by DrawPosition to know whether a full repaint must
\r
4153 Only DrawPosition may directly call this function, which makes use of
\r
4154 some state information. Other function should call DrawPosition specifying
\r
4155 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4157 BOOL DrawPositionNeedsFullRepaint()
\r
4159 BOOL result = FALSE;
\r
4162 Probably a slightly better policy would be to trigger a full repaint
\r
4163 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4164 but animation is fast enough that it's difficult to notice.
\r
4166 if( animInfo.piece == EmptySquare ) {
\r
4167 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4176 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4178 int row, column, x, y, square_color, piece_color;
\r
4179 ChessSquare piece;
\r
4181 HDC texture_hdc = NULL;
\r
4183 /* [AS] Initialize background textures if needed */
\r
4184 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4185 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4186 if( backTextureSquareSize != squareSize
\r
4187 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4188 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4189 backTextureSquareSize = squareSize;
\r
4190 RebuildTextureSquareInfo();
\r
4193 texture_hdc = CreateCompatibleDC( hdc );
\r
4196 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4197 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4199 SquareToPos(row, column, &x, &y);
\r
4201 piece = board[row][column];
\r
4203 square_color = ((column + row) % 2) == 1;
\r
4204 if( gameInfo.variant == VariantXiangqi ) {
\r
4205 square_color = !InPalace(row, column);
\r
4206 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4207 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4209 piece_color = (int) piece < (int) BlackPawn;
\r
4212 /* [HGM] holdings file: light square or black */
\r
4213 if(column == BOARD_LEFT-2) {
\r
4214 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4217 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4221 if(column == BOARD_RGHT + 1 ) {
\r
4222 if( row < gameInfo.holdingsSize )
\r
4225 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4229 if(column == BOARD_LEFT-1 ) /* left align */
\r
4230 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4231 else if( column == BOARD_RGHT) /* right align */
\r
4232 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4234 if (appData.monoMode) {
\r
4235 if (piece == EmptySquare) {
\r
4236 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4237 square_color ? WHITENESS : BLACKNESS);
\r
4239 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4242 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4243 /* [AS] Draw the square using a texture bitmap */
\r
4244 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4245 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4246 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4249 squareSize, squareSize,
\r
4252 backTextureSquareInfo[r][c].mode,
\r
4253 backTextureSquareInfo[r][c].x,
\r
4254 backTextureSquareInfo[r][c].y );
\r
4256 SelectObject( texture_hdc, hbm );
\r
4258 if (piece != EmptySquare) {
\r
4259 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4263 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4265 oldBrush = SelectObject(hdc, brush );
\r
4266 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4267 SelectObject(hdc, oldBrush);
\r
4268 if (piece != EmptySquare)
\r
4269 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4274 if( texture_hdc != NULL ) {
\r
4275 DeleteDC( texture_hdc );
\r
4279 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4280 void fputDW(FILE *f, int x)
\r
4282 fputc(x & 255, f);
\r
4283 fputc(x>>8 & 255, f);
\r
4284 fputc(x>>16 & 255, f);
\r
4285 fputc(x>>24 & 255, f);
\r
4288 #define MAX_CLIPS 200 /* more than enough */
\r
4291 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4293 // HBITMAP bufferBitmap;
\r
4298 int w = 100, h = 50;
\r
4300 if(logo == NULL) return;
\r
4301 // GetClientRect(hwndMain, &Rect);
\r
4302 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4303 // Rect.bottom-Rect.top+1);
\r
4304 tmphdc = CreateCompatibleDC(hdc);
\r
4305 hbm = SelectObject(tmphdc, logo);
\r
4306 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4310 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4311 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4312 SelectObject(tmphdc, hbm);
\r
4317 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4319 static Board lastReq, lastDrawn;
\r
4320 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4321 static int lastDrawnFlipView = 0;
\r
4322 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4323 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4326 HBITMAP bufferBitmap;
\r
4327 HBITMAP oldBitmap;
\r
4329 HRGN clips[MAX_CLIPS];
\r
4330 ChessSquare dragged_piece = EmptySquare;
\r
4332 /* I'm undecided on this - this function figures out whether a full
\r
4333 * repaint is necessary on its own, so there's no real reason to have the
\r
4334 * caller tell it that. I think this can safely be set to FALSE - but
\r
4335 * if we trust the callers not to request full repaints unnessesarily, then
\r
4336 * we could skip some clipping work. In other words, only request a full
\r
4337 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4338 * gamestart and similar) --Hawk
\r
4340 Boolean fullrepaint = repaint;
\r
4342 if( DrawPositionNeedsFullRepaint() ) {
\r
4343 fullrepaint = TRUE;
\r
4347 if( fullrepaint ) {
\r
4348 static int repaint_count = 0;
\r
4352 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4353 OutputDebugString( buf );
\r
4357 if (board == NULL) {
\r
4358 if (!lastReqValid) {
\r
4363 CopyBoard(lastReq, board);
\r
4367 if (doingSizing) {
\r
4371 if (IsIconic(hwndMain)) {
\r
4375 if (hdc == NULL) {
\r
4376 hdc = GetDC(hwndMain);
\r
4377 if (!appData.monoMode) {
\r
4378 SelectPalette(hdc, hPal, FALSE);
\r
4379 RealizePalette(hdc);
\r
4383 releaseDC = FALSE;
\r
4387 fprintf(debugFP, "*******************************\n"
\r
4389 "dragInfo.from (%d,%d)\n"
\r
4390 "dragInfo.start (%d,%d)\n"
\r
4391 "dragInfo.pos (%d,%d)\n"
\r
4392 "dragInfo.lastpos (%d,%d)\n",
\r
4393 repaint ? "TRUE" : "FALSE",
\r
4394 dragInfo.from.x, dragInfo.from.y,
\r
4395 dragInfo.start.x, dragInfo.start.y,
\r
4396 dragInfo.pos.x, dragInfo.pos.y,
\r
4397 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4398 fprintf(debugFP, "prev: ");
\r
4399 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4400 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4401 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4404 fprintf(debugFP, "\n");
\r
4405 fprintf(debugFP, "board: ");
\r
4406 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4407 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4408 fprintf(debugFP, "%d ", board[row][column]);
\r
4411 fprintf(debugFP, "\n");
\r
4415 /* Create some work-DCs */
\r
4416 hdcmem = CreateCompatibleDC(hdc);
\r
4417 tmphdc = CreateCompatibleDC(hdc);
\r
4419 /* If dragging is in progress, we temporarely remove the piece */
\r
4420 /* [HGM] or temporarily decrease count if stacked */
\r
4421 /* !! Moved to before board compare !! */
\r
4422 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4423 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4424 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4425 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4426 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4428 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4429 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4430 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4432 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4435 /* Figure out which squares need updating by comparing the
\r
4436 * newest board with the last drawn board and checking if
\r
4437 * flipping has changed.
\r
4439 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4440 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4441 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4442 if (lastDrawn[row][column] != board[row][column]) {
\r
4443 SquareToPos(row, column, &x, &y);
\r
4444 clips[num_clips++] =
\r
4445 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4449 for (i=0; i<2; i++) {
\r
4450 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4451 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4452 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4453 lastDrawnHighlight.sq[i].y >= 0) {
\r
4454 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4455 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4456 clips[num_clips++] =
\r
4457 CreateRectRgn(x - lineGap, y - lineGap,
\r
4458 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4460 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4461 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4462 clips[num_clips++] =
\r
4463 CreateRectRgn(x - lineGap, y - lineGap,
\r
4464 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4468 for (i=0; i<2; i++) {
\r
4469 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4470 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4471 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4472 lastDrawnPremove.sq[i].y >= 0) {
\r
4473 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4474 lastDrawnPremove.sq[i].x, &x, &y);
\r
4475 clips[num_clips++] =
\r
4476 CreateRectRgn(x - lineGap, y - lineGap,
\r
4477 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4479 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4480 premoveHighlightInfo.sq[i].y >= 0) {
\r
4481 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4482 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4483 clips[num_clips++] =
\r
4484 CreateRectRgn(x - lineGap, y - lineGap,
\r
4485 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4490 fullrepaint = TRUE;
\r
4493 /* Create a buffer bitmap - this is the actual bitmap
\r
4494 * being written to. When all the work is done, we can
\r
4495 * copy it to the real DC (the screen). This avoids
\r
4496 * the problems with flickering.
\r
4498 GetClientRect(hwndMain, &Rect);
\r
4499 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4500 Rect.bottom-Rect.top+1);
\r
4501 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4502 if (!appData.monoMode) {
\r
4503 SelectPalette(hdcmem, hPal, FALSE);
\r
4506 /* Create clips for dragging */
\r
4507 if (!fullrepaint) {
\r
4508 if (dragInfo.from.x >= 0) {
\r
4509 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4510 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4512 if (dragInfo.start.x >= 0) {
\r
4513 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4514 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4516 if (dragInfo.pos.x >= 0) {
\r
4517 x = dragInfo.pos.x - squareSize / 2;
\r
4518 y = dragInfo.pos.y - squareSize / 2;
\r
4519 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4521 if (dragInfo.lastpos.x >= 0) {
\r
4522 x = dragInfo.lastpos.x - squareSize / 2;
\r
4523 y = dragInfo.lastpos.y - squareSize / 2;
\r
4524 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4528 /* Are we animating a move?
\r
4530 * - remove the piece from the board (temporarely)
\r
4531 * - calculate the clipping region
\r
4533 if (!fullrepaint) {
\r
4534 if (animInfo.piece != EmptySquare) {
\r
4535 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4536 x = boardRect.left + animInfo.lastpos.x;
\r
4537 y = boardRect.top + animInfo.lastpos.y;
\r
4538 x2 = boardRect.left + animInfo.pos.x;
\r
4539 y2 = boardRect.top + animInfo.pos.y;
\r
4540 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4541 /* Slight kludge. The real problem is that after AnimateMove is
\r
4542 done, the position on the screen does not match lastDrawn.
\r
4543 This currently causes trouble only on e.p. captures in
\r
4544 atomic, where the piece moves to an empty square and then
\r
4545 explodes. The old and new positions both had an empty square
\r
4546 at the destination, but animation has drawn a piece there and
\r
4547 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4548 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4552 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4553 if (num_clips == 0)
\r
4554 fullrepaint = TRUE;
\r
4556 /* Set clipping on the memory DC */
\r
4557 if (!fullrepaint) {
\r
4558 SelectClipRgn(hdcmem, clips[0]);
\r
4559 for (x = 1; x < num_clips; x++) {
\r
4560 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4561 abort(); // this should never ever happen!
\r
4565 /* Do all the drawing to the memory DC */
\r
4566 if(explodeInfo.radius) { // [HGM] atomic
\r
4568 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4569 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4570 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4571 x += squareSize/2;
\r
4572 y += squareSize/2;
\r
4573 if(!fullrepaint) {
\r
4574 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4575 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4577 DrawGridOnDC(hdcmem);
\r
4578 DrawHighlightsOnDC(hdcmem);
\r
4579 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4580 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4581 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4582 SelectObject(hdcmem, oldBrush);
\r
4584 DrawGridOnDC(hdcmem);
\r
4585 DrawHighlightsOnDC(hdcmem);
\r
4586 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4589 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4590 if(appData.autoLogo) {
\r
4592 switch(gameMode) { // pick logos based on game mode
\r
4593 case IcsObserving:
\r
4594 whiteLogo = second.programLogo; // ICS logo
\r
4595 blackLogo = second.programLogo;
\r
4598 case IcsPlayingWhite:
\r
4599 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4600 blackLogo = second.programLogo; // ICS logo
\r
4602 case IcsPlayingBlack:
\r
4603 whiteLogo = second.programLogo; // ICS logo
\r
4604 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4606 case TwoMachinesPlay:
\r
4607 if(first.twoMachinesColor[0] == 'b') {
\r
4608 whiteLogo = second.programLogo;
\r
4609 blackLogo = first.programLogo;
\r
4612 case MachinePlaysWhite:
\r
4613 blackLogo = userLogo;
\r
4615 case MachinePlaysBlack:
\r
4616 whiteLogo = userLogo;
\r
4617 blackLogo = first.programLogo;
\r
4620 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4621 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4624 if( appData.highlightMoveWithArrow ) {
\r
4625 DrawArrowHighlight(hdcmem);
\r
4628 DrawCoordsOnDC(hdcmem);
\r
4630 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4631 /* to make sure lastDrawn contains what is actually drawn */
\r
4633 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4634 if (dragged_piece != EmptySquare) {
\r
4635 /* [HGM] or restack */
\r
4636 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4637 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4639 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4640 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4641 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4642 x = dragInfo.pos.x - squareSize / 2;
\r
4643 y = dragInfo.pos.y - squareSize / 2;
\r
4644 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4645 ((int) dragged_piece < (int) BlackPawn),
\r
4646 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4649 /* Put the animated piece back into place and draw it */
\r
4650 if (animInfo.piece != EmptySquare) {
\r
4651 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4652 x = boardRect.left + animInfo.pos.x;
\r
4653 y = boardRect.top + animInfo.pos.y;
\r
4654 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4655 ((int) animInfo.piece < (int) BlackPawn),
\r
4656 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4659 /* Release the bufferBitmap by selecting in the old bitmap
\r
4660 * and delete the memory DC
\r
4662 SelectObject(hdcmem, oldBitmap);
\r
4665 /* Set clipping on the target DC */
\r
4666 if (!fullrepaint) {
\r
4667 SelectClipRgn(hdc, clips[0]);
\r
4668 for (x = 1; x < num_clips; x++) {
\r
4669 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4670 abort(); // this should never ever happen!
\r
4674 /* Copy the new bitmap onto the screen in one go.
\r
4675 * This way we avoid any flickering
\r
4677 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4678 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4679 boardRect.right - boardRect.left,
\r
4680 boardRect.bottom - boardRect.top,
\r
4681 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4682 if(saveDiagFlag) {
\r
4683 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4684 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4686 GetObject(bufferBitmap, sizeof(b), &b);
\r
4687 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4688 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4689 bih.biWidth = b.bmWidth;
\r
4690 bih.biHeight = b.bmHeight;
\r
4692 bih.biBitCount = b.bmBitsPixel;
\r
4693 bih.biCompression = 0;
\r
4694 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4695 bih.biXPelsPerMeter = 0;
\r
4696 bih.biYPelsPerMeter = 0;
\r
4697 bih.biClrUsed = 0;
\r
4698 bih.biClrImportant = 0;
\r
4699 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4700 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4701 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4702 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4705 wb = b.bmWidthBytes;
\r
4707 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4708 int k = ((int*) pData)[i];
\r
4709 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4710 if(j >= 16) break;
\r
4712 if(j >= nrColors) nrColors = j+1;
\r
4714 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4716 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4717 for(w=0; w<(wb>>2); w+=2) {
\r
4718 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4719 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4720 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4721 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4722 pData[p++] = m | j<<4;
\r
4724 while(p&3) pData[p++] = 0;
\r
4727 wb = ((wb+31)>>5)<<2;
\r
4729 // write BITMAPFILEHEADER
\r
4730 fprintf(diagFile, "BM");
\r
4731 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4732 fputDW(diagFile, 0);
\r
4733 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4734 // write BITMAPINFOHEADER
\r
4735 fputDW(diagFile, 40);
\r
4736 fputDW(diagFile, b.bmWidth);
\r
4737 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4738 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4739 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4740 fputDW(diagFile, 0);
\r
4741 fputDW(diagFile, 0);
\r
4742 fputDW(diagFile, 0);
\r
4743 fputDW(diagFile, 0);
\r
4744 fputDW(diagFile, 0);
\r
4745 fputDW(diagFile, 0);
\r
4746 // write color table
\r
4748 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4749 // write bitmap data
\r
4750 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4751 fputc(pData[i], diagFile);
\r
4756 SelectObject(tmphdc, oldBitmap);
\r
4758 /* Massive cleanup */
\r
4759 for (x = 0; x < num_clips; x++)
\r
4760 DeleteObject(clips[x]);
\r
4763 DeleteObject(bufferBitmap);
\r
4766 ReleaseDC(hwndMain, hdc);
\r
4768 if (lastDrawnFlipView != flipView) {
\r
4770 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4772 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4775 /* CopyBoard(lastDrawn, board);*/
\r
4776 lastDrawnHighlight = highlightInfo;
\r
4777 lastDrawnPremove = premoveHighlightInfo;
\r
4778 lastDrawnFlipView = flipView;
\r
4779 lastDrawnValid = 1;
\r
4782 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4787 saveDiagFlag = 1; diagFile = f;
\r
4788 HDCDrawPosition(NULL, TRUE, NULL);
\r
4792 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4799 /*---------------------------------------------------------------------------*\
\r
4800 | CLIENT PAINT PROCEDURE
\r
4801 | This is the main event-handler for the WM_PAINT message.
\r
4803 \*---------------------------------------------------------------------------*/
\r
4805 PaintProc(HWND hwnd)
\r
4811 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4812 if (IsIconic(hwnd)) {
\r
4813 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4815 if (!appData.monoMode) {
\r
4816 SelectPalette(hdc, hPal, FALSE);
\r
4817 RealizePalette(hdc);
\r
4819 HDCDrawPosition(hdc, 1, NULL);
\r
4821 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4822 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4823 ETO_CLIPPED|ETO_OPAQUE,
\r
4824 &messageRect, messageText, strlen(messageText), NULL);
\r
4825 SelectObject(hdc, oldFont);
\r
4826 DisplayBothClocks();
\r
4828 EndPaint(hwnd,&ps);
\r
4836 * If the user selects on a border boundary, return -1; if off the board,
\r
4837 * return -2. Otherwise map the event coordinate to the square.
\r
4838 * The offset boardRect.left or boardRect.top must already have been
\r
4839 * subtracted from x.
\r
4842 EventToSquare(int x)
\r
4849 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4851 x /= (squareSize + lineGap);
\r
4852 if (x >= BOARD_SIZE)
\r
4863 DropEnable dropEnables[] = {
\r
4864 { 'P', DP_Pawn, "Pawn" },
\r
4865 { 'N', DP_Knight, "Knight" },
\r
4866 { 'B', DP_Bishop, "Bishop" },
\r
4867 { 'R', DP_Rook, "Rook" },
\r
4868 { 'Q', DP_Queen, "Queen" },
\r
4872 SetupDropMenu(HMENU hmenu)
\r
4874 int i, count, enable;
\r
4876 extern char white_holding[], black_holding[];
\r
4877 char item[MSG_SIZ];
\r
4879 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4880 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4881 dropEnables[i].piece);
\r
4883 while (p && *p++ == dropEnables[i].piece) count++;
\r
4884 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4885 enable = count > 0 || !appData.testLegality
\r
4886 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4887 && !appData.icsActive);
\r
4888 ModifyMenu(hmenu, dropEnables[i].command,
\r
4889 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4890 dropEnables[i].command, item);
\r
4894 static int fromX = -1, fromY = -1, toX, toY;
\r
4896 /* Event handler for mouse messages */
\r
4898 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4902 static int recursive = 0;
\r
4904 // BOOLEAN needsRedraw = FALSE;
\r
4905 BOOLEAN saveAnimate;
\r
4906 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4907 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4908 ChessMove moveType;
\r
4911 if (message == WM_MBUTTONUP) {
\r
4912 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4913 to the middle button: we simulate pressing the left button too!
\r
4915 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4916 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4922 pt.x = LOWORD(lParam);
\r
4923 pt.y = HIWORD(lParam);
\r
4924 x = EventToSquare(pt.x - boardRect.left);
\r
4925 y = EventToSquare(pt.y - boardRect.top);
\r
4926 if (!flipView && y >= 0) {
\r
4927 y = BOARD_HEIGHT - 1 - y;
\r
4929 if (flipView && x >= 0) {
\r
4930 x = BOARD_WIDTH - 1 - x;
\r
4933 switch (message) {
\r
4934 case WM_LBUTTONDOWN:
\r
4935 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4936 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4937 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4938 if(gameInfo.holdingsWidth &&
\r
4939 (WhiteOnMove(currentMove)
\r
4940 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4941 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4942 // click in right holdings, for determining promotion piece
\r
4943 ChessSquare p = boards[currentMove][y][x];
\r
4944 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4945 if(p != EmptySquare) {
\r
4946 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4947 fromX = fromY = -1;
\r
4951 DrawPosition(FALSE, boards[currentMove]);
\r
4955 sameAgain = FALSE;
\r
4957 /* Downclick vertically off board; check if on clock */
\r
4958 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4959 if (gameMode == EditPosition) {
\r
4960 SetWhiteToPlayEvent();
\r
4961 } else if (gameMode == IcsPlayingBlack ||
\r
4962 gameMode == MachinePlaysWhite) {
\r
4964 } else if (gameMode == EditGame) {
\r
4965 AdjustClock(flipClock, -1);
\r
4967 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4968 if (gameMode == EditPosition) {
\r
4969 SetBlackToPlayEvent();
\r
4970 } else if (gameMode == IcsPlayingWhite ||
\r
4971 gameMode == MachinePlaysBlack) {
\r
4973 } else if (gameMode == EditGame) {
\r
4974 AdjustClock(!flipClock, -1);
\r
4977 if (!appData.highlightLastMove) {
\r
4978 ClearHighlights();
\r
4979 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4981 fromX = fromY = -1;
\r
4982 dragInfo.start.x = dragInfo.start.y = -1;
\r
4983 dragInfo.from = dragInfo.start;
\r
4985 } else if (x < 0 || y < 0
\r
4986 /* [HGM] block clicks between board and holdings */
\r
4987 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4988 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4989 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4990 /* EditPosition, empty square, or different color piece;
\r
4991 click-click move is possible */
\r
4994 } else if (fromX == x && fromY == y) {
\r
4995 /* Downclick on same square again */
\r
4996 ClearHighlights();
\r
4997 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4998 sameAgain = TRUE;
\r
4999 } else if (fromX != -1 &&
\r
5000 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5002 /* Downclick on different square. */
\r
5003 /* [HGM] if on holdings file, should count as new first click ! */
\r
5004 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5007 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5008 to make sure move is legal before showing promotion popup */
\r
5009 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5010 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5011 fromX = fromY = -1;
\r
5012 ClearHighlights();
\r
5013 DrawPosition(FALSE, boards[currentMove]);
\r
5016 if(moveType != ImpossibleMove) {
\r
5017 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5018 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5019 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5020 appData.alwaysPromoteToQueen)) {
\r
5021 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5022 if (!appData.highlightLastMove) {
\r
5023 ClearHighlights();
\r
5024 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5027 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5028 SetHighlights(fromX, fromY, toX, toY);
\r
5029 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5030 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5031 If promotion to Q is legal, all are legal! */
\r
5032 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5033 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5034 // kludge to temporarily execute move on display, wthout promotng yet
\r
5035 promotionChoice = TRUE;
\r
5036 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5037 boards[currentMove][toY][toX] = p;
\r
5038 DrawPosition(FALSE, boards[currentMove]);
\r
5039 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5040 boards[currentMove][toY][toX] = q;
\r
5042 PromotionPopup(hwnd);
\r
5043 } else { /* not a promotion */
\r
5044 if (appData.animate || appData.highlightLastMove) {
\r
5045 SetHighlights(fromX, fromY, toX, toY);
\r
5047 ClearHighlights();
\r
5049 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5050 fromX = fromY = -1;
\r
5051 if (appData.animate && !appData.highlightLastMove) {
\r
5052 ClearHighlights();
\r
5053 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5059 /* [HGM] it seemed that braces were missing here */
\r
5060 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5061 fromX = fromY = -1;
\r
5065 ClearHighlights();
\r
5066 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5068 /* First downclick, or restart on a square with same color piece */
\r
5069 if (!frozen && OKToStartUserMove(x, y)) {
\r
5072 dragInfo.lastpos = pt;
\r
5073 dragInfo.from.x = fromX;
\r
5074 dragInfo.from.y = fromY;
\r
5075 dragInfo.start = dragInfo.from;
\r
5076 SetCapture(hwndMain);
\r
5078 fromX = fromY = -1;
\r
5079 dragInfo.start.x = dragInfo.start.y = -1;
\r
5080 dragInfo.from = dragInfo.start;
\r
5081 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5085 case WM_LBUTTONUP:
\r
5087 if (fromX == -1) break;
\r
5088 if (x == fromX && y == fromY) {
\r
5089 dragInfo.from.x = dragInfo.from.y = -1;
\r
5090 /* Upclick on same square */
\r
5092 /* Clicked same square twice: abort click-click move */
\r
5093 fromX = fromY = -1;
\r
5095 ClearPremoveHighlights();
\r
5097 /* First square clicked: start click-click move */
\r
5098 SetHighlights(fromX, fromY, -1, -1);
\r
5100 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5101 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5102 /* Errant click; ignore */
\r
5105 /* Finish drag move. */
\r
5106 if (appData.debugMode) {
\r
5107 fprintf(debugFP, "release\n");
\r
5109 dragInfo.from.x = dragInfo.from.y = -1;
\r
5112 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5113 appData.animate = appData.animate && !appData.animateDragging;
\r
5114 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5115 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5116 fromX = fromY = -1;
\r
5117 ClearHighlights();
\r
5118 DrawPosition(FALSE, boards[currentMove]);
\r
5121 if(moveType != ImpossibleMove) {
\r
5122 /* [HGM] use move type to determine if move is promotion.
\r
5123 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5124 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5125 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5126 appData.alwaysPromoteToQueen))
\r
5127 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5129 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5130 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5131 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5132 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5133 // kludge to temporarily execute move on display, wthout promotng yet
\r
5134 promotionChoice = TRUE;
\r
5135 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5136 boards[currentMove][toY][toX] = p;
\r
5137 DrawPosition(FALSE, boards[currentMove]);
\r
5138 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5139 boards[currentMove][toY][toX] = q;
\r
5142 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5144 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5145 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5146 moveType == WhiteCapturesEnPassant ||
\r
5147 moveType == BlackCapturesEnPassant ) )
\r
5148 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5149 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5152 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5153 appData.animate = saveAnimate;
\r
5154 fromX = fromY = -1;
\r
5155 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5156 ClearHighlights();
\r
5158 if (appData.animate || appData.animateDragging ||
\r
5159 appData.highlightDragging || gotPremove) {
\r
5160 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5163 dragInfo.start.x = dragInfo.start.y = -1;
\r
5164 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5167 case WM_MOUSEMOVE:
\r
5168 if ((appData.animateDragging || appData.highlightDragging)
\r
5169 && (wParam & MK_LBUTTON)
\r
5170 && dragInfo.from.x >= 0)
\r
5172 BOOL full_repaint = FALSE;
\r
5174 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5175 if (appData.animateDragging) {
\r
5176 dragInfo.pos = pt;
\r
5178 if (appData.highlightDragging) {
\r
5179 SetHighlights(fromX, fromY, x, y);
\r
5180 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5181 full_repaint = TRUE;
\r
5185 DrawPosition( full_repaint, NULL);
\r
5187 dragInfo.lastpos = dragInfo.pos;
\r
5191 case WM_MOUSEWHEEL: // [DM]
\r
5192 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5193 /* Mouse Wheel is being rolled forward
\r
5194 * Play moves forward
\r
5196 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5197 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5198 /* Mouse Wheel is being rolled backward
\r
5199 * Play moves backward
\r
5201 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5202 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5206 case WM_MBUTTONDOWN:
\r
5207 case WM_RBUTTONDOWN:
\r
5210 fromX = fromY = -1;
\r
5211 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5212 dragInfo.start.x = dragInfo.start.y = -1;
\r
5213 dragInfo.from = dragInfo.start;
\r
5214 dragInfo.lastpos = dragInfo.pos;
\r
5215 if (appData.highlightDragging) {
\r
5216 ClearHighlights();
\r
5219 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5220 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5221 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5222 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5223 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5226 DrawPosition(TRUE, NULL);
\r
5228 switch (gameMode) {
\r
5229 case EditPosition:
\r
5230 case IcsExamining:
\r
5231 if (x < 0 || y < 0) break;
\r
5234 if (message == WM_MBUTTONDOWN) {
\r
5235 buttonCount = 3; /* even if system didn't think so */
\r
5236 if (wParam & MK_SHIFT)
\r
5237 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5239 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5240 } else { /* message == WM_RBUTTONDOWN */
\r
5242 if (buttonCount == 3) {
\r
5243 if (wParam & MK_SHIFT)
\r
5244 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5246 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5248 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5251 /* Just have one menu, on the right button. Windows users don't
\r
5252 think to try the middle one, and sometimes other software steals
\r
5253 it, or it doesn't really exist. */
\r
5254 if(gameInfo.variant != VariantShogi)
\r
5255 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5257 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5261 case IcsPlayingWhite:
\r
5262 case IcsPlayingBlack:
\r
5264 case MachinePlaysWhite:
\r
5265 case MachinePlaysBlack:
\r
5266 if (appData.testLegality &&
\r
5267 gameInfo.variant != VariantBughouse &&
\r
5268 gameInfo.variant != VariantCrazyhouse) break;
\r
5269 if (x < 0 || y < 0) break;
\r
5272 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5273 SetupDropMenu(hmenu);
\r
5274 MenuPopup(hwnd, pt, hmenu, -1);
\r
5285 /* Preprocess messages for buttons in main window */
\r
5287 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5289 int id = GetWindowLong(hwnd, GWL_ID);
\r
5292 for (i=0; i<N_BUTTONS; i++) {
\r
5293 if (buttonDesc[i].id == id) break;
\r
5295 if (i == N_BUTTONS) return 0;
\r
5296 switch (message) {
\r
5301 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5302 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5309 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5312 if (appData.icsActive) {
\r
5313 if (GetKeyState(VK_SHIFT) < 0) {
\r
5315 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5316 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5320 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5321 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5328 if (appData.icsActive) {
\r
5329 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5330 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5332 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5334 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5335 PopUpMoveDialog((char)wParam);
\r
5341 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5344 /* Process messages for Promotion dialog box */
\r
5346 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5350 switch (message) {
\r
5351 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5352 /* Center the dialog over the application window */
\r
5353 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5354 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5355 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5356 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5357 SW_SHOW : SW_HIDE);
\r
5358 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5359 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5360 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5361 PieceToChar(WhiteAngel) != '~') ||
\r
5362 (PieceToChar(BlackAngel) >= 'A' &&
\r
5363 PieceToChar(BlackAngel) != '~') ) ?
\r
5364 SW_SHOW : SW_HIDE);
\r
5365 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5366 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5367 PieceToChar(WhiteMarshall) != '~') ||
\r
5368 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5369 PieceToChar(BlackMarshall) != '~') ) ?
\r
5370 SW_SHOW : SW_HIDE);
\r
5371 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5372 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5373 gameInfo.variant != VariantShogi ?
\r
5374 SW_SHOW : SW_HIDE);
\r
5375 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5376 gameInfo.variant != VariantShogi ?
\r
5377 SW_SHOW : SW_HIDE);
\r
5378 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5379 gameInfo.variant == VariantShogi ?
\r
5380 SW_SHOW : SW_HIDE);
\r
5381 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5382 gameInfo.variant == VariantShogi ?
\r
5383 SW_SHOW : SW_HIDE);
\r
5384 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5385 gameInfo.variant == VariantSuper ?
\r
5386 SW_SHOW : SW_HIDE);
\r
5389 case WM_COMMAND: /* message: received a command */
\r
5390 switch (LOWORD(wParam)) {
\r
5392 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5393 ClearHighlights();
\r
5394 DrawPosition(FALSE, NULL);
\r
5397 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5400 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5403 promoChar = PieceToChar(BlackRook);
\r
5406 promoChar = PieceToChar(BlackBishop);
\r
5408 case PB_Chancellor:
\r
5409 promoChar = PieceToChar(BlackMarshall);
\r
5411 case PB_Archbishop:
\r
5412 promoChar = PieceToChar(BlackAngel);
\r
5415 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5420 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5421 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5422 only show the popup when we are already sure the move is valid or
\r
5423 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5424 will figure out it is a promotion from the promoChar. */
\r
5425 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5426 if (!appData.highlightLastMove) {
\r
5427 ClearHighlights();
\r
5428 DrawPosition(FALSE, NULL);
\r
5435 /* Pop up promotion dialog */
\r
5437 PromotionPopup(HWND hwnd)
\r
5441 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5442 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5443 hwnd, (DLGPROC)lpProc);
\r
5444 FreeProcInstance(lpProc);
\r
5447 /* Toggle ShowThinking */
\r
5449 ToggleShowThinking()
\r
5451 appData.showThinking = !appData.showThinking;
\r
5452 ShowThinkingEvent();
\r
5456 LoadGameDialog(HWND hwnd, char* title)
\r
5460 char fileTitle[MSG_SIZ];
\r
5461 f = OpenFileDialog(hwnd, "rb", "",
\r
5462 appData.oldSaveStyle ? "gam" : "pgn",
\r
5464 title, &number, fileTitle, NULL);
\r
5466 cmailMsgLoaded = FALSE;
\r
5467 if (number == 0) {
\r
5468 int error = GameListBuild(f);
\r
5470 DisplayError("Cannot build game list", error);
\r
5471 } else if (!ListEmpty(&gameList) &&
\r
5472 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5473 GameListPopUp(f, fileTitle);
\r
5476 GameListDestroy();
\r
5479 LoadGame(f, number, fileTitle, FALSE);
\r
5484 ChangedConsoleFont()
\r
5487 CHARRANGE tmpsel, sel;
\r
5488 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5489 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5490 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5493 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5494 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5495 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5496 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5497 * size. This was undocumented in the version of MSVC++ that I had
\r
5498 * when I wrote the code, but is apparently documented now.
\r
5500 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5501 cfmt.bCharSet = f->lf.lfCharSet;
\r
5502 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5503 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5504 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5505 /* Why are the following seemingly needed too? */
\r
5506 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5507 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5508 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5510 tmpsel.cpMax = -1; /*999999?*/
\r
5511 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5512 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5513 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5514 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5516 paraf.cbSize = sizeof(paraf);
\r
5517 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5518 paraf.dxStartIndent = 0;
\r
5519 paraf.dxOffset = WRAP_INDENT;
\r
5520 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5521 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5524 /*---------------------------------------------------------------------------*\
\r
5526 * Window Proc for main window
\r
5528 \*---------------------------------------------------------------------------*/
\r
5530 /* Process messages for main window, etc. */
\r
5532 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5535 int wmId, wmEvent;
\r
5539 char fileTitle[MSG_SIZ];
\r
5540 char buf[MSG_SIZ];
\r
5541 static SnapData sd;
\r
5543 switch (message) {
\r
5545 case WM_PAINT: /* message: repaint portion of window */
\r
5549 case WM_ERASEBKGND:
\r
5550 if (IsIconic(hwnd)) {
\r
5551 /* Cheat; change the message */
\r
5552 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5554 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5558 case WM_LBUTTONDOWN:
\r
5559 case WM_MBUTTONDOWN:
\r
5560 case WM_RBUTTONDOWN:
\r
5561 case WM_LBUTTONUP:
\r
5562 case WM_MBUTTONUP:
\r
5563 case WM_RBUTTONUP:
\r
5564 case WM_MOUSEMOVE:
\r
5565 case WM_MOUSEWHEEL:
\r
5566 MouseEvent(hwnd, message, wParam, lParam);
\r
5571 if (appData.icsActive) {
\r
5572 if (wParam == '\t') {
\r
5573 if (GetKeyState(VK_SHIFT) < 0) {
\r
5575 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5576 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5580 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5581 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5585 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5586 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5588 SendMessage(h, message, wParam, lParam);
\r
5590 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5591 PopUpMoveDialog((char)wParam);
\r
5595 case WM_PALETTECHANGED:
\r
5596 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5598 HDC hdc = GetDC(hwndMain);
\r
5599 SelectPalette(hdc, hPal, TRUE);
\r
5600 nnew = RealizePalette(hdc);
\r
5602 paletteChanged = TRUE;
\r
5604 UpdateColors(hdc);
\r
5606 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5609 ReleaseDC(hwnd, hdc);
\r
5613 case WM_QUERYNEWPALETTE:
\r
5614 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5616 HDC hdc = GetDC(hwndMain);
\r
5617 paletteChanged = FALSE;
\r
5618 SelectPalette(hdc, hPal, FALSE);
\r
5619 nnew = RealizePalette(hdc);
\r
5621 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5623 ReleaseDC(hwnd, hdc);
\r
5628 case WM_COMMAND: /* message: command from application menu */
\r
5629 wmId = LOWORD(wParam);
\r
5630 wmEvent = HIWORD(wParam);
\r
5635 AnalysisPopDown();
\r
5638 case IDM_NewGameFRC:
\r
5639 if( NewGameFRC() == 0 ) {
\r
5641 AnalysisPopDown();
\r
5645 case IDM_NewVariant:
\r
5646 NewVariantPopup(hwnd);
\r
5649 case IDM_LoadGame:
\r
5650 LoadGameDialog(hwnd, "Load Game from File");
\r
5653 case IDM_LoadNextGame:
\r
5657 case IDM_LoadPrevGame:
\r
5661 case IDM_ReloadGame:
\r
5665 case IDM_LoadPosition:
\r
5666 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5667 Reset(FALSE, TRUE);
\r
5670 f = OpenFileDialog(hwnd, "rb", "",
\r
5671 appData.oldSaveStyle ? "pos" : "fen",
\r
5673 "Load Position from File", &number, fileTitle, NULL);
\r
5675 LoadPosition(f, number, fileTitle);
\r
5679 case IDM_LoadNextPosition:
\r
5680 ReloadPosition(1);
\r
5683 case IDM_LoadPrevPosition:
\r
5684 ReloadPosition(-1);
\r
5687 case IDM_ReloadPosition:
\r
5688 ReloadPosition(0);
\r
5691 case IDM_SaveGame:
\r
5692 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5693 f = OpenFileDialog(hwnd, "a", defName,
\r
5694 appData.oldSaveStyle ? "gam" : "pgn",
\r
5696 "Save Game to File", NULL, fileTitle, NULL);
\r
5698 SaveGame(f, 0, "");
\r
5702 case IDM_SavePosition:
\r
5703 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5704 f = OpenFileDialog(hwnd, "a", defName,
\r
5705 appData.oldSaveStyle ? "pos" : "fen",
\r
5707 "Save Position to File", NULL, fileTitle, NULL);
\r
5709 SavePosition(f, 0, "");
\r
5713 case IDM_SaveDiagram:
\r
5714 defName = "diagram";
\r
5715 f = OpenFileDialog(hwnd, "wb", defName,
\r
5718 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5724 case IDM_CopyGame:
\r
5725 CopyGameToClipboard();
\r
5728 case IDM_PasteGame:
\r
5729 PasteGameFromClipboard();
\r
5732 case IDM_CopyGameListToClipboard:
\r
5733 CopyGameListToClipboard();
\r
5736 /* [AS] Autodetect FEN or PGN data */
\r
5737 case IDM_PasteAny:
\r
5738 PasteGameOrFENFromClipboard();
\r
5741 /* [AS] Move history */
\r
5742 case IDM_ShowMoveHistory:
\r
5743 if( MoveHistoryIsUp() ) {
\r
5744 MoveHistoryPopDown();
\r
5747 MoveHistoryPopUp();
\r
5751 /* [AS] Eval graph */
\r
5752 case IDM_ShowEvalGraph:
\r
5753 if( EvalGraphIsUp() ) {
\r
5754 EvalGraphPopDown();
\r
5761 /* [AS] Engine output */
\r
5762 case IDM_ShowEngineOutput:
\r
5763 if( EngineOutputIsUp() ) {
\r
5764 EngineOutputPopDown();
\r
5767 EngineOutputPopUp();
\r
5771 /* [AS] User adjudication */
\r
5772 case IDM_UserAdjudication_White:
\r
5773 UserAdjudicationEvent( +1 );
\r
5776 case IDM_UserAdjudication_Black:
\r
5777 UserAdjudicationEvent( -1 );
\r
5780 case IDM_UserAdjudication_Draw:
\r
5781 UserAdjudicationEvent( 0 );
\r
5784 /* [AS] Game list options dialog */
\r
5785 case IDM_GameListOptions:
\r
5786 GameListOptions();
\r
5789 case IDM_CopyPosition:
\r
5790 CopyFENToClipboard();
\r
5793 case IDM_PastePosition:
\r
5794 PasteFENFromClipboard();
\r
5797 case IDM_MailMove:
\r
5801 case IDM_ReloadCMailMsg:
\r
5802 Reset(TRUE, TRUE);
\r
5803 ReloadCmailMsgEvent(FALSE);
\r
5806 case IDM_Minimize:
\r
5807 ShowWindow(hwnd, SW_MINIMIZE);
\r
5814 case IDM_MachineWhite:
\r
5815 MachineWhiteEvent();
\r
5817 * refresh the tags dialog only if it's visible
\r
5819 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5821 tags = PGNTags(&gameInfo);
\r
5822 TagsPopUp(tags, CmailMsg());
\r
5827 case IDM_MachineBlack:
\r
5828 MachineBlackEvent();
\r
5830 * refresh the tags dialog only if it's visible
\r
5832 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5834 tags = PGNTags(&gameInfo);
\r
5835 TagsPopUp(tags, CmailMsg());
\r
5840 case IDM_TwoMachines:
\r
5841 TwoMachinesEvent();
\r
5843 * refresh the tags dialog only if it's visible
\r
5845 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5847 tags = PGNTags(&gameInfo);
\r
5848 TagsPopUp(tags, CmailMsg());
\r
5853 case IDM_AnalysisMode:
\r
5854 if (!first.analysisSupport) {
\r
5855 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5856 DisplayError(buf, 0);
\r
5858 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5859 if (appData.icsActive) {
\r
5860 if (gameMode != IcsObserving) {
\r
5861 sprintf(buf, "You are not observing a game");
\r
5862 DisplayError(buf, 0);
\r
5863 /* secure check */
\r
5864 if (appData.icsEngineAnalyze) {
\r
5865 if (appData.debugMode)
\r
5866 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5867 ExitAnalyzeMode();
\r
5873 /* if enable, user want disable icsEngineAnalyze */
\r
5874 if (appData.icsEngineAnalyze) {
\r
5875 ExitAnalyzeMode();
\r
5879 appData.icsEngineAnalyze = TRUE;
\r
5880 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5883 if (!appData.showThinking) ToggleShowThinking();
\r
5884 AnalyzeModeEvent();
\r
5888 case IDM_AnalyzeFile:
\r
5889 if (!first.analysisSupport) {
\r
5890 char buf[MSG_SIZ];
\r
5891 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5892 DisplayError(buf, 0);
\r
5894 if (!appData.showThinking) ToggleShowThinking();
\r
5895 AnalyzeFileEvent();
\r
5896 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5897 AnalysisPeriodicEvent(1);
\r
5901 case IDM_IcsClient:
\r
5905 case IDM_EditGame:
\r
5909 case IDM_EditPosition:
\r
5910 EditPositionEvent();
\r
5913 case IDM_Training:
\r
5917 case IDM_ShowGameList:
\r
5918 ShowGameListProc();
\r
5921 case IDM_EditTags:
\r
5925 case IDM_EditComment:
\r
5926 if (commentDialogUp && editComment) {
\r
5929 EditCommentEvent();
\r
5949 case IDM_CallFlag:
\r
5969 case IDM_StopObserving:
\r
5970 StopObservingEvent();
\r
5973 case IDM_StopExamining:
\r
5974 StopExaminingEvent();
\r
5977 case IDM_TypeInMove:
\r
5978 PopUpMoveDialog('\000');
\r
5981 case IDM_TypeInName:
\r
5982 PopUpNameDialog('\000');
\r
5985 case IDM_Backward:
\r
5987 SetFocus(hwndMain);
\r
5992 SetFocus(hwndMain);
\r
5997 SetFocus(hwndMain);
\r
6002 SetFocus(hwndMain);
\r
6009 case IDM_TruncateGame:
\r
6010 TruncateGameEvent();
\r
6017 case IDM_RetractMove:
\r
6018 RetractMoveEvent();
\r
6021 case IDM_FlipView:
\r
6022 flipView = !flipView;
\r
6023 DrawPosition(FALSE, NULL);
\r
6026 case IDM_FlipClock:
\r
6027 flipClock = !flipClock;
\r
6028 DisplayBothClocks();
\r
6029 DrawPosition(FALSE, NULL);
\r
6032 case IDM_GeneralOptions:
\r
6033 GeneralOptionsPopup(hwnd);
\r
6034 DrawPosition(TRUE, NULL);
\r
6037 case IDM_BoardOptions:
\r
6038 BoardOptionsPopup(hwnd);
\r
6041 case IDM_EnginePlayOptions:
\r
6042 EnginePlayOptionsPopup(hwnd);
\r
6045 case IDM_OptionsUCI:
\r
6046 UciOptionsPopup(hwnd);
\r
6049 case IDM_IcsOptions:
\r
6050 IcsOptionsPopup(hwnd);
\r
6054 FontsOptionsPopup(hwnd);
\r
6058 SoundOptionsPopup(hwnd);
\r
6061 case IDM_CommPort:
\r
6062 CommPortOptionsPopup(hwnd);
\r
6065 case IDM_LoadOptions:
\r
6066 LoadOptionsPopup(hwnd);
\r
6069 case IDM_SaveOptions:
\r
6070 SaveOptionsPopup(hwnd);
\r
6073 case IDM_TimeControl:
\r
6074 TimeControlOptionsPopup(hwnd);
\r
6077 case IDM_SaveSettings:
\r
6078 SaveSettings(settingsFileName);
\r
6081 case IDM_SaveSettingsOnExit:
\r
6082 saveSettingsOnExit = !saveSettingsOnExit;
\r
6083 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6084 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6085 MF_CHECKED : MF_UNCHECKED));
\r
6096 case IDM_AboutGame:
\r
6101 appData.debugMode = !appData.debugMode;
\r
6102 if (appData.debugMode) {
\r
6103 char dir[MSG_SIZ];
\r
6104 GetCurrentDirectory(MSG_SIZ, dir);
\r
6105 SetCurrentDirectory(installDir);
\r
6106 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6107 SetCurrentDirectory(dir);
\r
6108 setbuf(debugFP, NULL);
\r
6115 case IDM_HELPCONTENTS:
\r
6116 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6117 MessageBox (GetFocus(),
\r
6118 "Unable to activate help",
\r
6119 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6123 case IDM_HELPSEARCH:
\r
6124 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
6125 MessageBox (GetFocus(),
\r
6126 "Unable to activate help",
\r
6127 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6131 case IDM_HELPHELP:
\r
6132 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6133 MessageBox (GetFocus(),
\r
6134 "Unable to activate help",
\r
6135 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6140 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6142 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6143 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6144 FreeProcInstance(lpProc);
\r
6147 case IDM_DirectCommand1:
\r
6148 AskQuestionEvent("Direct Command",
\r
6149 "Send to chess program:", "", "1");
\r
6151 case IDM_DirectCommand2:
\r
6152 AskQuestionEvent("Direct Command",
\r
6153 "Send to second chess program:", "", "2");
\r
6156 case EP_WhitePawn:
\r
6157 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6158 fromX = fromY = -1;
\r
6161 case EP_WhiteKnight:
\r
6162 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6163 fromX = fromY = -1;
\r
6166 case EP_WhiteBishop:
\r
6167 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6168 fromX = fromY = -1;
\r
6171 case EP_WhiteRook:
\r
6172 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6173 fromX = fromY = -1;
\r
6176 case EP_WhiteQueen:
\r
6177 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6178 fromX = fromY = -1;
\r
6181 case EP_WhiteFerz:
\r
6182 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6183 fromX = fromY = -1;
\r
6186 case EP_WhiteWazir:
\r
6187 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6188 fromX = fromY = -1;
\r
6191 case EP_WhiteAlfil:
\r
6192 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6193 fromX = fromY = -1;
\r
6196 case EP_WhiteCannon:
\r
6197 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6198 fromX = fromY = -1;
\r
6201 case EP_WhiteCardinal:
\r
6202 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6203 fromX = fromY = -1;
\r
6206 case EP_WhiteMarshall:
\r
6207 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6208 fromX = fromY = -1;
\r
6211 case EP_WhiteKing:
\r
6212 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6213 fromX = fromY = -1;
\r
6216 case EP_BlackPawn:
\r
6217 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6218 fromX = fromY = -1;
\r
6221 case EP_BlackKnight:
\r
6222 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6223 fromX = fromY = -1;
\r
6226 case EP_BlackBishop:
\r
6227 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6228 fromX = fromY = -1;
\r
6231 case EP_BlackRook:
\r
6232 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6233 fromX = fromY = -1;
\r
6236 case EP_BlackQueen:
\r
6237 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6238 fromX = fromY = -1;
\r
6241 case EP_BlackFerz:
\r
6242 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6243 fromX = fromY = -1;
\r
6246 case EP_BlackWazir:
\r
6247 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6248 fromX = fromY = -1;
\r
6251 case EP_BlackAlfil:
\r
6252 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6253 fromX = fromY = -1;
\r
6256 case EP_BlackCannon:
\r
6257 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6258 fromX = fromY = -1;
\r
6261 case EP_BlackCardinal:
\r
6262 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6263 fromX = fromY = -1;
\r
6266 case EP_BlackMarshall:
\r
6267 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6268 fromX = fromY = -1;
\r
6271 case EP_BlackKing:
\r
6272 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6273 fromX = fromY = -1;
\r
6276 case EP_EmptySquare:
\r
6277 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6278 fromX = fromY = -1;
\r
6281 case EP_ClearBoard:
\r
6282 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6283 fromX = fromY = -1;
\r
6287 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6288 fromX = fromY = -1;
\r
6292 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6293 fromX = fromY = -1;
\r
6297 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6298 fromX = fromY = -1;
\r
6302 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6303 fromX = fromY = -1;
\r
6307 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6308 fromX = fromY = -1;
\r
6312 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6313 fromX = fromY = -1;
\r
6317 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6318 fromX = fromY = -1;
\r
6322 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6323 fromX = fromY = -1;
\r
6327 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6328 fromX = fromY = -1;
\r
6332 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6338 case CLOCK_TIMER_ID:
\r
6339 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6340 clockTimerEvent = 0;
\r
6341 DecrementClocks(); /* call into back end */
\r
6343 case LOAD_GAME_TIMER_ID:
\r
6344 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6345 loadGameTimerEvent = 0;
\r
6346 AutoPlayGameLoop(); /* call into back end */
\r
6348 case ANALYSIS_TIMER_ID:
\r
6349 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6350 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6351 AnalysisPeriodicEvent(0);
\r
6353 KillTimer(hwnd, analysisTimerEvent);
\r
6354 analysisTimerEvent = 0;
\r
6357 case DELAYED_TIMER_ID:
\r
6358 KillTimer(hwnd, delayedTimerEvent);
\r
6359 delayedTimerEvent = 0;
\r
6360 delayedTimerCallback();
\r
6365 case WM_USER_Input:
\r
6366 InputEvent(hwnd, message, wParam, lParam);
\r
6369 /* [AS] Also move "attached" child windows */
\r
6370 case WM_WINDOWPOSCHANGING:
\r
6372 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6373 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6375 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6376 /* Window is moving */
\r
6379 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6380 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6381 rcMain.right = boardX + winWidth;
\r
6382 rcMain.top = boardY;
\r
6383 rcMain.bottom = boardY + winHeight;
\r
6385 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6386 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6387 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6388 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6389 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6396 /* [AS] Snapping */
\r
6397 case WM_ENTERSIZEMOVE:
\r
6398 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6399 if (hwnd == hwndMain) {
\r
6400 doingSizing = TRUE;
\r
6403 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6407 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6408 if (hwnd == hwndMain) {
\r
6409 lastSizing = wParam;
\r
6414 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6415 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6417 case WM_EXITSIZEMOVE:
\r
6418 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6419 if (hwnd == hwndMain) {
\r
6421 doingSizing = FALSE;
\r
6422 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6423 GetClientRect(hwnd, &client);
\r
6424 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6426 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6428 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6431 case WM_DESTROY: /* message: window being destroyed */
\r
6432 PostQuitMessage(0);
\r
6436 if (hwnd == hwndMain) {
\r
6441 default: /* Passes it on if unprocessed */
\r
6442 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6447 /*---------------------------------------------------------------------------*\
\r
6449 * Misc utility routines
\r
6451 \*---------------------------------------------------------------------------*/
\r
6454 * Decent random number generator, at least not as bad as Windows
\r
6455 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6457 unsigned int randstate;
\r
6462 randstate = randstate * 1664525 + 1013904223;
\r
6463 return (int) randstate & 0x7fffffff;
\r
6467 mysrandom(unsigned int seed)
\r
6474 * returns TRUE if user selects a different color, FALSE otherwise
\r
6478 ChangeColor(HWND hwnd, COLORREF *which)
\r
6480 static BOOL firstTime = TRUE;
\r
6481 static DWORD customColors[16];
\r
6483 COLORREF newcolor;
\r
6488 /* Make initial colors in use available as custom colors */
\r
6489 /* Should we put the compiled-in defaults here instead? */
\r
6491 customColors[i++] = lightSquareColor & 0xffffff;
\r
6492 customColors[i++] = darkSquareColor & 0xffffff;
\r
6493 customColors[i++] = whitePieceColor & 0xffffff;
\r
6494 customColors[i++] = blackPieceColor & 0xffffff;
\r
6495 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6496 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6498 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6499 customColors[i++] = textAttribs[ccl].color;
\r
6501 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6502 firstTime = FALSE;
\r
6505 cc.lStructSize = sizeof(cc);
\r
6506 cc.hwndOwner = hwnd;
\r
6507 cc.hInstance = NULL;
\r
6508 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6509 cc.lpCustColors = (LPDWORD) customColors;
\r
6510 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6512 if (!ChooseColor(&cc)) return FALSE;
\r
6514 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6515 if (newcolor == *which) return FALSE;
\r
6516 *which = newcolor;
\r
6520 InitDrawingColors();
\r
6521 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6526 MyLoadSound(MySound *ms)
\r
6532 if (ms->data) free(ms->data);
\r
6535 switch (ms->name[0]) {
\r
6541 /* System sound from Control Panel. Don't preload here. */
\r
6545 if (ms->name[1] == NULLCHAR) {
\r
6546 /* "!" alone = silence */
\r
6549 /* Builtin wave resource. Error if not found. */
\r
6550 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6551 if (h == NULL) break;
\r
6552 ms->data = (void *)LoadResource(hInst, h);
\r
6553 if (h == NULL) break;
\r
6558 /* .wav file. Error if not found. */
\r
6559 f = fopen(ms->name, "rb");
\r
6560 if (f == NULL) break;
\r
6561 if (fstat(fileno(f), &st) < 0) break;
\r
6562 ms->data = malloc(st.st_size);
\r
6563 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6569 char buf[MSG_SIZ];
\r
6570 sprintf(buf, "Error loading sound %s", ms->name);
\r
6571 DisplayError(buf, GetLastError());
\r
6577 MyPlaySound(MySound *ms)
\r
6579 BOOLEAN ok = FALSE;
\r
6580 switch (ms->name[0]) {
\r
6586 /* System sound from Control Panel (deprecated feature).
\r
6587 "$" alone or an unset sound name gets default beep (still in use). */
\r
6588 if (ms->name[1]) {
\r
6589 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6591 if (!ok) ok = MessageBeep(MB_OK);
\r
6594 /* Builtin wave resource, or "!" alone for silence */
\r
6595 if (ms->name[1]) {
\r
6596 if (ms->data == NULL) return FALSE;
\r
6597 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6603 /* .wav file. Error if not found. */
\r
6604 if (ms->data == NULL) return FALSE;
\r
6605 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6608 /* Don't print an error: this can happen innocently if the sound driver
\r
6609 is busy; for instance, if another instance of WinBoard is playing
\r
6610 a sound at about the same time. */
\r
6613 char buf[MSG_SIZ];
\r
6614 sprintf(buf, "Error playing sound %s", ms->name);
\r
6615 DisplayError(buf, GetLastError());
\r
6623 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6626 OPENFILENAME *ofn;
\r
6627 static UINT *number; /* gross that this is static */
\r
6629 switch (message) {
\r
6630 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6631 /* Center the dialog over the application window */
\r
6632 ofn = (OPENFILENAME *) lParam;
\r
6633 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6634 number = (UINT *) ofn->lCustData;
\r
6635 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6639 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6640 return FALSE; /* Allow for further processing */
\r
6643 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6644 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6646 return FALSE; /* Allow for further processing */
\r
6652 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6654 static UINT *number;
\r
6655 OPENFILENAME *ofname;
\r
6658 case WM_INITDIALOG:
\r
6659 ofname = (OPENFILENAME *)lParam;
\r
6660 number = (UINT *)(ofname->lCustData);
\r
6663 ofnot = (OFNOTIFY *)lParam;
\r
6664 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6665 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6674 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6675 char *nameFilt, char *dlgTitle, UINT *number,
\r
6676 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6678 OPENFILENAME openFileName;
\r
6679 char buf1[MSG_SIZ];
\r
6682 if (fileName == NULL) fileName = buf1;
\r
6683 if (defName == NULL) {
\r
6684 strcpy(fileName, "*.");
\r
6685 strcat(fileName, defExt);
\r
6687 strcpy(fileName, defName);
\r
6689 if (fileTitle) strcpy(fileTitle, "");
\r
6690 if (number) *number = 0;
\r
6692 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6693 openFileName.hwndOwner = hwnd;
\r
6694 openFileName.hInstance = (HANDLE) hInst;
\r
6695 openFileName.lpstrFilter = nameFilt;
\r
6696 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6697 openFileName.nMaxCustFilter = 0L;
\r
6698 openFileName.nFilterIndex = 1L;
\r
6699 openFileName.lpstrFile = fileName;
\r
6700 openFileName.nMaxFile = MSG_SIZ;
\r
6701 openFileName.lpstrFileTitle = fileTitle;
\r
6702 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6703 openFileName.lpstrInitialDir = NULL;
\r
6704 openFileName.lpstrTitle = dlgTitle;
\r
6705 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6706 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6707 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6708 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6709 openFileName.nFileOffset = 0;
\r
6710 openFileName.nFileExtension = 0;
\r
6711 openFileName.lpstrDefExt = defExt;
\r
6712 openFileName.lCustData = (LONG) number;
\r
6713 openFileName.lpfnHook = oldDialog ?
\r
6714 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6715 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6717 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6718 GetOpenFileName(&openFileName)) {
\r
6719 /* open the file */
\r
6720 f = fopen(openFileName.lpstrFile, write);
\r
6722 MessageBox(hwnd, "File open failed", NULL,
\r
6723 MB_OK|MB_ICONEXCLAMATION);
\r
6727 int err = CommDlgExtendedError();
\r
6728 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6737 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6739 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6742 * Get the first pop-up menu in the menu template. This is the
\r
6743 * menu that TrackPopupMenu displays.
\r
6745 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6747 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6750 * TrackPopup uses screen coordinates, so convert the
\r
6751 * coordinates of the mouse click to screen coordinates.
\r
6753 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6755 /* Draw and track the floating pop-up menu. */
\r
6756 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6757 pt.x, pt.y, 0, hwnd, NULL);
\r
6759 /* Destroy the menu.*/
\r
6760 DestroyMenu(hmenu);
\r
6765 int sizeX, sizeY, newSizeX, newSizeY;
\r
6767 } ResizeEditPlusButtonsClosure;
\r
6770 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6772 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6776 if (hChild == cl->hText) return TRUE;
\r
6777 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6778 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6779 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6780 ScreenToClient(cl->hDlg, &pt);
\r
6781 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6782 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6786 /* Resize a dialog that has a (rich) edit field filling most of
\r
6787 the top, with a row of buttons below */
\r
6789 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6792 int newTextHeight, newTextWidth;
\r
6793 ResizeEditPlusButtonsClosure cl;
\r
6795 /*if (IsIconic(hDlg)) return;*/
\r
6796 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6798 cl.hdwp = BeginDeferWindowPos(8);
\r
6800 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6801 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6802 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6803 if (newTextHeight < 0) {
\r
6804 newSizeY += -newTextHeight;
\r
6805 newTextHeight = 0;
\r
6807 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6808 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6814 cl.newSizeX = newSizeX;
\r
6815 cl.newSizeY = newSizeY;
\r
6816 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6818 EndDeferWindowPos(cl.hdwp);
\r
6821 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6823 RECT rChild, rParent;
\r
6824 int wChild, hChild, wParent, hParent;
\r
6825 int wScreen, hScreen, xNew, yNew;
\r
6828 /* Get the Height and Width of the child window */
\r
6829 GetWindowRect (hwndChild, &rChild);
\r
6830 wChild = rChild.right - rChild.left;
\r
6831 hChild = rChild.bottom - rChild.top;
\r
6833 /* Get the Height and Width of the parent window */
\r
6834 GetWindowRect (hwndParent, &rParent);
\r
6835 wParent = rParent.right - rParent.left;
\r
6836 hParent = rParent.bottom - rParent.top;
\r
6838 /* Get the display limits */
\r
6839 hdc = GetDC (hwndChild);
\r
6840 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6841 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6842 ReleaseDC(hwndChild, hdc);
\r
6844 /* Calculate new X position, then adjust for screen */
\r
6845 xNew = rParent.left + ((wParent - wChild) /2);
\r
6848 } else if ((xNew+wChild) > wScreen) {
\r
6849 xNew = wScreen - wChild;
\r
6852 /* Calculate new Y position, then adjust for screen */
\r
6854 yNew = rParent.top + ((hParent - hChild) /2);
\r
6857 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6862 } else if ((yNew+hChild) > hScreen) {
\r
6863 yNew = hScreen - hChild;
\r
6866 /* Set it, and return */
\r
6867 return SetWindowPos (hwndChild, NULL,
\r
6868 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6871 /* Center one window over another */
\r
6872 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6874 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6877 /*---------------------------------------------------------------------------*\
\r
6879 * Startup Dialog functions
\r
6881 \*---------------------------------------------------------------------------*/
\r
6883 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6885 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6887 while (*cd != NULL) {
\r
6888 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6894 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6896 char buf1[ARG_MAX];
\r
6899 if (str[0] == '@') {
\r
6900 FILE* f = fopen(str + 1, "r");
\r
6902 DisplayFatalError(str + 1, errno, 2);
\r
6905 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6907 buf1[len] = NULLCHAR;
\r
6911 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6914 char buf[MSG_SIZ];
\r
6915 char *end = strchr(str, '\n');
\r
6916 if (end == NULL) return;
\r
6917 memcpy(buf, str, end - str);
\r
6918 buf[end - str] = NULLCHAR;
\r
6919 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6925 SetStartupDialogEnables(HWND hDlg)
\r
6927 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6928 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6929 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6930 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6931 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6932 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6933 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6934 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6935 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6936 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6937 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6938 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6939 IsDlgButtonChecked(hDlg, OPT_View));
\r
6943 QuoteForFilename(char *filename)
\r
6945 int dquote, space;
\r
6946 dquote = strchr(filename, '"') != NULL;
\r
6947 space = strchr(filename, ' ') != NULL;
\r
6948 if (dquote || space) {
\r
6960 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6962 char buf[MSG_SIZ];
\r
6965 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6966 q = QuoteForFilename(nthcp);
\r
6967 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6968 if (*nthdir != NULLCHAR) {
\r
6969 q = QuoteForFilename(nthdir);
\r
6970 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6972 if (*nthcp == NULLCHAR) {
\r
6973 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6974 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6975 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6976 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6981 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6983 char buf[MSG_SIZ];
\r
6987 switch (message) {
\r
6988 case WM_INITDIALOG:
\r
6989 /* Center the dialog */
\r
6990 CenterWindow (hDlg, GetDesktopWindow());
\r
6991 /* Initialize the dialog items */
\r
6992 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6993 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6994 firstChessProgramNames);
\r
6995 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6996 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6997 secondChessProgramNames);
\r
6998 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6999 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7000 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7001 if (*appData.icsHelper != NULLCHAR) {
\r
7002 char *q = QuoteForFilename(appData.icsHelper);
\r
7003 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7005 if (*appData.icsHost == NULLCHAR) {
\r
7006 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7007 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7008 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7009 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7010 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7013 if (appData.icsActive) {
\r
7014 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7016 else if (appData.noChessProgram) {
\r
7017 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7020 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7023 SetStartupDialogEnables(hDlg);
\r
7027 switch (LOWORD(wParam)) {
\r
7029 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7030 strcpy(buf, "/fcp=");
\r
7031 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7033 ParseArgs(StringGet, &p);
\r
7034 strcpy(buf, "/scp=");
\r
7035 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7037 ParseArgs(StringGet, &p);
\r
7038 appData.noChessProgram = FALSE;
\r
7039 appData.icsActive = FALSE;
\r
7040 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7041 strcpy(buf, "/ics /icshost=");
\r
7042 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7044 ParseArgs(StringGet, &p);
\r
7045 if (appData.zippyPlay) {
\r
7046 strcpy(buf, "/fcp=");
\r
7047 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7049 ParseArgs(StringGet, &p);
\r
7051 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7052 appData.noChessProgram = TRUE;
\r
7053 appData.icsActive = FALSE;
\r
7055 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7056 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7059 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7060 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7062 ParseArgs(StringGet, &p);
\r
7064 EndDialog(hDlg, TRUE);
\r
7071 case IDM_HELPCONTENTS:
\r
7072 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7073 MessageBox (GetFocus(),
\r
7074 "Unable to activate help",
\r
7075 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7080 SetStartupDialogEnables(hDlg);
\r
7088 /*---------------------------------------------------------------------------*\
\r
7090 * About box dialog functions
\r
7092 \*---------------------------------------------------------------------------*/
\r
7094 /* Process messages for "About" dialog box */
\r
7096 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7098 switch (message) {
\r
7099 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7100 /* Center the dialog over the application window */
\r
7101 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7102 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7105 case WM_COMMAND: /* message: received a command */
\r
7106 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7107 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7108 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7116 /*---------------------------------------------------------------------------*\
\r
7118 * Comment Dialog functions
\r
7120 \*---------------------------------------------------------------------------*/
\r
7123 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7125 static HANDLE hwndText = NULL;
\r
7126 int len, newSizeX, newSizeY, flags;
\r
7127 static int sizeX, sizeY;
\r
7132 switch (message) {
\r
7133 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7134 /* Initialize the dialog items */
\r
7135 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7136 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7137 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7138 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7139 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7140 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7141 SetWindowText(hDlg, commentTitle);
\r
7142 if (editComment) {
\r
7143 SetFocus(hwndText);
\r
7145 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7147 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7148 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7149 MAKELPARAM(FALSE, 0));
\r
7150 /* Size and position the dialog */
\r
7151 if (!commentDialog) {
\r
7152 commentDialog = hDlg;
\r
7153 flags = SWP_NOZORDER;
\r
7154 GetClientRect(hDlg, &rect);
\r
7155 sizeX = rect.right;
\r
7156 sizeY = rect.bottom;
\r
7157 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7158 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7159 WINDOWPLACEMENT wp;
\r
7160 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7161 wp.length = sizeof(WINDOWPLACEMENT);
\r
7163 wp.showCmd = SW_SHOW;
\r
7164 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7165 wp.rcNormalPosition.left = commentX;
\r
7166 wp.rcNormalPosition.right = commentX + commentW;
\r
7167 wp.rcNormalPosition.top = commentY;
\r
7168 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7169 SetWindowPlacement(hDlg, &wp);
\r
7171 GetClientRect(hDlg, &rect);
\r
7172 newSizeX = rect.right;
\r
7173 newSizeY = rect.bottom;
\r
7174 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7175 newSizeX, newSizeY);
\r
7182 case WM_COMMAND: /* message: received a command */
\r
7183 switch (LOWORD(wParam)) {
\r
7185 if (editComment) {
\r
7187 /* Read changed options from the dialog box */
\r
7188 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7189 len = GetWindowTextLength(hwndText);
\r
7190 str = (char *) malloc(len + 1);
\r
7191 GetWindowText(hwndText, str, len + 1);
\r
7200 ReplaceComment(commentIndex, str);
\r
7207 case OPT_CancelComment:
\r
7211 case OPT_ClearComment:
\r
7212 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7215 case OPT_EditComment:
\r
7216 EditCommentEvent();
\r
7225 newSizeX = LOWORD(lParam);
\r
7226 newSizeY = HIWORD(lParam);
\r
7227 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7232 case WM_GETMINMAXINFO:
\r
7233 /* Prevent resizing window too small */
\r
7234 mmi = (MINMAXINFO *) lParam;
\r
7235 mmi->ptMinTrackSize.x = 100;
\r
7236 mmi->ptMinTrackSize.y = 100;
\r
7243 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7248 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7250 if (str == NULL) str = "";
\r
7251 p = (char *) malloc(2 * strlen(str) + 2);
\r
7254 if (*str == '\n') *q++ = '\r';
\r
7258 if (commentText != NULL) free(commentText);
\r
7260 commentIndex = index;
\r
7261 commentTitle = title;
\r
7263 editComment = edit;
\r
7265 if (commentDialog) {
\r
7266 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7267 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7269 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7270 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7271 hwndMain, (DLGPROC)lpProc);
\r
7272 FreeProcInstance(lpProc);
\r
7274 commentDialogUp = TRUE;
\r
7278 /*---------------------------------------------------------------------------*\
\r
7280 * Type-in move dialog functions
\r
7282 \*---------------------------------------------------------------------------*/
\r
7285 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7287 char move[MSG_SIZ];
\r
7289 ChessMove moveType;
\r
7290 int fromX, fromY, toX, toY;
\r
7293 switch (message) {
\r
7294 case WM_INITDIALOG:
\r
7295 move[0] = (char) lParam;
\r
7296 move[1] = NULLCHAR;
\r
7297 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7298 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7299 SetWindowText(hInput, move);
\r
7301 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7305 switch (LOWORD(wParam)) {
\r
7307 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7308 gameMode != Training) {
\r
7309 DisplayMoveError("Displayed move is not current");
\r
7311 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7312 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7313 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7314 if (gameMode != Training)
\r
7315 forwardMostMove = currentMove;
\r
7316 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7318 DisplayMoveError("Could not parse move");
\r
7321 EndDialog(hDlg, TRUE);
\r
7324 EndDialog(hDlg, FALSE);
\r
7335 PopUpMoveDialog(char firstchar)
\r
7339 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7340 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7341 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7342 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7343 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7344 gameMode == Training) {
\r
7345 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7346 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7347 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7348 FreeProcInstance(lpProc);
\r
7352 /*---------------------------------------------------------------------------*\
\r
7354 * Type-in name dialog functions
\r
7356 \*---------------------------------------------------------------------------*/
\r
7359 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7361 char move[MSG_SIZ];
\r
7364 switch (message) {
\r
7365 case WM_INITDIALOG:
\r
7366 move[0] = (char) lParam;
\r
7367 move[1] = NULLCHAR;
\r
7368 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7369 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7370 SetWindowText(hInput, move);
\r
7372 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7376 switch (LOWORD(wParam)) {
\r
7378 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7379 appData.userName = strdup(move);
\r
7382 EndDialog(hDlg, TRUE);
\r
7385 EndDialog(hDlg, FALSE);
\r
7396 PopUpNameDialog(char firstchar)
\r
7400 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7401 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7402 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7403 FreeProcInstance(lpProc);
\r
7406 /*---------------------------------------------------------------------------*\
\r
7410 \*---------------------------------------------------------------------------*/
\r
7412 /* Nonmodal error box */
\r
7413 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7414 WPARAM wParam, LPARAM lParam);
\r
7417 ErrorPopUp(char *title, char *content)
\r
7421 BOOLEAN modal = hwndMain == NULL;
\r
7439 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7440 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7443 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7445 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7446 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7447 hwndMain, (DLGPROC)lpProc);
\r
7448 FreeProcInstance(lpProc);
\r
7455 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7456 if (errorDialog == NULL) return;
\r
7457 DestroyWindow(errorDialog);
\r
7458 errorDialog = NULL;
\r
7462 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7467 switch (message) {
\r
7468 case WM_INITDIALOG:
\r
7469 GetWindowRect(hDlg, &rChild);
\r
7472 SetWindowPos(hDlg, NULL, rChild.left,
\r
7473 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7474 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7478 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7479 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7480 and it doesn't work when you resize the dialog.
\r
7481 For now, just give it a default position.
\r
7483 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7485 errorDialog = hDlg;
\r
7486 SetWindowText(hDlg, errorTitle);
\r
7487 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7488 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7492 switch (LOWORD(wParam)) {
\r
7495 if (errorDialog == hDlg) errorDialog = NULL;
\r
7496 DestroyWindow(hDlg);
\r
7508 HWND gothicDialog = NULL;
\r
7511 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7515 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7517 switch (message) {
\r
7518 case WM_INITDIALOG:
\r
7519 GetWindowRect(hDlg, &rChild);
\r
7521 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7525 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7526 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7527 and it doesn't work when you resize the dialog.
\r
7528 For now, just give it a default position.
\r
7530 gothicDialog = hDlg;
\r
7531 SetWindowText(hDlg, errorTitle);
\r
7532 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7533 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7537 switch (LOWORD(wParam)) {
\r
7540 if (errorDialog == hDlg) errorDialog = NULL;
\r
7541 DestroyWindow(hDlg);
\r
7553 GothicPopUp(char *title, VariantClass variant)
\r
7556 static char *lastTitle;
\r
7558 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7559 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7561 if(lastTitle != title && gothicDialog != NULL) {
\r
7562 DestroyWindow(gothicDialog);
\r
7563 gothicDialog = NULL;
\r
7565 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7566 title = lastTitle;
\r
7567 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7568 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7569 hwndMain, (DLGPROC)lpProc);
\r
7570 FreeProcInstance(lpProc);
\r
7575 /*---------------------------------------------------------------------------*\
\r
7577 * Ics Interaction console functions
\r
7579 \*---------------------------------------------------------------------------*/
\r
7581 #define HISTORY_SIZE 64
\r
7582 static char *history[HISTORY_SIZE];
\r
7583 int histIn = 0, histP = 0;
\r
7586 SaveInHistory(char *cmd)
\r
7588 if (history[histIn] != NULL) {
\r
7589 free(history[histIn]);
\r
7590 history[histIn] = NULL;
\r
7592 if (*cmd == NULLCHAR) return;
\r
7593 history[histIn] = StrSave(cmd);
\r
7594 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7595 if (history[histIn] != NULL) {
\r
7596 free(history[histIn]);
\r
7597 history[histIn] = NULL;
\r
7603 PrevInHistory(char *cmd)
\r
7606 if (histP == histIn) {
\r
7607 if (history[histIn] != NULL) free(history[histIn]);
\r
7608 history[histIn] = StrSave(cmd);
\r
7610 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7611 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7613 return history[histP];
\r
7619 if (histP == histIn) return NULL;
\r
7620 histP = (histP + 1) % HISTORY_SIZE;
\r
7621 return history[histP];
\r
7628 BOOLEAN immediate;
\r
7629 } IcsTextMenuEntry;
\r
7630 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7631 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7634 ParseIcsTextMenu(char *icsTextMenuString)
\r
7637 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7638 char *p = icsTextMenuString;
\r
7639 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7642 if (e->command != NULL) {
\r
7644 e->command = NULL;
\r
7648 e = icsTextMenuEntry;
\r
7649 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7650 if (*p == ';' || *p == '\n') {
\r
7651 e->item = strdup("-");
\r
7652 e->command = NULL;
\r
7654 } else if (*p == '-') {
\r
7655 e->item = strdup("-");
\r
7656 e->command = NULL;
\r
7660 char *q, *r, *s, *t;
\r
7662 q = strchr(p, ',');
\r
7663 if (q == NULL) break;
\r
7665 r = strchr(q + 1, ',');
\r
7666 if (r == NULL) break;
\r
7668 s = strchr(r + 1, ',');
\r
7669 if (s == NULL) break;
\r
7672 t = strchr(s + 1, c);
\r
7675 t = strchr(s + 1, c);
\r
7677 if (t != NULL) *t = NULLCHAR;
\r
7678 e->item = strdup(p);
\r
7679 e->command = strdup(q + 1);
\r
7680 e->getname = *(r + 1) != '0';
\r
7681 e->immediate = *(s + 1) != '0';
\r
7685 if (t == NULL) break;
\r
7694 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7698 hmenu = LoadMenu(hInst, "TextMenu");
\r
7699 h = GetSubMenu(hmenu, 0);
\r
7701 if (strcmp(e->item, "-") == 0) {
\r
7702 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7704 if (e->item[0] == '|') {
\r
7705 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7706 IDM_CommandX + i, &e->item[1]);
\r
7708 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7717 WNDPROC consoleTextWindowProc;
\r
7720 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7722 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7723 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7727 SetWindowText(hInput, command);
\r
7729 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7731 sel.cpMin = 999999;
\r
7732 sel.cpMax = 999999;
\r
7733 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7738 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7739 if (sel.cpMin == sel.cpMax) {
\r
7740 /* Expand to surrounding word */
\r
7743 tr.chrg.cpMax = sel.cpMin;
\r
7744 tr.chrg.cpMin = --sel.cpMin;
\r
7745 if (sel.cpMin < 0) break;
\r
7746 tr.lpstrText = name;
\r
7747 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7748 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7752 tr.chrg.cpMin = sel.cpMax;
\r
7753 tr.chrg.cpMax = ++sel.cpMax;
\r
7754 tr.lpstrText = name;
\r
7755 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7756 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7759 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7760 MessageBeep(MB_ICONEXCLAMATION);
\r
7764 tr.lpstrText = name;
\r
7765 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7767 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7768 MessageBeep(MB_ICONEXCLAMATION);
\r
7771 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7774 sprintf(buf, "%s %s", command, name);
\r
7775 SetWindowText(hInput, buf);
\r
7776 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7778 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7779 SetWindowText(hInput, buf);
\r
7780 sel.cpMin = 999999;
\r
7781 sel.cpMax = 999999;
\r
7782 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7788 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7793 switch (message) {
\r
7795 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7798 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7801 sel.cpMin = 999999;
\r
7802 sel.cpMax = 999999;
\r
7803 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7804 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7809 if (wParam == '\t') {
\r
7810 if (GetKeyState(VK_SHIFT) < 0) {
\r
7812 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7813 if (buttonDesc[0].hwnd) {
\r
7814 SetFocus(buttonDesc[0].hwnd);
\r
7816 SetFocus(hwndMain);
\r
7820 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7823 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7825 SendMessage(hInput, message, wParam, lParam);
\r
7829 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7831 return SendMessage(hInput, message, wParam, lParam);
\r
7832 case WM_MBUTTONDOWN:
\r
7833 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7834 case WM_RBUTTONDOWN:
\r
7835 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7836 /* Move selection here if it was empty */
\r
7838 pt.x = LOWORD(lParam);
\r
7839 pt.y = HIWORD(lParam);
\r
7840 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7841 if (sel.cpMin == sel.cpMax) {
\r
7842 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7843 sel.cpMax = sel.cpMin;
\r
7844 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7846 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7849 case WM_RBUTTONUP:
\r
7850 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7851 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7852 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7855 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7856 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7857 if (sel.cpMin == sel.cpMax) {
\r
7858 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7859 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7861 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7862 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7864 pt.x = LOWORD(lParam);
\r
7865 pt.y = HIWORD(lParam);
\r
7866 MenuPopup(hwnd, pt, hmenu, -1);
\r
7870 switch (LOWORD(wParam)) {
\r
7871 case IDM_QuickPaste:
\r
7873 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7874 if (sel.cpMin == sel.cpMax) {
\r
7875 MessageBeep(MB_ICONEXCLAMATION);
\r
7878 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7879 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7880 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7885 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7888 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7891 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7895 int i = LOWORD(wParam) - IDM_CommandX;
\r
7896 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7897 icsTextMenuEntry[i].command != NULL) {
\r
7898 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7899 icsTextMenuEntry[i].getname,
\r
7900 icsTextMenuEntry[i].immediate);
\r
7908 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7911 WNDPROC consoleInputWindowProc;
\r
7914 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7916 char buf[MSG_SIZ];
\r
7918 static BOOL sendNextChar = FALSE;
\r
7919 static BOOL quoteNextChar = FALSE;
\r
7920 InputSource *is = consoleInputSource;
\r
7924 switch (message) {
\r
7926 if (!appData.localLineEditing || sendNextChar) {
\r
7927 is->buf[0] = (CHAR) wParam;
\r
7929 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7930 sendNextChar = FALSE;
\r
7933 if (quoteNextChar) {
\r
7934 buf[0] = (char) wParam;
\r
7935 buf[1] = NULLCHAR;
\r
7936 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7937 quoteNextChar = FALSE;
\r
7941 case '\r': /* Enter key */
\r
7942 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7943 if (consoleEcho) SaveInHistory(is->buf);
\r
7944 is->buf[is->count++] = '\n';
\r
7945 is->buf[is->count] = NULLCHAR;
\r
7946 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7947 if (consoleEcho) {
\r
7948 ConsoleOutput(is->buf, is->count, TRUE);
\r
7949 } else if (appData.localLineEditing) {
\r
7950 ConsoleOutput("\n", 1, TRUE);
\r
7953 case '\033': /* Escape key */
\r
7954 SetWindowText(hwnd, "");
\r
7955 cf.cbSize = sizeof(CHARFORMAT);
\r
7956 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7957 if (consoleEcho) {
\r
7958 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7960 cf.crTextColor = COLOR_ECHOOFF;
\r
7962 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7963 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7965 case '\t': /* Tab key */
\r
7966 if (GetKeyState(VK_SHIFT) < 0) {
\r
7968 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7971 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7972 if (buttonDesc[0].hwnd) {
\r
7973 SetFocus(buttonDesc[0].hwnd);
\r
7975 SetFocus(hwndMain);
\r
7979 case '\023': /* Ctrl+S */
\r
7980 sendNextChar = TRUE;
\r
7982 case '\021': /* Ctrl+Q */
\r
7983 quoteNextChar = TRUE;
\r
7992 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7993 p = PrevInHistory(buf);
\r
7995 SetWindowText(hwnd, p);
\r
7996 sel.cpMin = 999999;
\r
7997 sel.cpMax = 999999;
\r
7998 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8003 p = NextInHistory();
\r
8005 SetWindowText(hwnd, p);
\r
8006 sel.cpMin = 999999;
\r
8007 sel.cpMax = 999999;
\r
8008 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8014 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8018 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8022 case WM_MBUTTONDOWN:
\r
8023 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8024 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8026 case WM_RBUTTONUP:
\r
8027 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8028 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8029 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8033 hmenu = LoadMenu(hInst, "InputMenu");
\r
8034 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8035 if (sel.cpMin == sel.cpMax) {
\r
8036 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8037 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8039 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8040 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8042 pt.x = LOWORD(lParam);
\r
8043 pt.y = HIWORD(lParam);
\r
8044 MenuPopup(hwnd, pt, hmenu, -1);
\r
8048 switch (LOWORD(wParam)) {
\r
8050 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8052 case IDM_SelectAll:
\r
8054 sel.cpMax = -1; /*999999?*/
\r
8055 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8058 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8061 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8064 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8069 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8072 #define CO_MAX 100000
\r
8073 #define CO_TRIM 1000
\r
8076 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8078 static SnapData sd;
\r
8079 static HWND hText, hInput /*, hFocus*/;
\r
8080 // InputSource *is = consoleInputSource;
\r
8082 static int sizeX, sizeY;
\r
8083 int newSizeX, newSizeY;
\r
8086 switch (message) {
\r
8087 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8088 hwndConsole = hDlg;
\r
8089 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8090 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8092 consoleTextWindowProc = (WNDPROC)
\r
8093 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8094 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8095 consoleInputWindowProc = (WNDPROC)
\r
8096 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8097 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8098 Colorize(ColorNormal, TRUE);
\r
8099 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8100 ChangedConsoleFont();
\r
8101 GetClientRect(hDlg, &rect);
\r
8102 sizeX = rect.right;
\r
8103 sizeY = rect.bottom;
\r
8104 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8105 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8106 WINDOWPLACEMENT wp;
\r
8107 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8108 wp.length = sizeof(WINDOWPLACEMENT);
\r
8110 wp.showCmd = SW_SHOW;
\r
8111 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8112 wp.rcNormalPosition.left = wpConsole.x;
\r
8113 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8114 wp.rcNormalPosition.top = wpConsole.y;
\r
8115 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8116 SetWindowPlacement(hDlg, &wp);
\r
8119 // [HGM] Chessknight's change 2004-07-13
\r
8120 else { /* Determine Defaults */
\r
8121 WINDOWPLACEMENT wp;
\r
8122 wpConsole.x = winWidth + 1;
\r
8123 wpConsole.y = boardY;
\r
8124 wpConsoleW = screenWidth - winWidth;
\r
8125 wpConsoleH = winHeight;
\r
8126 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8127 wp.length = sizeof(WINDOWPLACEMENT);
\r
8129 wp.showCmd = SW_SHOW;
\r
8130 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8131 wp.rcNormalPosition.left = wpConsole.x;
\r
8132 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8133 wp.rcNormalPosition.top = wpConsole.y;
\r
8134 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8135 SetWindowPlacement(hDlg, &wp);
\r
8150 if (IsIconic(hDlg)) break;
\r
8151 newSizeX = LOWORD(lParam);
\r
8152 newSizeY = HIWORD(lParam);
\r
8153 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8154 RECT rectText, rectInput;
\r
8156 int newTextHeight, newTextWidth;
\r
8157 GetWindowRect(hText, &rectText);
\r
8158 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8159 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8160 if (newTextHeight < 0) {
\r
8161 newSizeY += -newTextHeight;
\r
8162 newTextHeight = 0;
\r
8164 SetWindowPos(hText, NULL, 0, 0,
\r
8165 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8166 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8167 pt.x = rectInput.left;
\r
8168 pt.y = rectInput.top + newSizeY - sizeY;
\r
8169 ScreenToClient(hDlg, &pt);
\r
8170 SetWindowPos(hInput, NULL,
\r
8171 pt.x, pt.y, /* needs client coords */
\r
8172 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8173 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8179 case WM_GETMINMAXINFO:
\r
8180 /* Prevent resizing window too small */
\r
8181 mmi = (MINMAXINFO *) lParam;
\r
8182 mmi->ptMinTrackSize.x = 100;
\r
8183 mmi->ptMinTrackSize.y = 100;
\r
8186 /* [AS] Snapping */
\r
8187 case WM_ENTERSIZEMOVE:
\r
8188 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8191 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8194 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8196 case WM_EXITSIZEMOVE:
\r
8197 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8200 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8208 if (hwndConsole) return;
\r
8209 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8210 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8215 ConsoleOutput(char* data, int length, int forceVisible)
\r
8220 char buf[CO_MAX+1];
\r
8223 static int delayLF = 0;
\r
8224 CHARRANGE savesel, sel;
\r
8226 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8234 while (length--) {
\r
8242 } else if (*p == '\007') {
\r
8243 MyPlaySound(&sounds[(int)SoundBell]);
\r
8250 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8251 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8252 /* Save current selection */
\r
8253 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8254 exlen = GetWindowTextLength(hText);
\r
8255 /* Find out whether current end of text is visible */
\r
8256 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8257 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8258 /* Trim existing text if it's too long */
\r
8259 if (exlen + (q - buf) > CO_MAX) {
\r
8260 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8263 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8264 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8266 savesel.cpMin -= trim;
\r
8267 savesel.cpMax -= trim;
\r
8268 if (exlen < 0) exlen = 0;
\r
8269 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8270 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8272 /* Append the new text */
\r
8273 sel.cpMin = exlen;
\r
8274 sel.cpMax = exlen;
\r
8275 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8276 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8277 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8278 if (forceVisible || exlen == 0 ||
\r
8279 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8280 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8281 /* Scroll to make new end of text visible if old end of text
\r
8282 was visible or new text is an echo of user typein */
\r
8283 sel.cpMin = 9999999;
\r
8284 sel.cpMax = 9999999;
\r
8285 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8286 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8287 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8288 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8290 if (savesel.cpMax == exlen || forceVisible) {
\r
8291 /* Move insert point to new end of text if it was at the old
\r
8292 end of text or if the new text is an echo of user typein */
\r
8293 sel.cpMin = 9999999;
\r
8294 sel.cpMax = 9999999;
\r
8295 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8297 /* Restore previous selection */
\r
8298 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8300 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8307 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8311 COLORREF oldFg, oldBg;
\r
8315 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8317 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8318 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8319 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8322 rect.right = x + squareSize;
\r
8324 rect.bottom = y + squareSize;
\r
8327 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8328 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8329 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8330 &rect, str, strlen(str), NULL);
\r
8332 (void) SetTextColor(hdc, oldFg);
\r
8333 (void) SetBkColor(hdc, oldBg);
\r
8334 (void) SelectObject(hdc, oldFont);
\r
8338 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8339 RECT *rect, char *color, char *flagFell)
\r
8343 COLORREF oldFg, oldBg;
\r
8346 if (appData.clockMode) {
\r
8348 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8350 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8357 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8358 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8360 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8361 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8363 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8365 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8366 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8367 rect, str, strlen(str), NULL);
\r
8368 if(logoHeight > 0 && appData.clockMode) {
\r
8370 sprintf(buf, "%s %s", TimeString(timeRemaining), flagFell);
\r
8371 r.top = rect->top + logoHeight/2;
\r
8372 r.left = rect->left;
\r
8373 r.right = rect->right;
\r
8374 r.bottom = rect->bottom;
\r
8375 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8376 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8377 &r, str, strlen(str), NULL);
\r
8379 (void) SetTextColor(hdc, oldFg);
\r
8380 (void) SetBkColor(hdc, oldBg);
\r
8381 (void) SelectObject(hdc, oldFont);
\r
8386 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8392 if( count <= 0 ) {
\r
8393 if (appData.debugMode) {
\r
8394 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8397 return ERROR_INVALID_USER_BUFFER;
\r
8400 ResetEvent(ovl->hEvent);
\r
8401 ovl->Offset = ovl->OffsetHigh = 0;
\r
8402 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8406 err = GetLastError();
\r
8407 if (err == ERROR_IO_PENDING) {
\r
8408 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8412 err = GetLastError();
\r
8419 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8424 ResetEvent(ovl->hEvent);
\r
8425 ovl->Offset = ovl->OffsetHigh = 0;
\r
8426 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8430 err = GetLastError();
\r
8431 if (err == ERROR_IO_PENDING) {
\r
8432 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8436 err = GetLastError();
\r
8442 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8443 void CheckForInputBufferFull( InputSource * is )
\r
8445 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8446 /* Look for end of line */
\r
8447 char * p = is->buf;
\r
8449 while( p < is->next && *p != '\n' ) {
\r
8453 if( p >= is->next ) {
\r
8454 if (appData.debugMode) {
\r
8455 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8458 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8459 is->count = (DWORD) -1;
\r
8460 is->next = is->buf;
\r
8466 InputThread(LPVOID arg)
\r
8471 is = (InputSource *) arg;
\r
8472 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8473 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8474 while (is->hThread != NULL) {
\r
8475 is->error = DoReadFile(is->hFile, is->next,
\r
8476 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8477 &is->count, &ovl);
\r
8478 if (is->error == NO_ERROR) {
\r
8479 is->next += is->count;
\r
8481 if (is->error == ERROR_BROKEN_PIPE) {
\r
8482 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8485 is->count = (DWORD) -1;
\r
8486 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8491 CheckForInputBufferFull( is );
\r
8493 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8495 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8497 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8500 CloseHandle(ovl.hEvent);
\r
8501 CloseHandle(is->hFile);
\r
8503 if (appData.debugMode) {
\r
8504 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8511 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8513 NonOvlInputThread(LPVOID arg)
\r
8520 is = (InputSource *) arg;
\r
8521 while (is->hThread != NULL) {
\r
8522 is->error = ReadFile(is->hFile, is->next,
\r
8523 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8524 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8525 if (is->error == NO_ERROR) {
\r
8526 /* Change CRLF to LF */
\r
8527 if (is->next > is->buf) {
\r
8529 i = is->count + 1;
\r
8537 if (prev == '\r' && *p == '\n') {
\r
8549 if (is->error == ERROR_BROKEN_PIPE) {
\r
8550 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8553 is->count = (DWORD) -1;
\r
8557 CheckForInputBufferFull( is );
\r
8559 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8561 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8563 if (is->count < 0) break; /* Quit on error */
\r
8565 CloseHandle(is->hFile);
\r
8570 SocketInputThread(LPVOID arg)
\r
8574 is = (InputSource *) arg;
\r
8575 while (is->hThread != NULL) {
\r
8576 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8577 if ((int)is->count == SOCKET_ERROR) {
\r
8578 is->count = (DWORD) -1;
\r
8579 is->error = WSAGetLastError();
\r
8581 is->error = NO_ERROR;
\r
8582 is->next += is->count;
\r
8583 if (is->count == 0 && is->second == is) {
\r
8584 /* End of file on stderr; quit with no message */
\r
8588 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8590 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8592 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8598 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8602 is = (InputSource *) lParam;
\r
8603 if (is->lineByLine) {
\r
8604 /* Feed in lines one by one */
\r
8605 char *p = is->buf;
\r
8607 while (q < is->next) {
\r
8608 if (*q++ == '\n') {
\r
8609 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8614 /* Move any partial line to the start of the buffer */
\r
8616 while (p < is->next) {
\r
8621 if (is->error != NO_ERROR || is->count == 0) {
\r
8622 /* Notify backend of the error. Note: If there was a partial
\r
8623 line at the end, it is not flushed through. */
\r
8624 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8627 /* Feed in the whole chunk of input at once */
\r
8628 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8629 is->next = is->buf;
\r
8633 /*---------------------------------------------------------------------------*\
\r
8635 * Menu enables. Used when setting various modes.
\r
8637 \*---------------------------------------------------------------------------*/
\r
8645 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8647 while (enab->item > 0) {
\r
8648 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8653 Enables gnuEnables[] = {
\r
8654 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8655 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8656 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8657 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8658 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8659 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8660 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8661 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8662 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8663 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8667 Enables icsEnables[] = {
\r
8668 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8669 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8670 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8671 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8672 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8673 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8674 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8675 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8676 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8677 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8678 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8679 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8684 Enables zippyEnables[] = {
\r
8685 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8686 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8687 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8692 Enables ncpEnables[] = {
\r
8693 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8694 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8695 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8696 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8697 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8698 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8699 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8700 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8701 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8702 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8703 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8704 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8705 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8706 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8707 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8711 Enables trainingOnEnables[] = {
\r
8712 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8713 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8714 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8715 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8716 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8717 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8718 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8719 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8723 Enables trainingOffEnables[] = {
\r
8724 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8725 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8726 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8727 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8728 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8729 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8730 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8731 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8735 /* These modify either ncpEnables or gnuEnables */
\r
8736 Enables cmailEnables[] = {
\r
8737 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8738 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8739 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8740 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8741 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8742 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8743 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8747 Enables machineThinkingEnables[] = {
\r
8748 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8749 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8750 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8751 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8752 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8753 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8754 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8755 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8756 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8757 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8758 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8759 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8760 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8761 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8762 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8766 Enables userThinkingEnables[] = {
\r
8767 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8768 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8769 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8770 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8771 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8772 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8773 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8774 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8775 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8776 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8777 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8778 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8779 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8780 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8781 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8785 /*---------------------------------------------------------------------------*\
\r
8787 * Front-end interface functions exported by XBoard.
\r
8788 * Functions appear in same order as prototypes in frontend.h.
\r
8790 \*---------------------------------------------------------------------------*/
\r
8794 static UINT prevChecked = 0;
\r
8795 static int prevPausing = 0;
\r
8798 if (pausing != prevPausing) {
\r
8799 prevPausing = pausing;
\r
8800 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8801 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8802 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8805 switch (gameMode) {
\r
8806 case BeginningOfGame:
\r
8807 if (appData.icsActive)
\r
8808 nowChecked = IDM_IcsClient;
\r
8809 else if (appData.noChessProgram)
\r
8810 nowChecked = IDM_EditGame;
\r
8812 nowChecked = IDM_MachineBlack;
\r
8814 case MachinePlaysBlack:
\r
8815 nowChecked = IDM_MachineBlack;
\r
8817 case MachinePlaysWhite:
\r
8818 nowChecked = IDM_MachineWhite;
\r
8820 case TwoMachinesPlay:
\r
8821 nowChecked = IDM_TwoMachines;
\r
8824 nowChecked = IDM_AnalysisMode;
\r
8827 nowChecked = IDM_AnalyzeFile;
\r
8830 nowChecked = IDM_EditGame;
\r
8832 case PlayFromGameFile:
\r
8833 nowChecked = IDM_LoadGame;
\r
8835 case EditPosition:
\r
8836 nowChecked = IDM_EditPosition;
\r
8839 nowChecked = IDM_Training;
\r
8841 case IcsPlayingWhite:
\r
8842 case IcsPlayingBlack:
\r
8843 case IcsObserving:
\r
8845 nowChecked = IDM_IcsClient;
\r
8852 if (prevChecked != 0)
\r
8853 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8854 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8855 if (nowChecked != 0)
\r
8856 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8857 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8859 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8860 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8861 MF_BYCOMMAND|MF_ENABLED);
\r
8863 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8864 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8867 prevChecked = nowChecked;
\r
8869 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8870 if (appData.icsActive) {
\r
8871 if (appData.icsEngineAnalyze) {
\r
8872 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8873 MF_BYCOMMAND|MF_CHECKED);
\r
8875 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8876 MF_BYCOMMAND|MF_UNCHECKED);
\r
8884 HMENU hmenu = GetMenu(hwndMain);
\r
8885 SetMenuEnables(hmenu, icsEnables);
\r
8886 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8887 MF_BYPOSITION|MF_ENABLED);
\r
8889 if (appData.zippyPlay) {
\r
8890 SetMenuEnables(hmenu, zippyEnables);
\r
8891 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8892 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8893 MF_BYCOMMAND|MF_ENABLED);
\r
8901 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8907 HMENU hmenu = GetMenu(hwndMain);
\r
8908 SetMenuEnables(hmenu, ncpEnables);
\r
8909 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8910 MF_BYPOSITION|MF_GRAYED);
\r
8911 DrawMenuBar(hwndMain);
\r
8917 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8921 SetTrainingModeOn()
\r
8924 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8925 for (i = 0; i < N_BUTTONS; i++) {
\r
8926 if (buttonDesc[i].hwnd != NULL)
\r
8927 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8932 VOID SetTrainingModeOff()
\r
8935 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8936 for (i = 0; i < N_BUTTONS; i++) {
\r
8937 if (buttonDesc[i].hwnd != NULL)
\r
8938 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8944 SetUserThinkingEnables()
\r
8946 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8950 SetMachineThinkingEnables()
\r
8952 HMENU hMenu = GetMenu(hwndMain);
\r
8953 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8955 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8957 if (gameMode == MachinePlaysBlack) {
\r
8958 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8959 } else if (gameMode == MachinePlaysWhite) {
\r
8960 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8961 } else if (gameMode == TwoMachinesPlay) {
\r
8962 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8968 DisplayTitle(char *str)
\r
8970 char title[MSG_SIZ], *host;
\r
8971 if (str[0] != NULLCHAR) {
\r
8972 strcpy(title, str);
\r
8973 } else if (appData.icsActive) {
\r
8974 if (appData.icsCommPort[0] != NULLCHAR)
\r
8977 host = appData.icsHost;
\r
8978 sprintf(title, "%s: %s", szTitle, host);
\r
8979 } else if (appData.noChessProgram) {
\r
8980 strcpy(title, szTitle);
\r
8982 strcpy(title, szTitle);
\r
8983 strcat(title, ": ");
\r
8984 strcat(title, first.tidy);
\r
8986 SetWindowText(hwndMain, title);
\r
8991 DisplayMessage(char *str1, char *str2)
\r
8995 int remain = MESSAGE_TEXT_MAX - 1;
\r
8998 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8999 messageText[0] = NULLCHAR;
\r
9001 len = strlen(str1);
\r
9002 if (len > remain) len = remain;
\r
9003 strncpy(messageText, str1, len);
\r
9004 messageText[len] = NULLCHAR;
\r
9007 if (*str2 && remain >= 2) {
\r
9009 strcat(messageText, " ");
\r
9012 len = strlen(str2);
\r
9013 if (len > remain) len = remain;
\r
9014 strncat(messageText, str2, len);
\r
9016 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9018 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9019 hdc = GetDC(hwndMain);
\r
9020 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9021 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9022 &messageRect, messageText, strlen(messageText), NULL);
\r
9023 (void) SelectObject(hdc, oldFont);
\r
9024 (void) ReleaseDC(hwndMain, hdc);
\r
9028 DisplayError(char *str, int error)
\r
9030 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9036 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9037 NULL, error, LANG_NEUTRAL,
\r
9038 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9040 sprintf(buf, "%s:\n%s", str, buf2);
\r
9042 ErrorMap *em = errmap;
\r
9043 while (em->err != 0 && em->err != error) em++;
\r
9044 if (em->err != 0) {
\r
9045 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9047 sprintf(buf, "%s:\nError code %d", str, error);
\r
9052 ErrorPopUp("Error", buf);
\r
9057 DisplayMoveError(char *str)
\r
9059 fromX = fromY = -1;
\r
9060 ClearHighlights();
\r
9061 DrawPosition(FALSE, NULL);
\r
9062 if (appData.popupMoveErrors) {
\r
9063 ErrorPopUp("Error", str);
\r
9065 DisplayMessage(str, "");
\r
9066 moveErrorMessageUp = TRUE;
\r
9071 DisplayFatalError(char *str, int error, int exitStatus)
\r
9073 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9075 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9078 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9079 NULL, error, LANG_NEUTRAL,
\r
9080 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9082 sprintf(buf, "%s:\n%s", str, buf2);
\r
9084 ErrorMap *em = errmap;
\r
9085 while (em->err != 0 && em->err != error) em++;
\r
9086 if (em->err != 0) {
\r
9087 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9089 sprintf(buf, "%s:\nError code %d", str, error);
\r
9094 if (appData.debugMode) {
\r
9095 fprintf(debugFP, "%s: %s\n", label, str);
\r
9097 if (appData.popupExitMessage) {
\r
9098 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9099 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9101 ExitEvent(exitStatus);
\r
9106 DisplayInformation(char *str)
\r
9108 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9113 DisplayNote(char *str)
\r
9115 ErrorPopUp("Note", str);
\r
9120 char *title, *question, *replyPrefix;
\r
9125 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9127 static QuestionParams *qp;
\r
9128 char reply[MSG_SIZ];
\r
9131 switch (message) {
\r
9132 case WM_INITDIALOG:
\r
9133 qp = (QuestionParams *) lParam;
\r
9134 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9135 SetWindowText(hDlg, qp->title);
\r
9136 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9137 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9141 switch (LOWORD(wParam)) {
\r
9143 strcpy(reply, qp->replyPrefix);
\r
9144 if (*reply) strcat(reply, " ");
\r
9145 len = strlen(reply);
\r
9146 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9147 strcat(reply, "\n");
\r
9148 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9149 EndDialog(hDlg, TRUE);
\r
9150 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9153 EndDialog(hDlg, FALSE);
\r
9164 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9166 QuestionParams qp;
\r
9170 qp.question = question;
\r
9171 qp.replyPrefix = replyPrefix;
\r
9173 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9174 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9175 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9176 FreeProcInstance(lpProc);
\r
9179 /* [AS] Pick FRC position */
\r
9180 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9182 static int * lpIndexFRC;
\r
9188 case WM_INITDIALOG:
\r
9189 lpIndexFRC = (int *) lParam;
\r
9191 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9193 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9194 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9195 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9196 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9201 switch( LOWORD(wParam) ) {
\r
9203 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9204 EndDialog( hDlg, 0 );
\r
9205 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9208 EndDialog( hDlg, 1 );
\r
9210 case IDC_NFG_Edit:
\r
9211 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9212 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9214 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9217 case IDC_NFG_Random:
\r
9218 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9219 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9232 int index = appData.defaultFrcPosition;
\r
9233 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9235 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9237 if( result == 0 ) {
\r
9238 appData.defaultFrcPosition = index;
\r
9244 /* [AS] Game list options */
\r
9250 static GLT_Item GLT_ItemInfo[] = {
\r
9251 { GLT_EVENT, "Event" },
\r
9252 { GLT_SITE, "Site" },
\r
9253 { GLT_DATE, "Date" },
\r
9254 { GLT_ROUND, "Round" },
\r
9255 { GLT_PLAYERS, "Players" },
\r
9256 { GLT_RESULT, "Result" },
\r
9257 { GLT_WHITE_ELO, "White Rating" },
\r
9258 { GLT_BLACK_ELO, "Black Rating" },
\r
9259 { GLT_TIME_CONTROL,"Time Control" },
\r
9260 { GLT_VARIANT, "Variant" },
\r
9261 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9265 const char * GLT_FindItem( char id )
\r
9267 const char * result = 0;
\r
9269 GLT_Item * list = GLT_ItemInfo;
\r
9271 while( list->id != 0 ) {
\r
9272 if( list->id == id ) {
\r
9273 result = list->name;
\r
9283 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9285 const char * name = GLT_FindItem( id );
\r
9288 if( index >= 0 ) {
\r
9289 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9292 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9297 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9301 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9304 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9308 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9310 pc = GLT_ALL_TAGS;
\r
9313 if( strchr( tags, *pc ) == 0 ) {
\r
9314 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9319 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9322 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9324 char result = '\0';
\r
9327 GLT_Item * list = GLT_ItemInfo;
\r
9329 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9330 while( list->id != 0 ) {
\r
9331 if( strcmp( list->name, name ) == 0 ) {
\r
9332 result = list->id;
\r
9343 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9345 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9346 int idx2 = idx1 + delta;
\r
9347 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9349 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9352 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9353 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9354 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9355 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9359 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9361 static char glt[64];
\r
9362 static char * lpUserGLT;
\r
9366 case WM_INITDIALOG:
\r
9367 lpUserGLT = (char *) lParam;
\r
9369 strcpy( glt, lpUserGLT );
\r
9371 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9373 /* Initialize list */
\r
9374 GLT_TagsToList( hDlg, glt );
\r
9376 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9381 switch( LOWORD(wParam) ) {
\r
9384 char * pc = lpUserGLT;
\r
9386 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9390 id = GLT_ListItemToTag( hDlg, idx );
\r
9394 } while( id != '\0' );
\r
9396 EndDialog( hDlg, 0 );
\r
9399 EndDialog( hDlg, 1 );
\r
9402 case IDC_GLT_Default:
\r
9403 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9404 GLT_TagsToList( hDlg, glt );
\r
9407 case IDC_GLT_Restore:
\r
9408 strcpy( glt, lpUserGLT );
\r
9409 GLT_TagsToList( hDlg, glt );
\r
9413 GLT_MoveSelection( hDlg, -1 );
\r
9416 case IDC_GLT_Down:
\r
9417 GLT_MoveSelection( hDlg, +1 );
\r
9427 int GameListOptions()
\r
9431 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9433 strcpy( glt, appData.gameListTags );
\r
9435 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9437 if( result == 0 ) {
\r
9438 /* [AS] Memory leak here! */
\r
9439 appData.gameListTags = strdup( glt );
\r
9447 DisplayIcsInteractionTitle(char *str)
\r
9449 char consoleTitle[MSG_SIZ];
\r
9451 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9452 SetWindowText(hwndConsole, consoleTitle);
\r
9456 DrawPosition(int fullRedraw, Board board)
\r
9458 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9465 fromX = fromY = -1;
\r
9466 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9467 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9468 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9469 dragInfo.lastpos = dragInfo.pos;
\r
9470 dragInfo.start.x = dragInfo.start.y = -1;
\r
9471 dragInfo.from = dragInfo.start;
\r
9473 DrawPosition(TRUE, NULL);
\r
9479 CommentPopUp(char *title, char *str)
\r
9481 HWND hwnd = GetActiveWindow();
\r
9482 EitherCommentPopUp(0, title, str, FALSE);
\r
9483 SetActiveWindow(hwnd);
\r
9487 CommentPopDown(void)
\r
9489 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9490 if (commentDialog) {
\r
9491 ShowWindow(commentDialog, SW_HIDE);
\r
9493 commentDialogUp = FALSE;
\r
9497 EditCommentPopUp(int index, char *title, char *str)
\r
9499 EitherCommentPopUp(index, title, str, TRUE);
\r
9506 MyPlaySound(&sounds[(int)SoundMove]);
\r
9509 VOID PlayIcsWinSound()
\r
9511 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9514 VOID PlayIcsLossSound()
\r
9516 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9519 VOID PlayIcsDrawSound()
\r
9521 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9524 VOID PlayIcsUnfinishedSound()
\r
9526 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9532 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9540 consoleEcho = TRUE;
\r
9541 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9542 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9543 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9552 consoleEcho = FALSE;
\r
9553 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9554 /* This works OK: set text and background both to the same color */
\r
9556 cf.crTextColor = COLOR_ECHOOFF;
\r
9557 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9558 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9561 /* No Raw()...? */
\r
9563 void Colorize(ColorClass cc, int continuation)
\r
9565 currentColorClass = cc;
\r
9566 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9567 consoleCF.crTextColor = textAttribs[cc].color;
\r
9568 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9569 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9575 static char buf[MSG_SIZ];
\r
9576 DWORD bufsiz = MSG_SIZ;
\r
9578 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9579 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9581 if (!GetUserName(buf, &bufsiz)) {
\r
9582 /*DisplayError("Error getting user name", GetLastError());*/
\r
9583 strcpy(buf, "User");
\r
9591 static char buf[MSG_SIZ];
\r
9592 DWORD bufsiz = MSG_SIZ;
\r
9594 if (!GetComputerName(buf, &bufsiz)) {
\r
9595 /*DisplayError("Error getting host name", GetLastError());*/
\r
9596 strcpy(buf, "Unknown");
\r
9603 ClockTimerRunning()
\r
9605 return clockTimerEvent != 0;
\r
9611 if (clockTimerEvent == 0) return FALSE;
\r
9612 KillTimer(hwndMain, clockTimerEvent);
\r
9613 clockTimerEvent = 0;
\r
9618 StartClockTimer(long millisec)
\r
9620 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9621 (UINT) millisec, NULL);
\r
9625 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9628 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9630 if(appData.noGUI) return;
\r
9631 hdc = GetDC(hwndMain);
\r
9632 if (!IsIconic(hwndMain)) {
\r
9633 DisplayAClock(hdc, timeRemaining, highlight,
\r
9634 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9636 if (highlight && iconCurrent == iconBlack) {
\r
9637 iconCurrent = iconWhite;
\r
9638 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9639 if (IsIconic(hwndMain)) {
\r
9640 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9643 (void) ReleaseDC(hwndMain, hdc);
\r
9645 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9649 DisplayBlackClock(long timeRemaining, int highlight)
\r
9652 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9654 if(appData.noGUI) return;
\r
9655 hdc = GetDC(hwndMain);
\r
9656 if (!IsIconic(hwndMain)) {
\r
9657 DisplayAClock(hdc, timeRemaining, highlight,
\r
9658 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9660 if (highlight && iconCurrent == iconWhite) {
\r
9661 iconCurrent = iconBlack;
\r
9662 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9663 if (IsIconic(hwndMain)) {
\r
9664 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9667 (void) ReleaseDC(hwndMain, hdc);
\r
9669 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9674 LoadGameTimerRunning()
\r
9676 return loadGameTimerEvent != 0;
\r
9680 StopLoadGameTimer()
\r
9682 if (loadGameTimerEvent == 0) return FALSE;
\r
9683 KillTimer(hwndMain, loadGameTimerEvent);
\r
9684 loadGameTimerEvent = 0;
\r
9689 StartLoadGameTimer(long millisec)
\r
9691 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9692 (UINT) millisec, NULL);
\r
9700 char fileTitle[MSG_SIZ];
\r
9702 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9703 f = OpenFileDialog(hwndMain, "a", defName,
\r
9704 appData.oldSaveStyle ? "gam" : "pgn",
\r
9706 "Save Game to File", NULL, fileTitle, NULL);
\r
9708 SaveGame(f, 0, "");
\r
9715 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9717 if (delayedTimerEvent != 0) {
\r
9718 if (appData.debugMode) {
\r
9719 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9721 KillTimer(hwndMain, delayedTimerEvent);
\r
9722 delayedTimerEvent = 0;
\r
9723 delayedTimerCallback();
\r
9725 delayedTimerCallback = cb;
\r
9726 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9727 (UINT) millisec, NULL);
\r
9730 DelayedEventCallback
\r
9733 if (delayedTimerEvent) {
\r
9734 return delayedTimerCallback;
\r
9741 CancelDelayedEvent()
\r
9743 if (delayedTimerEvent) {
\r
9744 KillTimer(hwndMain, delayedTimerEvent);
\r
9745 delayedTimerEvent = 0;
\r
9749 DWORD GetWin32Priority(int nice)
\r
9750 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9752 REALTIME_PRIORITY_CLASS 0x00000100
\r
9753 HIGH_PRIORITY_CLASS 0x00000080
\r
9754 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9755 NORMAL_PRIORITY_CLASS 0x00000020
\r
9756 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9757 IDLE_PRIORITY_CLASS 0x00000040
\r
9759 if (nice < -15) return 0x00000080;
\r
9760 if (nice < 0) return 0x00008000;
\r
9761 if (nice == 0) return 0x00000020;
\r
9762 if (nice < 15) return 0x00004000;
\r
9763 return 0x00000040;
\r
9766 /* Start a child process running the given program.
\r
9767 The process's standard output can be read from "from", and its
\r
9768 standard input can be written to "to".
\r
9769 Exit with fatal error if anything goes wrong.
\r
9770 Returns an opaque pointer that can be used to destroy the process
\r
9774 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9776 #define BUFSIZE 4096
\r
9778 HANDLE hChildStdinRd, hChildStdinWr,
\r
9779 hChildStdoutRd, hChildStdoutWr;
\r
9780 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9781 SECURITY_ATTRIBUTES saAttr;
\r
9783 PROCESS_INFORMATION piProcInfo;
\r
9784 STARTUPINFO siStartInfo;
\r
9786 char buf[MSG_SIZ];
\r
9789 if (appData.debugMode) {
\r
9790 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9795 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9796 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9797 saAttr.bInheritHandle = TRUE;
\r
9798 saAttr.lpSecurityDescriptor = NULL;
\r
9801 * The steps for redirecting child's STDOUT:
\r
9802 * 1. Create anonymous pipe to be STDOUT for child.
\r
9803 * 2. Create a noninheritable duplicate of read handle,
\r
9804 * and close the inheritable read handle.
\r
9807 /* Create a pipe for the child's STDOUT. */
\r
9808 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9809 return GetLastError();
\r
9812 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9813 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9814 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9815 FALSE, /* not inherited */
\r
9816 DUPLICATE_SAME_ACCESS);
\r
9818 return GetLastError();
\r
9820 CloseHandle(hChildStdoutRd);
\r
9823 * The steps for redirecting child's STDIN:
\r
9824 * 1. Create anonymous pipe to be STDIN for child.
\r
9825 * 2. Create a noninheritable duplicate of write handle,
\r
9826 * and close the inheritable write handle.
\r
9829 /* Create a pipe for the child's STDIN. */
\r
9830 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9831 return GetLastError();
\r
9834 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9835 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9836 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9837 FALSE, /* not inherited */
\r
9838 DUPLICATE_SAME_ACCESS);
\r
9840 return GetLastError();
\r
9842 CloseHandle(hChildStdinWr);
\r
9844 /* Arrange to (1) look in dir for the child .exe file, and
\r
9845 * (2) have dir be the child's working directory. Interpret
\r
9846 * dir relative to the directory WinBoard loaded from. */
\r
9847 GetCurrentDirectory(MSG_SIZ, buf);
\r
9848 SetCurrentDirectory(installDir);
\r
9849 SetCurrentDirectory(dir);
\r
9851 /* Now create the child process. */
\r
9853 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9854 siStartInfo.lpReserved = NULL;
\r
9855 siStartInfo.lpDesktop = NULL;
\r
9856 siStartInfo.lpTitle = NULL;
\r
9857 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9858 siStartInfo.cbReserved2 = 0;
\r
9859 siStartInfo.lpReserved2 = NULL;
\r
9860 siStartInfo.hStdInput = hChildStdinRd;
\r
9861 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9862 siStartInfo.hStdError = hChildStdoutWr;
\r
9864 fSuccess = CreateProcess(NULL,
\r
9865 cmdLine, /* command line */
\r
9866 NULL, /* process security attributes */
\r
9867 NULL, /* primary thread security attrs */
\r
9868 TRUE, /* handles are inherited */
\r
9869 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9870 NULL, /* use parent's environment */
\r
9872 &siStartInfo, /* STARTUPINFO pointer */
\r
9873 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9875 err = GetLastError();
\r
9876 SetCurrentDirectory(buf); /* return to prev directory */
\r
9881 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9882 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9883 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9886 /* Close the handles we don't need in the parent */
\r
9887 CloseHandle(piProcInfo.hThread);
\r
9888 CloseHandle(hChildStdinRd);
\r
9889 CloseHandle(hChildStdoutWr);
\r
9891 /* Prepare return value */
\r
9892 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9893 cp->kind = CPReal;
\r
9894 cp->hProcess = piProcInfo.hProcess;
\r
9895 cp->pid = piProcInfo.dwProcessId;
\r
9896 cp->hFrom = hChildStdoutRdDup;
\r
9897 cp->hTo = hChildStdinWrDup;
\r
9899 *pr = (void *) cp;
\r
9901 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9902 2000 where engines sometimes don't see the initial command(s)
\r
9903 from WinBoard and hang. I don't understand how that can happen,
\r
9904 but the Sleep is harmless, so I've put it in. Others have also
\r
9905 reported what may be the same problem, so hopefully this will fix
\r
9906 it for them too. */
\r
9914 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9916 ChildProc *cp; int result;
\r
9918 cp = (ChildProc *) pr;
\r
9919 if (cp == NULL) return;
\r
9921 switch (cp->kind) {
\r
9923 /* TerminateProcess is considered harmful, so... */
\r
9924 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9925 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9926 /* The following doesn't work because the chess program
\r
9927 doesn't "have the same console" as WinBoard. Maybe
\r
9928 we could arrange for this even though neither WinBoard
\r
9929 nor the chess program uses a console for stdio? */
\r
9930 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9932 /* [AS] Special termination modes for misbehaving programs... */
\r
9933 if( signal == 9 ) {
\r
9934 result = TerminateProcess( cp->hProcess, 0 );
\r
9936 if ( appData.debugMode) {
\r
9937 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9940 else if( signal == 10 ) {
\r
9941 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9943 if( dw != WAIT_OBJECT_0 ) {
\r
9944 result = TerminateProcess( cp->hProcess, 0 );
\r
9946 if ( appData.debugMode) {
\r
9947 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9953 CloseHandle(cp->hProcess);
\r
9957 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9961 closesocket(cp->sock);
\r
9966 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9967 closesocket(cp->sock);
\r
9968 closesocket(cp->sock2);
\r
9976 InterruptChildProcess(ProcRef pr)
\r
9980 cp = (ChildProc *) pr;
\r
9981 if (cp == NULL) return;
\r
9982 switch (cp->kind) {
\r
9984 /* The following doesn't work because the chess program
\r
9985 doesn't "have the same console" as WinBoard. Maybe
\r
9986 we could arrange for this even though neither WinBoard
\r
9987 nor the chess program uses a console for stdio */
\r
9988 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9993 /* Can't interrupt */
\r
9997 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10004 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10006 char cmdLine[MSG_SIZ];
\r
10008 if (port[0] == NULLCHAR) {
\r
10009 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10011 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10013 return StartChildProcess(cmdLine, "", pr);
\r
10017 /* Code to open TCP sockets */
\r
10020 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10025 struct sockaddr_in sa, mysa;
\r
10026 struct hostent FAR *hp;
\r
10027 unsigned short uport;
\r
10028 WORD wVersionRequested;
\r
10031 /* Initialize socket DLL */
\r
10032 wVersionRequested = MAKEWORD(1, 1);
\r
10033 err = WSAStartup(wVersionRequested, &wsaData);
\r
10034 if (err != 0) return err;
\r
10036 /* Make socket */
\r
10037 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10038 err = WSAGetLastError();
\r
10043 /* Bind local address using (mostly) don't-care values.
\r
10045 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10046 mysa.sin_family = AF_INET;
\r
10047 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10048 uport = (unsigned short) 0;
\r
10049 mysa.sin_port = htons(uport);
\r
10050 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10051 == SOCKET_ERROR) {
\r
10052 err = WSAGetLastError();
\r
10057 /* Resolve remote host name */
\r
10058 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10059 if (!(hp = gethostbyname(host))) {
\r
10060 unsigned int b0, b1, b2, b3;
\r
10062 err = WSAGetLastError();
\r
10064 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10065 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10066 hp->h_addrtype = AF_INET;
\r
10067 hp->h_length = 4;
\r
10068 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10069 hp->h_addr_list[0] = (char *) malloc(4);
\r
10070 hp->h_addr_list[0][0] = (char) b0;
\r
10071 hp->h_addr_list[0][1] = (char) b1;
\r
10072 hp->h_addr_list[0][2] = (char) b2;
\r
10073 hp->h_addr_list[0][3] = (char) b3;
\r
10079 sa.sin_family = hp->h_addrtype;
\r
10080 uport = (unsigned short) atoi(port);
\r
10081 sa.sin_port = htons(uport);
\r
10082 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10084 /* Make connection */
\r
10085 if (connect(s, (struct sockaddr *) &sa,
\r
10086 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10087 err = WSAGetLastError();
\r
10092 /* Prepare return value */
\r
10093 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10094 cp->kind = CPSock;
\r
10096 *pr = (ProcRef *) cp;
\r
10102 OpenCommPort(char *name, ProcRef *pr)
\r
10107 char fullname[MSG_SIZ];
\r
10109 if (*name != '\\')
\r
10110 sprintf(fullname, "\\\\.\\%s", name);
\r
10112 strcpy(fullname, name);
\r
10114 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10115 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10116 if (h == (HANDLE) -1) {
\r
10117 return GetLastError();
\r
10121 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10123 /* Accumulate characters until a 100ms pause, then parse */
\r
10124 ct.ReadIntervalTimeout = 100;
\r
10125 ct.ReadTotalTimeoutMultiplier = 0;
\r
10126 ct.ReadTotalTimeoutConstant = 0;
\r
10127 ct.WriteTotalTimeoutMultiplier = 0;
\r
10128 ct.WriteTotalTimeoutConstant = 0;
\r
10129 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10131 /* Prepare return value */
\r
10132 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10133 cp->kind = CPComm;
\r
10136 *pr = (ProcRef *) cp;
\r
10142 OpenLoopback(ProcRef *pr)
\r
10144 DisplayFatalError("Not implemented", 0, 1);
\r
10150 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10154 SOCKET s, s2, s3;
\r
10155 struct sockaddr_in sa, mysa;
\r
10156 struct hostent FAR *hp;
\r
10157 unsigned short uport;
\r
10158 WORD wVersionRequested;
\r
10161 char stderrPortStr[MSG_SIZ];
\r
10163 /* Initialize socket DLL */
\r
10164 wVersionRequested = MAKEWORD(1, 1);
\r
10165 err = WSAStartup(wVersionRequested, &wsaData);
\r
10166 if (err != 0) return err;
\r
10168 /* Resolve remote host name */
\r
10169 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10170 if (!(hp = gethostbyname(host))) {
\r
10171 unsigned int b0, b1, b2, b3;
\r
10173 err = WSAGetLastError();
\r
10175 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10176 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10177 hp->h_addrtype = AF_INET;
\r
10178 hp->h_length = 4;
\r
10179 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10180 hp->h_addr_list[0] = (char *) malloc(4);
\r
10181 hp->h_addr_list[0][0] = (char) b0;
\r
10182 hp->h_addr_list[0][1] = (char) b1;
\r
10183 hp->h_addr_list[0][2] = (char) b2;
\r
10184 hp->h_addr_list[0][3] = (char) b3;
\r
10190 sa.sin_family = hp->h_addrtype;
\r
10191 uport = (unsigned short) 514;
\r
10192 sa.sin_port = htons(uport);
\r
10193 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10195 /* Bind local socket to unused "privileged" port address
\r
10197 s = INVALID_SOCKET;
\r
10198 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10199 mysa.sin_family = AF_INET;
\r
10200 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10201 for (fromPort = 1023;; fromPort--) {
\r
10202 if (fromPort < 0) {
\r
10204 return WSAEADDRINUSE;
\r
10206 if (s == INVALID_SOCKET) {
\r
10207 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10208 err = WSAGetLastError();
\r
10213 uport = (unsigned short) fromPort;
\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
10218 if (err == WSAEADDRINUSE) continue;
\r
10222 if (connect(s, (struct sockaddr *) &sa,
\r
10223 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10224 err = WSAGetLastError();
\r
10225 if (err == WSAEADDRINUSE) {
\r
10236 /* Bind stderr local socket to unused "privileged" port address
\r
10238 s2 = INVALID_SOCKET;
\r
10239 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10240 mysa.sin_family = AF_INET;
\r
10241 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10242 for (fromPort = 1023;; fromPort--) {
\r
10243 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10244 if (fromPort < 0) {
\r
10245 (void) closesocket(s);
\r
10247 return WSAEADDRINUSE;
\r
10249 if (s2 == INVALID_SOCKET) {
\r
10250 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10251 err = WSAGetLastError();
\r
10257 uport = (unsigned short) fromPort;
\r
10258 mysa.sin_port = htons(uport);
\r
10259 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10260 == SOCKET_ERROR) {
\r
10261 err = WSAGetLastError();
\r
10262 if (err == WSAEADDRINUSE) continue;
\r
10263 (void) closesocket(s);
\r
10267 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10268 err = WSAGetLastError();
\r
10269 if (err == WSAEADDRINUSE) {
\r
10271 s2 = INVALID_SOCKET;
\r
10274 (void) closesocket(s);
\r
10275 (void) closesocket(s2);
\r
10281 prevStderrPort = fromPort; // remember port used
\r
10282 sprintf(stderrPortStr, "%d", fromPort);
\r
10284 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10285 err = WSAGetLastError();
\r
10286 (void) closesocket(s);
\r
10287 (void) closesocket(s2);
\r
10292 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10293 err = WSAGetLastError();
\r
10294 (void) closesocket(s);
\r
10295 (void) closesocket(s2);
\r
10299 if (*user == NULLCHAR) user = UserName();
\r
10300 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10301 err = WSAGetLastError();
\r
10302 (void) closesocket(s);
\r
10303 (void) closesocket(s2);
\r
10307 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10308 err = WSAGetLastError();
\r
10309 (void) closesocket(s);
\r
10310 (void) closesocket(s2);
\r
10315 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10316 err = WSAGetLastError();
\r
10317 (void) closesocket(s);
\r
10318 (void) closesocket(s2);
\r
10322 (void) closesocket(s2); /* Stop listening */
\r
10324 /* Prepare return value */
\r
10325 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10326 cp->kind = CPRcmd;
\r
10329 *pr = (ProcRef *) cp;
\r
10336 AddInputSource(ProcRef pr, int lineByLine,
\r
10337 InputCallback func, VOIDSTAR closure)
\r
10339 InputSource *is, *is2 = NULL;
\r
10340 ChildProc *cp = (ChildProc *) pr;
\r
10342 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10343 is->lineByLine = lineByLine;
\r
10345 is->closure = closure;
\r
10346 is->second = NULL;
\r
10347 is->next = is->buf;
\r
10348 if (pr == NoProc) {
\r
10349 is->kind = CPReal;
\r
10350 consoleInputSource = is;
\r
10352 is->kind = cp->kind;
\r
10354 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10355 we create all threads suspended so that the is->hThread variable can be
\r
10356 safely assigned, then let the threads start with ResumeThread.
\r
10358 switch (cp->kind) {
\r
10360 is->hFile = cp->hFrom;
\r
10361 cp->hFrom = NULL; /* now owned by InputThread */
\r
10363 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10364 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10368 is->hFile = cp->hFrom;
\r
10369 cp->hFrom = NULL; /* now owned by InputThread */
\r
10371 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10372 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10376 is->sock = cp->sock;
\r
10378 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10379 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10383 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10385 is->sock = cp->sock;
\r
10386 is->second = is2;
\r
10387 is2->sock = cp->sock2;
\r
10388 is2->second = is2;
\r
10390 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10391 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10393 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10394 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10398 if( is->hThread != NULL ) {
\r
10399 ResumeThread( is->hThread );
\r
10402 if( is2 != NULL && is2->hThread != NULL ) {
\r
10403 ResumeThread( is2->hThread );
\r
10407 return (InputSourceRef) is;
\r
10411 RemoveInputSource(InputSourceRef isr)
\r
10415 is = (InputSource *) isr;
\r
10416 is->hThread = NULL; /* tell thread to stop */
\r
10417 CloseHandle(is->hThread);
\r
10418 if (is->second != NULL) {
\r
10419 is->second->hThread = NULL;
\r
10420 CloseHandle(is->second->hThread);
\r
10426 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10429 int outCount = SOCKET_ERROR;
\r
10430 ChildProc *cp = (ChildProc *) pr;
\r
10431 static OVERLAPPED ovl;
\r
10433 if (pr == NoProc) {
\r
10434 ConsoleOutput(message, count, FALSE);
\r
10438 if (ovl.hEvent == NULL) {
\r
10439 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10441 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10443 switch (cp->kind) {
\r
10446 outCount = send(cp->sock, message, count, 0);
\r
10447 if (outCount == SOCKET_ERROR) {
\r
10448 *outError = WSAGetLastError();
\r
10450 *outError = NO_ERROR;
\r
10455 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10456 &dOutCount, NULL)) {
\r
10457 *outError = NO_ERROR;
\r
10458 outCount = (int) dOutCount;
\r
10460 *outError = GetLastError();
\r
10465 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10466 &dOutCount, &ovl);
\r
10467 if (*outError == NO_ERROR) {
\r
10468 outCount = (int) dOutCount;
\r
10476 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10479 /* Ignore delay, not implemented for WinBoard */
\r
10480 return OutputToProcess(pr, message, count, outError);
\r
10485 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10486 char *buf, int count, int error)
\r
10488 DisplayFatalError("Not implemented", 0, 1);
\r
10491 /* see wgamelist.c for Game List functions */
\r
10492 /* see wedittags.c for Edit Tags functions */
\r
10499 char buf[MSG_SIZ];
\r
10502 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10503 f = fopen(buf, "r");
\r
10505 ProcessICSInitScript(f);
\r
10513 StartAnalysisClock()
\r
10515 if (analysisTimerEvent) return;
\r
10516 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10517 (UINT) 2000, NULL);
\r
10521 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10523 static HANDLE hwndText;
\r
10525 static int sizeX, sizeY;
\r
10526 int newSizeX, newSizeY, flags;
\r
10529 switch (message) {
\r
10530 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10531 /* Initialize the dialog items */
\r
10532 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10533 SetWindowText(hDlg, analysisTitle);
\r
10534 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10535 /* Size and position the dialog */
\r
10536 if (!analysisDialog) {
\r
10537 analysisDialog = hDlg;
\r
10538 flags = SWP_NOZORDER;
\r
10539 GetClientRect(hDlg, &rect);
\r
10540 sizeX = rect.right;
\r
10541 sizeY = rect.bottom;
\r
10542 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10543 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10544 WINDOWPLACEMENT wp;
\r
10545 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10546 wp.length = sizeof(WINDOWPLACEMENT);
\r
10548 wp.showCmd = SW_SHOW;
\r
10549 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10550 wp.rcNormalPosition.left = analysisX;
\r
10551 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10552 wp.rcNormalPosition.top = analysisY;
\r
10553 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10554 SetWindowPlacement(hDlg, &wp);
\r
10556 GetClientRect(hDlg, &rect);
\r
10557 newSizeX = rect.right;
\r
10558 newSizeY = rect.bottom;
\r
10559 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10560 newSizeX, newSizeY);
\r
10561 sizeX = newSizeX;
\r
10562 sizeY = newSizeY;
\r
10567 case WM_COMMAND: /* message: received a command */
\r
10568 switch (LOWORD(wParam)) {
\r
10570 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10571 ExitAnalyzeMode();
\r
10583 newSizeX = LOWORD(lParam);
\r
10584 newSizeY = HIWORD(lParam);
\r
10585 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10586 sizeX = newSizeX;
\r
10587 sizeY = newSizeY;
\r
10590 case WM_GETMINMAXINFO:
\r
10591 /* Prevent resizing window too small */
\r
10592 mmi = (MINMAXINFO *) lParam;
\r
10593 mmi->ptMinTrackSize.x = 100;
\r
10594 mmi->ptMinTrackSize.y = 100;
\r
10601 AnalysisPopUp(char* title, char* str)
\r
10607 EngineOutputPopUp();
\r
10610 if (str == NULL) str = "";
\r
10611 p = (char *) malloc(2 * strlen(str) + 2);
\r
10614 if (*str == '\n') *q++ = '\r';
\r
10618 if (analysisText != NULL) free(analysisText);
\r
10619 analysisText = p;
\r
10621 if (analysisDialog) {
\r
10622 SetWindowText(analysisDialog, title);
\r
10623 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10624 ShowWindow(analysisDialog, SW_SHOW);
\r
10626 analysisTitle = title;
\r
10627 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10628 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10629 hwndMain, (DLGPROC)lpProc);
\r
10630 FreeProcInstance(lpProc);
\r
10632 analysisDialogUp = TRUE;
\r
10636 AnalysisPopDown()
\r
10638 if (analysisDialog) {
\r
10639 ShowWindow(analysisDialog, SW_HIDE);
\r
10641 analysisDialogUp = FALSE;
\r
10646 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10648 highlightInfo.sq[0].x = fromX;
\r
10649 highlightInfo.sq[0].y = fromY;
\r
10650 highlightInfo.sq[1].x = toX;
\r
10651 highlightInfo.sq[1].y = toY;
\r
10655 ClearHighlights()
\r
10657 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10658 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10662 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10664 premoveHighlightInfo.sq[0].x = fromX;
\r
10665 premoveHighlightInfo.sq[0].y = fromY;
\r
10666 premoveHighlightInfo.sq[1].x = toX;
\r
10667 premoveHighlightInfo.sq[1].y = toY;
\r
10671 ClearPremoveHighlights()
\r
10673 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10674 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10678 ShutDownFrontEnd()
\r
10680 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10681 DeleteClipboardTempFiles();
\r
10687 if (IsIconic(hwndMain))
\r
10688 ShowWindow(hwndMain, SW_RESTORE);
\r
10690 SetActiveWindow(hwndMain);
\r
10694 * Prototypes for animation support routines
\r
10696 static void ScreenSquare(int column, int row, POINT * pt);
\r
10697 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10698 POINT frames[], int * nFrames);
\r
10702 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10703 { // [HGM] atomic: animate blast wave
\r
10705 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10706 explodeInfo.fromX = fromX;
\r
10707 explodeInfo.fromY = fromY;
\r
10708 explodeInfo.toX = toX;
\r
10709 explodeInfo.toY = toY;
\r
10710 for(i=1; i<nFrames; i++) {
\r
10711 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10712 DrawPosition(FALSE, NULL);
\r
10713 Sleep(appData.animSpeed);
\r
10715 explodeInfo.radius = 0;
\r
10716 DrawPosition(TRUE, NULL);
\r
10719 #define kFactor 4
\r
10722 AnimateMove(board, fromX, fromY, toX, toY)
\r
10729 ChessSquare piece;
\r
10730 POINT start, finish, mid;
\r
10731 POINT frames[kFactor * 2 + 1];
\r
10734 if (!appData.animate) return;
\r
10735 if (doingSizing) return;
\r
10736 if (fromY < 0 || fromX < 0) return;
\r
10737 piece = board[fromY][fromX];
\r
10738 if (piece >= EmptySquare) return;
\r
10740 ScreenSquare(fromX, fromY, &start);
\r
10741 ScreenSquare(toX, toY, &finish);
\r
10743 /* All pieces except knights move in straight line */
\r
10744 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10745 mid.x = start.x + (finish.x - start.x) / 2;
\r
10746 mid.y = start.y + (finish.y - start.y) / 2;
\r
10748 /* Knight: make diagonal movement then straight */
\r
10749 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10750 mid.x = start.x + (finish.x - start.x) / 2;
\r
10751 mid.y = finish.y;
\r
10753 mid.x = finish.x;
\r
10754 mid.y = start.y + (finish.y - start.y) / 2;
\r
10758 /* Don't use as many frames for very short moves */
\r
10759 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10760 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10762 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10764 animInfo.from.x = fromX;
\r
10765 animInfo.from.y = fromY;
\r
10766 animInfo.to.x = toX;
\r
10767 animInfo.to.y = toY;
\r
10768 animInfo.lastpos = start;
\r
10769 animInfo.piece = piece;
\r
10770 for (n = 0; n < nFrames; n++) {
\r
10771 animInfo.pos = frames[n];
\r
10772 DrawPosition(FALSE, NULL);
\r
10773 animInfo.lastpos = animInfo.pos;
\r
10774 Sleep(appData.animSpeed);
\r
10776 animInfo.pos = finish;
\r
10777 DrawPosition(FALSE, NULL);
\r
10778 animInfo.piece = EmptySquare;
\r
10779 if(gameInfo.variant == VariantAtomic &&
\r
10780 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10781 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10784 /* Convert board position to corner of screen rect and color */
\r
10787 ScreenSquare(column, row, pt)
\r
10788 int column; int row; POINT * pt;
\r
10791 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10792 pt->y = lineGap + row * (squareSize + lineGap);
\r
10794 pt->x = lineGap + column * (squareSize + lineGap);
\r
10795 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10799 /* Generate a series of frame coords from start->mid->finish.
\r
10800 The movement rate doubles until the half way point is
\r
10801 reached, then halves back down to the final destination,
\r
10802 which gives a nice slow in/out effect. The algorithmn
\r
10803 may seem to generate too many intermediates for short
\r
10804 moves, but remember that the purpose is to attract the
\r
10805 viewers attention to the piece about to be moved and
\r
10806 then to where it ends up. Too few frames would be less
\r
10810 Tween(start, mid, finish, factor, frames, nFrames)
\r
10811 POINT * start; POINT * mid;
\r
10812 POINT * finish; int factor;
\r
10813 POINT frames[]; int * nFrames;
\r
10815 int n, fraction = 1, count = 0;
\r
10817 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10818 for (n = 0; n < factor; n++)
\r
10820 for (n = 0; n < factor; n++) {
\r
10821 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10822 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10824 fraction = fraction / 2;
\r
10828 frames[count] = *mid;
\r
10831 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10833 for (n = 0; n < factor; n++) {
\r
10834 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10835 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10837 fraction = fraction * 2;
\r
10839 *nFrames = count;
\r
10843 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10848 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10849 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10851 OutputDebugString( buf );
\r
10854 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10856 EvalGraphSet( first, last, current, pvInfoList );
\r
10859 void SetProgramStats( FrontEndProgramStats * stats )
\r
10864 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10865 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10867 OutputDebugString( buf );
\r
10870 EngineOutputUpdate( stats );
\r