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;
\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 winHeight <= screenHeight
\r
704 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
705 && winWidth <= 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 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3238 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3239 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3240 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3241 GetWindowRect(hwndMain, &wrect);
\r
3242 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3243 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3245 // [HGM] placement: let attached windows follow size change.
\r
3246 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3247 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3248 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3249 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3250 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3252 /* compensate if menu bar wrapped */
\r
3253 GetClientRect(hwndMain, &crect);
\r
3254 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3255 winHeight += offby;
\r
3257 case WMSZ_TOPLEFT:
\r
3258 SetWindowPos(hwndMain, NULL,
\r
3259 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3260 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3263 case WMSZ_TOPRIGHT:
\r
3265 SetWindowPos(hwndMain, NULL,
\r
3266 wrect.left, wrect.bottom - winHeight,
\r
3267 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3270 case WMSZ_BOTTOMLEFT:
\r
3272 SetWindowPos(hwndMain, NULL,
\r
3273 wrect.right - winWidth, wrect.top,
\r
3274 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3277 case WMSZ_BOTTOMRIGHT:
\r
3281 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3282 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3287 for (i = 0; i < N_BUTTONS; i++) {
\r
3288 if (buttonDesc[i].hwnd != NULL) {
\r
3289 DestroyWindow(buttonDesc[i].hwnd);
\r
3290 buttonDesc[i].hwnd = NULL;
\r
3292 if (appData.showButtonBar) {
\r
3293 buttonDesc[i].hwnd =
\r
3294 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3295 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3296 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3297 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3298 (HMENU) buttonDesc[i].id,
\r
3299 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3301 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3302 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3303 MAKELPARAM(FALSE, 0));
\r
3305 if (buttonDesc[i].id == IDM_Pause)
\r
3306 hwndPause = buttonDesc[i].hwnd;
\r
3307 buttonDesc[i].wndproc = (WNDPROC)
\r
3308 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3311 if (gridPen != NULL) DeleteObject(gridPen);
\r
3312 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3313 if (premovePen != NULL) DeleteObject(premovePen);
\r
3314 if (lineGap != 0) {
\r
3315 logbrush.lbStyle = BS_SOLID;
\r
3316 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3318 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3319 lineGap, &logbrush, 0, NULL);
\r
3320 logbrush.lbColor = highlightSquareColor;
\r
3322 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3323 lineGap, &logbrush, 0, NULL);
\r
3325 logbrush.lbColor = premoveHighlightColor;
\r
3327 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3328 lineGap, &logbrush, 0, NULL);
\r
3330 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3331 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3332 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3333 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3334 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3335 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3336 BOARD_WIDTH * (squareSize + lineGap);
\r
3337 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3339 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3340 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3341 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3342 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3343 lineGap / 2 + (i * (squareSize + lineGap));
\r
3344 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3345 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3346 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3350 /* [HGM] Licensing requirement */
\r
3352 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3355 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3357 GothicPopUp( "", VariantNormal);
\r
3360 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3362 /* Load piece bitmaps for this board size */
\r
3363 for (i=0; i<=2; i++) {
\r
3364 for (piece = WhitePawn;
\r
3365 (int) piece < (int) BlackPawn;
\r
3366 piece = (ChessSquare) ((int) piece + 1)) {
\r
3367 if (pieceBitmap[i][piece] != NULL)
\r
3368 DeleteObject(pieceBitmap[i][piece]);
\r
3372 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3373 // Orthodox Chess pieces
\r
3374 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3375 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3376 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3377 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3378 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3379 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3380 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3381 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3382 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3383 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3384 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3385 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3386 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3387 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3388 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3389 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3390 // in Shogi, Hijack the unused Queen for Lance
\r
3391 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3392 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3393 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3395 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3396 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3397 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3400 if(squareSize <= 72 && squareSize >= 33) {
\r
3401 /* A & C are available in most sizes now */
\r
3402 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3403 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3404 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3405 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3406 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3407 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3408 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3409 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3410 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3411 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3412 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3413 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3414 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3415 } else { // Smirf-like
\r
3416 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3417 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3418 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3420 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3421 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3422 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3423 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3424 } else { // WinBoard standard
\r
3425 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3426 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3427 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3432 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3433 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3434 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3435 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3436 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3437 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3438 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3439 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3440 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3441 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3442 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3443 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3444 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3445 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3446 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3447 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3448 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3449 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3450 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3451 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3452 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3453 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3454 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3455 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3456 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3457 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3458 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3459 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3460 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3461 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3462 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3464 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3465 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3466 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3467 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3468 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3469 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3470 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3471 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3472 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3473 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3474 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3475 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3476 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3478 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3479 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3480 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3481 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3482 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3483 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3484 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3485 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3486 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3487 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3488 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3489 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3492 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3493 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3494 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3495 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3496 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3497 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3498 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3499 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3500 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3501 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3502 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3503 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3504 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3505 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3506 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3510 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3511 /* special Shogi support in this size */
\r
3512 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3513 for (piece = WhitePawn;
\r
3514 (int) piece < (int) BlackPawn;
\r
3515 piece = (ChessSquare) ((int) piece + 1)) {
\r
3516 if (pieceBitmap[i][piece] != NULL)
\r
3517 DeleteObject(pieceBitmap[i][piece]);
\r
3520 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3521 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3522 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3523 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3524 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3525 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3526 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3527 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3528 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3529 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3530 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3531 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3532 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3533 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3534 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3535 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3536 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3537 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3538 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3539 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3540 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3541 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3542 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3543 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3544 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3545 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3546 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3547 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3548 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3549 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3550 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3551 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3552 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3553 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3554 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3555 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3556 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3557 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3558 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3559 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3560 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3561 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3567 PieceBitmap(ChessSquare p, int kind)
\r
3569 if ((int) p >= (int) BlackPawn)
\r
3570 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3572 return pieceBitmap[kind][(int) p];
\r
3575 /***************************************************************/
\r
3577 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3578 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3580 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3581 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3585 SquareToPos(int row, int column, int * x, int * y)
\r
3588 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3589 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3591 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3592 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3597 DrawCoordsOnDC(HDC hdc)
\r
3599 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
3600 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
3601 char str[2] = { NULLCHAR, NULLCHAR };
\r
3602 int oldMode, oldAlign, x, y, start, i;
\r
3606 if (!appData.showCoords)
\r
3609 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3611 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3612 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3613 oldAlign = GetTextAlign(hdc);
\r
3614 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3616 y = boardRect.top + lineGap;
\r
3617 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3619 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3620 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3621 str[0] = files[start + i];
\r
3622 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3623 y += squareSize + lineGap;
\r
3626 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3628 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3629 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3630 str[0] = ranks[start + i];
\r
3631 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3632 x += squareSize + lineGap;
\r
3635 SelectObject(hdc, oldBrush);
\r
3636 SetBkMode(hdc, oldMode);
\r
3637 SetTextAlign(hdc, oldAlign);
\r
3638 SelectObject(hdc, oldFont);
\r
3642 DrawGridOnDC(HDC hdc)
\r
3646 if (lineGap != 0) {
\r
3647 oldPen = SelectObject(hdc, gridPen);
\r
3648 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3649 SelectObject(hdc, oldPen);
\r
3653 #define HIGHLIGHT_PEN 0
\r
3654 #define PREMOVE_PEN 1
\r
3657 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3660 HPEN oldPen, hPen;
\r
3661 if (lineGap == 0) return;
\r
3663 x1 = boardRect.left +
\r
3664 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3665 y1 = boardRect.top +
\r
3666 lineGap/2 + y * (squareSize + lineGap);
\r
3668 x1 = boardRect.left +
\r
3669 lineGap/2 + x * (squareSize + lineGap);
\r
3670 y1 = boardRect.top +
\r
3671 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3673 hPen = pen ? premovePen : highlightPen;
\r
3674 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3675 MoveToEx(hdc, x1, y1, NULL);
\r
3676 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3677 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3678 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3679 LineTo(hdc, x1, y1);
\r
3680 SelectObject(hdc, oldPen);
\r
3684 DrawHighlightsOnDC(HDC hdc)
\r
3687 for (i=0; i<2; i++) {
\r
3688 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3689 DrawHighlightOnDC(hdc, TRUE,
\r
3690 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3693 for (i=0; i<2; i++) {
\r
3694 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3695 premoveHighlightInfo.sq[i].y >= 0) {
\r
3696 DrawHighlightOnDC(hdc, TRUE,
\r
3697 premoveHighlightInfo.sq[i].x,
\r
3698 premoveHighlightInfo.sq[i].y,
\r
3704 /* Note: sqcolor is used only in monoMode */
\r
3705 /* Note that this code is largely duplicated in woptions.c,
\r
3706 function DrawSampleSquare, so that needs to be updated too */
\r
3708 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3710 HBITMAP oldBitmap;
\r
3714 if (appData.blindfold) return;
\r
3716 /* [AS] Use font-based pieces if needed */
\r
3717 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3718 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3719 CreatePiecesFromFont();
\r
3721 if( fontBitmapSquareSize == squareSize ) {
\r
3722 int index = TranslatePieceToFontPiece(piece);
\r
3724 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3728 squareSize, squareSize,
\r
3733 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3737 squareSize, squareSize,
\r
3746 if (appData.monoMode) {
\r
3747 SelectObject(tmphdc, PieceBitmap(piece,
\r
3748 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3749 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3750 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3752 tmpSize = squareSize;
\r
3754 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3755 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3756 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3757 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3758 x += (squareSize - minorSize)>>1;
\r
3759 y += squareSize - minorSize - 2;
\r
3760 tmpSize = minorSize;
\r
3762 if (color || appData.allWhite ) {
\r
3763 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3765 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3766 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3767 if(appData.upsideDown && color==flipView)
\r
3768 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3770 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3772 /* Use black piece color for outline of white pieces */
\r
3773 /* Not sure this looks really good (though xboard does it).
\r
3774 Maybe better to have another selectable color, default black */
\r
3775 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3776 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3777 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3779 /* Use black for outline of white pieces */
\r
3780 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3781 if(appData.upsideDown && color==flipView)
\r
3782 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3784 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3788 /* Use white piece color for details of black pieces */
\r
3789 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3790 WHITE_PIECE ones aren't always the right shape. */
\r
3791 /* Not sure this looks really good (though xboard does it).
\r
3792 Maybe better to have another selectable color, default medium gray? */
\r
3793 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3794 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3795 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3796 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3797 SelectObject(hdc, blackPieceBrush);
\r
3798 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3800 /* Use square color for details of black pieces */
\r
3801 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3802 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3803 if(appData.upsideDown && !flipView)
\r
3804 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3806 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3809 SelectObject(hdc, oldBrush);
\r
3810 SelectObject(tmphdc, oldBitmap);
\r
3814 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3815 int GetBackTextureMode( int algo )
\r
3817 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3821 case BACK_TEXTURE_MODE_PLAIN:
\r
3822 result = 1; /* Always use identity map */
\r
3824 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3825 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3833 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3834 to handle redraws cleanly (as random numbers would always be different).
\r
3836 VOID RebuildTextureSquareInfo()
\r
3846 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3848 if( liteBackTexture != NULL ) {
\r
3849 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3850 lite_w = bi.bmWidth;
\r
3851 lite_h = bi.bmHeight;
\r
3855 if( darkBackTexture != NULL ) {
\r
3856 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3857 dark_w = bi.bmWidth;
\r
3858 dark_h = bi.bmHeight;
\r
3862 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3863 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3864 if( (col + row) & 1 ) {
\r
3866 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3867 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3868 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3869 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3874 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3875 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3876 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3877 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3884 /* [AS] Arrow highlighting support */
\r
3886 static int A_WIDTH = 5; /* Width of arrow body */
\r
3888 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3889 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3891 static double Sqr( double x )
\r
3896 static int Round( double x )
\r
3898 return (int) (x + 0.5);
\r
3901 /* Draw an arrow between two points using current settings */
\r
3902 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3905 double dx, dy, j, k, x, y;
\r
3907 if( d_x == s_x ) {
\r
3908 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3910 arrow[0].x = s_x + A_WIDTH;
\r
3913 arrow[1].x = s_x + A_WIDTH;
\r
3914 arrow[1].y = d_y - h;
\r
3916 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3917 arrow[2].y = d_y - h;
\r
3922 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3923 arrow[4].y = d_y - h;
\r
3925 arrow[5].x = s_x - A_WIDTH;
\r
3926 arrow[5].y = d_y - h;
\r
3928 arrow[6].x = s_x - A_WIDTH;
\r
3931 else if( d_y == s_y ) {
\r
3932 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3935 arrow[0].y = s_y + A_WIDTH;
\r
3937 arrow[1].x = d_x - w;
\r
3938 arrow[1].y = s_y + A_WIDTH;
\r
3940 arrow[2].x = d_x - w;
\r
3941 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3946 arrow[4].x = d_x - w;
\r
3947 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3949 arrow[5].x = d_x - w;
\r
3950 arrow[5].y = s_y - A_WIDTH;
\r
3953 arrow[6].y = s_y - A_WIDTH;
\r
3956 /* [AS] Needed a lot of paper for this! :-) */
\r
3957 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3958 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3960 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3962 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3967 arrow[0].x = Round(x - j);
\r
3968 arrow[0].y = Round(y + j*dx);
\r
3970 arrow[1].x = Round(x + j);
\r
3971 arrow[1].y = Round(y - j*dx);
\r
3974 x = (double) d_x - k;
\r
3975 y = (double) d_y - k*dy;
\r
3978 x = (double) d_x + k;
\r
3979 y = (double) d_y + k*dy;
\r
3982 arrow[2].x = Round(x + j);
\r
3983 arrow[2].y = Round(y - j*dx);
\r
3985 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3986 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3991 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3992 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3994 arrow[6].x = Round(x - j);
\r
3995 arrow[6].y = Round(y + j*dx);
\r
3998 Polygon( hdc, arrow, 7 );
\r
4001 /* [AS] Draw an arrow between two squares */
\r
4002 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4004 int s_x, s_y, d_x, d_y;
\r
4011 if( s_col == d_col && s_row == d_row ) {
\r
4015 /* Get source and destination points */
\r
4016 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4017 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4020 d_y += squareSize / 4;
\r
4022 else if( d_y < s_y ) {
\r
4023 d_y += 3 * squareSize / 4;
\r
4026 d_y += squareSize / 2;
\r
4030 d_x += squareSize / 4;
\r
4032 else if( d_x < s_x ) {
\r
4033 d_x += 3 * squareSize / 4;
\r
4036 d_x += squareSize / 2;
\r
4039 s_x += squareSize / 2;
\r
4040 s_y += squareSize / 2;
\r
4042 /* Adjust width */
\r
4043 A_WIDTH = squareSize / 14;
\r
4046 stLB.lbStyle = BS_SOLID;
\r
4047 stLB.lbColor = appData.highlightArrowColor;
\r
4050 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4051 holdpen = SelectObject( hdc, hpen );
\r
4052 hbrush = CreateBrushIndirect( &stLB );
\r
4053 holdbrush = SelectObject( hdc, hbrush );
\r
4055 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4057 SelectObject( hdc, holdpen );
\r
4058 SelectObject( hdc, holdbrush );
\r
4059 DeleteObject( hpen );
\r
4060 DeleteObject( hbrush );
\r
4063 BOOL HasHighlightInfo()
\r
4065 BOOL result = FALSE;
\r
4067 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4068 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4076 BOOL IsDrawArrowEnabled()
\r
4078 BOOL result = FALSE;
\r
4080 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4087 VOID DrawArrowHighlight( HDC hdc )
\r
4089 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4090 DrawArrowBetweenSquares( hdc,
\r
4091 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4092 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4096 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4098 HRGN result = NULL;
\r
4100 if( HasHighlightInfo() ) {
\r
4101 int x1, y1, x2, y2;
\r
4102 int sx, sy, dx, dy;
\r
4104 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4105 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4107 sx = MIN( x1, x2 );
\r
4108 sy = MIN( y1, y2 );
\r
4109 dx = MAX( x1, x2 ) + squareSize;
\r
4110 dy = MAX( y1, y2 ) + squareSize;
\r
4112 result = CreateRectRgn( sx, sy, dx, dy );
\r
4119 Warning: this function modifies the behavior of several other functions.
\r
4121 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4122 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4123 repaint is scattered all over the place, which is not good for features such as
\r
4124 "arrow highlighting" that require a full repaint of the board.
\r
4126 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4127 user interaction, when speed is not so important) but especially to avoid errors
\r
4128 in the displayed graphics.
\r
4130 In such patched places, I always try refer to this function so there is a single
\r
4131 place to maintain knowledge.
\r
4133 To restore the original behavior, just return FALSE unconditionally.
\r
4135 BOOL IsFullRepaintPreferrable()
\r
4137 BOOL result = FALSE;
\r
4139 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4140 /* Arrow may appear on the board */
\r
4148 This function is called by DrawPosition to know whether a full repaint must
\r
4151 Only DrawPosition may directly call this function, which makes use of
\r
4152 some state information. Other function should call DrawPosition specifying
\r
4153 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4155 BOOL DrawPositionNeedsFullRepaint()
\r
4157 BOOL result = FALSE;
\r
4160 Probably a slightly better policy would be to trigger a full repaint
\r
4161 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4162 but animation is fast enough that it's difficult to notice.
\r
4164 if( animInfo.piece == EmptySquare ) {
\r
4165 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4174 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4176 int row, column, x, y, square_color, piece_color;
\r
4177 ChessSquare piece;
\r
4179 HDC texture_hdc = NULL;
\r
4181 /* [AS] Initialize background textures if needed */
\r
4182 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4183 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4184 if( backTextureSquareSize != squareSize
\r
4185 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4186 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4187 backTextureSquareSize = squareSize;
\r
4188 RebuildTextureSquareInfo();
\r
4191 texture_hdc = CreateCompatibleDC( hdc );
\r
4194 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4195 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4197 SquareToPos(row, column, &x, &y);
\r
4199 piece = board[row][column];
\r
4201 square_color = ((column + row) % 2) == 1;
\r
4202 if( gameInfo.variant == VariantXiangqi ) {
\r
4203 square_color = !InPalace(row, column);
\r
4204 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4205 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4207 piece_color = (int) piece < (int) BlackPawn;
\r
4210 /* [HGM] holdings file: light square or black */
\r
4211 if(column == BOARD_LEFT-2) {
\r
4212 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4215 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4219 if(column == BOARD_RGHT + 1 ) {
\r
4220 if( row < gameInfo.holdingsSize )
\r
4223 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4227 if(column == BOARD_LEFT-1 ) /* left align */
\r
4228 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4229 else if( column == BOARD_RGHT) /* right align */
\r
4230 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4232 if (appData.monoMode) {
\r
4233 if (piece == EmptySquare) {
\r
4234 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4235 square_color ? WHITENESS : BLACKNESS);
\r
4237 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4240 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4241 /* [AS] Draw the square using a texture bitmap */
\r
4242 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4243 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4244 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4247 squareSize, squareSize,
\r
4250 backTextureSquareInfo[r][c].mode,
\r
4251 backTextureSquareInfo[r][c].x,
\r
4252 backTextureSquareInfo[r][c].y );
\r
4254 SelectObject( texture_hdc, hbm );
\r
4256 if (piece != EmptySquare) {
\r
4257 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4261 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4263 oldBrush = SelectObject(hdc, brush );
\r
4264 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4265 SelectObject(hdc, oldBrush);
\r
4266 if (piece != EmptySquare)
\r
4267 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4272 if( texture_hdc != NULL ) {
\r
4273 DeleteDC( texture_hdc );
\r
4277 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4278 void fputDW(FILE *f, int x)
\r
4280 fputc(x & 255, f);
\r
4281 fputc(x>>8 & 255, f);
\r
4282 fputc(x>>16 & 255, f);
\r
4283 fputc(x>>24 & 255, f);
\r
4286 #define MAX_CLIPS 200 /* more than enough */
\r
4289 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4291 // HBITMAP bufferBitmap;
\r
4296 int w = 100, h = 50;
\r
4298 if(logo == NULL) return;
\r
4299 // GetClientRect(hwndMain, &Rect);
\r
4300 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4301 // Rect.bottom-Rect.top+1);
\r
4302 tmphdc = CreateCompatibleDC(hdc);
\r
4303 hbm = SelectObject(tmphdc, logo);
\r
4304 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4308 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4309 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4310 SelectObject(tmphdc, hbm);
\r
4315 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4317 static Board lastReq, lastDrawn;
\r
4318 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4319 static int lastDrawnFlipView = 0;
\r
4320 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4321 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4324 HBITMAP bufferBitmap;
\r
4325 HBITMAP oldBitmap;
\r
4327 HRGN clips[MAX_CLIPS];
\r
4328 ChessSquare dragged_piece = EmptySquare;
\r
4330 /* I'm undecided on this - this function figures out whether a full
\r
4331 * repaint is necessary on its own, so there's no real reason to have the
\r
4332 * caller tell it that. I think this can safely be set to FALSE - but
\r
4333 * if we trust the callers not to request full repaints unnessesarily, then
\r
4334 * we could skip some clipping work. In other words, only request a full
\r
4335 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4336 * gamestart and similar) --Hawk
\r
4338 Boolean fullrepaint = repaint;
\r
4340 if( DrawPositionNeedsFullRepaint() ) {
\r
4341 fullrepaint = TRUE;
\r
4345 if( fullrepaint ) {
\r
4346 static int repaint_count = 0;
\r
4350 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4351 OutputDebugString( buf );
\r
4355 if (board == NULL) {
\r
4356 if (!lastReqValid) {
\r
4361 CopyBoard(lastReq, board);
\r
4365 if (doingSizing) {
\r
4369 if (IsIconic(hwndMain)) {
\r
4373 if (hdc == NULL) {
\r
4374 hdc = GetDC(hwndMain);
\r
4375 if (!appData.monoMode) {
\r
4376 SelectPalette(hdc, hPal, FALSE);
\r
4377 RealizePalette(hdc);
\r
4381 releaseDC = FALSE;
\r
4385 fprintf(debugFP, "*******************************\n"
\r
4387 "dragInfo.from (%d,%d)\n"
\r
4388 "dragInfo.start (%d,%d)\n"
\r
4389 "dragInfo.pos (%d,%d)\n"
\r
4390 "dragInfo.lastpos (%d,%d)\n",
\r
4391 repaint ? "TRUE" : "FALSE",
\r
4392 dragInfo.from.x, dragInfo.from.y,
\r
4393 dragInfo.start.x, dragInfo.start.y,
\r
4394 dragInfo.pos.x, dragInfo.pos.y,
\r
4395 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4396 fprintf(debugFP, "prev: ");
\r
4397 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4398 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4399 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4402 fprintf(debugFP, "\n");
\r
4403 fprintf(debugFP, "board: ");
\r
4404 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4405 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4406 fprintf(debugFP, "%d ", board[row][column]);
\r
4409 fprintf(debugFP, "\n");
\r
4413 /* Create some work-DCs */
\r
4414 hdcmem = CreateCompatibleDC(hdc);
\r
4415 tmphdc = CreateCompatibleDC(hdc);
\r
4417 /* If dragging is in progress, we temporarely remove the piece */
\r
4418 /* [HGM] or temporarily decrease count if stacked */
\r
4419 /* !! Moved to before board compare !! */
\r
4420 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4421 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4422 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4423 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4424 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4426 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4427 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4428 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4430 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4433 /* Figure out which squares need updating by comparing the
\r
4434 * newest board with the last drawn board and checking if
\r
4435 * flipping has changed.
\r
4437 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4438 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4439 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4440 if (lastDrawn[row][column] != board[row][column]) {
\r
4441 SquareToPos(row, column, &x, &y);
\r
4442 clips[num_clips++] =
\r
4443 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4447 for (i=0; i<2; i++) {
\r
4448 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4449 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4450 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4451 lastDrawnHighlight.sq[i].y >= 0) {
\r
4452 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4453 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4454 clips[num_clips++] =
\r
4455 CreateRectRgn(x - lineGap, y - lineGap,
\r
4456 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4458 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4459 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4460 clips[num_clips++] =
\r
4461 CreateRectRgn(x - lineGap, y - lineGap,
\r
4462 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4466 for (i=0; i<2; i++) {
\r
4467 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4468 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4469 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4470 lastDrawnPremove.sq[i].y >= 0) {
\r
4471 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4472 lastDrawnPremove.sq[i].x, &x, &y);
\r
4473 clips[num_clips++] =
\r
4474 CreateRectRgn(x - lineGap, y - lineGap,
\r
4475 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4477 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4478 premoveHighlightInfo.sq[i].y >= 0) {
\r
4479 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4480 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4481 clips[num_clips++] =
\r
4482 CreateRectRgn(x - lineGap, y - lineGap,
\r
4483 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4488 fullrepaint = TRUE;
\r
4491 /* Create a buffer bitmap - this is the actual bitmap
\r
4492 * being written to. When all the work is done, we can
\r
4493 * copy it to the real DC (the screen). This avoids
\r
4494 * the problems with flickering.
\r
4496 GetClientRect(hwndMain, &Rect);
\r
4497 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4498 Rect.bottom-Rect.top+1);
\r
4499 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4500 if (!appData.monoMode) {
\r
4501 SelectPalette(hdcmem, hPal, FALSE);
\r
4504 /* Create clips for dragging */
\r
4505 if (!fullrepaint) {
\r
4506 if (dragInfo.from.x >= 0) {
\r
4507 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4508 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4510 if (dragInfo.start.x >= 0) {
\r
4511 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4512 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4514 if (dragInfo.pos.x >= 0) {
\r
4515 x = dragInfo.pos.x - squareSize / 2;
\r
4516 y = dragInfo.pos.y - squareSize / 2;
\r
4517 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4519 if (dragInfo.lastpos.x >= 0) {
\r
4520 x = dragInfo.lastpos.x - squareSize / 2;
\r
4521 y = dragInfo.lastpos.y - squareSize / 2;
\r
4522 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4526 /* Are we animating a move?
\r
4528 * - remove the piece from the board (temporarely)
\r
4529 * - calculate the clipping region
\r
4531 if (!fullrepaint) {
\r
4532 if (animInfo.piece != EmptySquare) {
\r
4533 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4534 x = boardRect.left + animInfo.lastpos.x;
\r
4535 y = boardRect.top + animInfo.lastpos.y;
\r
4536 x2 = boardRect.left + animInfo.pos.x;
\r
4537 y2 = boardRect.top + animInfo.pos.y;
\r
4538 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4539 /* Slight kludge. The real problem is that after AnimateMove is
\r
4540 done, the position on the screen does not match lastDrawn.
\r
4541 This currently causes trouble only on e.p. captures in
\r
4542 atomic, where the piece moves to an empty square and then
\r
4543 explodes. The old and new positions both had an empty square
\r
4544 at the destination, but animation has drawn a piece there and
\r
4545 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4546 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4550 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4551 if (num_clips == 0)
\r
4552 fullrepaint = TRUE;
\r
4554 /* Set clipping on the memory DC */
\r
4555 if (!fullrepaint) {
\r
4556 SelectClipRgn(hdcmem, clips[0]);
\r
4557 for (x = 1; x < num_clips; x++) {
\r
4558 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4559 abort(); // this should never ever happen!
\r
4563 /* Do all the drawing to the memory DC */
\r
4564 if(explodeInfo.radius) { // [HGM] atomic
\r
4566 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4567 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4568 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4569 x += squareSize/2;
\r
4570 y += squareSize/2;
\r
4571 if(!fullrepaint) {
\r
4572 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4573 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4575 DrawGridOnDC(hdcmem);
\r
4576 DrawHighlightsOnDC(hdcmem);
\r
4577 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4578 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4579 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4580 SelectObject(hdcmem, oldBrush);
\r
4582 DrawGridOnDC(hdcmem);
\r
4583 DrawHighlightsOnDC(hdcmem);
\r
4584 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4587 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4588 if(appData.autoLogo) {
\r
4590 switch(gameMode) { // pick logos based on game mode
\r
4591 case IcsObserving:
\r
4592 whiteLogo = second.programLogo; // ICS logo
\r
4593 blackLogo = second.programLogo;
\r
4596 case IcsPlayingWhite:
\r
4597 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4598 blackLogo = second.programLogo; // ICS logo
\r
4600 case IcsPlayingBlack:
\r
4601 whiteLogo = second.programLogo; // ICS logo
\r
4602 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4604 case TwoMachinesPlay:
\r
4605 if(first.twoMachinesColor[0] == 'b') {
\r
4606 whiteLogo = second.programLogo;
\r
4607 blackLogo = first.programLogo;
\r
4610 case MachinePlaysWhite:
\r
4611 blackLogo = userLogo;
\r
4613 case MachinePlaysBlack:
\r
4614 whiteLogo = userLogo;
\r
4615 blackLogo = first.programLogo;
\r
4618 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4619 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4622 if( appData.highlightMoveWithArrow ) {
\r
4623 DrawArrowHighlight(hdcmem);
\r
4626 DrawCoordsOnDC(hdcmem);
\r
4628 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4629 /* to make sure lastDrawn contains what is actually drawn */
\r
4631 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4632 if (dragged_piece != EmptySquare) {
\r
4633 /* [HGM] or restack */
\r
4634 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4635 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4637 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4638 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4639 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4640 x = dragInfo.pos.x - squareSize / 2;
\r
4641 y = dragInfo.pos.y - squareSize / 2;
\r
4642 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4643 ((int) dragged_piece < (int) BlackPawn),
\r
4644 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4647 /* Put the animated piece back into place and draw it */
\r
4648 if (animInfo.piece != EmptySquare) {
\r
4649 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4650 x = boardRect.left + animInfo.pos.x;
\r
4651 y = boardRect.top + animInfo.pos.y;
\r
4652 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4653 ((int) animInfo.piece < (int) BlackPawn),
\r
4654 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4657 /* Release the bufferBitmap by selecting in the old bitmap
\r
4658 * and delete the memory DC
\r
4660 SelectObject(hdcmem, oldBitmap);
\r
4663 /* Set clipping on the target DC */
\r
4664 if (!fullrepaint) {
\r
4665 SelectClipRgn(hdc, clips[0]);
\r
4666 for (x = 1; x < num_clips; x++) {
\r
4667 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4668 abort(); // this should never ever happen!
\r
4672 /* Copy the new bitmap onto the screen in one go.
\r
4673 * This way we avoid any flickering
\r
4675 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4676 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4677 boardRect.right - boardRect.left,
\r
4678 boardRect.bottom - boardRect.top,
\r
4679 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4680 if(saveDiagFlag) {
\r
4681 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4682 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4684 GetObject(bufferBitmap, sizeof(b), &b);
\r
4685 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4686 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4687 bih.biWidth = b.bmWidth;
\r
4688 bih.biHeight = b.bmHeight;
\r
4690 bih.biBitCount = b.bmBitsPixel;
\r
4691 bih.biCompression = 0;
\r
4692 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4693 bih.biXPelsPerMeter = 0;
\r
4694 bih.biYPelsPerMeter = 0;
\r
4695 bih.biClrUsed = 0;
\r
4696 bih.biClrImportant = 0;
\r
4697 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4698 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4699 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4700 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4703 wb = b.bmWidthBytes;
\r
4705 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4706 int k = ((int*) pData)[i];
\r
4707 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4708 if(j >= 16) break;
\r
4710 if(j >= nrColors) nrColors = j+1;
\r
4712 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4714 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4715 for(w=0; w<(wb>>2); w+=2) {
\r
4716 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4717 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4718 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4719 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4720 pData[p++] = m | j<<4;
\r
4722 while(p&3) pData[p++] = 0;
\r
4725 wb = ((wb+31)>>5)<<2;
\r
4727 // write BITMAPFILEHEADER
\r
4728 fprintf(diagFile, "BM");
\r
4729 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4730 fputDW(diagFile, 0);
\r
4731 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4732 // write BITMAPINFOHEADER
\r
4733 fputDW(diagFile, 40);
\r
4734 fputDW(diagFile, b.bmWidth);
\r
4735 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4736 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4737 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4738 fputDW(diagFile, 0);
\r
4739 fputDW(diagFile, 0);
\r
4740 fputDW(diagFile, 0);
\r
4741 fputDW(diagFile, 0);
\r
4742 fputDW(diagFile, 0);
\r
4743 fputDW(diagFile, 0);
\r
4744 // write color table
\r
4746 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4747 // write bitmap data
\r
4748 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4749 fputc(pData[i], diagFile);
\r
4754 SelectObject(tmphdc, oldBitmap);
\r
4756 /* Massive cleanup */
\r
4757 for (x = 0; x < num_clips; x++)
\r
4758 DeleteObject(clips[x]);
\r
4761 DeleteObject(bufferBitmap);
\r
4764 ReleaseDC(hwndMain, hdc);
\r
4766 if (lastDrawnFlipView != flipView) {
\r
4768 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4770 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4773 /* CopyBoard(lastDrawn, board);*/
\r
4774 lastDrawnHighlight = highlightInfo;
\r
4775 lastDrawnPremove = premoveHighlightInfo;
\r
4776 lastDrawnFlipView = flipView;
\r
4777 lastDrawnValid = 1;
\r
4780 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4785 saveDiagFlag = 1; diagFile = f;
\r
4786 HDCDrawPosition(NULL, TRUE, NULL);
\r
4790 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4797 /*---------------------------------------------------------------------------*\
\r
4798 | CLIENT PAINT PROCEDURE
\r
4799 | This is the main event-handler for the WM_PAINT message.
\r
4801 \*---------------------------------------------------------------------------*/
\r
4803 PaintProc(HWND hwnd)
\r
4809 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4810 if (IsIconic(hwnd)) {
\r
4811 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4813 if (!appData.monoMode) {
\r
4814 SelectPalette(hdc, hPal, FALSE);
\r
4815 RealizePalette(hdc);
\r
4817 HDCDrawPosition(hdc, 1, NULL);
\r
4819 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4820 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4821 ETO_CLIPPED|ETO_OPAQUE,
\r
4822 &messageRect, messageText, strlen(messageText), NULL);
\r
4823 SelectObject(hdc, oldFont);
\r
4824 DisplayBothClocks();
\r
4826 EndPaint(hwnd,&ps);
\r
4834 * If the user selects on a border boundary, return -1; if off the board,
\r
4835 * return -2. Otherwise map the event coordinate to the square.
\r
4836 * The offset boardRect.left or boardRect.top must already have been
\r
4837 * subtracted from x.
\r
4840 EventToSquare(int x)
\r
4847 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4849 x /= (squareSize + lineGap);
\r
4850 if (x >= BOARD_SIZE)
\r
4861 DropEnable dropEnables[] = {
\r
4862 { 'P', DP_Pawn, "Pawn" },
\r
4863 { 'N', DP_Knight, "Knight" },
\r
4864 { 'B', DP_Bishop, "Bishop" },
\r
4865 { 'R', DP_Rook, "Rook" },
\r
4866 { 'Q', DP_Queen, "Queen" },
\r
4870 SetupDropMenu(HMENU hmenu)
\r
4872 int i, count, enable;
\r
4874 extern char white_holding[], black_holding[];
\r
4875 char item[MSG_SIZ];
\r
4877 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4878 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4879 dropEnables[i].piece);
\r
4881 while (p && *p++ == dropEnables[i].piece) count++;
\r
4882 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4883 enable = count > 0 || !appData.testLegality
\r
4884 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4885 && !appData.icsActive);
\r
4886 ModifyMenu(hmenu, dropEnables[i].command,
\r
4887 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4888 dropEnables[i].command, item);
\r
4892 static int fromX = -1, fromY = -1, toX, toY;
\r
4894 /* Event handler for mouse messages */
\r
4896 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4900 static int recursive = 0;
\r
4902 // BOOLEAN needsRedraw = FALSE;
\r
4903 BOOLEAN saveAnimate;
\r
4904 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4905 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4906 ChessMove moveType;
\r
4909 if (message == WM_MBUTTONUP) {
\r
4910 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4911 to the middle button: we simulate pressing the left button too!
\r
4913 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4914 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4920 pt.x = LOWORD(lParam);
\r
4921 pt.y = HIWORD(lParam);
\r
4922 x = EventToSquare(pt.x - boardRect.left);
\r
4923 y = EventToSquare(pt.y - boardRect.top);
\r
4924 if (!flipView && y >= 0) {
\r
4925 y = BOARD_HEIGHT - 1 - y;
\r
4927 if (flipView && x >= 0) {
\r
4928 x = BOARD_WIDTH - 1 - x;
\r
4931 switch (message) {
\r
4932 case WM_LBUTTONDOWN:
\r
4933 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4934 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4935 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4936 if(gameInfo.holdingsWidth &&
\r
4937 (WhiteOnMove(currentMove)
\r
4938 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4939 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4940 // click in right holdings, for determining promotion piece
\r
4941 ChessSquare p = boards[currentMove][y][x];
\r
4942 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4943 if(p != EmptySquare) {
\r
4944 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4945 fromX = fromY = -1;
\r
4949 DrawPosition(FALSE, boards[currentMove]);
\r
4953 sameAgain = FALSE;
\r
4955 /* Downclick vertically off board; check if on clock */
\r
4956 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4957 if (gameMode == EditPosition) {
\r
4958 SetWhiteToPlayEvent();
\r
4959 } else if (gameMode == IcsPlayingBlack ||
\r
4960 gameMode == MachinePlaysWhite) {
\r
4962 } else if (gameMode == EditGame) {
\r
4963 AdjustClock(flipClock, -1);
\r
4965 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4966 if (gameMode == EditPosition) {
\r
4967 SetBlackToPlayEvent();
\r
4968 } else if (gameMode == IcsPlayingWhite ||
\r
4969 gameMode == MachinePlaysBlack) {
\r
4971 } else if (gameMode == EditGame) {
\r
4972 AdjustClock(!flipClock, -1);
\r
4975 if (!appData.highlightLastMove) {
\r
4976 ClearHighlights();
\r
4977 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4979 fromX = fromY = -1;
\r
4980 dragInfo.start.x = dragInfo.start.y = -1;
\r
4981 dragInfo.from = dragInfo.start;
\r
4983 } else if (x < 0 || y < 0
\r
4984 /* [HGM] block clicks between board and holdings */
\r
4985 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4986 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4987 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4988 /* EditPosition, empty square, or different color piece;
\r
4989 click-click move is possible */
\r
4992 } else if (fromX == x && fromY == y) {
\r
4993 /* Downclick on same square again */
\r
4994 ClearHighlights();
\r
4995 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4996 sameAgain = TRUE;
\r
4997 } else if (fromX != -1 &&
\r
4998 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5000 /* Downclick on different square. */
\r
5001 /* [HGM] if on holdings file, should count as new first click ! */
\r
5002 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5005 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5006 to make sure move is legal before showing promotion popup */
\r
5007 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5008 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5009 fromX = fromY = -1;
\r
5010 ClearHighlights();
\r
5011 DrawPosition(FALSE, boards[currentMove]);
\r
5014 if(moveType != ImpossibleMove) {
\r
5015 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5016 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5017 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5018 appData.alwaysPromoteToQueen)) {
\r
5019 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5020 if (!appData.highlightLastMove) {
\r
5021 ClearHighlights();
\r
5022 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5025 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5026 SetHighlights(fromX, fromY, toX, toY);
\r
5027 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5028 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5029 If promotion to Q is legal, all are legal! */
\r
5030 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5031 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5032 // kludge to temporarily execute move on display, wthout promotng yet
\r
5033 promotionChoice = TRUE;
\r
5034 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5035 boards[currentMove][toY][toX] = p;
\r
5036 DrawPosition(FALSE, boards[currentMove]);
\r
5037 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5038 boards[currentMove][toY][toX] = q;
\r
5040 PromotionPopup(hwnd);
\r
5041 } else { /* not a promotion */
\r
5042 if (appData.animate || appData.highlightLastMove) {
\r
5043 SetHighlights(fromX, fromY, toX, toY);
\r
5045 ClearHighlights();
\r
5047 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5048 fromX = fromY = -1;
\r
5049 if (appData.animate && !appData.highlightLastMove) {
\r
5050 ClearHighlights();
\r
5051 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5057 /* [HGM] it seemed that braces were missing here */
\r
5058 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5059 fromX = fromY = -1;
\r
5063 ClearHighlights();
\r
5064 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5066 /* First downclick, or restart on a square with same color piece */
\r
5067 if (!frozen && OKToStartUserMove(x, y)) {
\r
5070 dragInfo.lastpos = pt;
\r
5071 dragInfo.from.x = fromX;
\r
5072 dragInfo.from.y = fromY;
\r
5073 dragInfo.start = dragInfo.from;
\r
5074 SetCapture(hwndMain);
\r
5076 fromX = fromY = -1;
\r
5077 dragInfo.start.x = dragInfo.start.y = -1;
\r
5078 dragInfo.from = dragInfo.start;
\r
5079 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5083 case WM_LBUTTONUP:
\r
5085 if (fromX == -1) break;
\r
5086 if (x == fromX && y == fromY) {
\r
5087 dragInfo.from.x = dragInfo.from.y = -1;
\r
5088 /* Upclick on same square */
\r
5090 /* Clicked same square twice: abort click-click move */
\r
5091 fromX = fromY = -1;
\r
5093 ClearPremoveHighlights();
\r
5095 /* First square clicked: start click-click move */
\r
5096 SetHighlights(fromX, fromY, -1, -1);
\r
5098 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5099 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5100 /* Errant click; ignore */
\r
5103 /* Finish drag move. */
\r
5104 if (appData.debugMode) {
\r
5105 fprintf(debugFP, "release\n");
\r
5107 dragInfo.from.x = dragInfo.from.y = -1;
\r
5110 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5111 appData.animate = appData.animate && !appData.animateDragging;
\r
5112 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5113 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5114 fromX = fromY = -1;
\r
5115 ClearHighlights();
\r
5116 DrawPosition(FALSE, boards[currentMove]);
\r
5119 if(moveType != ImpossibleMove) {
\r
5120 /* [HGM] use move type to determine if move is promotion.
\r
5121 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5122 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5123 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5124 appData.alwaysPromoteToQueen))
\r
5125 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5127 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5128 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5129 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5130 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5131 // kludge to temporarily execute move on display, wthout promotng yet
\r
5132 promotionChoice = TRUE;
\r
5133 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5134 boards[currentMove][toY][toX] = p;
\r
5135 DrawPosition(FALSE, boards[currentMove]);
\r
5136 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5137 boards[currentMove][toY][toX] = q;
\r
5140 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5142 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5143 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5144 moveType == WhiteCapturesEnPassant ||
\r
5145 moveType == BlackCapturesEnPassant ) )
\r
5146 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5147 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5150 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5151 appData.animate = saveAnimate;
\r
5152 fromX = fromY = -1;
\r
5153 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5154 ClearHighlights();
\r
5156 if (appData.animate || appData.animateDragging ||
\r
5157 appData.highlightDragging || gotPremove) {
\r
5158 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5161 dragInfo.start.x = dragInfo.start.y = -1;
\r
5162 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5165 case WM_MOUSEMOVE:
\r
5166 if ((appData.animateDragging || appData.highlightDragging)
\r
5167 && (wParam & MK_LBUTTON)
\r
5168 && dragInfo.from.x >= 0)
\r
5170 BOOL full_repaint = FALSE;
\r
5172 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5173 if (appData.animateDragging) {
\r
5174 dragInfo.pos = pt;
\r
5176 if (appData.highlightDragging) {
\r
5177 SetHighlights(fromX, fromY, x, y);
\r
5178 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5179 full_repaint = TRUE;
\r
5183 DrawPosition( full_repaint, NULL);
\r
5185 dragInfo.lastpos = dragInfo.pos;
\r
5189 case WM_MOUSEWHEEL: // [DM]
\r
5190 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5191 /* Mouse Wheel is being rolled forward
\r
5192 * Play moves forward
\r
5194 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5195 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5196 /* Mouse Wheel is being rolled backward
\r
5197 * Play moves backward
\r
5199 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5200 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5204 case WM_MBUTTONDOWN:
\r
5205 case WM_RBUTTONDOWN:
\r
5208 fromX = fromY = -1;
\r
5209 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5210 dragInfo.start.x = dragInfo.start.y = -1;
\r
5211 dragInfo.from = dragInfo.start;
\r
5212 dragInfo.lastpos = dragInfo.pos;
\r
5213 if (appData.highlightDragging) {
\r
5214 ClearHighlights();
\r
5217 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5218 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5219 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5220 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5221 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5224 DrawPosition(TRUE, NULL);
\r
5226 switch (gameMode) {
\r
5227 case EditPosition:
\r
5228 case IcsExamining:
\r
5229 if (x < 0 || y < 0) break;
\r
5232 if (message == WM_MBUTTONDOWN) {
\r
5233 buttonCount = 3; /* even if system didn't think so */
\r
5234 if (wParam & MK_SHIFT)
\r
5235 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5237 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5238 } else { /* message == WM_RBUTTONDOWN */
\r
5240 if (buttonCount == 3) {
\r
5241 if (wParam & MK_SHIFT)
\r
5242 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5244 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5246 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5249 /* Just have one menu, on the right button. Windows users don't
\r
5250 think to try the middle one, and sometimes other software steals
\r
5251 it, or it doesn't really exist. */
\r
5252 if(gameInfo.variant != VariantShogi)
\r
5253 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5255 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5259 case IcsPlayingWhite:
\r
5260 case IcsPlayingBlack:
\r
5262 case MachinePlaysWhite:
\r
5263 case MachinePlaysBlack:
\r
5264 if (appData.testLegality &&
\r
5265 gameInfo.variant != VariantBughouse &&
\r
5266 gameInfo.variant != VariantCrazyhouse) break;
\r
5267 if (x < 0 || y < 0) break;
\r
5270 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5271 SetupDropMenu(hmenu);
\r
5272 MenuPopup(hwnd, pt, hmenu, -1);
\r
5283 /* Preprocess messages for buttons in main window */
\r
5285 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5287 int id = GetWindowLong(hwnd, GWL_ID);
\r
5290 for (i=0; i<N_BUTTONS; i++) {
\r
5291 if (buttonDesc[i].id == id) break;
\r
5293 if (i == N_BUTTONS) return 0;
\r
5294 switch (message) {
\r
5299 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5300 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5307 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5310 if (appData.icsActive) {
\r
5311 if (GetKeyState(VK_SHIFT) < 0) {
\r
5313 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5314 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5318 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5319 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5326 if (appData.icsActive) {
\r
5327 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5328 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5330 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5332 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5333 PopUpMoveDialog((char)wParam);
\r
5339 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5342 /* Process messages for Promotion dialog box */
\r
5344 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5348 switch (message) {
\r
5349 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5350 /* Center the dialog over the application window */
\r
5351 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5352 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5353 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5354 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5355 SW_SHOW : SW_HIDE);
\r
5356 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5357 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5358 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5359 PieceToChar(WhiteAngel) != '~') ||
\r
5360 (PieceToChar(BlackAngel) >= 'A' &&
\r
5361 PieceToChar(BlackAngel) != '~') ) ?
\r
5362 SW_SHOW : SW_HIDE);
\r
5363 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5364 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5365 PieceToChar(WhiteMarshall) != '~') ||
\r
5366 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5367 PieceToChar(BlackMarshall) != '~') ) ?
\r
5368 SW_SHOW : SW_HIDE);
\r
5369 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5370 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5371 gameInfo.variant != VariantShogi ?
\r
5372 SW_SHOW : SW_HIDE);
\r
5373 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5374 gameInfo.variant != VariantShogi ?
\r
5375 SW_SHOW : SW_HIDE);
\r
5376 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5377 gameInfo.variant == VariantShogi ?
\r
5378 SW_SHOW : SW_HIDE);
\r
5379 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5380 gameInfo.variant == VariantShogi ?
\r
5381 SW_SHOW : SW_HIDE);
\r
5382 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5383 gameInfo.variant == VariantSuper ?
\r
5384 SW_SHOW : SW_HIDE);
\r
5387 case WM_COMMAND: /* message: received a command */
\r
5388 switch (LOWORD(wParam)) {
\r
5390 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5391 ClearHighlights();
\r
5392 DrawPosition(FALSE, NULL);
\r
5395 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5398 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5401 promoChar = PieceToChar(BlackRook);
\r
5404 promoChar = PieceToChar(BlackBishop);
\r
5406 case PB_Chancellor:
\r
5407 promoChar = PieceToChar(BlackMarshall);
\r
5409 case PB_Archbishop:
\r
5410 promoChar = PieceToChar(BlackAngel);
\r
5413 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5418 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5419 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5420 only show the popup when we are already sure the move is valid or
\r
5421 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5422 will figure out it is a promotion from the promoChar. */
\r
5423 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5424 if (!appData.highlightLastMove) {
\r
5425 ClearHighlights();
\r
5426 DrawPosition(FALSE, NULL);
\r
5433 /* Pop up promotion dialog */
\r
5435 PromotionPopup(HWND hwnd)
\r
5439 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5440 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5441 hwnd, (DLGPROC)lpProc);
\r
5442 FreeProcInstance(lpProc);
\r
5445 /* Toggle ShowThinking */
\r
5447 ToggleShowThinking()
\r
5449 appData.showThinking = !appData.showThinking;
\r
5450 ShowThinkingEvent();
\r
5454 LoadGameDialog(HWND hwnd, char* title)
\r
5458 char fileTitle[MSG_SIZ];
\r
5459 f = OpenFileDialog(hwnd, "rb", "",
\r
5460 appData.oldSaveStyle ? "gam" : "pgn",
\r
5462 title, &number, fileTitle, NULL);
\r
5464 cmailMsgLoaded = FALSE;
\r
5465 if (number == 0) {
\r
5466 int error = GameListBuild(f);
\r
5468 DisplayError("Cannot build game list", error);
\r
5469 } else if (!ListEmpty(&gameList) &&
\r
5470 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5471 GameListPopUp(f, fileTitle);
\r
5474 GameListDestroy();
\r
5477 LoadGame(f, number, fileTitle, FALSE);
\r
5482 ChangedConsoleFont()
\r
5485 CHARRANGE tmpsel, sel;
\r
5486 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5487 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5488 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5491 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5492 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5493 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5494 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5495 * size. This was undocumented in the version of MSVC++ that I had
\r
5496 * when I wrote the code, but is apparently documented now.
\r
5498 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5499 cfmt.bCharSet = f->lf.lfCharSet;
\r
5500 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5501 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5502 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5503 /* Why are the following seemingly needed too? */
\r
5504 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5505 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5506 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5508 tmpsel.cpMax = -1; /*999999?*/
\r
5509 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5510 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5511 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5512 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5514 paraf.cbSize = sizeof(paraf);
\r
5515 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5516 paraf.dxStartIndent = 0;
\r
5517 paraf.dxOffset = WRAP_INDENT;
\r
5518 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5519 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5522 /*---------------------------------------------------------------------------*\
\r
5524 * Window Proc for main window
\r
5526 \*---------------------------------------------------------------------------*/
\r
5528 /* Process messages for main window, etc. */
\r
5530 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5533 int wmId, wmEvent;
\r
5537 char fileTitle[MSG_SIZ];
\r
5538 char buf[MSG_SIZ];
\r
5539 static SnapData sd;
\r
5541 switch (message) {
\r
5543 case WM_PAINT: /* message: repaint portion of window */
\r
5547 case WM_ERASEBKGND:
\r
5548 if (IsIconic(hwnd)) {
\r
5549 /* Cheat; change the message */
\r
5550 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5552 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5556 case WM_LBUTTONDOWN:
\r
5557 case WM_MBUTTONDOWN:
\r
5558 case WM_RBUTTONDOWN:
\r
5559 case WM_LBUTTONUP:
\r
5560 case WM_MBUTTONUP:
\r
5561 case WM_RBUTTONUP:
\r
5562 case WM_MOUSEMOVE:
\r
5563 case WM_MOUSEWHEEL:
\r
5564 MouseEvent(hwnd, message, wParam, lParam);
\r
5569 if (appData.icsActive) {
\r
5570 if (wParam == '\t') {
\r
5571 if (GetKeyState(VK_SHIFT) < 0) {
\r
5573 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5574 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5578 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5579 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5583 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5584 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5586 SendMessage(h, message, wParam, lParam);
\r
5588 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5589 PopUpMoveDialog((char)wParam);
\r
5593 case WM_PALETTECHANGED:
\r
5594 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5596 HDC hdc = GetDC(hwndMain);
\r
5597 SelectPalette(hdc, hPal, TRUE);
\r
5598 nnew = RealizePalette(hdc);
\r
5600 paletteChanged = TRUE;
\r
5602 UpdateColors(hdc);
\r
5604 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5607 ReleaseDC(hwnd, hdc);
\r
5611 case WM_QUERYNEWPALETTE:
\r
5612 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5614 HDC hdc = GetDC(hwndMain);
\r
5615 paletteChanged = FALSE;
\r
5616 SelectPalette(hdc, hPal, FALSE);
\r
5617 nnew = RealizePalette(hdc);
\r
5619 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5621 ReleaseDC(hwnd, hdc);
\r
5626 case WM_COMMAND: /* message: command from application menu */
\r
5627 wmId = LOWORD(wParam);
\r
5628 wmEvent = HIWORD(wParam);
\r
5633 AnalysisPopDown();
\r
5636 case IDM_NewGameFRC:
\r
5637 if( NewGameFRC() == 0 ) {
\r
5639 AnalysisPopDown();
\r
5643 case IDM_NewVariant:
\r
5644 NewVariantPopup(hwnd);
\r
5647 case IDM_LoadGame:
\r
5648 LoadGameDialog(hwnd, "Load Game from File");
\r
5651 case IDM_LoadNextGame:
\r
5655 case IDM_LoadPrevGame:
\r
5659 case IDM_ReloadGame:
\r
5663 case IDM_LoadPosition:
\r
5664 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5665 Reset(FALSE, TRUE);
\r
5668 f = OpenFileDialog(hwnd, "rb", "",
\r
5669 appData.oldSaveStyle ? "pos" : "fen",
\r
5671 "Load Position from File", &number, fileTitle, NULL);
\r
5673 LoadPosition(f, number, fileTitle);
\r
5677 case IDM_LoadNextPosition:
\r
5678 ReloadPosition(1);
\r
5681 case IDM_LoadPrevPosition:
\r
5682 ReloadPosition(-1);
\r
5685 case IDM_ReloadPosition:
\r
5686 ReloadPosition(0);
\r
5689 case IDM_SaveGame:
\r
5690 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5691 f = OpenFileDialog(hwnd, "a", defName,
\r
5692 appData.oldSaveStyle ? "gam" : "pgn",
\r
5694 "Save Game to File", NULL, fileTitle, NULL);
\r
5696 SaveGame(f, 0, "");
\r
5700 case IDM_SavePosition:
\r
5701 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5702 f = OpenFileDialog(hwnd, "a", defName,
\r
5703 appData.oldSaveStyle ? "pos" : "fen",
\r
5705 "Save Position to File", NULL, fileTitle, NULL);
\r
5707 SavePosition(f, 0, "");
\r
5711 case IDM_SaveDiagram:
\r
5712 defName = "diagram";
\r
5713 f = OpenFileDialog(hwnd, "wb", defName,
\r
5716 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5722 case IDM_CopyGame:
\r
5723 CopyGameToClipboard();
\r
5726 case IDM_PasteGame:
\r
5727 PasteGameFromClipboard();
\r
5730 case IDM_CopyGameListToClipboard:
\r
5731 CopyGameListToClipboard();
\r
5734 /* [AS] Autodetect FEN or PGN data */
\r
5735 case IDM_PasteAny:
\r
5736 PasteGameOrFENFromClipboard();
\r
5739 /* [AS] Move history */
\r
5740 case IDM_ShowMoveHistory:
\r
5741 if( MoveHistoryIsUp() ) {
\r
5742 MoveHistoryPopDown();
\r
5745 MoveHistoryPopUp();
\r
5749 /* [AS] Eval graph */
\r
5750 case IDM_ShowEvalGraph:
\r
5751 if( EvalGraphIsUp() ) {
\r
5752 EvalGraphPopDown();
\r
5759 /* [AS] Engine output */
\r
5760 case IDM_ShowEngineOutput:
\r
5761 if( EngineOutputIsUp() ) {
\r
5762 EngineOutputPopDown();
\r
5765 EngineOutputPopUp();
\r
5769 /* [AS] User adjudication */
\r
5770 case IDM_UserAdjudication_White:
\r
5771 UserAdjudicationEvent( +1 );
\r
5774 case IDM_UserAdjudication_Black:
\r
5775 UserAdjudicationEvent( -1 );
\r
5778 case IDM_UserAdjudication_Draw:
\r
5779 UserAdjudicationEvent( 0 );
\r
5782 /* [AS] Game list options dialog */
\r
5783 case IDM_GameListOptions:
\r
5784 GameListOptions();
\r
5787 case IDM_CopyPosition:
\r
5788 CopyFENToClipboard();
\r
5791 case IDM_PastePosition:
\r
5792 PasteFENFromClipboard();
\r
5795 case IDM_MailMove:
\r
5799 case IDM_ReloadCMailMsg:
\r
5800 Reset(TRUE, TRUE);
\r
5801 ReloadCmailMsgEvent(FALSE);
\r
5804 case IDM_Minimize:
\r
5805 ShowWindow(hwnd, SW_MINIMIZE);
\r
5812 case IDM_MachineWhite:
\r
5813 MachineWhiteEvent();
\r
5815 * refresh the tags dialog only if it's visible
\r
5817 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5819 tags = PGNTags(&gameInfo);
\r
5820 TagsPopUp(tags, CmailMsg());
\r
5825 case IDM_MachineBlack:
\r
5826 MachineBlackEvent();
\r
5828 * refresh the tags dialog only if it's visible
\r
5830 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5832 tags = PGNTags(&gameInfo);
\r
5833 TagsPopUp(tags, CmailMsg());
\r
5838 case IDM_TwoMachines:
\r
5839 TwoMachinesEvent();
\r
5841 * refresh the tags dialog only if it's visible
\r
5843 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5845 tags = PGNTags(&gameInfo);
\r
5846 TagsPopUp(tags, CmailMsg());
\r
5851 case IDM_AnalysisMode:
\r
5852 if (!first.analysisSupport) {
\r
5853 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5854 DisplayError(buf, 0);
\r
5856 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5857 if (appData.icsActive) {
\r
5858 if (gameMode != IcsObserving) {
\r
5859 sprintf(buf, "You are not observing a game");
\r
5860 DisplayError(buf, 0);
\r
5861 /* secure check */
\r
5862 if (appData.icsEngineAnalyze) {
\r
5863 if (appData.debugMode)
\r
5864 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5865 ExitAnalyzeMode();
\r
5871 /* if enable, user want disable icsEngineAnalyze */
\r
5872 if (appData.icsEngineAnalyze) {
\r
5873 ExitAnalyzeMode();
\r
5877 appData.icsEngineAnalyze = TRUE;
\r
5878 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5881 if (!appData.showThinking) ToggleShowThinking();
\r
5882 AnalyzeModeEvent();
\r
5886 case IDM_AnalyzeFile:
\r
5887 if (!first.analysisSupport) {
\r
5888 char buf[MSG_SIZ];
\r
5889 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5890 DisplayError(buf, 0);
\r
5892 if (!appData.showThinking) ToggleShowThinking();
\r
5893 AnalyzeFileEvent();
\r
5894 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5895 AnalysisPeriodicEvent(1);
\r
5899 case IDM_IcsClient:
\r
5903 case IDM_EditGame:
\r
5907 case IDM_EditPosition:
\r
5908 EditPositionEvent();
\r
5911 case IDM_Training:
\r
5915 case IDM_ShowGameList:
\r
5916 ShowGameListProc();
\r
5919 case IDM_EditTags:
\r
5923 case IDM_EditComment:
\r
5924 if (commentDialogUp && editComment) {
\r
5927 EditCommentEvent();
\r
5947 case IDM_CallFlag:
\r
5967 case IDM_StopObserving:
\r
5968 StopObservingEvent();
\r
5971 case IDM_StopExamining:
\r
5972 StopExaminingEvent();
\r
5975 case IDM_TypeInMove:
\r
5976 PopUpMoveDialog('\000');
\r
5979 case IDM_TypeInName:
\r
5980 PopUpNameDialog('\000');
\r
5983 case IDM_Backward:
\r
5985 SetFocus(hwndMain);
\r
5990 SetFocus(hwndMain);
\r
5995 SetFocus(hwndMain);
\r
6000 SetFocus(hwndMain);
\r
6007 case IDM_TruncateGame:
\r
6008 TruncateGameEvent();
\r
6015 case IDM_RetractMove:
\r
6016 RetractMoveEvent();
\r
6019 case IDM_FlipView:
\r
6020 flipView = !flipView;
\r
6021 DrawPosition(FALSE, NULL);
\r
6024 case IDM_FlipClock:
\r
6025 flipClock = !flipClock;
\r
6026 DisplayBothClocks();
\r
6027 DrawPosition(FALSE, NULL);
\r
6030 case IDM_GeneralOptions:
\r
6031 GeneralOptionsPopup(hwnd);
\r
6032 DrawPosition(TRUE, NULL);
\r
6035 case IDM_BoardOptions:
\r
6036 BoardOptionsPopup(hwnd);
\r
6039 case IDM_EnginePlayOptions:
\r
6040 EnginePlayOptionsPopup(hwnd);
\r
6043 case IDM_OptionsUCI:
\r
6044 UciOptionsPopup(hwnd);
\r
6047 case IDM_IcsOptions:
\r
6048 IcsOptionsPopup(hwnd);
\r
6052 FontsOptionsPopup(hwnd);
\r
6056 SoundOptionsPopup(hwnd);
\r
6059 case IDM_CommPort:
\r
6060 CommPortOptionsPopup(hwnd);
\r
6063 case IDM_LoadOptions:
\r
6064 LoadOptionsPopup(hwnd);
\r
6067 case IDM_SaveOptions:
\r
6068 SaveOptionsPopup(hwnd);
\r
6071 case IDM_TimeControl:
\r
6072 TimeControlOptionsPopup(hwnd);
\r
6075 case IDM_SaveSettings:
\r
6076 SaveSettings(settingsFileName);
\r
6079 case IDM_SaveSettingsOnExit:
\r
6080 saveSettingsOnExit = !saveSettingsOnExit;
\r
6081 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6082 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6083 MF_CHECKED : MF_UNCHECKED));
\r
6094 case IDM_AboutGame:
\r
6099 appData.debugMode = !appData.debugMode;
\r
6100 if (appData.debugMode) {
\r
6101 char dir[MSG_SIZ];
\r
6102 GetCurrentDirectory(MSG_SIZ, dir);
\r
6103 SetCurrentDirectory(installDir);
\r
6104 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6105 SetCurrentDirectory(dir);
\r
6106 setbuf(debugFP, NULL);
\r
6113 case IDM_HELPCONTENTS:
\r
6114 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6115 MessageBox (GetFocus(),
\r
6116 "Unable to activate help",
\r
6117 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6121 case IDM_HELPSEARCH:
\r
6122 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
6123 MessageBox (GetFocus(),
\r
6124 "Unable to activate help",
\r
6125 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6129 case IDM_HELPHELP:
\r
6130 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6131 MessageBox (GetFocus(),
\r
6132 "Unable to activate help",
\r
6133 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6138 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6140 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6141 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6142 FreeProcInstance(lpProc);
\r
6145 case IDM_DirectCommand1:
\r
6146 AskQuestionEvent("Direct Command",
\r
6147 "Send to chess program:", "", "1");
\r
6149 case IDM_DirectCommand2:
\r
6150 AskQuestionEvent("Direct Command",
\r
6151 "Send to second chess program:", "", "2");
\r
6154 case EP_WhitePawn:
\r
6155 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6156 fromX = fromY = -1;
\r
6159 case EP_WhiteKnight:
\r
6160 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6161 fromX = fromY = -1;
\r
6164 case EP_WhiteBishop:
\r
6165 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6166 fromX = fromY = -1;
\r
6169 case EP_WhiteRook:
\r
6170 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6171 fromX = fromY = -1;
\r
6174 case EP_WhiteQueen:
\r
6175 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6176 fromX = fromY = -1;
\r
6179 case EP_WhiteFerz:
\r
6180 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6181 fromX = fromY = -1;
\r
6184 case EP_WhiteWazir:
\r
6185 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6186 fromX = fromY = -1;
\r
6189 case EP_WhiteAlfil:
\r
6190 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6191 fromX = fromY = -1;
\r
6194 case EP_WhiteCannon:
\r
6195 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6196 fromX = fromY = -1;
\r
6199 case EP_WhiteCardinal:
\r
6200 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6201 fromX = fromY = -1;
\r
6204 case EP_WhiteMarshall:
\r
6205 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6206 fromX = fromY = -1;
\r
6209 case EP_WhiteKing:
\r
6210 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6211 fromX = fromY = -1;
\r
6214 case EP_BlackPawn:
\r
6215 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6216 fromX = fromY = -1;
\r
6219 case EP_BlackKnight:
\r
6220 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6221 fromX = fromY = -1;
\r
6224 case EP_BlackBishop:
\r
6225 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6226 fromX = fromY = -1;
\r
6229 case EP_BlackRook:
\r
6230 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6231 fromX = fromY = -1;
\r
6234 case EP_BlackQueen:
\r
6235 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6236 fromX = fromY = -1;
\r
6239 case EP_BlackFerz:
\r
6240 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6241 fromX = fromY = -1;
\r
6244 case EP_BlackWazir:
\r
6245 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6246 fromX = fromY = -1;
\r
6249 case EP_BlackAlfil:
\r
6250 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6251 fromX = fromY = -1;
\r
6254 case EP_BlackCannon:
\r
6255 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6256 fromX = fromY = -1;
\r
6259 case EP_BlackCardinal:
\r
6260 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6261 fromX = fromY = -1;
\r
6264 case EP_BlackMarshall:
\r
6265 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6266 fromX = fromY = -1;
\r
6269 case EP_BlackKing:
\r
6270 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6271 fromX = fromY = -1;
\r
6274 case EP_EmptySquare:
\r
6275 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6276 fromX = fromY = -1;
\r
6279 case EP_ClearBoard:
\r
6280 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6281 fromX = fromY = -1;
\r
6285 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6286 fromX = fromY = -1;
\r
6290 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6291 fromX = fromY = -1;
\r
6295 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6296 fromX = fromY = -1;
\r
6300 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6301 fromX = fromY = -1;
\r
6305 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6306 fromX = fromY = -1;
\r
6310 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6311 fromX = fromY = -1;
\r
6315 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6316 fromX = fromY = -1;
\r
6320 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6321 fromX = fromY = -1;
\r
6325 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6326 fromX = fromY = -1;
\r
6330 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6336 case CLOCK_TIMER_ID:
\r
6337 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6338 clockTimerEvent = 0;
\r
6339 DecrementClocks(); /* call into back end */
\r
6341 case LOAD_GAME_TIMER_ID:
\r
6342 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6343 loadGameTimerEvent = 0;
\r
6344 AutoPlayGameLoop(); /* call into back end */
\r
6346 case ANALYSIS_TIMER_ID:
\r
6347 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6348 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6349 AnalysisPeriodicEvent(0);
\r
6351 KillTimer(hwnd, analysisTimerEvent);
\r
6352 analysisTimerEvent = 0;
\r
6355 case DELAYED_TIMER_ID:
\r
6356 KillTimer(hwnd, delayedTimerEvent);
\r
6357 delayedTimerEvent = 0;
\r
6358 delayedTimerCallback();
\r
6363 case WM_USER_Input:
\r
6364 InputEvent(hwnd, message, wParam, lParam);
\r
6367 /* [AS] Also move "attached" child windows */
\r
6368 case WM_WINDOWPOSCHANGING:
\r
6370 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6371 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6373 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6374 /* Window is moving */
\r
6377 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6378 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6379 rcMain.right = boardX + winWidth;
\r
6380 rcMain.top = boardY;
\r
6381 rcMain.bottom = boardY + winHeight;
\r
6383 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6384 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6385 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6386 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6387 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6394 /* [AS] Snapping */
\r
6395 case WM_ENTERSIZEMOVE:
\r
6396 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6397 if (hwnd == hwndMain) {
\r
6398 doingSizing = TRUE;
\r
6401 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6405 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6406 if (hwnd == hwndMain) {
\r
6407 lastSizing = wParam;
\r
6412 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6413 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6415 case WM_EXITSIZEMOVE:
\r
6416 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6417 if (hwnd == hwndMain) {
\r
6419 doingSizing = FALSE;
\r
6420 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6421 GetClientRect(hwnd, &client);
\r
6422 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6424 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6426 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6429 case WM_DESTROY: /* message: window being destroyed */
\r
6430 PostQuitMessage(0);
\r
6434 if (hwnd == hwndMain) {
\r
6439 default: /* Passes it on if unprocessed */
\r
6440 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6445 /*---------------------------------------------------------------------------*\
\r
6447 * Misc utility routines
\r
6449 \*---------------------------------------------------------------------------*/
\r
6452 * Decent random number generator, at least not as bad as Windows
\r
6453 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6455 unsigned int randstate;
\r
6460 randstate = randstate * 1664525 + 1013904223;
\r
6461 return (int) randstate & 0x7fffffff;
\r
6465 mysrandom(unsigned int seed)
\r
6472 * returns TRUE if user selects a different color, FALSE otherwise
\r
6476 ChangeColor(HWND hwnd, COLORREF *which)
\r
6478 static BOOL firstTime = TRUE;
\r
6479 static DWORD customColors[16];
\r
6481 COLORREF newcolor;
\r
6486 /* Make initial colors in use available as custom colors */
\r
6487 /* Should we put the compiled-in defaults here instead? */
\r
6489 customColors[i++] = lightSquareColor & 0xffffff;
\r
6490 customColors[i++] = darkSquareColor & 0xffffff;
\r
6491 customColors[i++] = whitePieceColor & 0xffffff;
\r
6492 customColors[i++] = blackPieceColor & 0xffffff;
\r
6493 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6494 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6496 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6497 customColors[i++] = textAttribs[ccl].color;
\r
6499 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6500 firstTime = FALSE;
\r
6503 cc.lStructSize = sizeof(cc);
\r
6504 cc.hwndOwner = hwnd;
\r
6505 cc.hInstance = NULL;
\r
6506 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6507 cc.lpCustColors = (LPDWORD) customColors;
\r
6508 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6510 if (!ChooseColor(&cc)) return FALSE;
\r
6512 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6513 if (newcolor == *which) return FALSE;
\r
6514 *which = newcolor;
\r
6518 InitDrawingColors();
\r
6519 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6524 MyLoadSound(MySound *ms)
\r
6530 if (ms->data) free(ms->data);
\r
6533 switch (ms->name[0]) {
\r
6539 /* System sound from Control Panel. Don't preload here. */
\r
6543 if (ms->name[1] == NULLCHAR) {
\r
6544 /* "!" alone = silence */
\r
6547 /* Builtin wave resource. Error if not found. */
\r
6548 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6549 if (h == NULL) break;
\r
6550 ms->data = (void *)LoadResource(hInst, h);
\r
6551 if (h == NULL) break;
\r
6556 /* .wav file. Error if not found. */
\r
6557 f = fopen(ms->name, "rb");
\r
6558 if (f == NULL) break;
\r
6559 if (fstat(fileno(f), &st) < 0) break;
\r
6560 ms->data = malloc(st.st_size);
\r
6561 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6567 char buf[MSG_SIZ];
\r
6568 sprintf(buf, "Error loading sound %s", ms->name);
\r
6569 DisplayError(buf, GetLastError());
\r
6575 MyPlaySound(MySound *ms)
\r
6577 BOOLEAN ok = FALSE;
\r
6578 switch (ms->name[0]) {
\r
6584 /* System sound from Control Panel (deprecated feature).
\r
6585 "$" alone or an unset sound name gets default beep (still in use). */
\r
6586 if (ms->name[1]) {
\r
6587 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6589 if (!ok) ok = MessageBeep(MB_OK);
\r
6592 /* Builtin wave resource, or "!" alone for silence */
\r
6593 if (ms->name[1]) {
\r
6594 if (ms->data == NULL) return FALSE;
\r
6595 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6601 /* .wav file. Error if not found. */
\r
6602 if (ms->data == NULL) return FALSE;
\r
6603 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6606 /* Don't print an error: this can happen innocently if the sound driver
\r
6607 is busy; for instance, if another instance of WinBoard is playing
\r
6608 a sound at about the same time. */
\r
6611 char buf[MSG_SIZ];
\r
6612 sprintf(buf, "Error playing sound %s", ms->name);
\r
6613 DisplayError(buf, GetLastError());
\r
6621 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6624 OPENFILENAME *ofn;
\r
6625 static UINT *number; /* gross that this is static */
\r
6627 switch (message) {
\r
6628 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6629 /* Center the dialog over the application window */
\r
6630 ofn = (OPENFILENAME *) lParam;
\r
6631 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6632 number = (UINT *) ofn->lCustData;
\r
6633 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6637 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6638 return FALSE; /* Allow for further processing */
\r
6641 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6642 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6644 return FALSE; /* Allow for further processing */
\r
6650 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6652 static UINT *number;
\r
6653 OPENFILENAME *ofname;
\r
6656 case WM_INITDIALOG:
\r
6657 ofname = (OPENFILENAME *)lParam;
\r
6658 number = (UINT *)(ofname->lCustData);
\r
6661 ofnot = (OFNOTIFY *)lParam;
\r
6662 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6663 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6672 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6673 char *nameFilt, char *dlgTitle, UINT *number,
\r
6674 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6676 OPENFILENAME openFileName;
\r
6677 char buf1[MSG_SIZ];
\r
6680 if (fileName == NULL) fileName = buf1;
\r
6681 if (defName == NULL) {
\r
6682 strcpy(fileName, "*.");
\r
6683 strcat(fileName, defExt);
\r
6685 strcpy(fileName, defName);
\r
6687 if (fileTitle) strcpy(fileTitle, "");
\r
6688 if (number) *number = 0;
\r
6690 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6691 openFileName.hwndOwner = hwnd;
\r
6692 openFileName.hInstance = (HANDLE) hInst;
\r
6693 openFileName.lpstrFilter = nameFilt;
\r
6694 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6695 openFileName.nMaxCustFilter = 0L;
\r
6696 openFileName.nFilterIndex = 1L;
\r
6697 openFileName.lpstrFile = fileName;
\r
6698 openFileName.nMaxFile = MSG_SIZ;
\r
6699 openFileName.lpstrFileTitle = fileTitle;
\r
6700 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6701 openFileName.lpstrInitialDir = NULL;
\r
6702 openFileName.lpstrTitle = dlgTitle;
\r
6703 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6704 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6705 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6706 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6707 openFileName.nFileOffset = 0;
\r
6708 openFileName.nFileExtension = 0;
\r
6709 openFileName.lpstrDefExt = defExt;
\r
6710 openFileName.lCustData = (LONG) number;
\r
6711 openFileName.lpfnHook = oldDialog ?
\r
6712 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6713 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6715 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6716 GetOpenFileName(&openFileName)) {
\r
6717 /* open the file */
\r
6718 f = fopen(openFileName.lpstrFile, write);
\r
6720 MessageBox(hwnd, "File open failed", NULL,
\r
6721 MB_OK|MB_ICONEXCLAMATION);
\r
6725 int err = CommDlgExtendedError();
\r
6726 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6735 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6737 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6740 * Get the first pop-up menu in the menu template. This is the
\r
6741 * menu that TrackPopupMenu displays.
\r
6743 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6745 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6748 * TrackPopup uses screen coordinates, so convert the
\r
6749 * coordinates of the mouse click to screen coordinates.
\r
6751 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6753 /* Draw and track the floating pop-up menu. */
\r
6754 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6755 pt.x, pt.y, 0, hwnd, NULL);
\r
6757 /* Destroy the menu.*/
\r
6758 DestroyMenu(hmenu);
\r
6763 int sizeX, sizeY, newSizeX, newSizeY;
\r
6765 } ResizeEditPlusButtonsClosure;
\r
6768 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6770 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6774 if (hChild == cl->hText) return TRUE;
\r
6775 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6776 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6777 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6778 ScreenToClient(cl->hDlg, &pt);
\r
6779 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6780 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6784 /* Resize a dialog that has a (rich) edit field filling most of
\r
6785 the top, with a row of buttons below */
\r
6787 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6790 int newTextHeight, newTextWidth;
\r
6791 ResizeEditPlusButtonsClosure cl;
\r
6793 /*if (IsIconic(hDlg)) return;*/
\r
6794 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6796 cl.hdwp = BeginDeferWindowPos(8);
\r
6798 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6799 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6800 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6801 if (newTextHeight < 0) {
\r
6802 newSizeY += -newTextHeight;
\r
6803 newTextHeight = 0;
\r
6805 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6806 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6812 cl.newSizeX = newSizeX;
\r
6813 cl.newSizeY = newSizeY;
\r
6814 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6816 EndDeferWindowPos(cl.hdwp);
\r
6819 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6821 RECT rChild, rParent;
\r
6822 int wChild, hChild, wParent, hParent;
\r
6823 int wScreen, hScreen, xNew, yNew;
\r
6826 /* Get the Height and Width of the child window */
\r
6827 GetWindowRect (hwndChild, &rChild);
\r
6828 wChild = rChild.right - rChild.left;
\r
6829 hChild = rChild.bottom - rChild.top;
\r
6831 /* Get the Height and Width of the parent window */
\r
6832 GetWindowRect (hwndParent, &rParent);
\r
6833 wParent = rParent.right - rParent.left;
\r
6834 hParent = rParent.bottom - rParent.top;
\r
6836 /* Get the display limits */
\r
6837 hdc = GetDC (hwndChild);
\r
6838 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6839 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6840 ReleaseDC(hwndChild, hdc);
\r
6842 /* Calculate new X position, then adjust for screen */
\r
6843 xNew = rParent.left + ((wParent - wChild) /2);
\r
6846 } else if ((xNew+wChild) > wScreen) {
\r
6847 xNew = wScreen - wChild;
\r
6850 /* Calculate new Y position, then adjust for screen */
\r
6852 yNew = rParent.top + ((hParent - hChild) /2);
\r
6855 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6860 } else if ((yNew+hChild) > hScreen) {
\r
6861 yNew = hScreen - hChild;
\r
6864 /* Set it, and return */
\r
6865 return SetWindowPos (hwndChild, NULL,
\r
6866 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6869 /* Center one window over another */
\r
6870 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6872 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6875 /*---------------------------------------------------------------------------*\
\r
6877 * Startup Dialog functions
\r
6879 \*---------------------------------------------------------------------------*/
\r
6881 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6883 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6885 while (*cd != NULL) {
\r
6886 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6892 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6894 char buf1[ARG_MAX];
\r
6897 if (str[0] == '@') {
\r
6898 FILE* f = fopen(str + 1, "r");
\r
6900 DisplayFatalError(str + 1, errno, 2);
\r
6903 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6905 buf1[len] = NULLCHAR;
\r
6909 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6912 char buf[MSG_SIZ];
\r
6913 char *end = strchr(str, '\n');
\r
6914 if (end == NULL) return;
\r
6915 memcpy(buf, str, end - str);
\r
6916 buf[end - str] = NULLCHAR;
\r
6917 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6923 SetStartupDialogEnables(HWND hDlg)
\r
6925 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6926 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6927 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6928 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6929 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6930 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6931 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6932 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6933 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6934 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6935 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6936 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6937 IsDlgButtonChecked(hDlg, OPT_View));
\r
6941 QuoteForFilename(char *filename)
\r
6943 int dquote, space;
\r
6944 dquote = strchr(filename, '"') != NULL;
\r
6945 space = strchr(filename, ' ') != NULL;
\r
6946 if (dquote || space) {
\r
6958 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6960 char buf[MSG_SIZ];
\r
6963 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6964 q = QuoteForFilename(nthcp);
\r
6965 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6966 if (*nthdir != NULLCHAR) {
\r
6967 q = QuoteForFilename(nthdir);
\r
6968 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6970 if (*nthcp == NULLCHAR) {
\r
6971 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6972 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6973 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6974 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6979 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6981 char buf[MSG_SIZ];
\r
6985 switch (message) {
\r
6986 case WM_INITDIALOG:
\r
6987 /* Center the dialog */
\r
6988 CenterWindow (hDlg, GetDesktopWindow());
\r
6989 /* Initialize the dialog items */
\r
6990 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6991 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6992 firstChessProgramNames);
\r
6993 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6994 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6995 secondChessProgramNames);
\r
6996 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6997 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6998 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6999 if (*appData.icsHelper != NULLCHAR) {
\r
7000 char *q = QuoteForFilename(appData.icsHelper);
\r
7001 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7003 if (*appData.icsHost == NULLCHAR) {
\r
7004 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7005 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7006 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7007 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7008 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7011 if (appData.icsActive) {
\r
7012 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7014 else if (appData.noChessProgram) {
\r
7015 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7018 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7021 SetStartupDialogEnables(hDlg);
\r
7025 switch (LOWORD(wParam)) {
\r
7027 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7028 strcpy(buf, "/fcp=");
\r
7029 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7031 ParseArgs(StringGet, &p);
\r
7032 strcpy(buf, "/scp=");
\r
7033 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7035 ParseArgs(StringGet, &p);
\r
7036 appData.noChessProgram = FALSE;
\r
7037 appData.icsActive = FALSE;
\r
7038 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7039 strcpy(buf, "/ics /icshost=");
\r
7040 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7042 ParseArgs(StringGet, &p);
\r
7043 if (appData.zippyPlay) {
\r
7044 strcpy(buf, "/fcp=");
\r
7045 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7047 ParseArgs(StringGet, &p);
\r
7049 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7050 appData.noChessProgram = TRUE;
\r
7051 appData.icsActive = FALSE;
\r
7053 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7054 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7057 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7058 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7060 ParseArgs(StringGet, &p);
\r
7062 EndDialog(hDlg, TRUE);
\r
7069 case IDM_HELPCONTENTS:
\r
7070 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7071 MessageBox (GetFocus(),
\r
7072 "Unable to activate help",
\r
7073 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7078 SetStartupDialogEnables(hDlg);
\r
7086 /*---------------------------------------------------------------------------*\
\r
7088 * About box dialog functions
\r
7090 \*---------------------------------------------------------------------------*/
\r
7092 /* Process messages for "About" dialog box */
\r
7094 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7096 switch (message) {
\r
7097 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7098 /* Center the dialog over the application window */
\r
7099 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7100 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7103 case WM_COMMAND: /* message: received a command */
\r
7104 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7105 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7106 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7114 /*---------------------------------------------------------------------------*\
\r
7116 * Comment Dialog functions
\r
7118 \*---------------------------------------------------------------------------*/
\r
7121 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7123 static HANDLE hwndText = NULL;
\r
7124 int len, newSizeX, newSizeY, flags;
\r
7125 static int sizeX, sizeY;
\r
7130 switch (message) {
\r
7131 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7132 /* Initialize the dialog items */
\r
7133 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7134 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7135 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7136 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7137 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7138 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7139 SetWindowText(hDlg, commentTitle);
\r
7140 if (editComment) {
\r
7141 SetFocus(hwndText);
\r
7143 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7145 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7146 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7147 MAKELPARAM(FALSE, 0));
\r
7148 /* Size and position the dialog */
\r
7149 if (!commentDialog) {
\r
7150 commentDialog = hDlg;
\r
7151 flags = SWP_NOZORDER;
\r
7152 GetClientRect(hDlg, &rect);
\r
7153 sizeX = rect.right;
\r
7154 sizeY = rect.bottom;
\r
7155 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7156 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7157 WINDOWPLACEMENT wp;
\r
7158 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7159 wp.length = sizeof(WINDOWPLACEMENT);
\r
7161 wp.showCmd = SW_SHOW;
\r
7162 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7163 wp.rcNormalPosition.left = commentX;
\r
7164 wp.rcNormalPosition.right = commentX + commentW;
\r
7165 wp.rcNormalPosition.top = commentY;
\r
7166 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7167 SetWindowPlacement(hDlg, &wp);
\r
7169 GetClientRect(hDlg, &rect);
\r
7170 newSizeX = rect.right;
\r
7171 newSizeY = rect.bottom;
\r
7172 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7173 newSizeX, newSizeY);
\r
7180 case WM_COMMAND: /* message: received a command */
\r
7181 switch (LOWORD(wParam)) {
\r
7183 if (editComment) {
\r
7185 /* Read changed options from the dialog box */
\r
7186 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7187 len = GetWindowTextLength(hwndText);
\r
7188 str = (char *) malloc(len + 1);
\r
7189 GetWindowText(hwndText, str, len + 1);
\r
7198 ReplaceComment(commentIndex, str);
\r
7205 case OPT_CancelComment:
\r
7209 case OPT_ClearComment:
\r
7210 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7213 case OPT_EditComment:
\r
7214 EditCommentEvent();
\r
7223 newSizeX = LOWORD(lParam);
\r
7224 newSizeY = HIWORD(lParam);
\r
7225 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7230 case WM_GETMINMAXINFO:
\r
7231 /* Prevent resizing window too small */
\r
7232 mmi = (MINMAXINFO *) lParam;
\r
7233 mmi->ptMinTrackSize.x = 100;
\r
7234 mmi->ptMinTrackSize.y = 100;
\r
7241 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7246 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7248 if (str == NULL) str = "";
\r
7249 p = (char *) malloc(2 * strlen(str) + 2);
\r
7252 if (*str == '\n') *q++ = '\r';
\r
7256 if (commentText != NULL) free(commentText);
\r
7258 commentIndex = index;
\r
7259 commentTitle = title;
\r
7261 editComment = edit;
\r
7263 if (commentDialog) {
\r
7264 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7265 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7267 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7268 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7269 hwndMain, (DLGPROC)lpProc);
\r
7270 FreeProcInstance(lpProc);
\r
7272 commentDialogUp = TRUE;
\r
7276 /*---------------------------------------------------------------------------*\
\r
7278 * Type-in move dialog functions
\r
7280 \*---------------------------------------------------------------------------*/
\r
7283 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7285 char move[MSG_SIZ];
\r
7287 ChessMove moveType;
\r
7288 int fromX, fromY, toX, toY;
\r
7291 switch (message) {
\r
7292 case WM_INITDIALOG:
\r
7293 move[0] = (char) lParam;
\r
7294 move[1] = NULLCHAR;
\r
7295 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7296 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7297 SetWindowText(hInput, move);
\r
7299 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7303 switch (LOWORD(wParam)) {
\r
7305 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7306 gameMode != Training) {
\r
7307 DisplayMoveError("Displayed move is not current");
\r
7309 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7310 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7311 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7312 if (gameMode != Training)
\r
7313 forwardMostMove = currentMove;
\r
7314 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7316 DisplayMoveError("Could not parse move");
\r
7319 EndDialog(hDlg, TRUE);
\r
7322 EndDialog(hDlg, FALSE);
\r
7333 PopUpMoveDialog(char firstchar)
\r
7337 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7338 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7339 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7340 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7341 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7342 gameMode == Training) {
\r
7343 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7344 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7345 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7346 FreeProcInstance(lpProc);
\r
7350 /*---------------------------------------------------------------------------*\
\r
7352 * Type-in name dialog functions
\r
7354 \*---------------------------------------------------------------------------*/
\r
7357 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7359 char move[MSG_SIZ];
\r
7362 switch (message) {
\r
7363 case WM_INITDIALOG:
\r
7364 move[0] = (char) lParam;
\r
7365 move[1] = NULLCHAR;
\r
7366 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7367 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7368 SetWindowText(hInput, move);
\r
7370 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7374 switch (LOWORD(wParam)) {
\r
7376 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7377 appData.userName = strdup(move);
\r
7380 EndDialog(hDlg, TRUE);
\r
7383 EndDialog(hDlg, FALSE);
\r
7394 PopUpNameDialog(char firstchar)
\r
7398 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7399 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7400 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7401 FreeProcInstance(lpProc);
\r
7404 /*---------------------------------------------------------------------------*\
\r
7408 \*---------------------------------------------------------------------------*/
\r
7410 /* Nonmodal error box */
\r
7411 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7412 WPARAM wParam, LPARAM lParam);
\r
7415 ErrorPopUp(char *title, char *content)
\r
7419 BOOLEAN modal = hwndMain == NULL;
\r
7437 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7438 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7441 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7443 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7444 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7445 hwndMain, (DLGPROC)lpProc);
\r
7446 FreeProcInstance(lpProc);
\r
7453 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7454 if (errorDialog == NULL) return;
\r
7455 DestroyWindow(errorDialog);
\r
7456 errorDialog = NULL;
\r
7460 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7465 switch (message) {
\r
7466 case WM_INITDIALOG:
\r
7467 GetWindowRect(hDlg, &rChild);
\r
7470 SetWindowPos(hDlg, NULL, rChild.left,
\r
7471 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7472 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7476 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7477 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7478 and it doesn't work when you resize the dialog.
\r
7479 For now, just give it a default position.
\r
7481 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7483 errorDialog = hDlg;
\r
7484 SetWindowText(hDlg, errorTitle);
\r
7485 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7486 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7490 switch (LOWORD(wParam)) {
\r
7493 if (errorDialog == hDlg) errorDialog = NULL;
\r
7494 DestroyWindow(hDlg);
\r
7506 HWND gothicDialog = NULL;
\r
7509 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7513 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7515 switch (message) {
\r
7516 case WM_INITDIALOG:
\r
7517 GetWindowRect(hDlg, &rChild);
\r
7519 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7523 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7524 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7525 and it doesn't work when you resize the dialog.
\r
7526 For now, just give it a default position.
\r
7528 gothicDialog = hDlg;
\r
7529 SetWindowText(hDlg, errorTitle);
\r
7530 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7531 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7535 switch (LOWORD(wParam)) {
\r
7538 if (errorDialog == hDlg) errorDialog = NULL;
\r
7539 DestroyWindow(hDlg);
\r
7551 GothicPopUp(char *title, VariantClass variant)
\r
7554 static char *lastTitle;
\r
7556 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7557 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7559 if(lastTitle != title && gothicDialog != NULL) {
\r
7560 DestroyWindow(gothicDialog);
\r
7561 gothicDialog = NULL;
\r
7563 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7564 title = lastTitle;
\r
7565 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7566 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7567 hwndMain, (DLGPROC)lpProc);
\r
7568 FreeProcInstance(lpProc);
\r
7573 /*---------------------------------------------------------------------------*\
\r
7575 * Ics Interaction console functions
\r
7577 \*---------------------------------------------------------------------------*/
\r
7579 #define HISTORY_SIZE 64
\r
7580 static char *history[HISTORY_SIZE];
\r
7581 int histIn = 0, histP = 0;
\r
7584 SaveInHistory(char *cmd)
\r
7586 if (history[histIn] != NULL) {
\r
7587 free(history[histIn]);
\r
7588 history[histIn] = NULL;
\r
7590 if (*cmd == NULLCHAR) return;
\r
7591 history[histIn] = StrSave(cmd);
\r
7592 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7593 if (history[histIn] != NULL) {
\r
7594 free(history[histIn]);
\r
7595 history[histIn] = NULL;
\r
7601 PrevInHistory(char *cmd)
\r
7604 if (histP == histIn) {
\r
7605 if (history[histIn] != NULL) free(history[histIn]);
\r
7606 history[histIn] = StrSave(cmd);
\r
7608 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7609 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7611 return history[histP];
\r
7617 if (histP == histIn) return NULL;
\r
7618 histP = (histP + 1) % HISTORY_SIZE;
\r
7619 return history[histP];
\r
7626 BOOLEAN immediate;
\r
7627 } IcsTextMenuEntry;
\r
7628 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7629 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7632 ParseIcsTextMenu(char *icsTextMenuString)
\r
7635 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7636 char *p = icsTextMenuString;
\r
7637 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7640 if (e->command != NULL) {
\r
7642 e->command = NULL;
\r
7646 e = icsTextMenuEntry;
\r
7647 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7648 if (*p == ';' || *p == '\n') {
\r
7649 e->item = strdup("-");
\r
7650 e->command = NULL;
\r
7652 } else if (*p == '-') {
\r
7653 e->item = strdup("-");
\r
7654 e->command = NULL;
\r
7658 char *q, *r, *s, *t;
\r
7660 q = strchr(p, ',');
\r
7661 if (q == NULL) break;
\r
7663 r = strchr(q + 1, ',');
\r
7664 if (r == NULL) break;
\r
7666 s = strchr(r + 1, ',');
\r
7667 if (s == NULL) break;
\r
7670 t = strchr(s + 1, c);
\r
7673 t = strchr(s + 1, c);
\r
7675 if (t != NULL) *t = NULLCHAR;
\r
7676 e->item = strdup(p);
\r
7677 e->command = strdup(q + 1);
\r
7678 e->getname = *(r + 1) != '0';
\r
7679 e->immediate = *(s + 1) != '0';
\r
7683 if (t == NULL) break;
\r
7692 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7696 hmenu = LoadMenu(hInst, "TextMenu");
\r
7697 h = GetSubMenu(hmenu, 0);
\r
7699 if (strcmp(e->item, "-") == 0) {
\r
7700 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7702 if (e->item[0] == '|') {
\r
7703 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7704 IDM_CommandX + i, &e->item[1]);
\r
7706 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7715 WNDPROC consoleTextWindowProc;
\r
7718 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7720 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7721 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7725 SetWindowText(hInput, command);
\r
7727 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7729 sel.cpMin = 999999;
\r
7730 sel.cpMax = 999999;
\r
7731 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7736 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7737 if (sel.cpMin == sel.cpMax) {
\r
7738 /* Expand to surrounding word */
\r
7741 tr.chrg.cpMax = sel.cpMin;
\r
7742 tr.chrg.cpMin = --sel.cpMin;
\r
7743 if (sel.cpMin < 0) break;
\r
7744 tr.lpstrText = name;
\r
7745 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7746 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7750 tr.chrg.cpMin = sel.cpMax;
\r
7751 tr.chrg.cpMax = ++sel.cpMax;
\r
7752 tr.lpstrText = name;
\r
7753 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7754 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7757 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7758 MessageBeep(MB_ICONEXCLAMATION);
\r
7762 tr.lpstrText = name;
\r
7763 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7765 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7766 MessageBeep(MB_ICONEXCLAMATION);
\r
7769 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7772 sprintf(buf, "%s %s", command, name);
\r
7773 SetWindowText(hInput, buf);
\r
7774 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7776 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7777 SetWindowText(hInput, buf);
\r
7778 sel.cpMin = 999999;
\r
7779 sel.cpMax = 999999;
\r
7780 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7786 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7791 switch (message) {
\r
7793 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7796 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7799 sel.cpMin = 999999;
\r
7800 sel.cpMax = 999999;
\r
7801 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7802 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7807 if (wParam == '\t') {
\r
7808 if (GetKeyState(VK_SHIFT) < 0) {
\r
7810 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7811 if (buttonDesc[0].hwnd) {
\r
7812 SetFocus(buttonDesc[0].hwnd);
\r
7814 SetFocus(hwndMain);
\r
7818 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7821 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7823 SendMessage(hInput, message, wParam, lParam);
\r
7827 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7829 return SendMessage(hInput, message, wParam, lParam);
\r
7830 case WM_MBUTTONDOWN:
\r
7831 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7832 case WM_RBUTTONDOWN:
\r
7833 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7834 /* Move selection here if it was empty */
\r
7836 pt.x = LOWORD(lParam);
\r
7837 pt.y = HIWORD(lParam);
\r
7838 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7839 if (sel.cpMin == sel.cpMax) {
\r
7840 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7841 sel.cpMax = sel.cpMin;
\r
7842 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7844 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7847 case WM_RBUTTONUP:
\r
7848 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7849 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7850 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7853 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7854 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7855 if (sel.cpMin == sel.cpMax) {
\r
7856 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7857 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7859 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7860 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7862 pt.x = LOWORD(lParam);
\r
7863 pt.y = HIWORD(lParam);
\r
7864 MenuPopup(hwnd, pt, hmenu, -1);
\r
7868 switch (LOWORD(wParam)) {
\r
7869 case IDM_QuickPaste:
\r
7871 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7872 if (sel.cpMin == sel.cpMax) {
\r
7873 MessageBeep(MB_ICONEXCLAMATION);
\r
7876 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7877 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7878 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7883 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7886 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7889 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7893 int i = LOWORD(wParam) - IDM_CommandX;
\r
7894 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7895 icsTextMenuEntry[i].command != NULL) {
\r
7896 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7897 icsTextMenuEntry[i].getname,
\r
7898 icsTextMenuEntry[i].immediate);
\r
7906 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7909 WNDPROC consoleInputWindowProc;
\r
7912 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7914 char buf[MSG_SIZ];
\r
7916 static BOOL sendNextChar = FALSE;
\r
7917 static BOOL quoteNextChar = FALSE;
\r
7918 InputSource *is = consoleInputSource;
\r
7922 switch (message) {
\r
7924 if (!appData.localLineEditing || sendNextChar) {
\r
7925 is->buf[0] = (CHAR) wParam;
\r
7927 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7928 sendNextChar = FALSE;
\r
7931 if (quoteNextChar) {
\r
7932 buf[0] = (char) wParam;
\r
7933 buf[1] = NULLCHAR;
\r
7934 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7935 quoteNextChar = FALSE;
\r
7939 case '\r': /* Enter key */
\r
7940 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7941 if (consoleEcho) SaveInHistory(is->buf);
\r
7942 is->buf[is->count++] = '\n';
\r
7943 is->buf[is->count] = NULLCHAR;
\r
7944 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7945 if (consoleEcho) {
\r
7946 ConsoleOutput(is->buf, is->count, TRUE);
\r
7947 } else if (appData.localLineEditing) {
\r
7948 ConsoleOutput("\n", 1, TRUE);
\r
7951 case '\033': /* Escape key */
\r
7952 SetWindowText(hwnd, "");
\r
7953 cf.cbSize = sizeof(CHARFORMAT);
\r
7954 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7955 if (consoleEcho) {
\r
7956 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7958 cf.crTextColor = COLOR_ECHOOFF;
\r
7960 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7961 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7963 case '\t': /* Tab key */
\r
7964 if (GetKeyState(VK_SHIFT) < 0) {
\r
7966 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7969 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7970 if (buttonDesc[0].hwnd) {
\r
7971 SetFocus(buttonDesc[0].hwnd);
\r
7973 SetFocus(hwndMain);
\r
7977 case '\023': /* Ctrl+S */
\r
7978 sendNextChar = TRUE;
\r
7980 case '\021': /* Ctrl+Q */
\r
7981 quoteNextChar = TRUE;
\r
7990 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7991 p = PrevInHistory(buf);
\r
7993 SetWindowText(hwnd, p);
\r
7994 sel.cpMin = 999999;
\r
7995 sel.cpMax = 999999;
\r
7996 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8001 p = NextInHistory();
\r
8003 SetWindowText(hwnd, p);
\r
8004 sel.cpMin = 999999;
\r
8005 sel.cpMax = 999999;
\r
8006 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8012 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8016 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8020 case WM_MBUTTONDOWN:
\r
8021 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8022 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8024 case WM_RBUTTONUP:
\r
8025 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8026 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8027 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8031 hmenu = LoadMenu(hInst, "InputMenu");
\r
8032 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8033 if (sel.cpMin == sel.cpMax) {
\r
8034 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8035 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8037 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8038 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8040 pt.x = LOWORD(lParam);
\r
8041 pt.y = HIWORD(lParam);
\r
8042 MenuPopup(hwnd, pt, hmenu, -1);
\r
8046 switch (LOWORD(wParam)) {
\r
8048 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8050 case IDM_SelectAll:
\r
8052 sel.cpMax = -1; /*999999?*/
\r
8053 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8056 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8059 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8062 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8067 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8070 #define CO_MAX 100000
\r
8071 #define CO_TRIM 1000
\r
8074 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8076 static SnapData sd;
\r
8077 static HWND hText, hInput /*, hFocus*/;
\r
8078 // InputSource *is = consoleInputSource;
\r
8080 static int sizeX, sizeY;
\r
8081 int newSizeX, newSizeY;
\r
8084 switch (message) {
\r
8085 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8086 hwndConsole = hDlg;
\r
8087 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8088 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8090 consoleTextWindowProc = (WNDPROC)
\r
8091 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8092 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8093 consoleInputWindowProc = (WNDPROC)
\r
8094 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8095 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8096 Colorize(ColorNormal, TRUE);
\r
8097 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8098 ChangedConsoleFont();
\r
8099 GetClientRect(hDlg, &rect);
\r
8100 sizeX = rect.right;
\r
8101 sizeY = rect.bottom;
\r
8102 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8103 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8104 WINDOWPLACEMENT wp;
\r
8105 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8106 wp.length = sizeof(WINDOWPLACEMENT);
\r
8108 wp.showCmd = SW_SHOW;
\r
8109 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8110 wp.rcNormalPosition.left = wpConsole.x;
\r
8111 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8112 wp.rcNormalPosition.top = wpConsole.y;
\r
8113 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8114 SetWindowPlacement(hDlg, &wp);
\r
8117 // [HGM] Chessknight's change 2004-07-13
\r
8118 else { /* Determine Defaults */
\r
8119 WINDOWPLACEMENT wp;
\r
8120 wpConsole.x = winWidth + 1;
\r
8121 wpConsole.y = boardY;
\r
8122 wpConsoleW = screenWidth - winWidth;
\r
8123 wpConsoleH = winHeight;
\r
8124 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8125 wp.length = sizeof(WINDOWPLACEMENT);
\r
8127 wp.showCmd = SW_SHOW;
\r
8128 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8129 wp.rcNormalPosition.left = wpConsole.x;
\r
8130 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8131 wp.rcNormalPosition.top = wpConsole.y;
\r
8132 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8133 SetWindowPlacement(hDlg, &wp);
\r
8148 if (IsIconic(hDlg)) break;
\r
8149 newSizeX = LOWORD(lParam);
\r
8150 newSizeY = HIWORD(lParam);
\r
8151 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8152 RECT rectText, rectInput;
\r
8154 int newTextHeight, newTextWidth;
\r
8155 GetWindowRect(hText, &rectText);
\r
8156 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8157 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8158 if (newTextHeight < 0) {
\r
8159 newSizeY += -newTextHeight;
\r
8160 newTextHeight = 0;
\r
8162 SetWindowPos(hText, NULL, 0, 0,
\r
8163 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8164 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8165 pt.x = rectInput.left;
\r
8166 pt.y = rectInput.top + newSizeY - sizeY;
\r
8167 ScreenToClient(hDlg, &pt);
\r
8168 SetWindowPos(hInput, NULL,
\r
8169 pt.x, pt.y, /* needs client coords */
\r
8170 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8171 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8177 case WM_GETMINMAXINFO:
\r
8178 /* Prevent resizing window too small */
\r
8179 mmi = (MINMAXINFO *) lParam;
\r
8180 mmi->ptMinTrackSize.x = 100;
\r
8181 mmi->ptMinTrackSize.y = 100;
\r
8184 /* [AS] Snapping */
\r
8185 case WM_ENTERSIZEMOVE:
\r
8186 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8189 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8192 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8194 case WM_EXITSIZEMOVE:
\r
8195 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8198 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8206 if (hwndConsole) return;
\r
8207 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8208 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8213 ConsoleOutput(char* data, int length, int forceVisible)
\r
8218 char buf[CO_MAX+1];
\r
8221 static int delayLF = 0;
\r
8222 CHARRANGE savesel, sel;
\r
8224 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8232 while (length--) {
\r
8240 } else if (*p == '\007') {
\r
8241 MyPlaySound(&sounds[(int)SoundBell]);
\r
8248 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8249 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8250 /* Save current selection */
\r
8251 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8252 exlen = GetWindowTextLength(hText);
\r
8253 /* Find out whether current end of text is visible */
\r
8254 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8255 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8256 /* Trim existing text if it's too long */
\r
8257 if (exlen + (q - buf) > CO_MAX) {
\r
8258 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8261 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8262 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8264 savesel.cpMin -= trim;
\r
8265 savesel.cpMax -= trim;
\r
8266 if (exlen < 0) exlen = 0;
\r
8267 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8268 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8270 /* Append the new text */
\r
8271 sel.cpMin = exlen;
\r
8272 sel.cpMax = exlen;
\r
8273 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8274 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8275 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8276 if (forceVisible || exlen == 0 ||
\r
8277 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8278 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8279 /* Scroll to make new end of text visible if old end of text
\r
8280 was visible or new text is an echo of user typein */
\r
8281 sel.cpMin = 9999999;
\r
8282 sel.cpMax = 9999999;
\r
8283 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8284 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8285 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8286 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8288 if (savesel.cpMax == exlen || forceVisible) {
\r
8289 /* Move insert point to new end of text if it was at the old
\r
8290 end of text or if the new text is an echo of user typein */
\r
8291 sel.cpMin = 9999999;
\r
8292 sel.cpMax = 9999999;
\r
8293 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8295 /* Restore previous selection */
\r
8296 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8298 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8305 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8309 COLORREF oldFg, oldBg;
\r
8313 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8315 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8316 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8317 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8320 rect.right = x + squareSize;
\r
8322 rect.bottom = y + squareSize;
\r
8325 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8326 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8327 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8328 &rect, str, strlen(str), NULL);
\r
8330 (void) SetTextColor(hdc, oldFg);
\r
8331 (void) SetBkColor(hdc, oldBg);
\r
8332 (void) SelectObject(hdc, oldFont);
\r
8336 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8337 RECT *rect, char *color, char *flagFell)
\r
8341 COLORREF oldFg, oldBg;
\r
8344 if (appData.clockMode) {
\r
8346 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8348 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8355 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8356 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8358 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8359 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8361 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8363 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8364 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8365 rect, str, strlen(str), NULL);
\r
8366 if(logoHeight > 0 && appData.clockMode) {
\r
8368 sprintf(buf, "%s %s", TimeString(timeRemaining), flagFell);
\r
8369 r.top = rect->top + logoHeight/2;
\r
8370 r.left = rect->left;
\r
8371 r.right = rect->right;
\r
8372 r.bottom = rect->bottom;
\r
8373 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8374 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8375 &r, str, strlen(str), NULL);
\r
8377 (void) SetTextColor(hdc, oldFg);
\r
8378 (void) SetBkColor(hdc, oldBg);
\r
8379 (void) SelectObject(hdc, oldFont);
\r
8384 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8390 if( count <= 0 ) {
\r
8391 if (appData.debugMode) {
\r
8392 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8395 return ERROR_INVALID_USER_BUFFER;
\r
8398 ResetEvent(ovl->hEvent);
\r
8399 ovl->Offset = ovl->OffsetHigh = 0;
\r
8400 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8404 err = GetLastError();
\r
8405 if (err == ERROR_IO_PENDING) {
\r
8406 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8410 err = GetLastError();
\r
8417 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8422 ResetEvent(ovl->hEvent);
\r
8423 ovl->Offset = ovl->OffsetHigh = 0;
\r
8424 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8428 err = GetLastError();
\r
8429 if (err == ERROR_IO_PENDING) {
\r
8430 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8434 err = GetLastError();
\r
8440 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8441 void CheckForInputBufferFull( InputSource * is )
\r
8443 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8444 /* Look for end of line */
\r
8445 char * p = is->buf;
\r
8447 while( p < is->next && *p != '\n' ) {
\r
8451 if( p >= is->next ) {
\r
8452 if (appData.debugMode) {
\r
8453 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8456 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8457 is->count = (DWORD) -1;
\r
8458 is->next = is->buf;
\r
8464 InputThread(LPVOID arg)
\r
8469 is = (InputSource *) arg;
\r
8470 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8471 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8472 while (is->hThread != NULL) {
\r
8473 is->error = DoReadFile(is->hFile, is->next,
\r
8474 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8475 &is->count, &ovl);
\r
8476 if (is->error == NO_ERROR) {
\r
8477 is->next += is->count;
\r
8479 if (is->error == ERROR_BROKEN_PIPE) {
\r
8480 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8483 is->count = (DWORD) -1;
\r
8484 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8489 CheckForInputBufferFull( is );
\r
8491 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8493 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8495 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8498 CloseHandle(ovl.hEvent);
\r
8499 CloseHandle(is->hFile);
\r
8501 if (appData.debugMode) {
\r
8502 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8509 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8511 NonOvlInputThread(LPVOID arg)
\r
8518 is = (InputSource *) arg;
\r
8519 while (is->hThread != NULL) {
\r
8520 is->error = ReadFile(is->hFile, is->next,
\r
8521 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8522 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8523 if (is->error == NO_ERROR) {
\r
8524 /* Change CRLF to LF */
\r
8525 if (is->next > is->buf) {
\r
8527 i = is->count + 1;
\r
8535 if (prev == '\r' && *p == '\n') {
\r
8547 if (is->error == ERROR_BROKEN_PIPE) {
\r
8548 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8551 is->count = (DWORD) -1;
\r
8555 CheckForInputBufferFull( is );
\r
8557 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8559 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8561 if (is->count < 0) break; /* Quit on error */
\r
8563 CloseHandle(is->hFile);
\r
8568 SocketInputThread(LPVOID arg)
\r
8572 is = (InputSource *) arg;
\r
8573 while (is->hThread != NULL) {
\r
8574 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8575 if ((int)is->count == SOCKET_ERROR) {
\r
8576 is->count = (DWORD) -1;
\r
8577 is->error = WSAGetLastError();
\r
8579 is->error = NO_ERROR;
\r
8580 is->next += is->count;
\r
8581 if (is->count == 0 && is->second == is) {
\r
8582 /* End of file on stderr; quit with no message */
\r
8586 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8588 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8590 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8596 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8600 is = (InputSource *) lParam;
\r
8601 if (is->lineByLine) {
\r
8602 /* Feed in lines one by one */
\r
8603 char *p = is->buf;
\r
8605 while (q < is->next) {
\r
8606 if (*q++ == '\n') {
\r
8607 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8612 /* Move any partial line to the start of the buffer */
\r
8614 while (p < is->next) {
\r
8619 if (is->error != NO_ERROR || is->count == 0) {
\r
8620 /* Notify backend of the error. Note: If there was a partial
\r
8621 line at the end, it is not flushed through. */
\r
8622 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8625 /* Feed in the whole chunk of input at once */
\r
8626 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8627 is->next = is->buf;
\r
8631 /*---------------------------------------------------------------------------*\
\r
8633 * Menu enables. Used when setting various modes.
\r
8635 \*---------------------------------------------------------------------------*/
\r
8643 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8645 while (enab->item > 0) {
\r
8646 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8651 Enables gnuEnables[] = {
\r
8652 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8653 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8654 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8655 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8656 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8657 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8658 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8659 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8660 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8661 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8665 Enables icsEnables[] = {
\r
8666 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8667 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8668 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8669 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8670 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8671 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8672 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8673 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8674 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8675 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8676 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8677 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8682 Enables zippyEnables[] = {
\r
8683 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8684 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8685 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8690 Enables ncpEnables[] = {
\r
8691 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8692 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8693 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8694 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8695 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8696 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8697 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8698 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8699 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8700 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8701 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8702 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8703 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8704 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8705 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8709 Enables trainingOnEnables[] = {
\r
8710 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8711 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8712 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8713 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8714 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8715 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8716 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8717 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8721 Enables trainingOffEnables[] = {
\r
8722 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8723 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8724 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8725 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8726 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8727 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8728 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8729 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8733 /* These modify either ncpEnables or gnuEnables */
\r
8734 Enables cmailEnables[] = {
\r
8735 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8736 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8737 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8738 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8739 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8740 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8741 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8745 Enables machineThinkingEnables[] = {
\r
8746 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8747 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8748 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8749 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8750 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8751 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8752 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8753 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8754 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8755 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8756 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8757 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8758 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8759 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8760 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8764 Enables userThinkingEnables[] = {
\r
8765 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8766 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8767 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8768 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8769 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8770 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8771 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8772 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8773 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8774 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8775 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8776 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8777 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8778 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8779 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8783 /*---------------------------------------------------------------------------*\
\r
8785 * Front-end interface functions exported by XBoard.
\r
8786 * Functions appear in same order as prototypes in frontend.h.
\r
8788 \*---------------------------------------------------------------------------*/
\r
8792 static UINT prevChecked = 0;
\r
8793 static int prevPausing = 0;
\r
8796 if (pausing != prevPausing) {
\r
8797 prevPausing = pausing;
\r
8798 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8799 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8800 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8803 switch (gameMode) {
\r
8804 case BeginningOfGame:
\r
8805 if (appData.icsActive)
\r
8806 nowChecked = IDM_IcsClient;
\r
8807 else if (appData.noChessProgram)
\r
8808 nowChecked = IDM_EditGame;
\r
8810 nowChecked = IDM_MachineBlack;
\r
8812 case MachinePlaysBlack:
\r
8813 nowChecked = IDM_MachineBlack;
\r
8815 case MachinePlaysWhite:
\r
8816 nowChecked = IDM_MachineWhite;
\r
8818 case TwoMachinesPlay:
\r
8819 nowChecked = IDM_TwoMachines;
\r
8822 nowChecked = IDM_AnalysisMode;
\r
8825 nowChecked = IDM_AnalyzeFile;
\r
8828 nowChecked = IDM_EditGame;
\r
8830 case PlayFromGameFile:
\r
8831 nowChecked = IDM_LoadGame;
\r
8833 case EditPosition:
\r
8834 nowChecked = IDM_EditPosition;
\r
8837 nowChecked = IDM_Training;
\r
8839 case IcsPlayingWhite:
\r
8840 case IcsPlayingBlack:
\r
8841 case IcsObserving:
\r
8843 nowChecked = IDM_IcsClient;
\r
8850 if (prevChecked != 0)
\r
8851 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8852 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8853 if (nowChecked != 0)
\r
8854 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8855 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8857 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8858 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8859 MF_BYCOMMAND|MF_ENABLED);
\r
8861 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8862 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8865 prevChecked = nowChecked;
\r
8867 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8868 if (appData.icsActive) {
\r
8869 if (appData.icsEngineAnalyze) {
\r
8870 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8871 MF_BYCOMMAND|MF_CHECKED);
\r
8873 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8874 MF_BYCOMMAND|MF_UNCHECKED);
\r
8882 HMENU hmenu = GetMenu(hwndMain);
\r
8883 SetMenuEnables(hmenu, icsEnables);
\r
8884 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8885 MF_BYPOSITION|MF_ENABLED);
\r
8887 if (appData.zippyPlay) {
\r
8888 SetMenuEnables(hmenu, zippyEnables);
\r
8889 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8890 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8891 MF_BYCOMMAND|MF_ENABLED);
\r
8899 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8905 HMENU hmenu = GetMenu(hwndMain);
\r
8906 SetMenuEnables(hmenu, ncpEnables);
\r
8907 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8908 MF_BYPOSITION|MF_GRAYED);
\r
8909 DrawMenuBar(hwndMain);
\r
8915 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8919 SetTrainingModeOn()
\r
8922 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8923 for (i = 0; i < N_BUTTONS; i++) {
\r
8924 if (buttonDesc[i].hwnd != NULL)
\r
8925 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8930 VOID SetTrainingModeOff()
\r
8933 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8934 for (i = 0; i < N_BUTTONS; i++) {
\r
8935 if (buttonDesc[i].hwnd != NULL)
\r
8936 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8942 SetUserThinkingEnables()
\r
8944 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8948 SetMachineThinkingEnables()
\r
8950 HMENU hMenu = GetMenu(hwndMain);
\r
8951 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8953 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8955 if (gameMode == MachinePlaysBlack) {
\r
8956 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8957 } else if (gameMode == MachinePlaysWhite) {
\r
8958 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8959 } else if (gameMode == TwoMachinesPlay) {
\r
8960 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8966 DisplayTitle(char *str)
\r
8968 char title[MSG_SIZ], *host;
\r
8969 if (str[0] != NULLCHAR) {
\r
8970 strcpy(title, str);
\r
8971 } else if (appData.icsActive) {
\r
8972 if (appData.icsCommPort[0] != NULLCHAR)
\r
8975 host = appData.icsHost;
\r
8976 sprintf(title, "%s: %s", szTitle, host);
\r
8977 } else if (appData.noChessProgram) {
\r
8978 strcpy(title, szTitle);
\r
8980 strcpy(title, szTitle);
\r
8981 strcat(title, ": ");
\r
8982 strcat(title, first.tidy);
\r
8984 SetWindowText(hwndMain, title);
\r
8989 DisplayMessage(char *str1, char *str2)
\r
8993 int remain = MESSAGE_TEXT_MAX - 1;
\r
8996 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8997 messageText[0] = NULLCHAR;
\r
8999 len = strlen(str1);
\r
9000 if (len > remain) len = remain;
\r
9001 strncpy(messageText, str1, len);
\r
9002 messageText[len] = NULLCHAR;
\r
9005 if (*str2 && remain >= 2) {
\r
9007 strcat(messageText, " ");
\r
9010 len = strlen(str2);
\r
9011 if (len > remain) len = remain;
\r
9012 strncat(messageText, str2, len);
\r
9014 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9016 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9017 hdc = GetDC(hwndMain);
\r
9018 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9019 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9020 &messageRect, messageText, strlen(messageText), NULL);
\r
9021 (void) SelectObject(hdc, oldFont);
\r
9022 (void) ReleaseDC(hwndMain, hdc);
\r
9026 DisplayError(char *str, int error)
\r
9028 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9034 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9035 NULL, error, LANG_NEUTRAL,
\r
9036 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9038 sprintf(buf, "%s:\n%s", str, buf2);
\r
9040 ErrorMap *em = errmap;
\r
9041 while (em->err != 0 && em->err != error) em++;
\r
9042 if (em->err != 0) {
\r
9043 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9045 sprintf(buf, "%s:\nError code %d", str, error);
\r
9050 ErrorPopUp("Error", buf);
\r
9055 DisplayMoveError(char *str)
\r
9057 fromX = fromY = -1;
\r
9058 ClearHighlights();
\r
9059 DrawPosition(FALSE, NULL);
\r
9060 if (appData.popupMoveErrors) {
\r
9061 ErrorPopUp("Error", str);
\r
9063 DisplayMessage(str, "");
\r
9064 moveErrorMessageUp = TRUE;
\r
9069 DisplayFatalError(char *str, int error, int exitStatus)
\r
9071 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9073 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9076 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9077 NULL, error, LANG_NEUTRAL,
\r
9078 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9080 sprintf(buf, "%s:\n%s", str, buf2);
\r
9082 ErrorMap *em = errmap;
\r
9083 while (em->err != 0 && em->err != error) em++;
\r
9084 if (em->err != 0) {
\r
9085 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9087 sprintf(buf, "%s:\nError code %d", str, error);
\r
9092 if (appData.debugMode) {
\r
9093 fprintf(debugFP, "%s: %s\n", label, str);
\r
9095 if (appData.popupExitMessage) {
\r
9096 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9097 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9099 ExitEvent(exitStatus);
\r
9104 DisplayInformation(char *str)
\r
9106 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9111 DisplayNote(char *str)
\r
9113 ErrorPopUp("Note", str);
\r
9118 char *title, *question, *replyPrefix;
\r
9123 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9125 static QuestionParams *qp;
\r
9126 char reply[MSG_SIZ];
\r
9129 switch (message) {
\r
9130 case WM_INITDIALOG:
\r
9131 qp = (QuestionParams *) lParam;
\r
9132 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9133 SetWindowText(hDlg, qp->title);
\r
9134 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9135 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9139 switch (LOWORD(wParam)) {
\r
9141 strcpy(reply, qp->replyPrefix);
\r
9142 if (*reply) strcat(reply, " ");
\r
9143 len = strlen(reply);
\r
9144 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9145 strcat(reply, "\n");
\r
9146 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9147 EndDialog(hDlg, TRUE);
\r
9148 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9151 EndDialog(hDlg, FALSE);
\r
9162 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9164 QuestionParams qp;
\r
9168 qp.question = question;
\r
9169 qp.replyPrefix = replyPrefix;
\r
9171 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9172 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9173 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9174 FreeProcInstance(lpProc);
\r
9177 /* [AS] Pick FRC position */
\r
9178 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9180 static int * lpIndexFRC;
\r
9186 case WM_INITDIALOG:
\r
9187 lpIndexFRC = (int *) lParam;
\r
9189 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9191 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9192 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9193 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9194 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9199 switch( LOWORD(wParam) ) {
\r
9201 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9202 EndDialog( hDlg, 0 );
\r
9203 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9206 EndDialog( hDlg, 1 );
\r
9208 case IDC_NFG_Edit:
\r
9209 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9210 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9212 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9215 case IDC_NFG_Random:
\r
9216 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9217 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9230 int index = appData.defaultFrcPosition;
\r
9231 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9233 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9235 if( result == 0 ) {
\r
9236 appData.defaultFrcPosition = index;
\r
9242 /* [AS] Game list options */
\r
9248 static GLT_Item GLT_ItemInfo[] = {
\r
9249 { GLT_EVENT, "Event" },
\r
9250 { GLT_SITE, "Site" },
\r
9251 { GLT_DATE, "Date" },
\r
9252 { GLT_ROUND, "Round" },
\r
9253 { GLT_PLAYERS, "Players" },
\r
9254 { GLT_RESULT, "Result" },
\r
9255 { GLT_WHITE_ELO, "White Rating" },
\r
9256 { GLT_BLACK_ELO, "Black Rating" },
\r
9257 { GLT_TIME_CONTROL,"Time Control" },
\r
9258 { GLT_VARIANT, "Variant" },
\r
9259 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9263 const char * GLT_FindItem( char id )
\r
9265 const char * result = 0;
\r
9267 GLT_Item * list = GLT_ItemInfo;
\r
9269 while( list->id != 0 ) {
\r
9270 if( list->id == id ) {
\r
9271 result = list->name;
\r
9281 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9283 const char * name = GLT_FindItem( id );
\r
9286 if( index >= 0 ) {
\r
9287 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9290 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9295 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9299 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9302 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9306 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9308 pc = GLT_ALL_TAGS;
\r
9311 if( strchr( tags, *pc ) == 0 ) {
\r
9312 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9317 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9320 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9322 char result = '\0';
\r
9325 GLT_Item * list = GLT_ItemInfo;
\r
9327 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9328 while( list->id != 0 ) {
\r
9329 if( strcmp( list->name, name ) == 0 ) {
\r
9330 result = list->id;
\r
9341 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9343 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9344 int idx2 = idx1 + delta;
\r
9345 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9347 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9350 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9351 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9352 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9353 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9357 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9359 static char glt[64];
\r
9360 static char * lpUserGLT;
\r
9364 case WM_INITDIALOG:
\r
9365 lpUserGLT = (char *) lParam;
\r
9367 strcpy( glt, lpUserGLT );
\r
9369 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9371 /* Initialize list */
\r
9372 GLT_TagsToList( hDlg, glt );
\r
9374 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9379 switch( LOWORD(wParam) ) {
\r
9382 char * pc = lpUserGLT;
\r
9384 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9388 id = GLT_ListItemToTag( hDlg, idx );
\r
9392 } while( id != '\0' );
\r
9394 EndDialog( hDlg, 0 );
\r
9397 EndDialog( hDlg, 1 );
\r
9400 case IDC_GLT_Default:
\r
9401 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9402 GLT_TagsToList( hDlg, glt );
\r
9405 case IDC_GLT_Restore:
\r
9406 strcpy( glt, lpUserGLT );
\r
9407 GLT_TagsToList( hDlg, glt );
\r
9411 GLT_MoveSelection( hDlg, -1 );
\r
9414 case IDC_GLT_Down:
\r
9415 GLT_MoveSelection( hDlg, +1 );
\r
9425 int GameListOptions()
\r
9429 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9431 strcpy( glt, appData.gameListTags );
\r
9433 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9435 if( result == 0 ) {
\r
9436 /* [AS] Memory leak here! */
\r
9437 appData.gameListTags = strdup( glt );
\r
9445 DisplayIcsInteractionTitle(char *str)
\r
9447 char consoleTitle[MSG_SIZ];
\r
9449 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9450 SetWindowText(hwndConsole, consoleTitle);
\r
9454 DrawPosition(int fullRedraw, Board board)
\r
9456 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9463 fromX = fromY = -1;
\r
9464 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9465 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9466 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9467 dragInfo.lastpos = dragInfo.pos;
\r
9468 dragInfo.start.x = dragInfo.start.y = -1;
\r
9469 dragInfo.from = dragInfo.start;
\r
9471 DrawPosition(TRUE, NULL);
\r
9477 CommentPopUp(char *title, char *str)
\r
9479 HWND hwnd = GetActiveWindow();
\r
9480 EitherCommentPopUp(0, title, str, FALSE);
\r
9481 SetActiveWindow(hwnd);
\r
9485 CommentPopDown(void)
\r
9487 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9488 if (commentDialog) {
\r
9489 ShowWindow(commentDialog, SW_HIDE);
\r
9491 commentDialogUp = FALSE;
\r
9495 EditCommentPopUp(int index, char *title, char *str)
\r
9497 EitherCommentPopUp(index, title, str, TRUE);
\r
9504 MyPlaySound(&sounds[(int)SoundMove]);
\r
9507 VOID PlayIcsWinSound()
\r
9509 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9512 VOID PlayIcsLossSound()
\r
9514 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9517 VOID PlayIcsDrawSound()
\r
9519 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9522 VOID PlayIcsUnfinishedSound()
\r
9524 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9530 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9538 consoleEcho = TRUE;
\r
9539 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9540 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9541 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9550 consoleEcho = FALSE;
\r
9551 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9552 /* This works OK: set text and background both to the same color */
\r
9554 cf.crTextColor = COLOR_ECHOOFF;
\r
9555 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9556 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9559 /* No Raw()...? */
\r
9561 void Colorize(ColorClass cc, int continuation)
\r
9563 currentColorClass = cc;
\r
9564 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9565 consoleCF.crTextColor = textAttribs[cc].color;
\r
9566 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9567 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9573 static char buf[MSG_SIZ];
\r
9574 DWORD bufsiz = MSG_SIZ;
\r
9576 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9577 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9579 if (!GetUserName(buf, &bufsiz)) {
\r
9580 /*DisplayError("Error getting user name", GetLastError());*/
\r
9581 strcpy(buf, "User");
\r
9589 static char buf[MSG_SIZ];
\r
9590 DWORD bufsiz = MSG_SIZ;
\r
9592 if (!GetComputerName(buf, &bufsiz)) {
\r
9593 /*DisplayError("Error getting host name", GetLastError());*/
\r
9594 strcpy(buf, "Unknown");
\r
9601 ClockTimerRunning()
\r
9603 return clockTimerEvent != 0;
\r
9609 if (clockTimerEvent == 0) return FALSE;
\r
9610 KillTimer(hwndMain, clockTimerEvent);
\r
9611 clockTimerEvent = 0;
\r
9616 StartClockTimer(long millisec)
\r
9618 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9619 (UINT) millisec, NULL);
\r
9623 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9626 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9628 if(appData.noGUI) return;
\r
9629 hdc = GetDC(hwndMain);
\r
9630 if (!IsIconic(hwndMain)) {
\r
9631 DisplayAClock(hdc, timeRemaining, highlight,
\r
9632 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9634 if (highlight && iconCurrent == iconBlack) {
\r
9635 iconCurrent = iconWhite;
\r
9636 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9637 if (IsIconic(hwndMain)) {
\r
9638 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9641 (void) ReleaseDC(hwndMain, hdc);
\r
9643 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9647 DisplayBlackClock(long timeRemaining, int highlight)
\r
9650 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9652 if(appData.noGUI) return;
\r
9653 hdc = GetDC(hwndMain);
\r
9654 if (!IsIconic(hwndMain)) {
\r
9655 DisplayAClock(hdc, timeRemaining, highlight,
\r
9656 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9658 if (highlight && iconCurrent == iconWhite) {
\r
9659 iconCurrent = iconBlack;
\r
9660 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9661 if (IsIconic(hwndMain)) {
\r
9662 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9665 (void) ReleaseDC(hwndMain, hdc);
\r
9667 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9672 LoadGameTimerRunning()
\r
9674 return loadGameTimerEvent != 0;
\r
9678 StopLoadGameTimer()
\r
9680 if (loadGameTimerEvent == 0) return FALSE;
\r
9681 KillTimer(hwndMain, loadGameTimerEvent);
\r
9682 loadGameTimerEvent = 0;
\r
9687 StartLoadGameTimer(long millisec)
\r
9689 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9690 (UINT) millisec, NULL);
\r
9698 char fileTitle[MSG_SIZ];
\r
9700 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9701 f = OpenFileDialog(hwndMain, "a", defName,
\r
9702 appData.oldSaveStyle ? "gam" : "pgn",
\r
9704 "Save Game to File", NULL, fileTitle, NULL);
\r
9706 SaveGame(f, 0, "");
\r
9713 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9715 if (delayedTimerEvent != 0) {
\r
9716 if (appData.debugMode) {
\r
9717 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9719 KillTimer(hwndMain, delayedTimerEvent);
\r
9720 delayedTimerEvent = 0;
\r
9721 delayedTimerCallback();
\r
9723 delayedTimerCallback = cb;
\r
9724 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9725 (UINT) millisec, NULL);
\r
9728 DelayedEventCallback
\r
9731 if (delayedTimerEvent) {
\r
9732 return delayedTimerCallback;
\r
9739 CancelDelayedEvent()
\r
9741 if (delayedTimerEvent) {
\r
9742 KillTimer(hwndMain, delayedTimerEvent);
\r
9743 delayedTimerEvent = 0;
\r
9747 DWORD GetWin32Priority(int nice)
\r
9748 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9750 REALTIME_PRIORITY_CLASS 0x00000100
\r
9751 HIGH_PRIORITY_CLASS 0x00000080
\r
9752 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9753 NORMAL_PRIORITY_CLASS 0x00000020
\r
9754 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9755 IDLE_PRIORITY_CLASS 0x00000040
\r
9757 if (nice < -15) return 0x00000080;
\r
9758 if (nice < 0) return 0x00008000;
\r
9759 if (nice == 0) return 0x00000020;
\r
9760 if (nice < 15) return 0x00004000;
\r
9761 return 0x00000040;
\r
9764 /* Start a child process running the given program.
\r
9765 The process's standard output can be read from "from", and its
\r
9766 standard input can be written to "to".
\r
9767 Exit with fatal error if anything goes wrong.
\r
9768 Returns an opaque pointer that can be used to destroy the process
\r
9772 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9774 #define BUFSIZE 4096
\r
9776 HANDLE hChildStdinRd, hChildStdinWr,
\r
9777 hChildStdoutRd, hChildStdoutWr;
\r
9778 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9779 SECURITY_ATTRIBUTES saAttr;
\r
9781 PROCESS_INFORMATION piProcInfo;
\r
9782 STARTUPINFO siStartInfo;
\r
9784 char buf[MSG_SIZ];
\r
9787 if (appData.debugMode) {
\r
9788 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9793 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9794 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9795 saAttr.bInheritHandle = TRUE;
\r
9796 saAttr.lpSecurityDescriptor = NULL;
\r
9799 * The steps for redirecting child's STDOUT:
\r
9800 * 1. Create anonymous pipe to be STDOUT for child.
\r
9801 * 2. Create a noninheritable duplicate of read handle,
\r
9802 * and close the inheritable read handle.
\r
9805 /* Create a pipe for the child's STDOUT. */
\r
9806 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9807 return GetLastError();
\r
9810 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9811 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9812 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9813 FALSE, /* not inherited */
\r
9814 DUPLICATE_SAME_ACCESS);
\r
9816 return GetLastError();
\r
9818 CloseHandle(hChildStdoutRd);
\r
9821 * The steps for redirecting child's STDIN:
\r
9822 * 1. Create anonymous pipe to be STDIN for child.
\r
9823 * 2. Create a noninheritable duplicate of write handle,
\r
9824 * and close the inheritable write handle.
\r
9827 /* Create a pipe for the child's STDIN. */
\r
9828 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9829 return GetLastError();
\r
9832 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9833 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9834 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9835 FALSE, /* not inherited */
\r
9836 DUPLICATE_SAME_ACCESS);
\r
9838 return GetLastError();
\r
9840 CloseHandle(hChildStdinWr);
\r
9842 /* Arrange to (1) look in dir for the child .exe file, and
\r
9843 * (2) have dir be the child's working directory. Interpret
\r
9844 * dir relative to the directory WinBoard loaded from. */
\r
9845 GetCurrentDirectory(MSG_SIZ, buf);
\r
9846 SetCurrentDirectory(installDir);
\r
9847 SetCurrentDirectory(dir);
\r
9849 /* Now create the child process. */
\r
9851 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9852 siStartInfo.lpReserved = NULL;
\r
9853 siStartInfo.lpDesktop = NULL;
\r
9854 siStartInfo.lpTitle = NULL;
\r
9855 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9856 siStartInfo.cbReserved2 = 0;
\r
9857 siStartInfo.lpReserved2 = NULL;
\r
9858 siStartInfo.hStdInput = hChildStdinRd;
\r
9859 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9860 siStartInfo.hStdError = hChildStdoutWr;
\r
9862 fSuccess = CreateProcess(NULL,
\r
9863 cmdLine, /* command line */
\r
9864 NULL, /* process security attributes */
\r
9865 NULL, /* primary thread security attrs */
\r
9866 TRUE, /* handles are inherited */
\r
9867 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9868 NULL, /* use parent's environment */
\r
9870 &siStartInfo, /* STARTUPINFO pointer */
\r
9871 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9873 err = GetLastError();
\r
9874 SetCurrentDirectory(buf); /* return to prev directory */
\r
9879 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9880 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9881 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9884 /* Close the handles we don't need in the parent */
\r
9885 CloseHandle(piProcInfo.hThread);
\r
9886 CloseHandle(hChildStdinRd);
\r
9887 CloseHandle(hChildStdoutWr);
\r
9889 /* Prepare return value */
\r
9890 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9891 cp->kind = CPReal;
\r
9892 cp->hProcess = piProcInfo.hProcess;
\r
9893 cp->pid = piProcInfo.dwProcessId;
\r
9894 cp->hFrom = hChildStdoutRdDup;
\r
9895 cp->hTo = hChildStdinWrDup;
\r
9897 *pr = (void *) cp;
\r
9899 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9900 2000 where engines sometimes don't see the initial command(s)
\r
9901 from WinBoard and hang. I don't understand how that can happen,
\r
9902 but the Sleep is harmless, so I've put it in. Others have also
\r
9903 reported what may be the same problem, so hopefully this will fix
\r
9904 it for them too. */
\r
9912 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9914 ChildProc *cp; int result;
\r
9916 cp = (ChildProc *) pr;
\r
9917 if (cp == NULL) return;
\r
9919 switch (cp->kind) {
\r
9921 /* TerminateProcess is considered harmful, so... */
\r
9922 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9923 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9924 /* The following doesn't work because the chess program
\r
9925 doesn't "have the same console" as WinBoard. Maybe
\r
9926 we could arrange for this even though neither WinBoard
\r
9927 nor the chess program uses a console for stdio? */
\r
9928 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9930 /* [AS] Special termination modes for misbehaving programs... */
\r
9931 if( signal == 9 ) {
\r
9932 result = TerminateProcess( cp->hProcess, 0 );
\r
9934 if ( appData.debugMode) {
\r
9935 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9938 else if( signal == 10 ) {
\r
9939 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9941 if( dw != WAIT_OBJECT_0 ) {
\r
9942 result = TerminateProcess( cp->hProcess, 0 );
\r
9944 if ( appData.debugMode) {
\r
9945 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9951 CloseHandle(cp->hProcess);
\r
9955 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9959 closesocket(cp->sock);
\r
9964 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9965 closesocket(cp->sock);
\r
9966 closesocket(cp->sock2);
\r
9974 InterruptChildProcess(ProcRef pr)
\r
9978 cp = (ChildProc *) pr;
\r
9979 if (cp == NULL) return;
\r
9980 switch (cp->kind) {
\r
9982 /* The following doesn't work because the chess program
\r
9983 doesn't "have the same console" as WinBoard. Maybe
\r
9984 we could arrange for this even though neither WinBoard
\r
9985 nor the chess program uses a console for stdio */
\r
9986 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9991 /* Can't interrupt */
\r
9995 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10002 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10004 char cmdLine[MSG_SIZ];
\r
10006 if (port[0] == NULLCHAR) {
\r
10007 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10009 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10011 return StartChildProcess(cmdLine, "", pr);
\r
10015 /* Code to open TCP sockets */
\r
10018 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10023 struct sockaddr_in sa, mysa;
\r
10024 struct hostent FAR *hp;
\r
10025 unsigned short uport;
\r
10026 WORD wVersionRequested;
\r
10029 /* Initialize socket DLL */
\r
10030 wVersionRequested = MAKEWORD(1, 1);
\r
10031 err = WSAStartup(wVersionRequested, &wsaData);
\r
10032 if (err != 0) return err;
\r
10034 /* Make socket */
\r
10035 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10036 err = WSAGetLastError();
\r
10041 /* Bind local address using (mostly) don't-care values.
\r
10043 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10044 mysa.sin_family = AF_INET;
\r
10045 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10046 uport = (unsigned short) 0;
\r
10047 mysa.sin_port = htons(uport);
\r
10048 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10049 == SOCKET_ERROR) {
\r
10050 err = WSAGetLastError();
\r
10055 /* Resolve remote host name */
\r
10056 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10057 if (!(hp = gethostbyname(host))) {
\r
10058 unsigned int b0, b1, b2, b3;
\r
10060 err = WSAGetLastError();
\r
10062 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10063 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10064 hp->h_addrtype = AF_INET;
\r
10065 hp->h_length = 4;
\r
10066 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10067 hp->h_addr_list[0] = (char *) malloc(4);
\r
10068 hp->h_addr_list[0][0] = (char) b0;
\r
10069 hp->h_addr_list[0][1] = (char) b1;
\r
10070 hp->h_addr_list[0][2] = (char) b2;
\r
10071 hp->h_addr_list[0][3] = (char) b3;
\r
10077 sa.sin_family = hp->h_addrtype;
\r
10078 uport = (unsigned short) atoi(port);
\r
10079 sa.sin_port = htons(uport);
\r
10080 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10082 /* Make connection */
\r
10083 if (connect(s, (struct sockaddr *) &sa,
\r
10084 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10085 err = WSAGetLastError();
\r
10090 /* Prepare return value */
\r
10091 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10092 cp->kind = CPSock;
\r
10094 *pr = (ProcRef *) cp;
\r
10100 OpenCommPort(char *name, ProcRef *pr)
\r
10105 char fullname[MSG_SIZ];
\r
10107 if (*name != '\\')
\r
10108 sprintf(fullname, "\\\\.\\%s", name);
\r
10110 strcpy(fullname, name);
\r
10112 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10113 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10114 if (h == (HANDLE) -1) {
\r
10115 return GetLastError();
\r
10119 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10121 /* Accumulate characters until a 100ms pause, then parse */
\r
10122 ct.ReadIntervalTimeout = 100;
\r
10123 ct.ReadTotalTimeoutMultiplier = 0;
\r
10124 ct.ReadTotalTimeoutConstant = 0;
\r
10125 ct.WriteTotalTimeoutMultiplier = 0;
\r
10126 ct.WriteTotalTimeoutConstant = 0;
\r
10127 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10129 /* Prepare return value */
\r
10130 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10131 cp->kind = CPComm;
\r
10134 *pr = (ProcRef *) cp;
\r
10140 OpenLoopback(ProcRef *pr)
\r
10142 DisplayFatalError("Not implemented", 0, 1);
\r
10148 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10152 SOCKET s, s2, s3;
\r
10153 struct sockaddr_in sa, mysa;
\r
10154 struct hostent FAR *hp;
\r
10155 unsigned short uport;
\r
10156 WORD wVersionRequested;
\r
10159 char stderrPortStr[MSG_SIZ];
\r
10161 /* Initialize socket DLL */
\r
10162 wVersionRequested = MAKEWORD(1, 1);
\r
10163 err = WSAStartup(wVersionRequested, &wsaData);
\r
10164 if (err != 0) return err;
\r
10166 /* Resolve remote host name */
\r
10167 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10168 if (!(hp = gethostbyname(host))) {
\r
10169 unsigned int b0, b1, b2, b3;
\r
10171 err = WSAGetLastError();
\r
10173 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10174 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10175 hp->h_addrtype = AF_INET;
\r
10176 hp->h_length = 4;
\r
10177 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10178 hp->h_addr_list[0] = (char *) malloc(4);
\r
10179 hp->h_addr_list[0][0] = (char) b0;
\r
10180 hp->h_addr_list[0][1] = (char) b1;
\r
10181 hp->h_addr_list[0][2] = (char) b2;
\r
10182 hp->h_addr_list[0][3] = (char) b3;
\r
10188 sa.sin_family = hp->h_addrtype;
\r
10189 uport = (unsigned short) 514;
\r
10190 sa.sin_port = htons(uport);
\r
10191 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10193 /* Bind local socket to unused "privileged" port address
\r
10195 s = INVALID_SOCKET;
\r
10196 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10197 mysa.sin_family = AF_INET;
\r
10198 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10199 for (fromPort = 1023;; fromPort--) {
\r
10200 if (fromPort < 0) {
\r
10202 return WSAEADDRINUSE;
\r
10204 if (s == INVALID_SOCKET) {
\r
10205 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10206 err = WSAGetLastError();
\r
10211 uport = (unsigned short) fromPort;
\r
10212 mysa.sin_port = htons(uport);
\r
10213 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10214 == SOCKET_ERROR) {
\r
10215 err = WSAGetLastError();
\r
10216 if (err == WSAEADDRINUSE) continue;
\r
10220 if (connect(s, (struct sockaddr *) &sa,
\r
10221 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10222 err = WSAGetLastError();
\r
10223 if (err == WSAEADDRINUSE) {
\r
10234 /* Bind stderr local socket to unused "privileged" port address
\r
10236 s2 = INVALID_SOCKET;
\r
10237 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10238 mysa.sin_family = AF_INET;
\r
10239 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10240 for (fromPort = 1023;; fromPort--) {
\r
10241 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10242 if (fromPort < 0) {
\r
10243 (void) closesocket(s);
\r
10245 return WSAEADDRINUSE;
\r
10247 if (s2 == INVALID_SOCKET) {
\r
10248 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10249 err = WSAGetLastError();
\r
10255 uport = (unsigned short) fromPort;
\r
10256 mysa.sin_port = htons(uport);
\r
10257 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10258 == SOCKET_ERROR) {
\r
10259 err = WSAGetLastError();
\r
10260 if (err == WSAEADDRINUSE) continue;
\r
10261 (void) closesocket(s);
\r
10265 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10266 err = WSAGetLastError();
\r
10267 if (err == WSAEADDRINUSE) {
\r
10269 s2 = INVALID_SOCKET;
\r
10272 (void) closesocket(s);
\r
10273 (void) closesocket(s2);
\r
10279 prevStderrPort = fromPort; // remember port used
\r
10280 sprintf(stderrPortStr, "%d", fromPort);
\r
10282 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10283 err = WSAGetLastError();
\r
10284 (void) closesocket(s);
\r
10285 (void) closesocket(s2);
\r
10290 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10291 err = WSAGetLastError();
\r
10292 (void) closesocket(s);
\r
10293 (void) closesocket(s2);
\r
10297 if (*user == NULLCHAR) user = UserName();
\r
10298 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10299 err = WSAGetLastError();
\r
10300 (void) closesocket(s);
\r
10301 (void) closesocket(s2);
\r
10305 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10306 err = WSAGetLastError();
\r
10307 (void) closesocket(s);
\r
10308 (void) closesocket(s2);
\r
10313 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10314 err = WSAGetLastError();
\r
10315 (void) closesocket(s);
\r
10316 (void) closesocket(s2);
\r
10320 (void) closesocket(s2); /* Stop listening */
\r
10322 /* Prepare return value */
\r
10323 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10324 cp->kind = CPRcmd;
\r
10327 *pr = (ProcRef *) cp;
\r
10334 AddInputSource(ProcRef pr, int lineByLine,
\r
10335 InputCallback func, VOIDSTAR closure)
\r
10337 InputSource *is, *is2 = NULL;
\r
10338 ChildProc *cp = (ChildProc *) pr;
\r
10340 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10341 is->lineByLine = lineByLine;
\r
10343 is->closure = closure;
\r
10344 is->second = NULL;
\r
10345 is->next = is->buf;
\r
10346 if (pr == NoProc) {
\r
10347 is->kind = CPReal;
\r
10348 consoleInputSource = is;
\r
10350 is->kind = cp->kind;
\r
10352 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10353 we create all threads suspended so that the is->hThread variable can be
\r
10354 safely assigned, then let the threads start with ResumeThread.
\r
10356 switch (cp->kind) {
\r
10358 is->hFile = cp->hFrom;
\r
10359 cp->hFrom = NULL; /* now owned by InputThread */
\r
10361 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10362 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10366 is->hFile = cp->hFrom;
\r
10367 cp->hFrom = NULL; /* now owned by InputThread */
\r
10369 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10370 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10374 is->sock = cp->sock;
\r
10376 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10377 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10381 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10383 is->sock = cp->sock;
\r
10384 is->second = is2;
\r
10385 is2->sock = cp->sock2;
\r
10386 is2->second = is2;
\r
10388 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10389 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10391 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10392 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10396 if( is->hThread != NULL ) {
\r
10397 ResumeThread( is->hThread );
\r
10400 if( is2 != NULL && is2->hThread != NULL ) {
\r
10401 ResumeThread( is2->hThread );
\r
10405 return (InputSourceRef) is;
\r
10409 RemoveInputSource(InputSourceRef isr)
\r
10413 is = (InputSource *) isr;
\r
10414 is->hThread = NULL; /* tell thread to stop */
\r
10415 CloseHandle(is->hThread);
\r
10416 if (is->second != NULL) {
\r
10417 is->second->hThread = NULL;
\r
10418 CloseHandle(is->second->hThread);
\r
10424 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10427 int outCount = SOCKET_ERROR;
\r
10428 ChildProc *cp = (ChildProc *) pr;
\r
10429 static OVERLAPPED ovl;
\r
10431 if (pr == NoProc) {
\r
10432 ConsoleOutput(message, count, FALSE);
\r
10436 if (ovl.hEvent == NULL) {
\r
10437 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10439 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10441 switch (cp->kind) {
\r
10444 outCount = send(cp->sock, message, count, 0);
\r
10445 if (outCount == SOCKET_ERROR) {
\r
10446 *outError = WSAGetLastError();
\r
10448 *outError = NO_ERROR;
\r
10453 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10454 &dOutCount, NULL)) {
\r
10455 *outError = NO_ERROR;
\r
10456 outCount = (int) dOutCount;
\r
10458 *outError = GetLastError();
\r
10463 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10464 &dOutCount, &ovl);
\r
10465 if (*outError == NO_ERROR) {
\r
10466 outCount = (int) dOutCount;
\r
10474 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10477 /* Ignore delay, not implemented for WinBoard */
\r
10478 return OutputToProcess(pr, message, count, outError);
\r
10483 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10484 char *buf, int count, int error)
\r
10486 DisplayFatalError("Not implemented", 0, 1);
\r
10489 /* see wgamelist.c for Game List functions */
\r
10490 /* see wedittags.c for Edit Tags functions */
\r
10497 char buf[MSG_SIZ];
\r
10500 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10501 f = fopen(buf, "r");
\r
10503 ProcessICSInitScript(f);
\r
10511 StartAnalysisClock()
\r
10513 if (analysisTimerEvent) return;
\r
10514 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10515 (UINT) 2000, NULL);
\r
10519 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10521 static HANDLE hwndText;
\r
10523 static int sizeX, sizeY;
\r
10524 int newSizeX, newSizeY, flags;
\r
10527 switch (message) {
\r
10528 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10529 /* Initialize the dialog items */
\r
10530 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10531 SetWindowText(hDlg, analysisTitle);
\r
10532 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10533 /* Size and position the dialog */
\r
10534 if (!analysisDialog) {
\r
10535 analysisDialog = hDlg;
\r
10536 flags = SWP_NOZORDER;
\r
10537 GetClientRect(hDlg, &rect);
\r
10538 sizeX = rect.right;
\r
10539 sizeY = rect.bottom;
\r
10540 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10541 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10542 WINDOWPLACEMENT wp;
\r
10543 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10544 wp.length = sizeof(WINDOWPLACEMENT);
\r
10546 wp.showCmd = SW_SHOW;
\r
10547 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10548 wp.rcNormalPosition.left = analysisX;
\r
10549 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10550 wp.rcNormalPosition.top = analysisY;
\r
10551 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10552 SetWindowPlacement(hDlg, &wp);
\r
10554 GetClientRect(hDlg, &rect);
\r
10555 newSizeX = rect.right;
\r
10556 newSizeY = rect.bottom;
\r
10557 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10558 newSizeX, newSizeY);
\r
10559 sizeX = newSizeX;
\r
10560 sizeY = newSizeY;
\r
10565 case WM_COMMAND: /* message: received a command */
\r
10566 switch (LOWORD(wParam)) {
\r
10568 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10569 ExitAnalyzeMode();
\r
10581 newSizeX = LOWORD(lParam);
\r
10582 newSizeY = HIWORD(lParam);
\r
10583 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10584 sizeX = newSizeX;
\r
10585 sizeY = newSizeY;
\r
10588 case WM_GETMINMAXINFO:
\r
10589 /* Prevent resizing window too small */
\r
10590 mmi = (MINMAXINFO *) lParam;
\r
10591 mmi->ptMinTrackSize.x = 100;
\r
10592 mmi->ptMinTrackSize.y = 100;
\r
10599 AnalysisPopUp(char* title, char* str)
\r
10605 EngineOutputPopUp();
\r
10608 if (str == NULL) str = "";
\r
10609 p = (char *) malloc(2 * strlen(str) + 2);
\r
10612 if (*str == '\n') *q++ = '\r';
\r
10616 if (analysisText != NULL) free(analysisText);
\r
10617 analysisText = p;
\r
10619 if (analysisDialog) {
\r
10620 SetWindowText(analysisDialog, title);
\r
10621 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10622 ShowWindow(analysisDialog, SW_SHOW);
\r
10624 analysisTitle = title;
\r
10625 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10626 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10627 hwndMain, (DLGPROC)lpProc);
\r
10628 FreeProcInstance(lpProc);
\r
10630 analysisDialogUp = TRUE;
\r
10634 AnalysisPopDown()
\r
10636 if (analysisDialog) {
\r
10637 ShowWindow(analysisDialog, SW_HIDE);
\r
10639 analysisDialogUp = FALSE;
\r
10644 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10646 highlightInfo.sq[0].x = fromX;
\r
10647 highlightInfo.sq[0].y = fromY;
\r
10648 highlightInfo.sq[1].x = toX;
\r
10649 highlightInfo.sq[1].y = toY;
\r
10653 ClearHighlights()
\r
10655 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10656 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10660 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10662 premoveHighlightInfo.sq[0].x = fromX;
\r
10663 premoveHighlightInfo.sq[0].y = fromY;
\r
10664 premoveHighlightInfo.sq[1].x = toX;
\r
10665 premoveHighlightInfo.sq[1].y = toY;
\r
10669 ClearPremoveHighlights()
\r
10671 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10672 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10676 ShutDownFrontEnd()
\r
10678 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10679 DeleteClipboardTempFiles();
\r
10685 if (IsIconic(hwndMain))
\r
10686 ShowWindow(hwndMain, SW_RESTORE);
\r
10688 SetActiveWindow(hwndMain);
\r
10692 * Prototypes for animation support routines
\r
10694 static void ScreenSquare(int column, int row, POINT * pt);
\r
10695 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10696 POINT frames[], int * nFrames);
\r
10700 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10701 { // [HGM] atomic: animate blast wave
\r
10703 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10704 explodeInfo.fromX = fromX;
\r
10705 explodeInfo.fromY = fromY;
\r
10706 explodeInfo.toX = toX;
\r
10707 explodeInfo.toY = toY;
\r
10708 for(i=1; i<nFrames; i++) {
\r
10709 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10710 DrawPosition(FALSE, NULL);
\r
10711 Sleep(appData.animSpeed);
\r
10713 explodeInfo.radius = 0;
\r
10714 DrawPosition(TRUE, NULL);
\r
10717 #define kFactor 4
\r
10720 AnimateMove(board, fromX, fromY, toX, toY)
\r
10727 ChessSquare piece;
\r
10728 POINT start, finish, mid;
\r
10729 POINT frames[kFactor * 2 + 1];
\r
10732 if (!appData.animate) return;
\r
10733 if (doingSizing) return;
\r
10734 if (fromY < 0 || fromX < 0) return;
\r
10735 piece = board[fromY][fromX];
\r
10736 if (piece >= EmptySquare) return;
\r
10738 ScreenSquare(fromX, fromY, &start);
\r
10739 ScreenSquare(toX, toY, &finish);
\r
10741 /* All pieces except knights move in straight line */
\r
10742 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10743 mid.x = start.x + (finish.x - start.x) / 2;
\r
10744 mid.y = start.y + (finish.y - start.y) / 2;
\r
10746 /* Knight: make diagonal movement then straight */
\r
10747 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10748 mid.x = start.x + (finish.x - start.x) / 2;
\r
10749 mid.y = finish.y;
\r
10751 mid.x = finish.x;
\r
10752 mid.y = start.y + (finish.y - start.y) / 2;
\r
10756 /* Don't use as many frames for very short moves */
\r
10757 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10758 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10760 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10762 animInfo.from.x = fromX;
\r
10763 animInfo.from.y = fromY;
\r
10764 animInfo.to.x = toX;
\r
10765 animInfo.to.y = toY;
\r
10766 animInfo.lastpos = start;
\r
10767 animInfo.piece = piece;
\r
10768 for (n = 0; n < nFrames; n++) {
\r
10769 animInfo.pos = frames[n];
\r
10770 DrawPosition(FALSE, NULL);
\r
10771 animInfo.lastpos = animInfo.pos;
\r
10772 Sleep(appData.animSpeed);
\r
10774 animInfo.pos = finish;
\r
10775 DrawPosition(FALSE, NULL);
\r
10776 animInfo.piece = EmptySquare;
\r
10777 if(gameInfo.variant == VariantAtomic &&
\r
10778 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10779 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10782 /* Convert board position to corner of screen rect and color */
\r
10785 ScreenSquare(column, row, pt)
\r
10786 int column; int row; POINT * pt;
\r
10789 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10790 pt->y = lineGap + row * (squareSize + lineGap);
\r
10792 pt->x = lineGap + column * (squareSize + lineGap);
\r
10793 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10797 /* Generate a series of frame coords from start->mid->finish.
\r
10798 The movement rate doubles until the half way point is
\r
10799 reached, then halves back down to the final destination,
\r
10800 which gives a nice slow in/out effect. The algorithmn
\r
10801 may seem to generate too many intermediates for short
\r
10802 moves, but remember that the purpose is to attract the
\r
10803 viewers attention to the piece about to be moved and
\r
10804 then to where it ends up. Too few frames would be less
\r
10808 Tween(start, mid, finish, factor, frames, nFrames)
\r
10809 POINT * start; POINT * mid;
\r
10810 POINT * finish; int factor;
\r
10811 POINT frames[]; int * nFrames;
\r
10813 int n, fraction = 1, count = 0;
\r
10815 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10816 for (n = 0; n < factor; n++)
\r
10818 for (n = 0; n < factor; n++) {
\r
10819 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10820 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10822 fraction = fraction / 2;
\r
10826 frames[count] = *mid;
\r
10829 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10831 for (n = 0; n < factor; n++) {
\r
10832 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10833 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10835 fraction = fraction * 2;
\r
10837 *nFrames = count;
\r
10841 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10846 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10847 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10849 OutputDebugString( buf );
\r
10852 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10854 EvalGraphSet( first, last, current, pvInfoList );
\r
10857 void SetProgramStats( FrontEndProgramStats * stats )
\r
10862 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10863 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10865 OutputDebugString( buf );
\r
10868 EngineOutputUpdate( stats );
\r