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