2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
5 * Massachusetts. Enhancements Copyright
\r
6 * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software
\r
9 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
10 * which was written and is copyrighted by Wayne Christopher.
\r
12 * The following terms apply to Digital Equipment Corporation's copyright
\r
13 * interest in XBoard:
\r
14 * ------------------------------------------------------------------------
\r
15 * All Rights Reserved
\r
17 * Permission to use, copy, modify, and distribute this software and its
\r
18 * documentation for any purpose and without fee is hereby granted,
\r
19 * provided that the above copyright notice appear in all copies and that
\r
20 * both that copyright notice and this permission notice appear in
\r
21 * supporting documentation, and that the name of Digital not be
\r
22 * used in advertising or publicity pertaining to distribution of the
\r
23 * software without specific, written prior permission.
\r
25 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
26 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
27 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
28 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
29 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
30 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
32 * ------------------------------------------------------------------------
\r
34 * The following terms apply to the enhanced version of XBoard
\r
35 * distributed by the Free Software Foundation:
\r
36 * ------------------------------------------------------------------------
\r
38 * GNU XBoard is free software: you can redistribute it and/or modify
\r
39 * it under the terms of the GNU General Public License as published by
\r
40 * the Free Software Foundation, either version 3 of the License, or (at
\r
41 * your option) any later version.
\r
43 * GNU XBoard is distributed in the hope that it will be useful, but
\r
44 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
45 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
46 * General Public License for more details.
\r
48 * You should have received a copy of the GNU General Public License
\r
49 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
51 *------------------------------------------------------------------------
\r
52 ** See the file ChangeLog for a revision history. */
\r
56 #include <windows.h>
\r
57 #include <winuser.h>
\r
58 #include <winsock.h>
\r
59 #include <commctrl.h>
\r
65 #include <sys/stat.h>
\r
68 #include <commdlg.h>
\r
70 #include <richedit.h>
\r
71 #include <mmsystem.h>
\r
80 #include "winboard.h"
\r
81 #include "frontend.h"
\r
82 #include "backend.h"
\r
84 #include "wclipbrd.h"
\r
85 #include "wgamelist.h"
\r
86 #include "wedittags.h"
\r
87 #include "woptions.h"
\r
88 #include "wsockerr.h"
\r
89 #include "defaults.h"
\r
93 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
96 void mysrandom(unsigned int seed);
\r
98 extern int whiteFlag, blackFlag;
\r
99 Boolean flipClock = FALSE;
\r
101 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
102 VOID NewVariantPopup(HWND hwnd);
\r
103 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
104 /*char*/int promoChar));
\r
105 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
106 void DisplayMove P((int moveNumber));
\r
107 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\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[] = "I C S 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 static int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
487 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
492 #define JAWS_ALT_INTERCEPT
\r
493 #define JAWS_KB_NAVIGATION
\r
494 #define JAWS_MENU_ITEMS
\r
495 #define JAWS_SILENCE
\r
496 #define JAWS_REPLAY
\r
497 #define JAWS_DELETE(X) X
\r
498 #define SAYMACHINEMOVE()
\r
502 /*---------------------------------------------------------------------------*\
\r
506 \*---------------------------------------------------------------------------*/
\r
509 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
510 LPSTR lpCmdLine, int nCmdShow)
\r
513 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
514 // INITCOMMONCONTROLSEX ex;
\r
518 LoadLibrary("RICHED32.DLL");
\r
519 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
521 if (!InitApplication(hInstance)) {
\r
524 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
530 // InitCommonControlsEx(&ex);
\r
531 InitCommonControls();
\r
533 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
534 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
535 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
537 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
539 while (GetMessage(&msg, /* message structure */
\r
540 NULL, /* handle of window receiving the message */
\r
541 0, /* lowest message to examine */
\r
542 0)) /* highest message to examine */
\r
545 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
546 // [HGM] navigate: switch between all windows with tab
\r
547 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
548 int i, currentElement = 0;
\r
550 // first determine what element of the chain we come from (if any)
\r
551 if(appData.icsActive) {
\r
552 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
553 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
555 if(engineOutputDialog && EngineOutputIsUp()) {
\r
556 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
557 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
559 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
560 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
562 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
563 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
564 if(msg.hwnd == e1) currentElement = 2; else
\r
565 if(msg.hwnd == e2) currentElement = 3; else
\r
566 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
567 if(msg.hwnd == mh) currentElement = 4; else
\r
568 if(msg.hwnd == evalGraphDialog) currentElement = 7; else
\r
569 if(msg.hwnd == hText) currentElement = 5; else
\r
570 if(msg.hwnd == hInput) currentElement = 6; else
\r
571 for (i = 0; i < N_BUTTONS; i++) {
\r
572 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
575 // determine where to go to
\r
576 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
578 currentElement = (currentElement + direction) % 7;
\r
579 switch(currentElement) {
\r
581 h = hwndMain; break; // passing this case always makes the loop exit
\r
583 h = buttonDesc[0].hwnd; break; // could be NULL
\r
585 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
588 if(!EngineOutputIsUp()) continue;
\r
591 if(!MoveHistoryIsUp()) continue;
\r
593 // case 5: // input to eval graph does not seem to get here!
\r
594 // if(!EvalGraphIsUp()) continue;
\r
595 // h = evalGraphDialog; break;
\r
597 if(!appData.icsActive) continue;
\r
601 if(!appData.icsActive) continue;
\r
607 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
608 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
611 continue; // this message now has been processed
\r
615 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
616 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
617 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
618 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
619 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
620 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
621 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
622 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
623 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
624 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
625 TranslateMessage(&msg); /* Translates virtual key codes */
\r
626 DispatchMessage(&msg); /* Dispatches message to window */
\r
631 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
634 /*---------------------------------------------------------------------------*\
\r
636 * Initialization functions
\r
638 \*---------------------------------------------------------------------------*/
\r
642 { // update user logo if necessary
\r
643 static char oldUserName[MSG_SIZ], *curName;
\r
645 if(appData.autoLogo) {
\r
646 curName = UserName();
\r
647 if(strcmp(curName, oldUserName)) {
\r
648 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
649 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
650 strcpy(oldUserName, curName);
\r
656 InitApplication(HINSTANCE hInstance)
\r
660 /* Fill in window class structure with parameters that describe the */
\r
663 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
664 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
665 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
666 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
667 wc.hInstance = hInstance; /* Owner of this class */
\r
668 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
669 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
670 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
671 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
672 wc.lpszClassName = szAppName; /* Name to register as */
\r
674 /* Register the window class and return success/failure code. */
\r
675 if (!RegisterClass(&wc)) return FALSE;
\r
677 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
678 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
680 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
681 wc.hInstance = hInstance;
\r
682 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
683 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
684 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
685 wc.lpszMenuName = NULL;
\r
686 wc.lpszClassName = szConsoleName;
\r
688 if (!RegisterClass(&wc)) return FALSE;
\r
693 /* Set by InitInstance, used by EnsureOnScreen */
\r
694 int screenHeight, screenWidth;
\r
697 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
699 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
700 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
701 if (*x > screenWidth - 32) *x = 0;
\r
702 if (*y > screenHeight - 32) *y = 0;
\r
703 if (*x < minX) *x = minX;
\r
704 if (*y < minY) *y = minY;
\r
708 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
710 HWND hwnd; /* Main window handle. */
\r
712 WINDOWPLACEMENT wp;
\r
715 hInst = hInstance; /* Store instance handle in our global variable */
\r
717 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
718 *filepart = NULLCHAR;
\r
720 GetCurrentDirectory(MSG_SIZ, installDir);
\r
722 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
723 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
724 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
725 if (appData.debugMode) {
\r
726 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
727 setbuf(debugFP, NULL);
\r
732 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
733 // InitEngineUCI( installDir, &second );
\r
735 /* Create a main window for this application instance. */
\r
736 hwnd = CreateWindow(szAppName, szTitle,
\r
737 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
738 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
739 NULL, NULL, hInstance, NULL);
\r
742 /* If window could not be created, return "failure" */
\r
747 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
748 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
749 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
751 if (first.programLogo == NULL && appData.debugMode) {
\r
752 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
754 } else if(appData.autoLogo) {
\r
755 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
757 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
758 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
762 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
763 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
765 if (second.programLogo == NULL && appData.debugMode) {
\r
766 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
768 } else if(appData.autoLogo) {
\r
770 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
771 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
772 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
774 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
775 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
776 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
782 iconWhite = LoadIcon(hInstance, "icon_white");
\r
783 iconBlack = LoadIcon(hInstance, "icon_black");
\r
784 iconCurrent = iconWhite;
\r
785 InitDrawingColors();
\r
786 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
787 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
788 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
789 /* Compute window size for each board size, and use the largest
\r
790 size that fits on this screen as the default. */
\r
791 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
792 if (boardSize == (BoardSize)-1 &&
\r
793 winH <= screenHeight
\r
794 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
795 && winW <= screenWidth) {
\r
796 boardSize = (BoardSize)ibs;
\r
800 InitDrawingSizes(boardSize, 0);
\r
802 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
804 /* [AS] Load textures if specified */
\r
805 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
807 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
808 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
809 liteBackTextureMode = appData.liteBackTextureMode;
\r
811 if (liteBackTexture == NULL && appData.debugMode) {
\r
812 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
816 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
817 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
818 darkBackTextureMode = appData.darkBackTextureMode;
\r
820 if (darkBackTexture == NULL && appData.debugMode) {
\r
821 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
825 mysrandom( (unsigned) time(NULL) );
\r
827 /* [AS] Restore layout */
\r
828 if( wpMoveHistory.visible ) {
\r
829 MoveHistoryPopUp();
\r
832 if( wpEvalGraph.visible ) {
\r
836 if( wpEngineOutput.visible ) {
\r
837 EngineOutputPopUp();
\r
842 /* Make the window visible; update its client area; and return "success" */
\r
843 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
844 wp.length = sizeof(WINDOWPLACEMENT);
\r
846 wp.showCmd = nCmdShow;
\r
847 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
848 wp.rcNormalPosition.left = boardX;
\r
849 wp.rcNormalPosition.right = boardX + winWidth;
\r
850 wp.rcNormalPosition.top = boardY;
\r
851 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
852 SetWindowPlacement(hwndMain, &wp);
\r
854 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
855 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
859 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
860 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
862 ShowWindow(hwndConsole, nCmdShow);
\r
864 UpdateWindow(hwnd);
\r
872 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
873 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
874 ArgSettingsFilename,
\r
875 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
883 String *pString; // ArgString
\r
884 int *pInt; // ArgInt
\r
885 float *pFloat; // ArgFloat
\r
886 Boolean *pBoolean; // ArgBoolean
\r
887 COLORREF *pColor; // ArgColor
\r
888 ColorClass cc; // ArgAttribs
\r
889 String *pFilename; // ArgFilename
\r
890 BoardSize *pBoardSize; // ArgBoardSize
\r
891 int whichFont; // ArgFont
\r
892 DCB *pDCB; // ArgCommSettings
\r
893 String *pFilename; // ArgSettingsFilename
\r
901 ArgDescriptor argDescriptors[] = {
\r
902 /* positional arguments */
\r
903 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
904 { "", ArgNone, NULL },
\r
905 /* keyword arguments */
\r
906 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
907 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
908 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
909 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
910 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
911 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
912 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
913 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
914 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
915 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
916 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
917 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
918 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
919 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
920 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
921 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
922 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
923 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
925 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
927 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
929 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
930 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
932 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
933 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
934 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
935 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
936 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
937 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
938 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
939 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
940 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
941 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
942 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
943 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
944 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
945 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
946 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
947 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
948 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
949 /*!!bitmapDirectory?*/
\r
950 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
951 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
952 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
953 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
954 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
955 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
956 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
957 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
958 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
959 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
960 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
961 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
962 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
963 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
964 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
965 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
966 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
967 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
968 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
969 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
970 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
971 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
972 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
973 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
974 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
975 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
976 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
977 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
978 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
979 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
980 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
981 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
982 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
983 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
984 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
985 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
986 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
987 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
988 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
989 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
990 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
991 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
992 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
993 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
994 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
995 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
996 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
997 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
998 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
999 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1000 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1001 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1002 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1003 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1004 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1005 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1006 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1007 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1008 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1009 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1010 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1011 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1012 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1013 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1014 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1015 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1016 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1017 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1018 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1019 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1020 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1021 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1022 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1023 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1024 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1025 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1026 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1027 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1028 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1029 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1030 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1031 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1032 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1033 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1034 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1035 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1036 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1037 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1038 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1039 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1040 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1041 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1042 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1043 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1044 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1045 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1046 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1047 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1048 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1049 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1050 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1051 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1052 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1053 TRUE }, /* must come after all fonts */
\r
1054 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1055 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1056 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1057 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1058 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1059 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1060 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1061 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1062 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1063 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1064 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1065 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1066 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1067 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1068 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1069 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1070 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1071 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1072 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1073 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1074 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1075 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1076 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1077 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1078 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1079 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1080 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1081 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1082 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1083 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1084 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1086 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1087 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1089 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1090 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1091 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1092 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1093 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1094 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1095 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1096 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1097 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1098 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1099 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1100 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1101 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1102 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1103 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1104 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1105 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1106 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1107 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1108 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1109 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1110 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1111 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1112 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1113 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1114 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1115 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1116 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1117 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1118 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1119 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1120 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1121 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1122 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1123 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1124 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1125 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1126 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1127 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1128 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1129 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1130 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1131 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1132 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1133 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1134 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1135 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1136 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1137 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1138 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1139 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1140 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1141 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1142 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1143 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1144 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1145 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1146 { "highlightLastMove", ArgBoolean,
\r
1147 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1148 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1149 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1150 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1151 { "highlightDragging", ArgBoolean,
\r
1152 (LPVOID) &appData.highlightDragging, TRUE },
\r
1153 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1154 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1155 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1156 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1157 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1158 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1159 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1160 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1161 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1162 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1163 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1164 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1165 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1166 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1167 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1168 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1169 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1170 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1171 { "soundShout", ArgFilename,
\r
1172 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1173 { "soundSShout", ArgFilename,
\r
1174 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1175 { "soundChannel1", ArgFilename,
\r
1176 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1177 { "soundChannel", ArgFilename,
\r
1178 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1179 { "soundKibitz", ArgFilename,
\r
1180 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1181 { "soundTell", ArgFilename,
\r
1182 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1183 { "soundChallenge", ArgFilename,
\r
1184 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1185 { "soundRequest", ArgFilename,
\r
1186 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1187 { "soundSeek", ArgFilename,
\r
1188 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1189 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1190 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1191 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1192 { "soundIcsLoss", ArgFilename,
\r
1193 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1194 { "soundIcsDraw", ArgFilename,
\r
1195 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1196 { "soundIcsUnfinished", ArgFilename,
\r
1197 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1198 { "soundIcsAlarm", ArgFilename,
\r
1199 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1200 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1201 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1202 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1203 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1204 { "reuseChessPrograms", ArgBoolean,
\r
1205 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1206 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1207 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1208 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1209 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1210 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1211 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1212 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1213 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1214 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1215 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1216 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1217 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1218 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1219 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1220 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1222 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1224 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1225 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1226 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1227 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1228 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1229 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1230 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1231 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1232 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1233 /* [AS] New features */
\r
1234 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1235 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1236 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1237 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1238 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1239 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1240 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1241 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1242 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1243 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1244 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1245 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1246 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1247 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1248 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1249 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1250 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1251 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1252 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1253 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1254 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1255 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1256 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1257 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1258 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1259 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1260 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1261 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1262 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1263 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1264 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1265 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1266 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1267 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1268 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1269 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1270 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1271 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1272 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1273 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1274 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1275 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1276 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1277 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1278 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1279 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1280 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1281 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1282 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1283 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1285 /* [HGM] board-size, adjudication and misc. options */
\r
1286 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1287 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1288 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1289 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1290 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1291 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1292 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1293 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1294 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1295 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1296 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1297 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1298 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1299 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1300 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1301 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1302 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1303 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1304 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1305 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1306 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1307 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1308 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1309 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1310 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1311 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1312 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1313 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1314 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1315 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1316 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1319 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1320 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1321 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1322 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1323 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1324 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1325 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1326 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1327 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1328 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1329 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1330 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1331 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1333 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1334 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1335 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1336 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1337 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1338 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1339 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1341 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1342 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1343 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1344 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1345 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1346 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1347 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1348 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1349 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1350 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1351 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1352 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1353 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1354 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1355 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1356 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1357 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1358 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1359 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1361 /* [HGM] options for broadcasting and time odds */
\r
1362 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1363 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1364 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1365 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1366 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1367 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1368 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1369 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1370 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1371 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1372 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1374 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1375 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1376 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1377 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1378 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1379 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1380 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1381 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1382 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1383 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1384 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1385 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1386 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1387 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1388 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1389 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1390 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1391 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1392 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1393 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1394 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1395 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1396 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1397 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1398 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1399 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1400 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1401 /* [AS] Layout stuff */
\r
1402 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1403 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1404 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1405 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1406 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1408 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1409 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1410 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1411 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1412 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1414 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1415 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1416 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1417 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1418 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1420 { NULL, ArgNone, NULL, FALSE }
\r
1424 /* Kludge for indirection files on command line */
\r
1425 char* lastIndirectionFilename;
\r
1426 ArgDescriptor argDescriptorIndirection =
\r
1427 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1431 ExitArgError(char *msg, char *badArg)
\r
1433 char buf[MSG_SIZ];
\r
1435 sprintf(buf, "%s %s", msg, badArg);
\r
1436 DisplayFatalError(buf, 0, 2);
\r
1440 /* Command line font name parser. NULL name means do nothing.
\r
1441 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1442 For backward compatibility, syntax without the colon is also
\r
1443 accepted, but font names with digits in them won't work in that case.
\r
1446 ParseFontName(char *name, MyFontParams *mfp)
\r
1449 if (name == NULL) return;
\r
1451 q = strchr(p, ':');
\r
1453 if (q - p >= sizeof(mfp->faceName))
\r
1454 ExitArgError("Font name too long:", name);
\r
1455 memcpy(mfp->faceName, p, q - p);
\r
1456 mfp->faceName[q - p] = NULLCHAR;
\r
1459 q = mfp->faceName;
\r
1460 while (*p && !isdigit(*p)) {
\r
1462 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1463 ExitArgError("Font name too long:", name);
\r
1465 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1468 if (!*p) ExitArgError("Font point size missing:", name);
\r
1469 mfp->pointSize = (float) atof(p);
\r
1470 mfp->bold = (strchr(p, 'b') != NULL);
\r
1471 mfp->italic = (strchr(p, 'i') != NULL);
\r
1472 mfp->underline = (strchr(p, 'u') != NULL);
\r
1473 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1476 /* Color name parser.
\r
1477 X version accepts X color names, but this one
\r
1478 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1480 ParseColorName(char *name)
\r
1482 int red, green, blue, count;
\r
1483 char buf[MSG_SIZ];
\r
1485 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1487 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1488 &red, &green, &blue);
\r
1491 sprintf(buf, "Can't parse color name %s", name);
\r
1492 DisplayError(buf, 0);
\r
1493 return RGB(0, 0, 0);
\r
1495 return PALETTERGB(red, green, blue);
\r
1499 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1501 char *e = argValue;
\r
1505 if (*e == 'b') eff |= CFE_BOLD;
\r
1506 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1507 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1508 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1509 else if (*e == '#' || isdigit(*e)) break;
\r
1513 *color = ParseColorName(e);
\r
1518 ParseBoardSize(char *name)
\r
1520 BoardSize bs = SizeTiny;
\r
1521 while (sizeInfo[bs].name != NULL) {
\r
1522 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1525 ExitArgError("Unrecognized board size value", name);
\r
1526 return bs; /* not reached */
\r
1531 StringGet(void *getClosure)
\r
1533 char **p = (char **) getClosure;
\r
1538 FileGet(void *getClosure)
\r
1541 FILE* f = (FILE*) getClosure;
\r
1544 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1551 /* Parse settings file named "name". If file found, return the
\r
1552 full name in fullname and return TRUE; else return FALSE */
\r
1554 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1558 int ok; char buf[MSG_SIZ];
\r
1560 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1561 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1562 sprintf(buf, "%s.ini", name);
\r
1563 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1566 f = fopen(fullname, "r");
\r
1568 ParseArgs(FileGet, f);
\r
1577 ParseArgs(GetFunc get, void *cl)
\r
1579 char argName[ARG_MAX];
\r
1580 char argValue[ARG_MAX];
\r
1581 ArgDescriptor *ad;
\r
1590 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1591 if (ch == NULLCHAR) break;
\r
1593 /* Comment to end of line */
\r
1595 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1597 } else if (ch == '/' || ch == '-') {
\r
1600 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1601 ch != '\n' && ch != '\t') {
\r
1607 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1608 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1610 if (ad->argName == NULL)
\r
1611 ExitArgError("Unrecognized argument", argName);
\r
1613 } else if (ch == '@') {
\r
1614 /* Indirection file */
\r
1615 ad = &argDescriptorIndirection;
\r
1618 /* Positional argument */
\r
1619 ad = &argDescriptors[posarg++];
\r
1620 strcpy(argName, ad->argName);
\r
1623 if (ad->argType == ArgTrue) {
\r
1624 *(Boolean *) ad->argLoc = TRUE;
\r
1627 if (ad->argType == ArgFalse) {
\r
1628 *(Boolean *) ad->argLoc = FALSE;
\r
1632 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1633 if (ch == NULLCHAR || ch == '\n') {
\r
1634 ExitArgError("No value provided for argument", argName);
\r
1638 // Quoting with { }. No characters have to (or can) be escaped.
\r
1639 // Thus the string cannot contain a '}' character.
\r
1659 } else if (ch == '\'' || ch == '"') {
\r
1660 // Quoting with ' ' or " ", with \ as escape character.
\r
1661 // Inconvenient for long strings that may contain Windows filenames.
\r
1678 if (ch == start) {
\r
1687 if (ad->argType == ArgFilename
\r
1688 || ad->argType == ArgSettingsFilename) {
\r
1694 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1718 for (i = 0; i < 3; i++) {
\r
1719 if (ch >= '0' && ch <= '7') {
\r
1720 octval = octval*8 + (ch - '0');
\r
1727 *q++ = (char) octval;
\r
1738 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1745 switch (ad->argType) {
\r
1747 *(int *) ad->argLoc = atoi(argValue);
\r
1751 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1755 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1759 *(int *) ad->argLoc = atoi(argValue);
\r
1760 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1764 *(float *) ad->argLoc = (float) atof(argValue);
\r
1769 *(char **) ad->argLoc = strdup(argValue);
\r
1772 case ArgSettingsFilename:
\r
1774 char fullname[MSG_SIZ];
\r
1775 if (ParseSettingsFile(argValue, fullname)) {
\r
1776 if (ad->argLoc != NULL) {
\r
1777 *(char **) ad->argLoc = strdup(fullname);
\r
1780 if (ad->argLoc != NULL) {
\r
1782 ExitArgError("Failed to open indirection file", argValue);
\r
1789 switch (argValue[0]) {
\r
1792 *(Boolean *) ad->argLoc = TRUE;
\r
1796 *(Boolean *) ad->argLoc = FALSE;
\r
1799 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1805 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1808 case ArgAttribs: {
\r
1809 ColorClass cc = (ColorClass)ad->argLoc;
\r
1810 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1814 case ArgBoardSize:
\r
1815 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1819 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1822 case ArgCommSettings:
\r
1823 ParseCommSettings(argValue, &dcb);
\r
1827 ExitArgError("Unrecognized argument", argValue);
\r
1836 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1838 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1839 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1842 lf->lfEscapement = 0;
\r
1843 lf->lfOrientation = 0;
\r
1844 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1845 lf->lfItalic = mfp->italic;
\r
1846 lf->lfUnderline = mfp->underline;
\r
1847 lf->lfStrikeOut = mfp->strikeout;
\r
1848 lf->lfCharSet = DEFAULT_CHARSET;
\r
1849 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1850 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1851 lf->lfQuality = DEFAULT_QUALITY;
\r
1852 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1853 strcpy(lf->lfFaceName, mfp->faceName);
\r
1857 CreateFontInMF(MyFont *mf)
\r
1859 LFfromMFP(&mf->lf, &mf->mfp);
\r
1860 if (mf->hf) DeleteObject(mf->hf);
\r
1861 mf->hf = CreateFontIndirect(&mf->lf);
\r
1865 SetDefaultTextAttribs()
\r
1868 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1869 ParseAttribs(&textAttribs[cc].color,
\r
1870 &textAttribs[cc].effects,
\r
1871 defaultTextAttribs[cc]);
\r
1876 SetDefaultSounds()
\r
1880 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1881 textAttribs[cc].sound.name = strdup("");
\r
1882 textAttribs[cc].sound.data = NULL;
\r
1884 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1885 sounds[sc].name = strdup("");
\r
1886 sounds[sc].data = NULL;
\r
1888 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1896 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1897 MyLoadSound(&textAttribs[cc].sound);
\r
1899 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1900 MyLoadSound(&sounds[sc]);
\r
1905 InitAppData(LPSTR lpCmdLine)
\r
1908 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1911 programName = szAppName;
\r
1913 /* Initialize to defaults */
\r
1914 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1915 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1916 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1917 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1918 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1919 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1920 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1921 SetDefaultTextAttribs();
\r
1922 SetDefaultSounds();
\r
1923 appData.movesPerSession = MOVES_PER_SESSION;
\r
1924 appData.initString = INIT_STRING;
\r
1925 appData.secondInitString = INIT_STRING;
\r
1926 appData.firstComputerString = COMPUTER_STRING;
\r
1927 appData.secondComputerString = COMPUTER_STRING;
\r
1928 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1929 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1930 appData.firstPlaysBlack = FALSE;
\r
1931 appData.noChessProgram = FALSE;
\r
1932 chessProgram = FALSE;
\r
1933 appData.firstHost = FIRST_HOST;
\r
1934 appData.secondHost = SECOND_HOST;
\r
1935 appData.firstDirectory = FIRST_DIRECTORY;
\r
1936 appData.secondDirectory = SECOND_DIRECTORY;
\r
1937 appData.bitmapDirectory = "";
\r
1938 appData.remoteShell = REMOTE_SHELL;
\r
1939 appData.remoteUser = "";
\r
1940 appData.timeDelay = TIME_DELAY;
\r
1941 appData.timeControl = TIME_CONTROL;
\r
1942 appData.timeIncrement = TIME_INCREMENT;
\r
1943 appData.icsActive = FALSE;
\r
1944 appData.icsHost = "";
\r
1945 appData.icsPort = ICS_PORT;
\r
1946 appData.icsCommPort = ICS_COMM_PORT;
\r
1947 appData.icsLogon = ICS_LOGON;
\r
1948 appData.icsHelper = "";
\r
1949 appData.useTelnet = FALSE;
\r
1950 appData.telnetProgram = TELNET_PROGRAM;
\r
1951 appData.gateway = "";
\r
1952 appData.loadGameFile = "";
\r
1953 appData.loadGameIndex = 0;
\r
1954 appData.saveGameFile = "";
\r
1955 appData.autoSaveGames = FALSE;
\r
1956 appData.loadPositionFile = "";
\r
1957 appData.loadPositionIndex = 1;
\r
1958 appData.savePositionFile = "";
\r
1959 appData.matchMode = FALSE;
\r
1960 appData.matchGames = 0;
\r
1961 appData.monoMode = FALSE;
\r
1962 appData.debugMode = FALSE;
\r
1963 appData.clockMode = TRUE;
\r
1964 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1965 appData.Iconic = FALSE; /*unused*/
\r
1966 appData.searchTime = "";
\r
1967 appData.searchDepth = 0;
\r
1968 appData.showCoords = FALSE;
\r
1969 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1970 appData.autoCallFlag = FALSE;
\r
1971 appData.flipView = FALSE;
\r
1972 appData.autoFlipView = TRUE;
\r
1973 appData.cmailGameName = "";
\r
1974 appData.alwaysPromoteToQueen = FALSE;
\r
1975 appData.oldSaveStyle = FALSE;
\r
1976 appData.quietPlay = FALSE;
\r
1977 appData.showThinking = FALSE;
\r
1978 appData.ponderNextMove = TRUE;
\r
1979 appData.periodicUpdates = TRUE;
\r
1980 appData.popupExitMessage = TRUE;
\r
1981 appData.popupMoveErrors = FALSE;
\r
1982 appData.autoObserve = FALSE;
\r
1983 appData.autoComment = FALSE;
\r
1984 appData.animate = TRUE;
\r
1985 appData.animSpeed = 10;
\r
1986 appData.animateDragging = TRUE;
\r
1987 appData.highlightLastMove = TRUE;
\r
1988 appData.getMoveList = TRUE;
\r
1989 appData.testLegality = TRUE;
\r
1990 appData.premove = TRUE;
\r
1991 appData.premoveWhite = FALSE;
\r
1992 appData.premoveWhiteText = "";
\r
1993 appData.premoveBlack = FALSE;
\r
1994 appData.premoveBlackText = "";
\r
1995 appData.icsAlarm = TRUE;
\r
1996 appData.icsAlarmTime = 5000;
\r
1997 appData.autoRaiseBoard = TRUE;
\r
1998 appData.localLineEditing = TRUE;
\r
1999 appData.colorize = TRUE;
\r
2000 appData.reuseFirst = TRUE;
\r
2001 appData.reuseSecond = TRUE;
\r
2002 appData.blindfold = FALSE;
\r
2003 appData.icsEngineAnalyze = FALSE;
\r
2004 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2005 dcb.DCBlength = sizeof(DCB);
\r
2006 dcb.BaudRate = 9600;
\r
2007 dcb.fBinary = TRUE;
\r
2008 dcb.fParity = FALSE;
\r
2009 dcb.fOutxCtsFlow = FALSE;
\r
2010 dcb.fOutxDsrFlow = FALSE;
\r
2011 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2012 dcb.fDsrSensitivity = FALSE;
\r
2013 dcb.fTXContinueOnXoff = TRUE;
\r
2014 dcb.fOutX = FALSE;
\r
2016 dcb.fNull = FALSE;
\r
2017 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2018 dcb.fAbortOnError = FALSE;
\r
2020 dcb.Parity = SPACEPARITY;
\r
2021 dcb.StopBits = ONESTOPBIT;
\r
2022 settingsFileName = SETTINGS_FILE;
\r
2023 saveSettingsOnExit = TRUE;
\r
2024 boardX = CW_USEDEFAULT;
\r
2025 boardY = CW_USEDEFAULT;
\r
2026 analysisX = CW_USEDEFAULT;
\r
2027 analysisY = CW_USEDEFAULT;
\r
2028 analysisW = CW_USEDEFAULT;
\r
2029 analysisH = CW_USEDEFAULT;
\r
2030 commentX = CW_USEDEFAULT;
\r
2031 commentY = CW_USEDEFAULT;
\r
2032 commentW = CW_USEDEFAULT;
\r
2033 commentH = CW_USEDEFAULT;
\r
2034 editTagsX = CW_USEDEFAULT;
\r
2035 editTagsY = CW_USEDEFAULT;
\r
2036 editTagsW = CW_USEDEFAULT;
\r
2037 editTagsH = CW_USEDEFAULT;
\r
2038 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2039 icsNames = ICS_NAMES;
\r
2040 firstChessProgramNames = FCP_NAMES;
\r
2041 secondChessProgramNames = SCP_NAMES;
\r
2042 appData.initialMode = "";
\r
2043 appData.variant = "normal";
\r
2044 appData.firstProtocolVersion = PROTOVER;
\r
2045 appData.secondProtocolVersion = PROTOVER;
\r
2046 appData.showButtonBar = TRUE;
\r
2048 /* [AS] New properties (see comments in header file) */
\r
2049 appData.firstScoreIsAbsolute = FALSE;
\r
2050 appData.secondScoreIsAbsolute = FALSE;
\r
2051 appData.saveExtendedInfoInPGN = FALSE;
\r
2052 appData.hideThinkingFromHuman = FALSE;
\r
2053 appData.liteBackTextureFile = "";
\r
2054 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2055 appData.darkBackTextureFile = "";
\r
2056 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2057 appData.renderPiecesWithFont = "";
\r
2058 appData.fontToPieceTable = "";
\r
2059 appData.fontBackColorWhite = 0;
\r
2060 appData.fontForeColorWhite = 0;
\r
2061 appData.fontBackColorBlack = 0;
\r
2062 appData.fontForeColorBlack = 0;
\r
2063 appData.fontPieceSize = 80;
\r
2064 appData.overrideLineGap = 1;
\r
2065 appData.adjudicateLossThreshold = 0;
\r
2066 appData.delayBeforeQuit = 0;
\r
2067 appData.delayAfterQuit = 0;
\r
2068 appData.nameOfDebugFile = "winboard.debug";
\r
2069 appData.pgnEventHeader = "Computer Chess Game";
\r
2070 appData.defaultFrcPosition = -1;
\r
2071 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2072 appData.saveOutOfBookInfo = TRUE;
\r
2073 appData.showEvalInMoveHistory = TRUE;
\r
2074 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2075 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2076 appData.highlightMoveWithArrow = FALSE;
\r
2077 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2078 appData.useStickyWindows = TRUE;
\r
2079 appData.adjudicateDrawMoves = 0;
\r
2080 appData.autoDisplayComment = TRUE;
\r
2081 appData.autoDisplayTags = TRUE;
\r
2082 appData.firstIsUCI = FALSE;
\r
2083 appData.secondIsUCI = FALSE;
\r
2084 appData.firstHasOwnBookUCI = TRUE;
\r
2085 appData.secondHasOwnBookUCI = TRUE;
\r
2086 appData.polyglotDir = "";
\r
2087 appData.usePolyglotBook = FALSE;
\r
2088 appData.polyglotBook = "";
\r
2089 appData.defaultHashSize = 64;
\r
2090 appData.defaultCacheSizeEGTB = 4;
\r
2091 appData.defaultPathEGTB = "c:\\egtb";
\r
2092 appData.firstOptions = "";
\r
2093 appData.secondOptions = "";
\r
2095 InitWindowPlacement( &wpGameList );
\r
2096 InitWindowPlacement( &wpMoveHistory );
\r
2097 InitWindowPlacement( &wpEvalGraph );
\r
2098 InitWindowPlacement( &wpEngineOutput );
\r
2099 InitWindowPlacement( &wpConsole );
\r
2101 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2102 appData.NrFiles = -1;
\r
2103 appData.NrRanks = -1;
\r
2104 appData.holdingsSize = -1;
\r
2105 appData.testClaims = FALSE;
\r
2106 appData.checkMates = FALSE;
\r
2107 appData.materialDraws= FALSE;
\r
2108 appData.trivialDraws = FALSE;
\r
2109 appData.ruleMoves = 51;
\r
2110 appData.drawRepeats = 6;
\r
2111 appData.matchPause = 10000;
\r
2112 appData.alphaRank = FALSE;
\r
2113 appData.allWhite = FALSE;
\r
2114 appData.upsideDown = FALSE;
\r
2115 appData.serverPause = 15;
\r
2116 appData.serverMovesName = NULL;
\r
2117 appData.suppressLoadMoves = FALSE;
\r
2118 appData.firstTimeOdds = 1;
\r
2119 appData.secondTimeOdds = 1;
\r
2120 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2121 appData.secondAccumulateTC = 1;
\r
2122 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2123 appData.secondNPS = -1;
\r
2124 appData.engineComments = 1;
\r
2125 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2126 appData.egtFormats = "";
\r
2129 appData.zippyTalk = ZIPPY_TALK;
\r
2130 appData.zippyPlay = ZIPPY_PLAY;
\r
2131 appData.zippyLines = ZIPPY_LINES;
\r
2132 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2133 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2134 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2135 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2136 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2137 appData.zippyUseI = ZIPPY_USE_I;
\r
2138 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2139 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2140 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2141 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2142 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2143 appData.zippyAbort = ZIPPY_ABORT;
\r
2144 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2145 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2146 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2149 /* Point font array elements to structures and
\r
2150 parse default font names */
\r
2151 for (i=0; i<NUM_FONTS; i++) {
\r
2152 for (j=0; j<NUM_SIZES; j++) {
\r
2153 font[j][i] = &fontRec[j][i];
\r
2154 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2158 /* Parse default settings file if any */
\r
2159 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2160 settingsFileName = strdup(buf);
\r
2163 /* Parse command line */
\r
2164 ParseArgs(StringGet, &lpCmdLine);
\r
2166 /* [HGM] make sure board size is acceptable */
\r
2167 if(appData.NrFiles > BOARD_SIZE ||
\r
2168 appData.NrRanks > BOARD_SIZE )
\r
2169 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2171 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2172 * with options from the command line, we now make an even higher priority
\r
2173 * overrule by WB options attached to the engine command line. This so that
\r
2174 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2177 if(appData.firstChessProgram != NULL) {
\r
2178 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2179 static char *f = "first";
\r
2180 char buf[MSG_SIZ], *q = buf;
\r
2181 if(p != NULL) { // engine command line contains WinBoard options
\r
2182 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2183 ParseArgs(StringGet, &q);
\r
2184 p[-1] = 0; // cut them offengine command line
\r
2187 // now do same for second chess program
\r
2188 if(appData.secondChessProgram != NULL) {
\r
2189 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2190 static char *s = "second";
\r
2191 char buf[MSG_SIZ], *q = buf;
\r
2192 if(p != NULL) { // engine command line contains WinBoard options
\r
2193 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2194 ParseArgs(StringGet, &q);
\r
2195 p[-1] = 0; // cut them offengine command line
\r
2200 /* Propagate options that affect others */
\r
2201 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2202 if (appData.icsActive || appData.noChessProgram) {
\r
2203 chessProgram = FALSE; /* not local chess program mode */
\r
2206 /* Open startup dialog if needed */
\r
2207 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2208 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2209 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2210 *appData.secondChessProgram == NULLCHAR))) {
\r
2213 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2214 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2215 FreeProcInstance(lpProc);
\r
2218 /* Make sure save files land in the right (?) directory */
\r
2219 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2220 appData.saveGameFile = strdup(buf);
\r
2222 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2223 appData.savePositionFile = strdup(buf);
\r
2226 /* Finish initialization for fonts and sounds */
\r
2227 for (i=0; i<NUM_FONTS; i++) {
\r
2228 for (j=0; j<NUM_SIZES; j++) {
\r
2229 CreateFontInMF(font[j][i]);
\r
2232 /* xboard, and older WinBoards, controlled the move sound with the
\r
2233 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2234 always turn the option on (so that the backend will call us),
\r
2235 then let the user turn the sound off by setting it to silence if
\r
2236 desired. To accommodate old winboard.ini files saved by old
\r
2237 versions of WinBoard, we also turn off the sound if the option
\r
2238 was initially set to false. */
\r
2239 if (!appData.ringBellAfterMoves) {
\r
2240 sounds[(int)SoundMove].name = strdup("");
\r
2241 appData.ringBellAfterMoves = TRUE;
\r
2243 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2244 SetCurrentDirectory(installDir);
\r
2246 SetCurrentDirectory(currDir);
\r
2248 p = icsTextMenuString;
\r
2249 if (p[0] == '@') {
\r
2250 FILE* f = fopen(p + 1, "r");
\r
2252 DisplayFatalError(p + 1, errno, 2);
\r
2255 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2257 buf[i] = NULLCHAR;
\r
2260 ParseIcsTextMenu(strdup(p));
\r
2267 HMENU hmenu = GetMenu(hwndMain);
\r
2269 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2270 MF_BYCOMMAND|((appData.icsActive &&
\r
2271 *appData.icsCommPort != NULLCHAR) ?
\r
2272 MF_ENABLED : MF_GRAYED));
\r
2273 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2274 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2275 MF_CHECKED : MF_UNCHECKED));
\r
2280 SaveSettings(char* name)
\r
2283 ArgDescriptor *ad;
\r
2284 WINDOWPLACEMENT wp;
\r
2285 char dir[MSG_SIZ];
\r
2287 if (!hwndMain) return;
\r
2289 GetCurrentDirectory(MSG_SIZ, dir);
\r
2290 SetCurrentDirectory(installDir);
\r
2291 f = fopen(name, "w");
\r
2292 SetCurrentDirectory(dir);
\r
2294 DisplayError(name, errno);
\r
2297 fprintf(f, ";\n");
\r
2298 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2299 fprintf(f, ";\n");
\r
2300 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2301 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2302 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2303 fprintf(f, ";\n");
\r
2305 wp.length = sizeof(WINDOWPLACEMENT);
\r
2306 GetWindowPlacement(hwndMain, &wp);
\r
2307 boardX = wp.rcNormalPosition.left;
\r
2308 boardY = wp.rcNormalPosition.top;
\r
2310 if (hwndConsole) {
\r
2311 GetWindowPlacement(hwndConsole, &wp);
\r
2312 wpConsole.x = wp.rcNormalPosition.left;
\r
2313 wpConsole.y = wp.rcNormalPosition.top;
\r
2314 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2315 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2318 if (analysisDialog) {
\r
2319 GetWindowPlacement(analysisDialog, &wp);
\r
2320 analysisX = wp.rcNormalPosition.left;
\r
2321 analysisY = wp.rcNormalPosition.top;
\r
2322 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2323 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2326 if (commentDialog) {
\r
2327 GetWindowPlacement(commentDialog, &wp);
\r
2328 commentX = wp.rcNormalPosition.left;
\r
2329 commentY = wp.rcNormalPosition.top;
\r
2330 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2331 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2334 if (editTagsDialog) {
\r
2335 GetWindowPlacement(editTagsDialog, &wp);
\r
2336 editTagsX = wp.rcNormalPosition.left;
\r
2337 editTagsY = wp.rcNormalPosition.top;
\r
2338 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2339 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2342 if (gameListDialog) {
\r
2343 GetWindowPlacement(gameListDialog, &wp);
\r
2344 wpGameList.x = wp.rcNormalPosition.left;
\r
2345 wpGameList.y = wp.rcNormalPosition.top;
\r
2346 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2347 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2350 /* [AS] Move history */
\r
2351 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2353 if( moveHistoryDialog ) {
\r
2354 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2355 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2356 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2357 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2358 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2361 /* [AS] Eval graph */
\r
2362 wpEvalGraph.visible = EvalGraphIsUp();
\r
2364 if( evalGraphDialog ) {
\r
2365 GetWindowPlacement(evalGraphDialog, &wp);
\r
2366 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2367 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2368 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2369 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2372 /* [AS] Engine output */
\r
2373 wpEngineOutput.visible = EngineOutputIsUp();
\r
2375 if( engineOutputDialog ) {
\r
2376 GetWindowPlacement(engineOutputDialog, &wp);
\r
2377 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2378 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2379 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2380 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2383 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2384 if (!ad->save) continue;
\r
2385 switch (ad->argType) {
\r
2388 char *p = *(char **)ad->argLoc;
\r
2389 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2390 /* Quote multiline values or \-containing values
\r
2391 with { } if possible */
\r
2392 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2394 /* Else quote with " " */
\r
2395 fprintf(f, "/%s=\"", ad->argName);
\r
2397 if (*p == '\n') fprintf(f, "\n");
\r
2398 else if (*p == '\r') fprintf(f, "\\r");
\r
2399 else if (*p == '\t') fprintf(f, "\\t");
\r
2400 else if (*p == '\b') fprintf(f, "\\b");
\r
2401 else if (*p == '\f') fprintf(f, "\\f");
\r
2402 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2403 else if (*p == '\"') fprintf(f, "\\\"");
\r
2404 else if (*p == '\\') fprintf(f, "\\\\");
\r
2408 fprintf(f, "\"\n");
\r
2414 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2417 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2420 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2423 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2426 fprintf(f, "/%s=%s\n", ad->argName,
\r
2427 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2430 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2433 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2437 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2438 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2439 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2444 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2445 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2446 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2447 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2448 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2449 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2450 (ta->effects) ? " " : "",
\r
2451 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2455 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2456 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2458 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2461 case ArgBoardSize:
\r
2462 fprintf(f, "/%s=%s\n", ad->argName,
\r
2463 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2468 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2469 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2470 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2471 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2472 ad->argName, mfp->faceName, mfp->pointSize,
\r
2473 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2474 mfp->bold ? "b" : "",
\r
2475 mfp->italic ? "i" : "",
\r
2476 mfp->underline ? "u" : "",
\r
2477 mfp->strikeout ? "s" : "");
\r
2481 case ArgCommSettings:
\r
2482 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2484 case ArgSettingsFilename: ;
\r
2492 /*---------------------------------------------------------------------------*\
\r
2494 * GDI board drawing routines
\r
2496 \*---------------------------------------------------------------------------*/
\r
2498 /* [AS] Draw square using background texture */
\r
2499 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2504 return; /* Should never happen! */
\r
2507 SetGraphicsMode( dst, GM_ADVANCED );
\r
2514 /* X reflection */
\r
2519 x.eDx = (FLOAT) dw + dx - 1;
\r
2522 SetWorldTransform( dst, &x );
\r
2525 /* Y reflection */
\r
2531 x.eDy = (FLOAT) dh + dy - 1;
\r
2533 SetWorldTransform( dst, &x );
\r
2541 x.eDx = (FLOAT) dx;
\r
2542 x.eDy = (FLOAT) dy;
\r
2545 SetWorldTransform( dst, &x );
\r
2549 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2557 SetWorldTransform( dst, &x );
\r
2559 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2562 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2564 PM_WP = (int) WhitePawn,
\r
2565 PM_WN = (int) WhiteKnight,
\r
2566 PM_WB = (int) WhiteBishop,
\r
2567 PM_WR = (int) WhiteRook,
\r
2568 PM_WQ = (int) WhiteQueen,
\r
2569 PM_WF = (int) WhiteFerz,
\r
2570 PM_WW = (int) WhiteWazir,
\r
2571 PM_WE = (int) WhiteAlfil,
\r
2572 PM_WM = (int) WhiteMan,
\r
2573 PM_WO = (int) WhiteCannon,
\r
2574 PM_WU = (int) WhiteUnicorn,
\r
2575 PM_WH = (int) WhiteNightrider,
\r
2576 PM_WA = (int) WhiteAngel,
\r
2577 PM_WC = (int) WhiteMarshall,
\r
2578 PM_WAB = (int) WhiteCardinal,
\r
2579 PM_WD = (int) WhiteDragon,
\r
2580 PM_WL = (int) WhiteLance,
\r
2581 PM_WS = (int) WhiteCobra,
\r
2582 PM_WV = (int) WhiteFalcon,
\r
2583 PM_WSG = (int) WhiteSilver,
\r
2584 PM_WG = (int) WhiteGrasshopper,
\r
2585 PM_WK = (int) WhiteKing,
\r
2586 PM_BP = (int) BlackPawn,
\r
2587 PM_BN = (int) BlackKnight,
\r
2588 PM_BB = (int) BlackBishop,
\r
2589 PM_BR = (int) BlackRook,
\r
2590 PM_BQ = (int) BlackQueen,
\r
2591 PM_BF = (int) BlackFerz,
\r
2592 PM_BW = (int) BlackWazir,
\r
2593 PM_BE = (int) BlackAlfil,
\r
2594 PM_BM = (int) BlackMan,
\r
2595 PM_BO = (int) BlackCannon,
\r
2596 PM_BU = (int) BlackUnicorn,
\r
2597 PM_BH = (int) BlackNightrider,
\r
2598 PM_BA = (int) BlackAngel,
\r
2599 PM_BC = (int) BlackMarshall,
\r
2600 PM_BG = (int) BlackGrasshopper,
\r
2601 PM_BAB = (int) BlackCardinal,
\r
2602 PM_BD = (int) BlackDragon,
\r
2603 PM_BL = (int) BlackLance,
\r
2604 PM_BS = (int) BlackCobra,
\r
2605 PM_BV = (int) BlackFalcon,
\r
2606 PM_BSG = (int) BlackSilver,
\r
2607 PM_BK = (int) BlackKing
\r
2610 static HFONT hPieceFont = NULL;
\r
2611 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2612 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2613 static int fontBitmapSquareSize = 0;
\r
2614 static char pieceToFontChar[(int) EmptySquare] =
\r
2615 { 'p', 'n', 'b', 'r', 'q',
\r
2616 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2617 'k', 'o', 'm', 'v', 't', 'w',
\r
2618 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2621 extern BOOL SetCharTable( char *table, const char * map );
\r
2622 /* [HGM] moved to backend.c */
\r
2624 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2627 BYTE r1 = GetRValue( color );
\r
2628 BYTE g1 = GetGValue( color );
\r
2629 BYTE b1 = GetBValue( color );
\r
2635 /* Create a uniform background first */
\r
2636 hbrush = CreateSolidBrush( color );
\r
2637 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2638 FillRect( hdc, &rc, hbrush );
\r
2639 DeleteObject( hbrush );
\r
2642 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2643 int steps = squareSize / 2;
\r
2646 for( i=0; i<steps; i++ ) {
\r
2647 BYTE r = r1 - (r1-r2) * i / steps;
\r
2648 BYTE g = g1 - (g1-g2) * i / steps;
\r
2649 BYTE b = b1 - (b1-b2) * i / steps;
\r
2651 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2652 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2653 FillRect( hdc, &rc, hbrush );
\r
2654 DeleteObject(hbrush);
\r
2657 else if( mode == 2 ) {
\r
2658 /* Diagonal gradient, good more or less for every piece */
\r
2659 POINT triangle[3];
\r
2660 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2661 HBRUSH hbrush_old;
\r
2662 int steps = squareSize;
\r
2665 triangle[0].x = squareSize - steps;
\r
2666 triangle[0].y = squareSize;
\r
2667 triangle[1].x = squareSize;
\r
2668 triangle[1].y = squareSize;
\r
2669 triangle[2].x = squareSize;
\r
2670 triangle[2].y = squareSize - steps;
\r
2672 for( i=0; i<steps; i++ ) {
\r
2673 BYTE r = r1 - (r1-r2) * i / steps;
\r
2674 BYTE g = g1 - (g1-g2) * i / steps;
\r
2675 BYTE b = b1 - (b1-b2) * i / steps;
\r
2677 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2678 hbrush_old = SelectObject( hdc, hbrush );
\r
2679 Polygon( hdc, triangle, 3 );
\r
2680 SelectObject( hdc, hbrush_old );
\r
2681 DeleteObject(hbrush);
\r
2686 SelectObject( hdc, hpen );
\r
2691 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2692 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2693 piece: follow the steps as explained below.
\r
2695 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2699 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2703 int backColor = whitePieceColor;
\r
2704 int foreColor = blackPieceColor;
\r
2706 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2707 backColor = appData.fontBackColorWhite;
\r
2708 foreColor = appData.fontForeColorWhite;
\r
2710 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2711 backColor = appData.fontBackColorBlack;
\r
2712 foreColor = appData.fontForeColorBlack;
\r
2716 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2718 hbm_old = SelectObject( hdc, hbm );
\r
2722 rc.right = squareSize;
\r
2723 rc.bottom = squareSize;
\r
2725 /* Step 1: background is now black */
\r
2726 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2728 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2730 pt.x = (squareSize - sz.cx) / 2;
\r
2731 pt.y = (squareSize - sz.cy) / 2;
\r
2733 SetBkMode( hdc, TRANSPARENT );
\r
2734 SetTextColor( hdc, chroma );
\r
2735 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2736 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2738 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2739 /* Step 3: the area outside the piece is filled with white */
\r
2740 // FloodFill( hdc, 0, 0, chroma );
\r
2741 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2742 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2743 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2744 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2745 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2747 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2748 but if the start point is not inside the piece we're lost!
\r
2749 There should be a better way to do this... if we could create a region or path
\r
2750 from the fill operation we would be fine for example.
\r
2752 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2753 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2755 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2756 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2757 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2759 SelectObject( dc2, bm2 );
\r
2760 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2761 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2762 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2763 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2764 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2767 DeleteObject( bm2 );
\r
2770 SetTextColor( hdc, 0 );
\r
2772 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2773 draw the piece again in black for safety.
\r
2775 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2777 SelectObject( hdc, hbm_old );
\r
2779 if( hPieceMask[index] != NULL ) {
\r
2780 DeleteObject( hPieceMask[index] );
\r
2783 hPieceMask[index] = hbm;
\r
2786 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2788 SelectObject( hdc, hbm );
\r
2791 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2792 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2793 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2795 SelectObject( dc1, hPieceMask[index] );
\r
2796 SelectObject( dc2, bm2 );
\r
2797 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2798 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2801 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2802 the piece background and deletes (makes transparent) the rest.
\r
2803 Thanks to that mask, we are free to paint the background with the greates
\r
2804 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2805 We use this, to make gradients and give the pieces a "roundish" look.
\r
2807 SetPieceBackground( hdc, backColor, 2 );
\r
2808 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2812 DeleteObject( bm2 );
\r
2815 SetTextColor( hdc, foreColor );
\r
2816 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2818 SelectObject( hdc, hbm_old );
\r
2820 if( hPieceFace[index] != NULL ) {
\r
2821 DeleteObject( hPieceFace[index] );
\r
2824 hPieceFace[index] = hbm;
\r
2827 static int TranslatePieceToFontPiece( int piece )
\r
2857 case BlackMarshall:
\r
2861 case BlackNightrider:
\r
2867 case BlackUnicorn:
\r
2871 case BlackGrasshopper:
\r
2883 case BlackCardinal:
\r
2890 case WhiteMarshall:
\r
2894 case WhiteNightrider:
\r
2900 case WhiteUnicorn:
\r
2904 case WhiteGrasshopper:
\r
2916 case WhiteCardinal:
\r
2925 void CreatePiecesFromFont()
\r
2928 HDC hdc_window = NULL;
\r
2934 if( fontBitmapSquareSize < 0 ) {
\r
2935 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2939 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2940 fontBitmapSquareSize = -1;
\r
2944 if( fontBitmapSquareSize != squareSize ) {
\r
2945 hdc_window = GetDC( hwndMain );
\r
2946 hdc = CreateCompatibleDC( hdc_window );
\r
2948 if( hPieceFont != NULL ) {
\r
2949 DeleteObject( hPieceFont );
\r
2952 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2953 hPieceMask[i] = NULL;
\r
2954 hPieceFace[i] = NULL;
\r
2960 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2961 fontHeight = appData.fontPieceSize;
\r
2964 fontHeight = (fontHeight * squareSize) / 100;
\r
2966 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2968 lf.lfEscapement = 0;
\r
2969 lf.lfOrientation = 0;
\r
2970 lf.lfWeight = FW_NORMAL;
\r
2972 lf.lfUnderline = 0;
\r
2973 lf.lfStrikeOut = 0;
\r
2974 lf.lfCharSet = DEFAULT_CHARSET;
\r
2975 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2976 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2977 lf.lfQuality = PROOF_QUALITY;
\r
2978 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2979 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2980 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2982 hPieceFont = CreateFontIndirect( &lf );
\r
2984 if( hPieceFont == NULL ) {
\r
2985 fontBitmapSquareSize = -2;
\r
2988 /* Setup font-to-piece character table */
\r
2989 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2990 /* No (or wrong) global settings, try to detect the font */
\r
2991 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2993 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2995 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2996 /* DiagramTT* family */
\r
2997 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2999 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3000 /* Fairy symbols */
\r
3001 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3003 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3004 /* Good Companion (Some characters get warped as literal :-( */
\r
3005 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3006 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3007 SetCharTable(pieceToFontChar, s);
\r
3010 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3011 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3015 /* Create bitmaps */
\r
3016 hfont_old = SelectObject( hdc, hPieceFont );
\r
3018 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3019 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3020 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3021 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3022 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3023 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3024 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3025 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3026 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3027 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3028 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3029 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3031 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3032 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3033 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3034 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3035 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3036 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3037 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3038 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3039 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3040 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3042 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3043 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3048 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3050 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3051 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3055 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3056 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3064 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3065 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3066 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3068 SelectObject( hdc, hfont_old );
\r
3070 fontBitmapSquareSize = squareSize;
\r
3074 if( hdc != NULL ) {
\r
3078 if( hdc_window != NULL ) {
\r
3079 ReleaseDC( hwndMain, hdc_window );
\r
3084 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3088 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3089 if (gameInfo.event &&
\r
3090 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3091 strcmp(name, "k80s") == 0) {
\r
3092 strcpy(name, "tim");
\r
3094 return LoadBitmap(hinst, name);
\r
3098 /* Insert a color into the program's logical palette
\r
3099 structure. This code assumes the given color is
\r
3100 the result of the RGB or PALETTERGB macro, and it
\r
3101 knows how those macros work (which is documented).
\r
3104 InsertInPalette(COLORREF color)
\r
3106 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3108 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3109 DisplayFatalError("Too many colors", 0, 1);
\r
3110 pLogPal->palNumEntries--;
\r
3114 pe->peFlags = (char) 0;
\r
3115 pe->peRed = (char) (0xFF & color);
\r
3116 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3117 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3123 InitDrawingColors()
\r
3125 if (pLogPal == NULL) {
\r
3126 /* Allocate enough memory for a logical palette with
\r
3127 * PALETTESIZE entries and set the size and version fields
\r
3128 * of the logical palette structure.
\r
3130 pLogPal = (NPLOGPALETTE)
\r
3131 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3132 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3133 pLogPal->palVersion = 0x300;
\r
3135 pLogPal->palNumEntries = 0;
\r
3137 InsertInPalette(lightSquareColor);
\r
3138 InsertInPalette(darkSquareColor);
\r
3139 InsertInPalette(whitePieceColor);
\r
3140 InsertInPalette(blackPieceColor);
\r
3141 InsertInPalette(highlightSquareColor);
\r
3142 InsertInPalette(premoveHighlightColor);
\r
3144 /* create a logical color palette according the information
\r
3145 * in the LOGPALETTE structure.
\r
3147 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3149 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3150 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3151 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3152 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3153 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3154 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3155 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3156 /* [AS] Force rendering of the font-based pieces */
\r
3157 if( fontBitmapSquareSize > 0 ) {
\r
3158 fontBitmapSquareSize = 0;
\r
3164 BoardWidth(int boardSize, int n)
\r
3165 { /* [HGM] argument n added to allow different width and height */
\r
3166 int lineGap = sizeInfo[boardSize].lineGap;
\r
3168 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3169 lineGap = appData.overrideLineGap;
\r
3172 return (n + 1) * lineGap +
\r
3173 n * sizeInfo[boardSize].squareSize;
\r
3176 /* Respond to board resize by dragging edge */
\r
3178 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3180 BoardSize newSize = NUM_SIZES - 1;
\r
3181 static int recurse = 0;
\r
3182 if (IsIconic(hwndMain)) return;
\r
3183 if (recurse > 0) return;
\r
3185 while (newSize > 0) {
\r
3186 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3187 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3188 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3191 boardSize = newSize;
\r
3192 InitDrawingSizes(boardSize, flags);
\r
3199 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3201 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3202 ChessSquare piece;
\r
3203 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3205 SIZE clockSize, messageSize;
\r
3207 char buf[MSG_SIZ];
\r
3209 HMENU hmenu = GetMenu(hwndMain);
\r
3210 RECT crect, wrect, oldRect;
\r
3212 LOGBRUSH logbrush;
\r
3214 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3215 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3217 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3218 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3220 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3221 oldRect.top = boardY;
\r
3222 oldRect.right = boardX + winWidth;
\r
3223 oldRect.bottom = boardY + winHeight;
\r
3225 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3226 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3227 squareSize = sizeInfo[boardSize].squareSize;
\r
3228 lineGap = sizeInfo[boardSize].lineGap;
\r
3229 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3231 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3232 lineGap = appData.overrideLineGap;
\r
3235 if (tinyLayout != oldTinyLayout) {
\r
3236 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3238 style &= ~WS_SYSMENU;
\r
3239 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3240 "&Minimize\tCtrl+F4");
\r
3242 style |= WS_SYSMENU;
\r
3243 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3245 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3247 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3248 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3249 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3251 DrawMenuBar(hwndMain);
\r
3254 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3255 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3257 /* Get text area sizes */
\r
3258 hdc = GetDC(hwndMain);
\r
3259 if (appData.clockMode) {
\r
3260 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3262 sprintf(buf, "White");
\r
3264 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3265 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3266 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3267 str = "We only care about the height here";
\r
3268 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3269 SelectObject(hdc, oldFont);
\r
3270 ReleaseDC(hwndMain, hdc);
\r
3272 /* Compute where everything goes */
\r
3273 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3274 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3275 logoHeight = 2*clockSize.cy;
\r
3276 leftLogoRect.left = OUTER_MARGIN;
\r
3277 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3278 leftLogoRect.top = OUTER_MARGIN;
\r
3279 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3281 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3282 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3283 rightLogoRect.top = OUTER_MARGIN;
\r
3284 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3287 whiteRect.left = leftLogoRect.right;
\r
3288 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3289 whiteRect.top = OUTER_MARGIN;
\r
3290 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3292 blackRect.right = rightLogoRect.left;
\r
3293 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3294 blackRect.top = whiteRect.top;
\r
3295 blackRect.bottom = whiteRect.bottom;
\r
3297 whiteRect.left = OUTER_MARGIN;
\r
3298 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3299 whiteRect.top = OUTER_MARGIN;
\r
3300 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3302 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3303 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3304 blackRect.top = whiteRect.top;
\r
3305 blackRect.bottom = whiteRect.bottom;
\r
3308 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3309 if (appData.showButtonBar) {
\r
3310 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3311 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3313 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3315 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3316 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3318 boardRect.left = OUTER_MARGIN;
\r
3319 boardRect.right = boardRect.left + boardWidth;
\r
3320 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3321 boardRect.bottom = boardRect.top + boardHeight;
\r
3323 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3324 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3325 oldBoardSize = boardSize;
\r
3326 oldTinyLayout = tinyLayout;
\r
3327 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3328 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3329 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3330 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3331 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3332 winHeight = winH; // without disturbing window attachments
\r
3333 GetWindowRect(hwndMain, &wrect);
\r
3334 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3335 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3337 // [HGM] placement: let attached windows follow size change.
\r
3338 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3339 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3340 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3341 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3342 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3344 /* compensate if menu bar wrapped */
\r
3345 GetClientRect(hwndMain, &crect);
\r
3346 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3347 winHeight += offby;
\r
3349 case WMSZ_TOPLEFT:
\r
3350 SetWindowPos(hwndMain, NULL,
\r
3351 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3352 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3355 case WMSZ_TOPRIGHT:
\r
3357 SetWindowPos(hwndMain, NULL,
\r
3358 wrect.left, wrect.bottom - winHeight,
\r
3359 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3362 case WMSZ_BOTTOMLEFT:
\r
3364 SetWindowPos(hwndMain, NULL,
\r
3365 wrect.right - winWidth, wrect.top,
\r
3366 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3369 case WMSZ_BOTTOMRIGHT:
\r
3373 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3374 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3379 for (i = 0; i < N_BUTTONS; i++) {
\r
3380 if (buttonDesc[i].hwnd != NULL) {
\r
3381 DestroyWindow(buttonDesc[i].hwnd);
\r
3382 buttonDesc[i].hwnd = NULL;
\r
3384 if (appData.showButtonBar) {
\r
3385 buttonDesc[i].hwnd =
\r
3386 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3387 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3388 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3389 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3390 (HMENU) buttonDesc[i].id,
\r
3391 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3393 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3394 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3395 MAKELPARAM(FALSE, 0));
\r
3397 if (buttonDesc[i].id == IDM_Pause)
\r
3398 hwndPause = buttonDesc[i].hwnd;
\r
3399 buttonDesc[i].wndproc = (WNDPROC)
\r
3400 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3403 if (gridPen != NULL) DeleteObject(gridPen);
\r
3404 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3405 if (premovePen != NULL) DeleteObject(premovePen);
\r
3406 if (lineGap != 0) {
\r
3407 logbrush.lbStyle = BS_SOLID;
\r
3408 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3410 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3411 lineGap, &logbrush, 0, NULL);
\r
3412 logbrush.lbColor = highlightSquareColor;
\r
3414 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3415 lineGap, &logbrush, 0, NULL);
\r
3417 logbrush.lbColor = premoveHighlightColor;
\r
3419 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3420 lineGap, &logbrush, 0, NULL);
\r
3422 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3423 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3424 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3425 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3426 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3427 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3428 BOARD_WIDTH * (squareSize + lineGap);
\r
3429 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3431 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3432 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3433 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3434 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3435 lineGap / 2 + (i * (squareSize + lineGap));
\r
3436 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3437 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3438 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3442 /* [HGM] Licensing requirement */
\r
3444 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3447 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3449 GothicPopUp( "", VariantNormal);
\r
3452 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3454 /* Load piece bitmaps for this board size */
\r
3455 for (i=0; i<=2; i++) {
\r
3456 for (piece = WhitePawn;
\r
3457 (int) piece < (int) BlackPawn;
\r
3458 piece = (ChessSquare) ((int) piece + 1)) {
\r
3459 if (pieceBitmap[i][piece] != NULL)
\r
3460 DeleteObject(pieceBitmap[i][piece]);
\r
3464 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3465 // Orthodox Chess pieces
\r
3466 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3467 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3468 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3469 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3470 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3471 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3472 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3473 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3474 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3475 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3476 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3477 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3478 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3479 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3480 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3481 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3482 // in Shogi, Hijack the unused Queen for Lance
\r
3483 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3484 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3485 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3487 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3488 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3489 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3492 if(squareSize <= 72 && squareSize >= 33) {
\r
3493 /* A & C are available in most sizes now */
\r
3494 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3495 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3496 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3497 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3498 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3499 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3500 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3501 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3502 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3503 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3504 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3505 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3506 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3507 } else { // Smirf-like
\r
3508 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3509 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3510 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3512 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3513 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3514 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3515 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3516 } else { // WinBoard standard
\r
3517 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3518 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3519 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3524 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3525 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3526 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3527 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3528 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3529 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3530 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3531 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3532 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3533 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3534 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3535 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3536 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3537 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3538 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3539 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3540 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3541 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3542 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3543 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3544 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3545 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3546 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3547 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3548 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3549 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3550 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3551 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3552 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3553 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3554 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3556 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3557 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3558 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3559 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3560 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3561 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3562 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3563 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3564 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3565 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3566 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3567 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3568 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3570 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3571 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3572 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3573 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3574 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3575 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3576 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3577 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3578 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3579 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3580 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3581 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3584 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3585 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3586 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3587 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3588 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3589 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3590 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3591 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3592 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3593 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3594 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3595 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3596 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3597 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3598 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3602 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3603 /* special Shogi support in this size */
\r
3604 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3605 for (piece = WhitePawn;
\r
3606 (int) piece < (int) BlackPawn;
\r
3607 piece = (ChessSquare) ((int) piece + 1)) {
\r
3608 if (pieceBitmap[i][piece] != NULL)
\r
3609 DeleteObject(pieceBitmap[i][piece]);
\r
3612 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3613 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3614 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3615 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3616 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3617 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3618 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3619 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3620 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3621 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3622 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3623 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3624 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3625 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3626 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3627 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3628 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3629 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3630 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3631 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3632 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3633 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3634 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3635 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3636 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3637 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3638 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3639 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3640 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3641 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3642 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3643 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3644 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3645 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3646 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3647 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3648 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3649 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3650 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3651 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3652 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3653 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3659 PieceBitmap(ChessSquare p, int kind)
\r
3661 if ((int) p >= (int) BlackPawn)
\r
3662 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3664 return pieceBitmap[kind][(int) p];
\r
3667 /***************************************************************/
\r
3669 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3670 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3672 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3673 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3677 SquareToPos(int row, int column, int * x, int * y)
\r
3680 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3681 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3683 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3684 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3689 DrawCoordsOnDC(HDC hdc)
\r
3691 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
3692 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
3693 char str[2] = { NULLCHAR, NULLCHAR };
\r
3694 int oldMode, oldAlign, x, y, start, i;
\r
3698 if (!appData.showCoords)
\r
3701 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3703 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3704 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3705 oldAlign = GetTextAlign(hdc);
\r
3706 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3708 y = boardRect.top + lineGap;
\r
3709 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3711 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3712 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3713 str[0] = files[start + i];
\r
3714 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3715 y += squareSize + lineGap;
\r
3718 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3720 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3721 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3722 str[0] = ranks[start + i];
\r
3723 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3724 x += squareSize + lineGap;
\r
3727 SelectObject(hdc, oldBrush);
\r
3728 SetBkMode(hdc, oldMode);
\r
3729 SetTextAlign(hdc, oldAlign);
\r
3730 SelectObject(hdc, oldFont);
\r
3734 DrawGridOnDC(HDC hdc)
\r
3738 if (lineGap != 0) {
\r
3739 oldPen = SelectObject(hdc, gridPen);
\r
3740 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3741 SelectObject(hdc, oldPen);
\r
3745 #define HIGHLIGHT_PEN 0
\r
3746 #define PREMOVE_PEN 1
\r
3749 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3752 HPEN oldPen, hPen;
\r
3753 if (lineGap == 0) return;
\r
3755 x1 = boardRect.left +
\r
3756 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3757 y1 = boardRect.top +
\r
3758 lineGap/2 + y * (squareSize + lineGap);
\r
3760 x1 = boardRect.left +
\r
3761 lineGap/2 + x * (squareSize + lineGap);
\r
3762 y1 = boardRect.top +
\r
3763 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3765 hPen = pen ? premovePen : highlightPen;
\r
3766 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3767 MoveToEx(hdc, x1, y1, NULL);
\r
3768 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3769 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3770 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3771 LineTo(hdc, x1, y1);
\r
3772 SelectObject(hdc, oldPen);
\r
3776 DrawHighlightsOnDC(HDC hdc)
\r
3779 for (i=0; i<2; i++) {
\r
3780 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3781 DrawHighlightOnDC(hdc, TRUE,
\r
3782 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3785 for (i=0; i<2; i++) {
\r
3786 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3787 premoveHighlightInfo.sq[i].y >= 0) {
\r
3788 DrawHighlightOnDC(hdc, TRUE,
\r
3789 premoveHighlightInfo.sq[i].x,
\r
3790 premoveHighlightInfo.sq[i].y,
\r
3796 /* Note: sqcolor is used only in monoMode */
\r
3797 /* Note that this code is largely duplicated in woptions.c,
\r
3798 function DrawSampleSquare, so that needs to be updated too */
\r
3800 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3802 HBITMAP oldBitmap;
\r
3806 if (appData.blindfold) return;
\r
3808 /* [AS] Use font-based pieces if needed */
\r
3809 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3810 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3811 CreatePiecesFromFont();
\r
3813 if( fontBitmapSquareSize == squareSize ) {
\r
3814 int index = TranslatePieceToFontPiece(piece);
\r
3816 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3820 squareSize, squareSize,
\r
3825 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3829 squareSize, squareSize,
\r
3838 if (appData.monoMode) {
\r
3839 SelectObject(tmphdc, PieceBitmap(piece,
\r
3840 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3841 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3842 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3844 tmpSize = squareSize;
\r
3846 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3847 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3848 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3849 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3850 x += (squareSize - minorSize)>>1;
\r
3851 y += squareSize - minorSize - 2;
\r
3852 tmpSize = minorSize;
\r
3854 if (color || appData.allWhite ) {
\r
3855 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3857 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3858 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3859 if(appData.upsideDown && color==flipView)
\r
3860 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3862 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3864 /* Use black piece color for outline of white pieces */
\r
3865 /* Not sure this looks really good (though xboard does it).
\r
3866 Maybe better to have another selectable color, default black */
\r
3867 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3868 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3869 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3871 /* Use black for outline of white pieces */
\r
3872 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3873 if(appData.upsideDown && color==flipView)
\r
3874 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3876 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3880 /* Use white piece color for details of black pieces */
\r
3881 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3882 WHITE_PIECE ones aren't always the right shape. */
\r
3883 /* Not sure this looks really good (though xboard does it).
\r
3884 Maybe better to have another selectable color, default medium gray? */
\r
3885 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3886 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3887 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3888 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3889 SelectObject(hdc, blackPieceBrush);
\r
3890 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3892 /* Use square color for details of black pieces */
\r
3893 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3894 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3895 if(appData.upsideDown && !flipView)
\r
3896 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3898 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3901 SelectObject(hdc, oldBrush);
\r
3902 SelectObject(tmphdc, oldBitmap);
\r
3906 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3907 int GetBackTextureMode( int algo )
\r
3909 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3913 case BACK_TEXTURE_MODE_PLAIN:
\r
3914 result = 1; /* Always use identity map */
\r
3916 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3917 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3925 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3926 to handle redraws cleanly (as random numbers would always be different).
\r
3928 VOID RebuildTextureSquareInfo()
\r
3938 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3940 if( liteBackTexture != NULL ) {
\r
3941 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3942 lite_w = bi.bmWidth;
\r
3943 lite_h = bi.bmHeight;
\r
3947 if( darkBackTexture != NULL ) {
\r
3948 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3949 dark_w = bi.bmWidth;
\r
3950 dark_h = bi.bmHeight;
\r
3954 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3955 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3956 if( (col + row) & 1 ) {
\r
3958 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3959 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3960 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3961 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3966 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3967 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3968 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3969 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3976 /* [AS] Arrow highlighting support */
\r
3978 static int A_WIDTH = 5; /* Width of arrow body */
\r
3980 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3981 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3983 static double Sqr( double x )
\r
3988 static int Round( double x )
\r
3990 return (int) (x + 0.5);
\r
3993 /* Draw an arrow between two points using current settings */
\r
3994 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3997 double dx, dy, j, k, x, y;
\r
3999 if( d_x == s_x ) {
\r
4000 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4002 arrow[0].x = s_x + A_WIDTH;
\r
4005 arrow[1].x = s_x + A_WIDTH;
\r
4006 arrow[1].y = d_y - h;
\r
4008 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4009 arrow[2].y = d_y - h;
\r
4014 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4015 arrow[4].y = d_y - h;
\r
4017 arrow[5].x = s_x - A_WIDTH;
\r
4018 arrow[5].y = d_y - h;
\r
4020 arrow[6].x = s_x - A_WIDTH;
\r
4023 else if( d_y == s_y ) {
\r
4024 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4027 arrow[0].y = s_y + A_WIDTH;
\r
4029 arrow[1].x = d_x - w;
\r
4030 arrow[1].y = s_y + A_WIDTH;
\r
4032 arrow[2].x = d_x - w;
\r
4033 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4038 arrow[4].x = d_x - w;
\r
4039 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4041 arrow[5].x = d_x - w;
\r
4042 arrow[5].y = s_y - A_WIDTH;
\r
4045 arrow[6].y = s_y - A_WIDTH;
\r
4048 /* [AS] Needed a lot of paper for this! :-) */
\r
4049 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4050 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4052 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4054 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4059 arrow[0].x = Round(x - j);
\r
4060 arrow[0].y = Round(y + j*dx);
\r
4062 arrow[1].x = Round(x + j);
\r
4063 arrow[1].y = Round(y - j*dx);
\r
4066 x = (double) d_x - k;
\r
4067 y = (double) d_y - k*dy;
\r
4070 x = (double) d_x + k;
\r
4071 y = (double) d_y + k*dy;
\r
4074 arrow[2].x = Round(x + j);
\r
4075 arrow[2].y = Round(y - j*dx);
\r
4077 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4078 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4083 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4084 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4086 arrow[6].x = Round(x - j);
\r
4087 arrow[6].y = Round(y + j*dx);
\r
4090 Polygon( hdc, arrow, 7 );
\r
4093 /* [AS] Draw an arrow between two squares */
\r
4094 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4096 int s_x, s_y, d_x, d_y;
\r
4103 if( s_col == d_col && s_row == d_row ) {
\r
4107 /* Get source and destination points */
\r
4108 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4109 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4112 d_y += squareSize / 4;
\r
4114 else if( d_y < s_y ) {
\r
4115 d_y += 3 * squareSize / 4;
\r
4118 d_y += squareSize / 2;
\r
4122 d_x += squareSize / 4;
\r
4124 else if( d_x < s_x ) {
\r
4125 d_x += 3 * squareSize / 4;
\r
4128 d_x += squareSize / 2;
\r
4131 s_x += squareSize / 2;
\r
4132 s_y += squareSize / 2;
\r
4134 /* Adjust width */
\r
4135 A_WIDTH = squareSize / 14;
\r
4138 stLB.lbStyle = BS_SOLID;
\r
4139 stLB.lbColor = appData.highlightArrowColor;
\r
4142 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4143 holdpen = SelectObject( hdc, hpen );
\r
4144 hbrush = CreateBrushIndirect( &stLB );
\r
4145 holdbrush = SelectObject( hdc, hbrush );
\r
4147 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4149 SelectObject( hdc, holdpen );
\r
4150 SelectObject( hdc, holdbrush );
\r
4151 DeleteObject( hpen );
\r
4152 DeleteObject( hbrush );
\r
4155 BOOL HasHighlightInfo()
\r
4157 BOOL result = FALSE;
\r
4159 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4160 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4168 BOOL IsDrawArrowEnabled()
\r
4170 BOOL result = FALSE;
\r
4172 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4179 VOID DrawArrowHighlight( HDC hdc )
\r
4181 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4182 DrawArrowBetweenSquares( hdc,
\r
4183 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4184 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4188 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4190 HRGN result = NULL;
\r
4192 if( HasHighlightInfo() ) {
\r
4193 int x1, y1, x2, y2;
\r
4194 int sx, sy, dx, dy;
\r
4196 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4197 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4199 sx = MIN( x1, x2 );
\r
4200 sy = MIN( y1, y2 );
\r
4201 dx = MAX( x1, x2 ) + squareSize;
\r
4202 dy = MAX( y1, y2 ) + squareSize;
\r
4204 result = CreateRectRgn( sx, sy, dx, dy );
\r
4211 Warning: this function modifies the behavior of several other functions.
\r
4213 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4214 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4215 repaint is scattered all over the place, which is not good for features such as
\r
4216 "arrow highlighting" that require a full repaint of the board.
\r
4218 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4219 user interaction, when speed is not so important) but especially to avoid errors
\r
4220 in the displayed graphics.
\r
4222 In such patched places, I always try refer to this function so there is a single
\r
4223 place to maintain knowledge.
\r
4225 To restore the original behavior, just return FALSE unconditionally.
\r
4227 BOOL IsFullRepaintPreferrable()
\r
4229 BOOL result = FALSE;
\r
4231 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4232 /* Arrow may appear on the board */
\r
4240 This function is called by DrawPosition to know whether a full repaint must
\r
4243 Only DrawPosition may directly call this function, which makes use of
\r
4244 some state information. Other function should call DrawPosition specifying
\r
4245 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4247 BOOL DrawPositionNeedsFullRepaint()
\r
4249 BOOL result = FALSE;
\r
4252 Probably a slightly better policy would be to trigger a full repaint
\r
4253 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4254 but animation is fast enough that it's difficult to notice.
\r
4256 if( animInfo.piece == EmptySquare ) {
\r
4257 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4266 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4268 int row, column, x, y, square_color, piece_color;
\r
4269 ChessSquare piece;
\r
4271 HDC texture_hdc = NULL;
\r
4273 /* [AS] Initialize background textures if needed */
\r
4274 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4275 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4276 if( backTextureSquareSize != squareSize
\r
4277 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4278 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4279 backTextureSquareSize = squareSize;
\r
4280 RebuildTextureSquareInfo();
\r
4283 texture_hdc = CreateCompatibleDC( hdc );
\r
4286 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4287 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4289 SquareToPos(row, column, &x, &y);
\r
4291 piece = board[row][column];
\r
4293 square_color = ((column + row) % 2) == 1;
\r
4294 if( gameInfo.variant == VariantXiangqi ) {
\r
4295 square_color = !InPalace(row, column);
\r
4296 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4297 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4299 piece_color = (int) piece < (int) BlackPawn;
\r
4302 /* [HGM] holdings file: light square or black */
\r
4303 if(column == BOARD_LEFT-2) {
\r
4304 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4307 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4311 if(column == BOARD_RGHT + 1 ) {
\r
4312 if( row < gameInfo.holdingsSize )
\r
4315 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4319 if(column == BOARD_LEFT-1 ) /* left align */
\r
4320 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4321 else if( column == BOARD_RGHT) /* right align */
\r
4322 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4324 if (appData.monoMode) {
\r
4325 if (piece == EmptySquare) {
\r
4326 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4327 square_color ? WHITENESS : BLACKNESS);
\r
4329 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4332 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4333 /* [AS] Draw the square using a texture bitmap */
\r
4334 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4335 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4336 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4339 squareSize, squareSize,
\r
4342 backTextureSquareInfo[r][c].mode,
\r
4343 backTextureSquareInfo[r][c].x,
\r
4344 backTextureSquareInfo[r][c].y );
\r
4346 SelectObject( texture_hdc, hbm );
\r
4348 if (piece != EmptySquare) {
\r
4349 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4353 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4355 oldBrush = SelectObject(hdc, brush );
\r
4356 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4357 SelectObject(hdc, oldBrush);
\r
4358 if (piece != EmptySquare)
\r
4359 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4364 if( texture_hdc != NULL ) {
\r
4365 DeleteDC( texture_hdc );
\r
4369 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4370 void fputDW(FILE *f, int x)
\r
4372 fputc(x & 255, f);
\r
4373 fputc(x>>8 & 255, f);
\r
4374 fputc(x>>16 & 255, f);
\r
4375 fputc(x>>24 & 255, f);
\r
4378 #define MAX_CLIPS 200 /* more than enough */
\r
4381 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4383 // HBITMAP bufferBitmap;
\r
4388 int w = 100, h = 50;
\r
4390 if(logo == NULL) return;
\r
4391 // GetClientRect(hwndMain, &Rect);
\r
4392 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4393 // Rect.bottom-Rect.top+1);
\r
4394 tmphdc = CreateCompatibleDC(hdc);
\r
4395 hbm = SelectObject(tmphdc, logo);
\r
4396 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4400 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4401 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4402 SelectObject(tmphdc, hbm);
\r
4407 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4409 static Board lastReq, lastDrawn;
\r
4410 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4411 static int lastDrawnFlipView = 0;
\r
4412 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4413 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4416 HBITMAP bufferBitmap;
\r
4417 HBITMAP oldBitmap;
\r
4419 HRGN clips[MAX_CLIPS];
\r
4420 ChessSquare dragged_piece = EmptySquare;
\r
4422 /* I'm undecided on this - this function figures out whether a full
\r
4423 * repaint is necessary on its own, so there's no real reason to have the
\r
4424 * caller tell it that. I think this can safely be set to FALSE - but
\r
4425 * if we trust the callers not to request full repaints unnessesarily, then
\r
4426 * we could skip some clipping work. In other words, only request a full
\r
4427 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4428 * gamestart and similar) --Hawk
\r
4430 Boolean fullrepaint = repaint;
\r
4432 if( DrawPositionNeedsFullRepaint() ) {
\r
4433 fullrepaint = TRUE;
\r
4437 if( fullrepaint ) {
\r
4438 static int repaint_count = 0;
\r
4442 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4443 OutputDebugString( buf );
\r
4447 if (board == NULL) {
\r
4448 if (!lastReqValid) {
\r
4453 CopyBoard(lastReq, board);
\r
4457 if (doingSizing) {
\r
4461 if (IsIconic(hwndMain)) {
\r
4465 if (hdc == NULL) {
\r
4466 hdc = GetDC(hwndMain);
\r
4467 if (!appData.monoMode) {
\r
4468 SelectPalette(hdc, hPal, FALSE);
\r
4469 RealizePalette(hdc);
\r
4473 releaseDC = FALSE;
\r
4477 fprintf(debugFP, "*******************************\n"
\r
4479 "dragInfo.from (%d,%d)\n"
\r
4480 "dragInfo.start (%d,%d)\n"
\r
4481 "dragInfo.pos (%d,%d)\n"
\r
4482 "dragInfo.lastpos (%d,%d)\n",
\r
4483 repaint ? "TRUE" : "FALSE",
\r
4484 dragInfo.from.x, dragInfo.from.y,
\r
4485 dragInfo.start.x, dragInfo.start.y,
\r
4486 dragInfo.pos.x, dragInfo.pos.y,
\r
4487 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4488 fprintf(debugFP, "prev: ");
\r
4489 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4490 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4491 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4494 fprintf(debugFP, "\n");
\r
4495 fprintf(debugFP, "board: ");
\r
4496 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4497 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4498 fprintf(debugFP, "%d ", board[row][column]);
\r
4501 fprintf(debugFP, "\n");
\r
4505 /* Create some work-DCs */
\r
4506 hdcmem = CreateCompatibleDC(hdc);
\r
4507 tmphdc = CreateCompatibleDC(hdc);
\r
4509 /* If dragging is in progress, we temporarely remove the piece */
\r
4510 /* [HGM] or temporarily decrease count if stacked */
\r
4511 /* !! Moved to before board compare !! */
\r
4512 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4513 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4514 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4515 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4516 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4518 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4519 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4520 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4522 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4525 /* Figure out which squares need updating by comparing the
\r
4526 * newest board with the last drawn board and checking if
\r
4527 * flipping has changed.
\r
4529 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4530 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4531 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4532 if (lastDrawn[row][column] != board[row][column]) {
\r
4533 SquareToPos(row, column, &x, &y);
\r
4534 clips[num_clips++] =
\r
4535 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4539 for (i=0; i<2; i++) {
\r
4540 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4541 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4542 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4543 lastDrawnHighlight.sq[i].y >= 0) {
\r
4544 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4545 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4546 clips[num_clips++] =
\r
4547 CreateRectRgn(x - lineGap, y - lineGap,
\r
4548 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4550 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4551 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4552 clips[num_clips++] =
\r
4553 CreateRectRgn(x - lineGap, y - lineGap,
\r
4554 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4558 for (i=0; i<2; i++) {
\r
4559 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4560 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4561 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4562 lastDrawnPremove.sq[i].y >= 0) {
\r
4563 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4564 lastDrawnPremove.sq[i].x, &x, &y);
\r
4565 clips[num_clips++] =
\r
4566 CreateRectRgn(x - lineGap, y - lineGap,
\r
4567 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4569 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4570 premoveHighlightInfo.sq[i].y >= 0) {
\r
4571 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4572 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4573 clips[num_clips++] =
\r
4574 CreateRectRgn(x - lineGap, y - lineGap,
\r
4575 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4580 fullrepaint = TRUE;
\r
4583 /* Create a buffer bitmap - this is the actual bitmap
\r
4584 * being written to. When all the work is done, we can
\r
4585 * copy it to the real DC (the screen). This avoids
\r
4586 * the problems with flickering.
\r
4588 GetClientRect(hwndMain, &Rect);
\r
4589 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4590 Rect.bottom-Rect.top+1);
\r
4591 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4592 if (!appData.monoMode) {
\r
4593 SelectPalette(hdcmem, hPal, FALSE);
\r
4596 /* Create clips for dragging */
\r
4597 if (!fullrepaint) {
\r
4598 if (dragInfo.from.x >= 0) {
\r
4599 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4600 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4602 if (dragInfo.start.x >= 0) {
\r
4603 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4604 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4606 if (dragInfo.pos.x >= 0) {
\r
4607 x = dragInfo.pos.x - squareSize / 2;
\r
4608 y = dragInfo.pos.y - squareSize / 2;
\r
4609 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4611 if (dragInfo.lastpos.x >= 0) {
\r
4612 x = dragInfo.lastpos.x - squareSize / 2;
\r
4613 y = dragInfo.lastpos.y - squareSize / 2;
\r
4614 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4618 /* Are we animating a move?
\r
4620 * - remove the piece from the board (temporarely)
\r
4621 * - calculate the clipping region
\r
4623 if (!fullrepaint) {
\r
4624 if (animInfo.piece != EmptySquare) {
\r
4625 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4626 x = boardRect.left + animInfo.lastpos.x;
\r
4627 y = boardRect.top + animInfo.lastpos.y;
\r
4628 x2 = boardRect.left + animInfo.pos.x;
\r
4629 y2 = boardRect.top + animInfo.pos.y;
\r
4630 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4631 /* Slight kludge. The real problem is that after AnimateMove is
\r
4632 done, the position on the screen does not match lastDrawn.
\r
4633 This currently causes trouble only on e.p. captures in
\r
4634 atomic, where the piece moves to an empty square and then
\r
4635 explodes. The old and new positions both had an empty square
\r
4636 at the destination, but animation has drawn a piece there and
\r
4637 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4638 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4642 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4643 if (num_clips == 0)
\r
4644 fullrepaint = TRUE;
\r
4646 /* Set clipping on the memory DC */
\r
4647 if (!fullrepaint) {
\r
4648 SelectClipRgn(hdcmem, clips[0]);
\r
4649 for (x = 1; x < num_clips; x++) {
\r
4650 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4651 abort(); // this should never ever happen!
\r
4655 /* Do all the drawing to the memory DC */
\r
4656 if(explodeInfo.radius) { // [HGM] atomic
\r
4658 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4659 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4660 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4661 x += squareSize/2;
\r
4662 y += squareSize/2;
\r
4663 if(!fullrepaint) {
\r
4664 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4665 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4667 DrawGridOnDC(hdcmem);
\r
4668 DrawHighlightsOnDC(hdcmem);
\r
4669 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4670 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4671 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4672 SelectObject(hdcmem, oldBrush);
\r
4674 DrawGridOnDC(hdcmem);
\r
4675 DrawHighlightsOnDC(hdcmem);
\r
4676 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4679 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4680 if(appData.autoLogo) {
\r
4682 switch(gameMode) { // pick logos based on game mode
\r
4683 case IcsObserving:
\r
4684 whiteLogo = second.programLogo; // ICS logo
\r
4685 blackLogo = second.programLogo;
\r
4688 case IcsPlayingWhite:
\r
4689 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4690 blackLogo = second.programLogo; // ICS logo
\r
4692 case IcsPlayingBlack:
\r
4693 whiteLogo = second.programLogo; // ICS logo
\r
4694 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4696 case TwoMachinesPlay:
\r
4697 if(first.twoMachinesColor[0] == 'b') {
\r
4698 whiteLogo = second.programLogo;
\r
4699 blackLogo = first.programLogo;
\r
4702 case MachinePlaysWhite:
\r
4703 blackLogo = userLogo;
\r
4705 case MachinePlaysBlack:
\r
4706 whiteLogo = userLogo;
\r
4707 blackLogo = first.programLogo;
\r
4710 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4711 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4714 if( appData.highlightMoveWithArrow ) {
\r
4715 DrawArrowHighlight(hdcmem);
\r
4718 DrawCoordsOnDC(hdcmem);
\r
4720 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4721 /* to make sure lastDrawn contains what is actually drawn */
\r
4723 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4724 if (dragged_piece != EmptySquare) {
\r
4725 /* [HGM] or restack */
\r
4726 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4727 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4729 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4730 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4731 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4732 x = dragInfo.pos.x - squareSize / 2;
\r
4733 y = dragInfo.pos.y - squareSize / 2;
\r
4734 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4735 ((int) dragged_piece < (int) BlackPawn),
\r
4736 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4739 /* Put the animated piece back into place and draw it */
\r
4740 if (animInfo.piece != EmptySquare) {
\r
4741 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4742 x = boardRect.left + animInfo.pos.x;
\r
4743 y = boardRect.top + animInfo.pos.y;
\r
4744 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4745 ((int) animInfo.piece < (int) BlackPawn),
\r
4746 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4749 /* Release the bufferBitmap by selecting in the old bitmap
\r
4750 * and delete the memory DC
\r
4752 SelectObject(hdcmem, oldBitmap);
\r
4755 /* Set clipping on the target DC */
\r
4756 if (!fullrepaint) {
\r
4757 SelectClipRgn(hdc, clips[0]);
\r
4758 for (x = 1; x < num_clips; x++) {
\r
4759 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4760 abort(); // this should never ever happen!
\r
4764 /* Copy the new bitmap onto the screen in one go.
\r
4765 * This way we avoid any flickering
\r
4767 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4768 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4769 boardRect.right - boardRect.left,
\r
4770 boardRect.bottom - boardRect.top,
\r
4771 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4772 if(saveDiagFlag) {
\r
4773 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4774 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4776 GetObject(bufferBitmap, sizeof(b), &b);
\r
4777 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4778 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4779 bih.biWidth = b.bmWidth;
\r
4780 bih.biHeight = b.bmHeight;
\r
4782 bih.biBitCount = b.bmBitsPixel;
\r
4783 bih.biCompression = 0;
\r
4784 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4785 bih.biXPelsPerMeter = 0;
\r
4786 bih.biYPelsPerMeter = 0;
\r
4787 bih.biClrUsed = 0;
\r
4788 bih.biClrImportant = 0;
\r
4789 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4790 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4791 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4792 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4795 wb = b.bmWidthBytes;
\r
4797 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4798 int k = ((int*) pData)[i];
\r
4799 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4800 if(j >= 16) break;
\r
4802 if(j >= nrColors) nrColors = j+1;
\r
4804 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4806 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4807 for(w=0; w<(wb>>2); w+=2) {
\r
4808 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4809 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4810 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4811 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4812 pData[p++] = m | j<<4;
\r
4814 while(p&3) pData[p++] = 0;
\r
4817 wb = ((wb+31)>>5)<<2;
\r
4819 // write BITMAPFILEHEADER
\r
4820 fprintf(diagFile, "BM");
\r
4821 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4822 fputDW(diagFile, 0);
\r
4823 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4824 // write BITMAPINFOHEADER
\r
4825 fputDW(diagFile, 40);
\r
4826 fputDW(diagFile, b.bmWidth);
\r
4827 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4828 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4829 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4830 fputDW(diagFile, 0);
\r
4831 fputDW(diagFile, 0);
\r
4832 fputDW(diagFile, 0);
\r
4833 fputDW(diagFile, 0);
\r
4834 fputDW(diagFile, 0);
\r
4835 fputDW(diagFile, 0);
\r
4836 // write color table
\r
4838 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4839 // write bitmap data
\r
4840 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4841 fputc(pData[i], diagFile);
\r
4846 SelectObject(tmphdc, oldBitmap);
\r
4848 /* Massive cleanup */
\r
4849 for (x = 0; x < num_clips; x++)
\r
4850 DeleteObject(clips[x]);
\r
4853 DeleteObject(bufferBitmap);
\r
4856 ReleaseDC(hwndMain, hdc);
\r
4858 if (lastDrawnFlipView != flipView) {
\r
4860 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4862 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4865 /* CopyBoard(lastDrawn, board);*/
\r
4866 lastDrawnHighlight = highlightInfo;
\r
4867 lastDrawnPremove = premoveHighlightInfo;
\r
4868 lastDrawnFlipView = flipView;
\r
4869 lastDrawnValid = 1;
\r
4872 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4877 saveDiagFlag = 1; diagFile = f;
\r
4878 HDCDrawPosition(NULL, TRUE, NULL);
\r
4882 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4889 /*---------------------------------------------------------------------------*\
\r
4890 | CLIENT PAINT PROCEDURE
\r
4891 | This is the main event-handler for the WM_PAINT message.
\r
4893 \*---------------------------------------------------------------------------*/
\r
4895 PaintProc(HWND hwnd)
\r
4901 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4902 if (IsIconic(hwnd)) {
\r
4903 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4905 if (!appData.monoMode) {
\r
4906 SelectPalette(hdc, hPal, FALSE);
\r
4907 RealizePalette(hdc);
\r
4909 HDCDrawPosition(hdc, 1, NULL);
\r
4911 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4912 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4913 ETO_CLIPPED|ETO_OPAQUE,
\r
4914 &messageRect, messageText, strlen(messageText), NULL);
\r
4915 SelectObject(hdc, oldFont);
\r
4916 DisplayBothClocks();
\r
4918 EndPaint(hwnd,&ps);
\r
4926 * If the user selects on a border boundary, return -1; if off the board,
\r
4927 * return -2. Otherwise map the event coordinate to the square.
\r
4928 * The offset boardRect.left or boardRect.top must already have been
\r
4929 * subtracted from x.
\r
4932 EventToSquare(int x)
\r
4939 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4941 x /= (squareSize + lineGap);
\r
4942 if (x >= BOARD_SIZE)
\r
4953 DropEnable dropEnables[] = {
\r
4954 { 'P', DP_Pawn, "Pawn" },
\r
4955 { 'N', DP_Knight, "Knight" },
\r
4956 { 'B', DP_Bishop, "Bishop" },
\r
4957 { 'R', DP_Rook, "Rook" },
\r
4958 { 'Q', DP_Queen, "Queen" },
\r
4962 SetupDropMenu(HMENU hmenu)
\r
4964 int i, count, enable;
\r
4966 extern char white_holding[], black_holding[];
\r
4967 char item[MSG_SIZ];
\r
4969 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4970 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4971 dropEnables[i].piece);
\r
4973 while (p && *p++ == dropEnables[i].piece) count++;
\r
4974 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4975 enable = count > 0 || !appData.testLegality
\r
4976 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4977 && !appData.icsActive);
\r
4978 ModifyMenu(hmenu, dropEnables[i].command,
\r
4979 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4980 dropEnables[i].command, item);
\r
4984 /* Event handler for mouse messages */
\r
4986 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4990 static int recursive = 0;
\r
4992 // BOOLEAN needsRedraw = FALSE;
\r
4993 BOOLEAN saveAnimate;
\r
4994 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4995 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4996 ChessMove moveType;
\r
4999 if (message == WM_MBUTTONUP) {
\r
5000 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5001 to the middle button: we simulate pressing the left button too!
\r
5003 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5004 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5010 pt.x = LOWORD(lParam);
\r
5011 pt.y = HIWORD(lParam);
\r
5012 x = EventToSquare(pt.x - boardRect.left);
\r
5013 y = EventToSquare(pt.y - boardRect.top);
\r
5014 if (!flipView && y >= 0) {
\r
5015 y = BOARD_HEIGHT - 1 - y;
\r
5017 if (flipView && x >= 0) {
\r
5018 x = BOARD_WIDTH - 1 - x;
\r
5021 switch (message) {
\r
5022 case WM_LBUTTONDOWN:
\r
5023 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5024 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5025 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5026 if(gameInfo.holdingsWidth &&
\r
5027 (WhiteOnMove(currentMove)
\r
5028 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5029 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5030 // click in right holdings, for determining promotion piece
\r
5031 ChessSquare p = boards[currentMove][y][x];
\r
5032 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5033 if(p != EmptySquare) {
\r
5034 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5035 fromX = fromY = -1;
\r
5039 DrawPosition(FALSE, boards[currentMove]);
\r
5043 sameAgain = FALSE;
\r
5045 /* Downclick vertically off board; check if on clock */
\r
5046 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5047 if (gameMode == EditPosition) {
\r
5048 SetWhiteToPlayEvent();
\r
5049 } else if (gameMode == IcsPlayingBlack ||
\r
5050 gameMode == MachinePlaysWhite) {
\r
5052 } else if (gameMode == EditGame) {
\r
5053 AdjustClock(flipClock, -1);
\r
5055 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5056 if (gameMode == EditPosition) {
\r
5057 SetBlackToPlayEvent();
\r
5058 } else if (gameMode == IcsPlayingWhite ||
\r
5059 gameMode == MachinePlaysBlack) {
\r
5061 } else if (gameMode == EditGame) {
\r
5062 AdjustClock(!flipClock, -1);
\r
5065 if (!appData.highlightLastMove) {
\r
5066 ClearHighlights();
\r
5067 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5069 fromX = fromY = -1;
\r
5070 dragInfo.start.x = dragInfo.start.y = -1;
\r
5071 dragInfo.from = dragInfo.start;
\r
5073 } else if (x < 0 || y < 0
\r
5074 /* [HGM] block clicks between board and holdings */
\r
5075 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5076 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5077 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5078 /* EditPosition, empty square, or different color piece;
\r
5079 click-click move is possible */
\r
5082 } else if (fromX == x && fromY == y) {
\r
5083 /* Downclick on same square again */
\r
5084 ClearHighlights();
\r
5085 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5086 sameAgain = TRUE;
\r
5087 } else if (fromX != -1 &&
\r
5088 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5090 /* Downclick on different square. */
\r
5091 /* [HGM] if on holdings file, should count as new first click ! */
\r
5092 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5095 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5096 to make sure move is legal before showing promotion popup */
\r
5097 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5098 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5099 fromX = fromY = -1;
\r
5100 ClearHighlights();
\r
5101 DrawPosition(FALSE, boards[currentMove]);
\r
5104 if(moveType != ImpossibleMove) {
\r
5105 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5106 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5107 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5108 appData.alwaysPromoteToQueen)) {
\r
5109 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5110 if (!appData.highlightLastMove) {
\r
5111 ClearHighlights();
\r
5112 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5115 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5116 SetHighlights(fromX, fromY, toX, toY);
\r
5117 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5118 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5119 If promotion to Q is legal, all are legal! */
\r
5120 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5121 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5122 // kludge to temporarily execute move on display, wthout promotng yet
\r
5123 promotionChoice = TRUE;
\r
5124 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5125 boards[currentMove][toY][toX] = p;
\r
5126 DrawPosition(FALSE, boards[currentMove]);
\r
5127 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5128 boards[currentMove][toY][toX] = q;
\r
5130 PromotionPopup(hwnd);
\r
5131 } else { /* not a promotion */
\r
5132 if (appData.animate || appData.highlightLastMove) {
\r
5133 SetHighlights(fromX, fromY, toX, toY);
\r
5135 ClearHighlights();
\r
5137 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5138 fromX = fromY = -1;
\r
5139 if (appData.animate && !appData.highlightLastMove) {
\r
5140 ClearHighlights();
\r
5141 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5147 /* [HGM] it seemed that braces were missing here */
\r
5148 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5149 fromX = fromY = -1;
\r
5153 ClearHighlights();
\r
5154 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5156 /* First downclick, or restart on a square with same color piece */
\r
5157 if (!frozen && OKToStartUserMove(x, y)) {
\r
5160 dragInfo.lastpos = pt;
\r
5161 dragInfo.from.x = fromX;
\r
5162 dragInfo.from.y = fromY;
\r
5163 dragInfo.start = dragInfo.from;
\r
5164 SetCapture(hwndMain);
\r
5166 fromX = fromY = -1;
\r
5167 dragInfo.start.x = dragInfo.start.y = -1;
\r
5168 dragInfo.from = dragInfo.start;
\r
5169 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5173 case WM_LBUTTONUP:
\r
5175 if (fromX == -1) break;
\r
5176 if (x == fromX && y == fromY) {
\r
5177 dragInfo.from.x = dragInfo.from.y = -1;
\r
5178 /* Upclick on same square */
\r
5180 /* Clicked same square twice: abort click-click move */
\r
5181 fromX = fromY = -1;
\r
5183 ClearPremoveHighlights();
\r
5185 /* First square clicked: start click-click move */
\r
5186 SetHighlights(fromX, fromY, -1, -1);
\r
5188 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5189 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5190 /* Errant click; ignore */
\r
5193 /* Finish drag move. */
\r
5194 if (appData.debugMode) {
\r
5195 fprintf(debugFP, "release\n");
\r
5197 dragInfo.from.x = dragInfo.from.y = -1;
\r
5200 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5201 appData.animate = appData.animate && !appData.animateDragging;
\r
5202 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5203 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5204 fromX = fromY = -1;
\r
5205 ClearHighlights();
\r
5206 DrawPosition(FALSE, boards[currentMove]);
\r
5207 appData.animate = saveAnimate;
\r
5210 if(moveType != ImpossibleMove) {
\r
5211 /* [HGM] use move type to determine if move is promotion.
\r
5212 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5213 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5214 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5215 appData.alwaysPromoteToQueen))
\r
5216 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5218 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5219 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5220 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5221 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5222 // kludge to temporarily execute move on display, wthout promotng yet
\r
5223 promotionChoice = TRUE;
\r
5224 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5225 boards[currentMove][toY][toX] = p;
\r
5226 DrawPosition(FALSE, boards[currentMove]);
\r
5227 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5228 boards[currentMove][toY][toX] = q;
\r
5229 appData.animate = saveAnimate;
\r
5232 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5234 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5235 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5236 moveType == WhiteCapturesEnPassant ||
\r
5237 moveType == BlackCapturesEnPassant ) )
\r
5238 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5239 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5242 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5243 appData.animate = saveAnimate;
\r
5244 fromX = fromY = -1;
\r
5245 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5246 ClearHighlights();
\r
5248 if (appData.animate || appData.animateDragging ||
\r
5249 appData.highlightDragging || gotPremove) {
\r
5250 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5253 dragInfo.start.x = dragInfo.start.y = -1;
\r
5254 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5257 case WM_MOUSEMOVE:
\r
5258 if ((appData.animateDragging || appData.highlightDragging)
\r
5259 && (wParam & MK_LBUTTON)
\r
5260 && dragInfo.from.x >= 0)
\r
5262 BOOL full_repaint = FALSE;
\r
5264 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5265 if (appData.animateDragging) {
\r
5266 dragInfo.pos = pt;
\r
5268 if (appData.highlightDragging) {
\r
5269 SetHighlights(fromX, fromY, x, y);
\r
5270 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5271 full_repaint = TRUE;
\r
5275 DrawPosition( full_repaint, NULL);
\r
5277 dragInfo.lastpos = dragInfo.pos;
\r
5281 case WM_MOUSEWHEEL: // [DM]
\r
5282 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5283 /* Mouse Wheel is being rolled forward
\r
5284 * Play moves forward
\r
5286 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5287 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5288 /* Mouse Wheel is being rolled backward
\r
5289 * Play moves backward
\r
5291 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5292 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5296 case WM_MBUTTONDOWN:
\r
5297 case WM_RBUTTONDOWN:
\r
5300 fromX = fromY = -1;
\r
5301 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5302 dragInfo.start.x = dragInfo.start.y = -1;
\r
5303 dragInfo.from = dragInfo.start;
\r
5304 dragInfo.lastpos = dragInfo.pos;
\r
5305 if (appData.highlightDragging) {
\r
5306 ClearHighlights();
\r
5309 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5310 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5311 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5312 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5313 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5316 DrawPosition(TRUE, NULL);
\r
5318 switch (gameMode) {
\r
5319 case EditPosition:
\r
5320 case IcsExamining:
\r
5321 if (x < 0 || y < 0) break;
\r
5324 if (message == WM_MBUTTONDOWN) {
\r
5325 buttonCount = 3; /* even if system didn't think so */
\r
5326 if (wParam & MK_SHIFT)
\r
5327 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5329 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5330 } else { /* message == WM_RBUTTONDOWN */
\r
5332 if (buttonCount == 3) {
\r
5333 if (wParam & MK_SHIFT)
\r
5334 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5336 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5338 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5341 /* Just have one menu, on the right button. Windows users don't
\r
5342 think to try the middle one, and sometimes other software steals
\r
5343 it, or it doesn't really exist. */
\r
5344 if(gameInfo.variant != VariantShogi)
\r
5345 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5347 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5351 case IcsPlayingWhite:
\r
5352 case IcsPlayingBlack:
\r
5354 case MachinePlaysWhite:
\r
5355 case MachinePlaysBlack:
\r
5356 if (appData.testLegality &&
\r
5357 gameInfo.variant != VariantBughouse &&
\r
5358 gameInfo.variant != VariantCrazyhouse) break;
\r
5359 if (x < 0 || y < 0) break;
\r
5362 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5363 SetupDropMenu(hmenu);
\r
5364 MenuPopup(hwnd, pt, hmenu, -1);
\r
5375 /* Preprocess messages for buttons in main window */
\r
5377 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5379 int id = GetWindowLong(hwnd, GWL_ID);
\r
5382 for (i=0; i<N_BUTTONS; i++) {
\r
5383 if (buttonDesc[i].id == id) break;
\r
5385 if (i == N_BUTTONS) return 0;
\r
5386 switch (message) {
\r
5391 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5392 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5399 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5402 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5403 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5404 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5405 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5407 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5409 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5410 PopUpMoveDialog((char)wParam);
\r
5416 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5419 /* Process messages for Promotion dialog box */
\r
5421 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5425 switch (message) {
\r
5426 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5427 /* Center the dialog over the application window */
\r
5428 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5429 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5430 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5431 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5432 SW_SHOW : SW_HIDE);
\r
5433 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5434 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5435 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5436 PieceToChar(WhiteAngel) != '~') ||
\r
5437 (PieceToChar(BlackAngel) >= 'A' &&
\r
5438 PieceToChar(BlackAngel) != '~') ) ?
\r
5439 SW_SHOW : SW_HIDE);
\r
5440 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5441 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5442 PieceToChar(WhiteMarshall) != '~') ||
\r
5443 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5444 PieceToChar(BlackMarshall) != '~') ) ?
\r
5445 SW_SHOW : SW_HIDE);
\r
5446 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5447 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5448 gameInfo.variant != VariantShogi ?
\r
5449 SW_SHOW : SW_HIDE);
\r
5450 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5451 gameInfo.variant != VariantShogi ?
\r
5452 SW_SHOW : SW_HIDE);
\r
5453 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5454 gameInfo.variant == VariantShogi ?
\r
5455 SW_SHOW : SW_HIDE);
\r
5456 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5457 gameInfo.variant == VariantShogi ?
\r
5458 SW_SHOW : SW_HIDE);
\r
5459 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5460 gameInfo.variant == VariantSuper ?
\r
5461 SW_SHOW : SW_HIDE);
\r
5464 case WM_COMMAND: /* message: received a command */
\r
5465 switch (LOWORD(wParam)) {
\r
5467 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5468 ClearHighlights();
\r
5469 DrawPosition(FALSE, NULL);
\r
5472 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5475 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5478 promoChar = PieceToChar(BlackRook);
\r
5481 promoChar = PieceToChar(BlackBishop);
\r
5483 case PB_Chancellor:
\r
5484 promoChar = PieceToChar(BlackMarshall);
\r
5486 case PB_Archbishop:
\r
5487 promoChar = PieceToChar(BlackAngel);
\r
5490 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5495 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5496 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5497 only show the popup when we are already sure the move is valid or
\r
5498 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5499 will figure out it is a promotion from the promoChar. */
\r
5500 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5501 if (!appData.highlightLastMove) {
\r
5502 ClearHighlights();
\r
5503 DrawPosition(FALSE, NULL);
\r
5510 /* Pop up promotion dialog */
\r
5512 PromotionPopup(HWND hwnd)
\r
5516 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5517 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5518 hwnd, (DLGPROC)lpProc);
\r
5519 FreeProcInstance(lpProc);
\r
5522 /* Toggle ShowThinking */
\r
5524 ToggleShowThinking()
\r
5526 appData.showThinking = !appData.showThinking;
\r
5527 ShowThinkingEvent();
\r
5531 LoadGameDialog(HWND hwnd, char* title)
\r
5535 char fileTitle[MSG_SIZ];
\r
5536 f = OpenFileDialog(hwnd, "rb", "",
\r
5537 appData.oldSaveStyle ? "gam" : "pgn",
\r
5539 title, &number, fileTitle, NULL);
\r
5541 cmailMsgLoaded = FALSE;
\r
5542 if (number == 0) {
\r
5543 int error = GameListBuild(f);
\r
5545 DisplayError("Cannot build game list", error);
\r
5546 } else if (!ListEmpty(&gameList) &&
\r
5547 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5548 GameListPopUp(f, fileTitle);
\r
5551 GameListDestroy();
\r
5554 LoadGame(f, number, fileTitle, FALSE);
\r
5559 ChangedConsoleFont()
\r
5562 CHARRANGE tmpsel, sel;
\r
5563 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5564 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5565 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5568 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5569 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5570 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5571 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5572 * size. This was undocumented in the version of MSVC++ that I had
\r
5573 * when I wrote the code, but is apparently documented now.
\r
5575 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5576 cfmt.bCharSet = f->lf.lfCharSet;
\r
5577 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5578 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5579 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5580 /* Why are the following seemingly needed too? */
\r
5581 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5582 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5583 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5585 tmpsel.cpMax = -1; /*999999?*/
\r
5586 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5587 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5588 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5589 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5591 paraf.cbSize = sizeof(paraf);
\r
5592 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5593 paraf.dxStartIndent = 0;
\r
5594 paraf.dxOffset = WRAP_INDENT;
\r
5595 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5596 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5599 /*---------------------------------------------------------------------------*\
\r
5601 * Window Proc for main window
\r
5603 \*---------------------------------------------------------------------------*/
\r
5605 /* Process messages for main window, etc. */
\r
5607 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5610 int wmId, wmEvent;
\r
5614 char fileTitle[MSG_SIZ];
\r
5615 char buf[MSG_SIZ];
\r
5616 static SnapData sd;
\r
5618 switch (message) {
\r
5620 case WM_PAINT: /* message: repaint portion of window */
\r
5624 case WM_ERASEBKGND:
\r
5625 if (IsIconic(hwnd)) {
\r
5626 /* Cheat; change the message */
\r
5627 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5629 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5633 case WM_LBUTTONDOWN:
\r
5634 case WM_MBUTTONDOWN:
\r
5635 case WM_RBUTTONDOWN:
\r
5636 case WM_LBUTTONUP:
\r
5637 case WM_MBUTTONUP:
\r
5638 case WM_RBUTTONUP:
\r
5639 case WM_MOUSEMOVE:
\r
5640 case WM_MOUSEWHEEL:
\r
5641 MouseEvent(hwnd, message, wParam, lParam);
\r
5644 JAWS_KB_NAVIGATION
\r
5648 JAWS_ALT_INTERCEPT
\r
5650 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5651 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5652 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5653 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5655 SendMessage(h, message, wParam, lParam);
\r
5656 } else if(lParam != KF_REPEAT) {
\r
5657 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5658 PopUpMoveDialog((char)wParam);
\r
5659 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5660 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5665 case WM_PALETTECHANGED:
\r
5666 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5668 HDC hdc = GetDC(hwndMain);
\r
5669 SelectPalette(hdc, hPal, TRUE);
\r
5670 nnew = RealizePalette(hdc);
\r
5672 paletteChanged = TRUE;
\r
5674 UpdateColors(hdc);
\r
5676 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5679 ReleaseDC(hwnd, hdc);
\r
5683 case WM_QUERYNEWPALETTE:
\r
5684 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5686 HDC hdc = GetDC(hwndMain);
\r
5687 paletteChanged = FALSE;
\r
5688 SelectPalette(hdc, hPal, FALSE);
\r
5689 nnew = RealizePalette(hdc);
\r
5691 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5693 ReleaseDC(hwnd, hdc);
\r
5698 case WM_COMMAND: /* message: command from application menu */
\r
5699 wmId = LOWORD(wParam);
\r
5700 wmEvent = HIWORD(wParam);
\r
5705 AnalysisPopDown();
\r
5706 SAY("new game enter a move to play against the computer with white");
\r
5709 case IDM_NewGameFRC:
\r
5710 if( NewGameFRC() == 0 ) {
\r
5712 AnalysisPopDown();
\r
5716 case IDM_NewVariant:
\r
5717 NewVariantPopup(hwnd);
\r
5720 case IDM_LoadGame:
\r
5721 LoadGameDialog(hwnd, "Load Game from File");
\r
5724 case IDM_LoadNextGame:
\r
5728 case IDM_LoadPrevGame:
\r
5732 case IDM_ReloadGame:
\r
5736 case IDM_LoadPosition:
\r
5737 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5738 Reset(FALSE, TRUE);
\r
5741 f = OpenFileDialog(hwnd, "rb", "",
\r
5742 appData.oldSaveStyle ? "pos" : "fen",
\r
5744 "Load Position from File", &number, fileTitle, NULL);
\r
5746 LoadPosition(f, number, fileTitle);
\r
5750 case IDM_LoadNextPosition:
\r
5751 ReloadPosition(1);
\r
5754 case IDM_LoadPrevPosition:
\r
5755 ReloadPosition(-1);
\r
5758 case IDM_ReloadPosition:
\r
5759 ReloadPosition(0);
\r
5762 case IDM_SaveGame:
\r
5763 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5764 f = OpenFileDialog(hwnd, "a", defName,
\r
5765 appData.oldSaveStyle ? "gam" : "pgn",
\r
5767 "Save Game to File", NULL, fileTitle, NULL);
\r
5769 SaveGame(f, 0, "");
\r
5773 case IDM_SavePosition:
\r
5774 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5775 f = OpenFileDialog(hwnd, "a", defName,
\r
5776 appData.oldSaveStyle ? "pos" : "fen",
\r
5778 "Save Position to File", NULL, fileTitle, NULL);
\r
5780 SavePosition(f, 0, "");
\r
5784 case IDM_SaveDiagram:
\r
5785 defName = "diagram";
\r
5786 f = OpenFileDialog(hwnd, "wb", defName,
\r
5789 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5795 case IDM_CopyGame:
\r
5796 CopyGameToClipboard();
\r
5799 case IDM_PasteGame:
\r
5800 PasteGameFromClipboard();
\r
5803 case IDM_CopyGameListToClipboard:
\r
5804 CopyGameListToClipboard();
\r
5807 /* [AS] Autodetect FEN or PGN data */
\r
5808 case IDM_PasteAny:
\r
5809 PasteGameOrFENFromClipboard();
\r
5812 /* [AS] Move history */
\r
5813 case IDM_ShowMoveHistory:
\r
5814 if( MoveHistoryIsUp() ) {
\r
5815 MoveHistoryPopDown();
\r
5818 MoveHistoryPopUp();
\r
5822 /* [AS] Eval graph */
\r
5823 case IDM_ShowEvalGraph:
\r
5824 if( EvalGraphIsUp() ) {
\r
5825 EvalGraphPopDown();
\r
5829 SetFocus(hwndMain);
\r
5833 /* [AS] Engine output */
\r
5834 case IDM_ShowEngineOutput:
\r
5835 if( EngineOutputIsUp() ) {
\r
5836 EngineOutputPopDown();
\r
5839 EngineOutputPopUp();
\r
5843 /* [AS] User adjudication */
\r
5844 case IDM_UserAdjudication_White:
\r
5845 UserAdjudicationEvent( +1 );
\r
5848 case IDM_UserAdjudication_Black:
\r
5849 UserAdjudicationEvent( -1 );
\r
5852 case IDM_UserAdjudication_Draw:
\r
5853 UserAdjudicationEvent( 0 );
\r
5856 /* [AS] Game list options dialog */
\r
5857 case IDM_GameListOptions:
\r
5858 GameListOptions();
\r
5861 case IDM_CopyPosition:
\r
5862 CopyFENToClipboard();
\r
5865 case IDM_PastePosition:
\r
5866 PasteFENFromClipboard();
\r
5869 case IDM_MailMove:
\r
5873 case IDM_ReloadCMailMsg:
\r
5874 Reset(TRUE, TRUE);
\r
5875 ReloadCmailMsgEvent(FALSE);
\r
5878 case IDM_Minimize:
\r
5879 ShowWindow(hwnd, SW_MINIMIZE);
\r
5886 case IDM_MachineWhite:
\r
5887 MachineWhiteEvent();
\r
5889 * refresh the tags dialog only if it's visible
\r
5891 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5893 tags = PGNTags(&gameInfo);
\r
5894 TagsPopUp(tags, CmailMsg());
\r
5897 SAY("computer starts playing white");
\r
5900 case IDM_MachineBlack:
\r
5901 MachineBlackEvent();
\r
5903 * refresh the tags dialog only if it's visible
\r
5905 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5907 tags = PGNTags(&gameInfo);
\r
5908 TagsPopUp(tags, CmailMsg());
\r
5911 SAY("computer starts playing black");
\r
5914 case IDM_TwoMachines:
\r
5915 TwoMachinesEvent();
\r
5917 * refresh the tags dialog only if it's visible
\r
5919 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5921 tags = PGNTags(&gameInfo);
\r
5922 TagsPopUp(tags, CmailMsg());
\r
5925 SAY("programs start playing each other");
\r
5928 case IDM_AnalysisMode:
\r
5929 if (!first.analysisSupport) {
\r
5930 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5931 DisplayError(buf, 0);
\r
5933 SAY("analyzing current position");
\r
5934 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5935 if (appData.icsActive) {
\r
5936 if (gameMode != IcsObserving) {
\r
5937 sprintf(buf, "You are not observing a game");
\r
5938 DisplayError(buf, 0);
\r
5939 /* secure check */
\r
5940 if (appData.icsEngineAnalyze) {
\r
5941 if (appData.debugMode)
\r
5942 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5943 ExitAnalyzeMode();
\r
5949 /* if enable, user want disable icsEngineAnalyze */
\r
5950 if (appData.icsEngineAnalyze) {
\r
5951 ExitAnalyzeMode();
\r
5955 appData.icsEngineAnalyze = TRUE;
\r
5956 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5959 if (!appData.showThinking) ToggleShowThinking();
\r
5960 AnalyzeModeEvent();
\r
5964 case IDM_AnalyzeFile:
\r
5965 if (!first.analysisSupport) {
\r
5966 char buf[MSG_SIZ];
\r
5967 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5968 DisplayError(buf, 0);
\r
5970 if (!appData.showThinking) ToggleShowThinking();
\r
5971 AnalyzeFileEvent();
\r
5972 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5973 AnalysisPeriodicEvent(1);
\r
5977 case IDM_IcsClient:
\r
5981 case IDM_EditGame:
\r
5986 case IDM_EditPosition:
\r
5987 EditPositionEvent();
\r
5988 SAY("to set up a position type a FEN");
\r
5991 case IDM_Training:
\r
5995 case IDM_ShowGameList:
\r
5996 ShowGameListProc();
\r
5999 case IDM_EditTags:
\r
6003 case IDM_EditComment:
\r
6004 if (commentDialogUp && editComment) {
\r
6007 EditCommentEvent();
\r
6027 case IDM_CallFlag:
\r
6047 case IDM_StopObserving:
\r
6048 StopObservingEvent();
\r
6051 case IDM_StopExamining:
\r
6052 StopExaminingEvent();
\r
6055 case IDM_TypeInMove:
\r
6056 PopUpMoveDialog('\000');
\r
6059 case IDM_TypeInName:
\r
6060 PopUpNameDialog('\000');
\r
6063 case IDM_Backward:
\r
6065 SetFocus(hwndMain);
\r
6072 SetFocus(hwndMain);
\r
6077 SetFocus(hwndMain);
\r
6082 SetFocus(hwndMain);
\r
6089 case IDM_TruncateGame:
\r
6090 TruncateGameEvent();
\r
6097 case IDM_RetractMove:
\r
6098 RetractMoveEvent();
\r
6101 case IDM_FlipView:
\r
6102 flipView = !flipView;
\r
6103 DrawPosition(FALSE, NULL);
\r
6106 case IDM_FlipClock:
\r
6107 flipClock = !flipClock;
\r
6108 DisplayBothClocks();
\r
6109 DrawPosition(FALSE, NULL);
\r
6112 case IDM_GeneralOptions:
\r
6113 GeneralOptionsPopup(hwnd);
\r
6114 DrawPosition(TRUE, NULL);
\r
6117 case IDM_BoardOptions:
\r
6118 BoardOptionsPopup(hwnd);
\r
6121 case IDM_EnginePlayOptions:
\r
6122 EnginePlayOptionsPopup(hwnd);
\r
6125 case IDM_OptionsUCI:
\r
6126 UciOptionsPopup(hwnd);
\r
6129 case IDM_IcsOptions:
\r
6130 IcsOptionsPopup(hwnd);
\r
6134 FontsOptionsPopup(hwnd);
\r
6138 SoundOptionsPopup(hwnd);
\r
6141 case IDM_CommPort:
\r
6142 CommPortOptionsPopup(hwnd);
\r
6145 case IDM_LoadOptions:
\r
6146 LoadOptionsPopup(hwnd);
\r
6149 case IDM_SaveOptions:
\r
6150 SaveOptionsPopup(hwnd);
\r
6153 case IDM_TimeControl:
\r
6154 TimeControlOptionsPopup(hwnd);
\r
6157 case IDM_SaveSettings:
\r
6158 SaveSettings(settingsFileName);
\r
6161 case IDM_SaveSettingsOnExit:
\r
6162 saveSettingsOnExit = !saveSettingsOnExit;
\r
6163 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6164 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6165 MF_CHECKED : MF_UNCHECKED));
\r
6176 case IDM_AboutGame:
\r
6181 appData.debugMode = !appData.debugMode;
\r
6182 if (appData.debugMode) {
\r
6183 char dir[MSG_SIZ];
\r
6184 GetCurrentDirectory(MSG_SIZ, dir);
\r
6185 SetCurrentDirectory(installDir);
\r
6186 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6187 SetCurrentDirectory(dir);
\r
6188 setbuf(debugFP, NULL);
\r
6195 case IDM_HELPCONTENTS:
\r
6196 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6197 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6198 MessageBox (GetFocus(),
\r
6199 "Unable to activate help",
\r
6200 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6204 case IDM_HELPSEARCH:
\r
6205 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6206 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6207 MessageBox (GetFocus(),
\r
6208 "Unable to activate help",
\r
6209 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6213 case IDM_HELPHELP:
\r
6214 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6215 MessageBox (GetFocus(),
\r
6216 "Unable to activate help",
\r
6217 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6222 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6224 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6225 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6226 FreeProcInstance(lpProc);
\r
6229 case IDM_DirectCommand1:
\r
6230 AskQuestionEvent("Direct Command",
\r
6231 "Send to chess program:", "", "1");
\r
6233 case IDM_DirectCommand2:
\r
6234 AskQuestionEvent("Direct Command",
\r
6235 "Send to second chess program:", "", "2");
\r
6238 case EP_WhitePawn:
\r
6239 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6240 fromX = fromY = -1;
\r
6243 case EP_WhiteKnight:
\r
6244 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6245 fromX = fromY = -1;
\r
6248 case EP_WhiteBishop:
\r
6249 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6250 fromX = fromY = -1;
\r
6253 case EP_WhiteRook:
\r
6254 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6255 fromX = fromY = -1;
\r
6258 case EP_WhiteQueen:
\r
6259 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6260 fromX = fromY = -1;
\r
6263 case EP_WhiteFerz:
\r
6264 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6265 fromX = fromY = -1;
\r
6268 case EP_WhiteWazir:
\r
6269 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6270 fromX = fromY = -1;
\r
6273 case EP_WhiteAlfil:
\r
6274 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6275 fromX = fromY = -1;
\r
6278 case EP_WhiteCannon:
\r
6279 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6280 fromX = fromY = -1;
\r
6283 case EP_WhiteCardinal:
\r
6284 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6285 fromX = fromY = -1;
\r
6288 case EP_WhiteMarshall:
\r
6289 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6290 fromX = fromY = -1;
\r
6293 case EP_WhiteKing:
\r
6294 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6295 fromX = fromY = -1;
\r
6298 case EP_BlackPawn:
\r
6299 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6300 fromX = fromY = -1;
\r
6303 case EP_BlackKnight:
\r
6304 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6305 fromX = fromY = -1;
\r
6308 case EP_BlackBishop:
\r
6309 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6310 fromX = fromY = -1;
\r
6313 case EP_BlackRook:
\r
6314 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6315 fromX = fromY = -1;
\r
6318 case EP_BlackQueen:
\r
6319 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6320 fromX = fromY = -1;
\r
6323 case EP_BlackFerz:
\r
6324 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6325 fromX = fromY = -1;
\r
6328 case EP_BlackWazir:
\r
6329 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6330 fromX = fromY = -1;
\r
6333 case EP_BlackAlfil:
\r
6334 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6335 fromX = fromY = -1;
\r
6338 case EP_BlackCannon:
\r
6339 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6340 fromX = fromY = -1;
\r
6343 case EP_BlackCardinal:
\r
6344 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6345 fromX = fromY = -1;
\r
6348 case EP_BlackMarshall:
\r
6349 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6350 fromX = fromY = -1;
\r
6353 case EP_BlackKing:
\r
6354 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6355 fromX = fromY = -1;
\r
6358 case EP_EmptySquare:
\r
6359 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6360 fromX = fromY = -1;
\r
6363 case EP_ClearBoard:
\r
6364 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6365 fromX = fromY = -1;
\r
6369 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6370 fromX = fromY = -1;
\r
6374 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6375 fromX = fromY = -1;
\r
6379 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6380 fromX = fromY = -1;
\r
6384 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6385 fromX = fromY = -1;
\r
6389 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6390 fromX = fromY = -1;
\r
6394 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6395 fromX = fromY = -1;
\r
6399 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6400 fromX = fromY = -1;
\r
6404 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6405 fromX = fromY = -1;
\r
6409 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6410 fromX = fromY = -1;
\r
6414 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6420 case CLOCK_TIMER_ID:
\r
6421 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6422 clockTimerEvent = 0;
\r
6423 DecrementClocks(); /* call into back end */
\r
6425 case LOAD_GAME_TIMER_ID:
\r
6426 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6427 loadGameTimerEvent = 0;
\r
6428 AutoPlayGameLoop(); /* call into back end */
\r
6430 case ANALYSIS_TIMER_ID:
\r
6431 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6432 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6433 AnalysisPeriodicEvent(0);
\r
6435 KillTimer(hwnd, analysisTimerEvent);
\r
6436 analysisTimerEvent = 0;
\r
6439 case DELAYED_TIMER_ID:
\r
6440 KillTimer(hwnd, delayedTimerEvent);
\r
6441 delayedTimerEvent = 0;
\r
6442 delayedTimerCallback();
\r
6447 case WM_USER_Input:
\r
6448 InputEvent(hwnd, message, wParam, lParam);
\r
6451 /* [AS] Also move "attached" child windows */
\r
6452 case WM_WINDOWPOSCHANGING:
\r
6454 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6455 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6457 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6458 /* Window is moving */
\r
6461 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6462 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6463 rcMain.right = boardX + winWidth;
\r
6464 rcMain.top = boardY;
\r
6465 rcMain.bottom = boardY + winHeight;
\r
6467 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6468 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6469 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6470 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6471 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6478 /* [AS] Snapping */
\r
6479 case WM_ENTERSIZEMOVE:
\r
6480 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6481 if (hwnd == hwndMain) {
\r
6482 doingSizing = TRUE;
\r
6485 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6489 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6490 if (hwnd == hwndMain) {
\r
6491 lastSizing = wParam;
\r
6496 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6497 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6499 case WM_EXITSIZEMOVE:
\r
6500 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6501 if (hwnd == hwndMain) {
\r
6503 doingSizing = FALSE;
\r
6504 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6505 GetClientRect(hwnd, &client);
\r
6506 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6508 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6510 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6513 case WM_DESTROY: /* message: window being destroyed */
\r
6514 PostQuitMessage(0);
\r
6518 if (hwnd == hwndMain) {
\r
6523 default: /* Passes it on if unprocessed */
\r
6524 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6529 /*---------------------------------------------------------------------------*\
\r
6531 * Misc utility routines
\r
6533 \*---------------------------------------------------------------------------*/
\r
6536 * Decent random number generator, at least not as bad as Windows
\r
6537 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6539 unsigned int randstate;
\r
6544 randstate = randstate * 1664525 + 1013904223;
\r
6545 return (int) randstate & 0x7fffffff;
\r
6549 mysrandom(unsigned int seed)
\r
6556 * returns TRUE if user selects a different color, FALSE otherwise
\r
6560 ChangeColor(HWND hwnd, COLORREF *which)
\r
6562 static BOOL firstTime = TRUE;
\r
6563 static DWORD customColors[16];
\r
6565 COLORREF newcolor;
\r
6570 /* Make initial colors in use available as custom colors */
\r
6571 /* Should we put the compiled-in defaults here instead? */
\r
6573 customColors[i++] = lightSquareColor & 0xffffff;
\r
6574 customColors[i++] = darkSquareColor & 0xffffff;
\r
6575 customColors[i++] = whitePieceColor & 0xffffff;
\r
6576 customColors[i++] = blackPieceColor & 0xffffff;
\r
6577 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6578 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6580 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6581 customColors[i++] = textAttribs[ccl].color;
\r
6583 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6584 firstTime = FALSE;
\r
6587 cc.lStructSize = sizeof(cc);
\r
6588 cc.hwndOwner = hwnd;
\r
6589 cc.hInstance = NULL;
\r
6590 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6591 cc.lpCustColors = (LPDWORD) customColors;
\r
6592 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6594 if (!ChooseColor(&cc)) return FALSE;
\r
6596 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6597 if (newcolor == *which) return FALSE;
\r
6598 *which = newcolor;
\r
6602 InitDrawingColors();
\r
6603 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6608 MyLoadSound(MySound *ms)
\r
6614 if (ms->data) free(ms->data);
\r
6617 switch (ms->name[0]) {
\r
6623 /* System sound from Control Panel. Don't preload here. */
\r
6627 if (ms->name[1] == NULLCHAR) {
\r
6628 /* "!" alone = silence */
\r
6631 /* Builtin wave resource. Error if not found. */
\r
6632 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6633 if (h == NULL) break;
\r
6634 ms->data = (void *)LoadResource(hInst, h);
\r
6635 if (h == NULL) break;
\r
6640 /* .wav file. Error if not found. */
\r
6641 f = fopen(ms->name, "rb");
\r
6642 if (f == NULL) break;
\r
6643 if (fstat(fileno(f), &st) < 0) break;
\r
6644 ms->data = malloc(st.st_size);
\r
6645 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6651 char buf[MSG_SIZ];
\r
6652 sprintf(buf, "Error loading sound %s", ms->name);
\r
6653 DisplayError(buf, GetLastError());
\r
6659 MyPlaySound(MySound *ms)
\r
6661 BOOLEAN ok = FALSE;
\r
6662 if(appData.debugMode) fprintf(debugFP, "make sound %s %x %d\n", ms->name, ms, ms->name[0]);
\r
6663 switch (ms->name[0]) {
\r
6665 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6670 /* System sound from Control Panel (deprecated feature).
\r
6671 "$" alone or an unset sound name gets default beep (still in use). */
\r
6672 if (ms->name[1]) {
\r
6673 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6675 if (!ok) ok = MessageBeep(MB_OK);
\r
6678 /* Builtin wave resource, or "!" alone for silence */
\r
6679 if (ms->name[1]) {
\r
6680 if (ms->data == NULL) return FALSE;
\r
6681 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6687 /* .wav file. Error if not found. */
\r
6688 if (ms->data == NULL) return FALSE;
\r
6689 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6692 /* Don't print an error: this can happen innocently if the sound driver
\r
6693 is busy; for instance, if another instance of WinBoard is playing
\r
6694 a sound at about the same time. */
\r
6697 char buf[MSG_SIZ];
\r
6698 sprintf(buf, "Error playing sound %s", ms->name);
\r
6699 DisplayError(buf, GetLastError());
\r
6707 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6710 OPENFILENAME *ofn;
\r
6711 static UINT *number; /* gross that this is static */
\r
6713 switch (message) {
\r
6714 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6715 /* Center the dialog over the application window */
\r
6716 ofn = (OPENFILENAME *) lParam;
\r
6717 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6718 number = (UINT *) ofn->lCustData;
\r
6719 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6723 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6724 return FALSE; /* Allow for further processing */
\r
6727 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6728 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6730 return FALSE; /* Allow for further processing */
\r
6736 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6738 static UINT *number;
\r
6739 OPENFILENAME *ofname;
\r
6742 case WM_INITDIALOG:
\r
6743 ofname = (OPENFILENAME *)lParam;
\r
6744 number = (UINT *)(ofname->lCustData);
\r
6747 ofnot = (OFNOTIFY *)lParam;
\r
6748 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6749 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6758 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6759 char *nameFilt, char *dlgTitle, UINT *number,
\r
6760 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6762 OPENFILENAME openFileName;
\r
6763 char buf1[MSG_SIZ];
\r
6766 if (fileName == NULL) fileName = buf1;
\r
6767 if (defName == NULL) {
\r
6768 strcpy(fileName, "*.");
\r
6769 strcat(fileName, defExt);
\r
6771 strcpy(fileName, defName);
\r
6773 if (fileTitle) strcpy(fileTitle, "");
\r
6774 if (number) *number = 0;
\r
6776 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6777 openFileName.hwndOwner = hwnd;
\r
6778 openFileName.hInstance = (HANDLE) hInst;
\r
6779 openFileName.lpstrFilter = nameFilt;
\r
6780 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6781 openFileName.nMaxCustFilter = 0L;
\r
6782 openFileName.nFilterIndex = 1L;
\r
6783 openFileName.lpstrFile = fileName;
\r
6784 openFileName.nMaxFile = MSG_SIZ;
\r
6785 openFileName.lpstrFileTitle = fileTitle;
\r
6786 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6787 openFileName.lpstrInitialDir = NULL;
\r
6788 openFileName.lpstrTitle = dlgTitle;
\r
6789 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6790 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6791 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6792 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6793 openFileName.nFileOffset = 0;
\r
6794 openFileName.nFileExtension = 0;
\r
6795 openFileName.lpstrDefExt = defExt;
\r
6796 openFileName.lCustData = (LONG) number;
\r
6797 openFileName.lpfnHook = oldDialog ?
\r
6798 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6799 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6801 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6802 GetOpenFileName(&openFileName)) {
\r
6803 /* open the file */
\r
6804 f = fopen(openFileName.lpstrFile, write);
\r
6806 MessageBox(hwnd, "File open failed", NULL,
\r
6807 MB_OK|MB_ICONEXCLAMATION);
\r
6811 int err = CommDlgExtendedError();
\r
6812 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6821 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6823 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6826 * Get the first pop-up menu in the menu template. This is the
\r
6827 * menu that TrackPopupMenu displays.
\r
6829 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6831 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6834 * TrackPopup uses screen coordinates, so convert the
\r
6835 * coordinates of the mouse click to screen coordinates.
\r
6837 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6839 /* Draw and track the floating pop-up menu. */
\r
6840 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6841 pt.x, pt.y, 0, hwnd, NULL);
\r
6843 /* Destroy the menu.*/
\r
6844 DestroyMenu(hmenu);
\r
6849 int sizeX, sizeY, newSizeX, newSizeY;
\r
6851 } ResizeEditPlusButtonsClosure;
\r
6854 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6856 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6860 if (hChild == cl->hText) return TRUE;
\r
6861 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6862 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6863 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6864 ScreenToClient(cl->hDlg, &pt);
\r
6865 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6866 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6870 /* Resize a dialog that has a (rich) edit field filling most of
\r
6871 the top, with a row of buttons below */
\r
6873 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6876 int newTextHeight, newTextWidth;
\r
6877 ResizeEditPlusButtonsClosure cl;
\r
6879 /*if (IsIconic(hDlg)) return;*/
\r
6880 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6882 cl.hdwp = BeginDeferWindowPos(8);
\r
6884 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6885 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6886 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6887 if (newTextHeight < 0) {
\r
6888 newSizeY += -newTextHeight;
\r
6889 newTextHeight = 0;
\r
6891 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6892 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6898 cl.newSizeX = newSizeX;
\r
6899 cl.newSizeY = newSizeY;
\r
6900 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6902 EndDeferWindowPos(cl.hdwp);
\r
6905 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6907 RECT rChild, rParent;
\r
6908 int wChild, hChild, wParent, hParent;
\r
6909 int wScreen, hScreen, xNew, yNew;
\r
6912 /* Get the Height and Width of the child window */
\r
6913 GetWindowRect (hwndChild, &rChild);
\r
6914 wChild = rChild.right - rChild.left;
\r
6915 hChild = rChild.bottom - rChild.top;
\r
6917 /* Get the Height and Width of the parent window */
\r
6918 GetWindowRect (hwndParent, &rParent);
\r
6919 wParent = rParent.right - rParent.left;
\r
6920 hParent = rParent.bottom - rParent.top;
\r
6922 /* Get the display limits */
\r
6923 hdc = GetDC (hwndChild);
\r
6924 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6925 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6926 ReleaseDC(hwndChild, hdc);
\r
6928 /* Calculate new X position, then adjust for screen */
\r
6929 xNew = rParent.left + ((wParent - wChild) /2);
\r
6932 } else if ((xNew+wChild) > wScreen) {
\r
6933 xNew = wScreen - wChild;
\r
6936 /* Calculate new Y position, then adjust for screen */
\r
6938 yNew = rParent.top + ((hParent - hChild) /2);
\r
6941 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6946 } else if ((yNew+hChild) > hScreen) {
\r
6947 yNew = hScreen - hChild;
\r
6950 /* Set it, and return */
\r
6951 return SetWindowPos (hwndChild, NULL,
\r
6952 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6955 /* Center one window over another */
\r
6956 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6958 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6961 /*---------------------------------------------------------------------------*\
\r
6963 * Startup Dialog functions
\r
6965 \*---------------------------------------------------------------------------*/
\r
6967 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6969 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6971 while (*cd != NULL) {
\r
6972 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6978 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6980 char buf1[ARG_MAX];
\r
6983 if (str[0] == '@') {
\r
6984 FILE* f = fopen(str + 1, "r");
\r
6986 DisplayFatalError(str + 1, errno, 2);
\r
6989 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6991 buf1[len] = NULLCHAR;
\r
6995 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6998 char buf[MSG_SIZ];
\r
6999 char *end = strchr(str, '\n');
\r
7000 if (end == NULL) return;
\r
7001 memcpy(buf, str, end - str);
\r
7002 buf[end - str] = NULLCHAR;
\r
7003 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7009 SetStartupDialogEnables(HWND hDlg)
\r
7011 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7012 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7013 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7014 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7015 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7016 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7017 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7018 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7019 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7020 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7021 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7022 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7023 IsDlgButtonChecked(hDlg, OPT_View));
\r
7027 QuoteForFilename(char *filename)
\r
7029 int dquote, space;
\r
7030 dquote = strchr(filename, '"') != NULL;
\r
7031 space = strchr(filename, ' ') != NULL;
\r
7032 if (dquote || space) {
\r
7044 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7046 char buf[MSG_SIZ];
\r
7049 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7050 q = QuoteForFilename(nthcp);
\r
7051 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7052 if (*nthdir != NULLCHAR) {
\r
7053 q = QuoteForFilename(nthdir);
\r
7054 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7056 if (*nthcp == NULLCHAR) {
\r
7057 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7058 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7059 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7060 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7065 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7067 char buf[MSG_SIZ];
\r
7071 switch (message) {
\r
7072 case WM_INITDIALOG:
\r
7073 /* Center the dialog */
\r
7074 CenterWindow (hDlg, GetDesktopWindow());
\r
7075 /* Initialize the dialog items */
\r
7076 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7077 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7078 firstChessProgramNames);
\r
7079 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7080 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7081 secondChessProgramNames);
\r
7082 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7083 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7084 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7085 if (*appData.icsHelper != NULLCHAR) {
\r
7086 char *q = QuoteForFilename(appData.icsHelper);
\r
7087 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7089 if (*appData.icsHost == NULLCHAR) {
\r
7090 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7091 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7092 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7093 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7094 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7097 if (appData.icsActive) {
\r
7098 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7100 else if (appData.noChessProgram) {
\r
7101 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7104 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7107 SetStartupDialogEnables(hDlg);
\r
7111 switch (LOWORD(wParam)) {
\r
7113 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7114 strcpy(buf, "/fcp=");
\r
7115 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7117 ParseArgs(StringGet, &p);
\r
7118 strcpy(buf, "/scp=");
\r
7119 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7121 ParseArgs(StringGet, &p);
\r
7122 appData.noChessProgram = FALSE;
\r
7123 appData.icsActive = FALSE;
\r
7124 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7125 strcpy(buf, "/ics /icshost=");
\r
7126 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7128 ParseArgs(StringGet, &p);
\r
7129 if (appData.zippyPlay) {
\r
7130 strcpy(buf, "/fcp=");
\r
7131 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7133 ParseArgs(StringGet, &p);
\r
7135 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7136 appData.noChessProgram = TRUE;
\r
7137 appData.icsActive = FALSE;
\r
7139 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7140 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7143 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7144 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7146 ParseArgs(StringGet, &p);
\r
7148 EndDialog(hDlg, TRUE);
\r
7155 case IDM_HELPCONTENTS:
\r
7156 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7157 MessageBox (GetFocus(),
\r
7158 "Unable to activate help",
\r
7159 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7164 SetStartupDialogEnables(hDlg);
\r
7172 /*---------------------------------------------------------------------------*\
\r
7174 * About box dialog functions
\r
7176 \*---------------------------------------------------------------------------*/
\r
7178 /* Process messages for "About" dialog box */
\r
7180 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7182 switch (message) {
\r
7183 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7184 /* Center the dialog over the application window */
\r
7185 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7186 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7189 case WM_COMMAND: /* message: received a command */
\r
7190 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7191 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7192 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7200 /*---------------------------------------------------------------------------*\
\r
7202 * Comment Dialog functions
\r
7204 \*---------------------------------------------------------------------------*/
\r
7207 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7209 static HANDLE hwndText = NULL;
\r
7210 int len, newSizeX, newSizeY, flags;
\r
7211 static int sizeX, sizeY;
\r
7216 switch (message) {
\r
7217 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7218 /* Initialize the dialog items */
\r
7219 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7220 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7221 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7222 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7223 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7224 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7225 SetWindowText(hDlg, commentTitle);
\r
7226 if (editComment) {
\r
7227 SetFocus(hwndText);
\r
7229 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7231 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7232 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7233 MAKELPARAM(FALSE, 0));
\r
7234 /* Size and position the dialog */
\r
7235 if (!commentDialog) {
\r
7236 commentDialog = hDlg;
\r
7237 flags = SWP_NOZORDER;
\r
7238 GetClientRect(hDlg, &rect);
\r
7239 sizeX = rect.right;
\r
7240 sizeY = rect.bottom;
\r
7241 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7242 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7243 WINDOWPLACEMENT wp;
\r
7244 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7245 wp.length = sizeof(WINDOWPLACEMENT);
\r
7247 wp.showCmd = SW_SHOW;
\r
7248 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7249 wp.rcNormalPosition.left = commentX;
\r
7250 wp.rcNormalPosition.right = commentX + commentW;
\r
7251 wp.rcNormalPosition.top = commentY;
\r
7252 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7253 SetWindowPlacement(hDlg, &wp);
\r
7255 GetClientRect(hDlg, &rect);
\r
7256 newSizeX = rect.right;
\r
7257 newSizeY = rect.bottom;
\r
7258 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7259 newSizeX, newSizeY);
\r
7266 case WM_COMMAND: /* message: received a command */
\r
7267 switch (LOWORD(wParam)) {
\r
7269 if (editComment) {
\r
7271 /* Read changed options from the dialog box */
\r
7272 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7273 len = GetWindowTextLength(hwndText);
\r
7274 str = (char *) malloc(len + 1);
\r
7275 GetWindowText(hwndText, str, len + 1);
\r
7284 ReplaceComment(commentIndex, str);
\r
7291 case OPT_CancelComment:
\r
7295 case OPT_ClearComment:
\r
7296 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7299 case OPT_EditComment:
\r
7300 EditCommentEvent();
\r
7309 newSizeX = LOWORD(lParam);
\r
7310 newSizeY = HIWORD(lParam);
\r
7311 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7316 case WM_GETMINMAXINFO:
\r
7317 /* Prevent resizing window too small */
\r
7318 mmi = (MINMAXINFO *) lParam;
\r
7319 mmi->ptMinTrackSize.x = 100;
\r
7320 mmi->ptMinTrackSize.y = 100;
\r
7327 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7332 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7334 if (str == NULL) str = "";
\r
7335 p = (char *) malloc(2 * strlen(str) + 2);
\r
7338 if (*str == '\n') *q++ = '\r';
\r
7342 if (commentText != NULL) free(commentText);
\r
7344 commentIndex = index;
\r
7345 commentTitle = title;
\r
7347 editComment = edit;
\r
7349 if (commentDialog) {
\r
7350 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7351 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7353 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7354 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7355 hwndMain, (DLGPROC)lpProc);
\r
7356 FreeProcInstance(lpProc);
\r
7358 commentDialogUp = TRUE;
\r
7362 /*---------------------------------------------------------------------------*\
\r
7364 * Type-in move dialog functions
\r
7366 \*---------------------------------------------------------------------------*/
\r
7369 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7371 char move[MSG_SIZ];
\r
7373 ChessMove moveType;
\r
7374 int fromX, fromY, toX, toY;
\r
7377 switch (message) {
\r
7378 case WM_INITDIALOG:
\r
7379 move[0] = (char) lParam;
\r
7380 move[1] = NULLCHAR;
\r
7381 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7382 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7383 SetWindowText(hInput, move);
\r
7385 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7389 switch (LOWORD(wParam)) {
\r
7391 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7392 { int n; Board board;
\r
7394 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7395 EditPositionPasteFEN(move);
\r
7396 EndDialog(hDlg, TRUE);
\r
7399 // [HGM] movenum: allow move number to be typed in any mode
\r
7400 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7401 currentMove = 2*n-1;
\r
7402 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7403 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7404 EndDialog(hDlg, TRUE);
\r
7405 DrawPosition(TRUE, boards[currentMove]);
\r
7406 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7407 else DisplayMessage("", "");
\r
7411 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7412 gameMode != Training) {
\r
7413 DisplayMoveError("Displayed move is not current");
\r
7415 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7416 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7417 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7418 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7419 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7420 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7421 if (gameMode != Training)
\r
7422 forwardMostMove = currentMove;
\r
7423 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7425 DisplayMoveError("Could not parse move");
\r
7428 EndDialog(hDlg, TRUE);
\r
7431 EndDialog(hDlg, FALSE);
\r
7442 PopUpMoveDialog(char firstchar)
\r
7446 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7447 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7448 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7449 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7450 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7451 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7452 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7453 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7454 gameMode == Training) {
\r
7455 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7456 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7457 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7458 FreeProcInstance(lpProc);
\r
7462 /*---------------------------------------------------------------------------*\
\r
7464 * Type-in name dialog functions
\r
7466 \*---------------------------------------------------------------------------*/
\r
7469 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7471 char move[MSG_SIZ];
\r
7474 switch (message) {
\r
7475 case WM_INITDIALOG:
\r
7476 move[0] = (char) lParam;
\r
7477 move[1] = NULLCHAR;
\r
7478 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7479 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7480 SetWindowText(hInput, move);
\r
7482 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7486 switch (LOWORD(wParam)) {
\r
7488 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7489 appData.userName = strdup(move);
\r
7492 EndDialog(hDlg, TRUE);
\r
7495 EndDialog(hDlg, FALSE);
\r
7506 PopUpNameDialog(char firstchar)
\r
7510 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7511 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7512 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7513 FreeProcInstance(lpProc);
\r
7516 /*---------------------------------------------------------------------------*\
\r
7520 \*---------------------------------------------------------------------------*/
\r
7522 /* Nonmodal error box */
\r
7523 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7524 WPARAM wParam, LPARAM lParam);
\r
7527 ErrorPopUp(char *title, char *content)
\r
7531 BOOLEAN modal = hwndMain == NULL;
\r
7549 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7550 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7553 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7555 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7556 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7557 hwndMain, (DLGPROC)lpProc);
\r
7558 FreeProcInstance(lpProc);
\r
7565 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7566 if (errorDialog == NULL) return;
\r
7567 DestroyWindow(errorDialog);
\r
7568 errorDialog = NULL;
\r
7572 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7577 switch (message) {
\r
7578 case WM_INITDIALOG:
\r
7579 GetWindowRect(hDlg, &rChild);
\r
7582 SetWindowPos(hDlg, NULL, rChild.left,
\r
7583 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7584 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7588 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7589 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7590 and it doesn't work when you resize the dialog.
\r
7591 For now, just give it a default position.
\r
7593 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7595 errorDialog = hDlg;
\r
7596 SetWindowText(hDlg, errorTitle);
\r
7597 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7598 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7602 switch (LOWORD(wParam)) {
\r
7605 if (errorDialog == hDlg) errorDialog = NULL;
\r
7606 DestroyWindow(hDlg);
\r
7618 HWND gothicDialog = NULL;
\r
7621 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7625 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7627 switch (message) {
\r
7628 case WM_INITDIALOG:
\r
7629 GetWindowRect(hDlg, &rChild);
\r
7631 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7635 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7636 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7637 and it doesn't work when you resize the dialog.
\r
7638 For now, just give it a default position.
\r
7640 gothicDialog = hDlg;
\r
7641 SetWindowText(hDlg, errorTitle);
\r
7642 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7643 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7647 switch (LOWORD(wParam)) {
\r
7650 if (errorDialog == hDlg) errorDialog = NULL;
\r
7651 DestroyWindow(hDlg);
\r
7663 GothicPopUp(char *title, VariantClass variant)
\r
7666 static char *lastTitle;
\r
7668 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7669 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7671 if(lastTitle != title && gothicDialog != NULL) {
\r
7672 DestroyWindow(gothicDialog);
\r
7673 gothicDialog = NULL;
\r
7675 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7676 title = lastTitle;
\r
7677 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7678 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7679 hwndMain, (DLGPROC)lpProc);
\r
7680 FreeProcInstance(lpProc);
\r
7685 /*---------------------------------------------------------------------------*\
\r
7687 * Ics Interaction console functions
\r
7689 \*---------------------------------------------------------------------------*/
\r
7691 #define HISTORY_SIZE 64
\r
7692 static char *history[HISTORY_SIZE];
\r
7693 int histIn = 0, histP = 0;
\r
7696 SaveInHistory(char *cmd)
\r
7698 if (history[histIn] != NULL) {
\r
7699 free(history[histIn]);
\r
7700 history[histIn] = NULL;
\r
7702 if (*cmd == NULLCHAR) return;
\r
7703 history[histIn] = StrSave(cmd);
\r
7704 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7705 if (history[histIn] != NULL) {
\r
7706 free(history[histIn]);
\r
7707 history[histIn] = NULL;
\r
7713 PrevInHistory(char *cmd)
\r
7716 if (histP == histIn) {
\r
7717 if (history[histIn] != NULL) free(history[histIn]);
\r
7718 history[histIn] = StrSave(cmd);
\r
7720 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7721 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7723 return history[histP];
\r
7729 if (histP == histIn) return NULL;
\r
7730 histP = (histP + 1) % HISTORY_SIZE;
\r
7731 return history[histP];
\r
7738 BOOLEAN immediate;
\r
7739 } IcsTextMenuEntry;
\r
7740 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7741 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7744 ParseIcsTextMenu(char *icsTextMenuString)
\r
7747 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7748 char *p = icsTextMenuString;
\r
7749 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7752 if (e->command != NULL) {
\r
7754 e->command = NULL;
\r
7758 e = icsTextMenuEntry;
\r
7759 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7760 if (*p == ';' || *p == '\n') {
\r
7761 e->item = strdup("-");
\r
7762 e->command = NULL;
\r
7764 } else if (*p == '-') {
\r
7765 e->item = strdup("-");
\r
7766 e->command = NULL;
\r
7770 char *q, *r, *s, *t;
\r
7772 q = strchr(p, ',');
\r
7773 if (q == NULL) break;
\r
7775 r = strchr(q + 1, ',');
\r
7776 if (r == NULL) break;
\r
7778 s = strchr(r + 1, ',');
\r
7779 if (s == NULL) break;
\r
7782 t = strchr(s + 1, c);
\r
7785 t = strchr(s + 1, c);
\r
7787 if (t != NULL) *t = NULLCHAR;
\r
7788 e->item = strdup(p);
\r
7789 e->command = strdup(q + 1);
\r
7790 e->getname = *(r + 1) != '0';
\r
7791 e->immediate = *(s + 1) != '0';
\r
7795 if (t == NULL) break;
\r
7804 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7808 hmenu = LoadMenu(hInst, "TextMenu");
\r
7809 h = GetSubMenu(hmenu, 0);
\r
7811 if (strcmp(e->item, "-") == 0) {
\r
7812 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7814 if (e->item[0] == '|') {
\r
7815 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7816 IDM_CommandX + i, &e->item[1]);
\r
7818 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7827 WNDPROC consoleTextWindowProc;
\r
7830 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7832 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7833 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7837 SetWindowText(hInput, command);
\r
7839 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7841 sel.cpMin = 999999;
\r
7842 sel.cpMax = 999999;
\r
7843 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7848 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7849 if (sel.cpMin == sel.cpMax) {
\r
7850 /* Expand to surrounding word */
\r
7853 tr.chrg.cpMax = sel.cpMin;
\r
7854 tr.chrg.cpMin = --sel.cpMin;
\r
7855 if (sel.cpMin < 0) break;
\r
7856 tr.lpstrText = name;
\r
7857 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7858 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7862 tr.chrg.cpMin = sel.cpMax;
\r
7863 tr.chrg.cpMax = ++sel.cpMax;
\r
7864 tr.lpstrText = name;
\r
7865 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7866 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7869 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7870 MessageBeep(MB_ICONEXCLAMATION);
\r
7874 tr.lpstrText = name;
\r
7875 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7877 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7878 MessageBeep(MB_ICONEXCLAMATION);
\r
7881 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7884 sprintf(buf, "%s %s", command, name);
\r
7885 SetWindowText(hInput, buf);
\r
7886 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7888 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7889 SetWindowText(hInput, buf);
\r
7890 sel.cpMin = 999999;
\r
7891 sel.cpMax = 999999;
\r
7892 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7898 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7903 switch (message) {
\r
7905 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7908 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7911 sel.cpMin = 999999;
\r
7912 sel.cpMax = 999999;
\r
7913 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7914 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7919 if(wParam != '\022') {
\r
7920 if (wParam == '\t') {
\r
7921 if (GetKeyState(VK_SHIFT) < 0) {
\r
7923 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7924 if (buttonDesc[0].hwnd) {
\r
7925 SetFocus(buttonDesc[0].hwnd);
\r
7927 SetFocus(hwndMain);
\r
7931 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7934 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7935 JAWS_DELETE( SetFocus(hInput); )
\r
7936 SendMessage(hInput, message, wParam, lParam);
\r
7939 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7940 case WM_RBUTTONUP:
\r
7941 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7942 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7943 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7946 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7947 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7948 if (sel.cpMin == sel.cpMax) {
\r
7949 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7950 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7952 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7953 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7955 pt.x = LOWORD(lParam);
\r
7956 pt.y = HIWORD(lParam);
\r
7957 MenuPopup(hwnd, pt, hmenu, -1);
\r
7961 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7963 return SendMessage(hInput, message, wParam, lParam);
\r
7964 case WM_MBUTTONDOWN:
\r
7965 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7966 case WM_RBUTTONDOWN:
\r
7967 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7968 /* Move selection here if it was empty */
\r
7970 pt.x = LOWORD(lParam);
\r
7971 pt.y = HIWORD(lParam);
\r
7972 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7973 if (sel.cpMin == sel.cpMax) {
\r
7974 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7975 sel.cpMax = sel.cpMin;
\r
7976 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7978 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7982 switch (LOWORD(wParam)) {
\r
7983 case IDM_QuickPaste:
\r
7985 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7986 if (sel.cpMin == sel.cpMax) {
\r
7987 MessageBeep(MB_ICONEXCLAMATION);
\r
7990 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7991 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7992 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7997 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8000 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8003 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8007 int i = LOWORD(wParam) - IDM_CommandX;
\r
8008 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8009 icsTextMenuEntry[i].command != NULL) {
\r
8010 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8011 icsTextMenuEntry[i].getname,
\r
8012 icsTextMenuEntry[i].immediate);
\r
8020 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8023 WNDPROC consoleInputWindowProc;
\r
8026 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8028 char buf[MSG_SIZ];
\r
8030 static BOOL sendNextChar = FALSE;
\r
8031 static BOOL quoteNextChar = FALSE;
\r
8032 InputSource *is = consoleInputSource;
\r
8036 switch (message) {
\r
8038 if (!appData.localLineEditing || sendNextChar) {
\r
8039 is->buf[0] = (CHAR) wParam;
\r
8041 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8042 sendNextChar = FALSE;
\r
8045 if (quoteNextChar) {
\r
8046 buf[0] = (char) wParam;
\r
8047 buf[1] = NULLCHAR;
\r
8048 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8049 quoteNextChar = FALSE;
\r
8053 case '\r': /* Enter key */
\r
8054 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8055 if (consoleEcho) SaveInHistory(is->buf);
\r
8056 is->buf[is->count++] = '\n';
\r
8057 is->buf[is->count] = NULLCHAR;
\r
8058 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8059 if (consoleEcho) {
\r
8060 ConsoleOutput(is->buf, is->count, TRUE);
\r
8061 } else if (appData.localLineEditing) {
\r
8062 ConsoleOutput("\n", 1, TRUE);
\r
8065 case '\033': /* Escape key */
\r
8066 SetWindowText(hwnd, "");
\r
8067 cf.cbSize = sizeof(CHARFORMAT);
\r
8068 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8069 if (consoleEcho) {
\r
8070 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8072 cf.crTextColor = COLOR_ECHOOFF;
\r
8074 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8075 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8077 case '\t': /* Tab key */
\r
8078 if (GetKeyState(VK_SHIFT) < 0) {
\r
8080 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8083 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8084 if (buttonDesc[0].hwnd) {
\r
8085 SetFocus(buttonDesc[0].hwnd);
\r
8087 SetFocus(hwndMain);
\r
8091 case '\023': /* Ctrl+S */
\r
8092 sendNextChar = TRUE;
\r
8094 case '\021': /* Ctrl+Q */
\r
8095 quoteNextChar = TRUE;
\r
8105 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8106 p = PrevInHistory(buf);
\r
8108 SetWindowText(hwnd, p);
\r
8109 sel.cpMin = 999999;
\r
8110 sel.cpMax = 999999;
\r
8111 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8116 p = NextInHistory();
\r
8118 SetWindowText(hwnd, p);
\r
8119 sel.cpMin = 999999;
\r
8120 sel.cpMax = 999999;
\r
8121 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8127 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8131 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8135 case WM_MBUTTONDOWN:
\r
8136 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8137 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8139 case WM_RBUTTONUP:
\r
8140 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8141 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8142 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8146 hmenu = LoadMenu(hInst, "InputMenu");
\r
8147 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8148 if (sel.cpMin == sel.cpMax) {
\r
8149 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8150 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8152 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8153 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8155 pt.x = LOWORD(lParam);
\r
8156 pt.y = HIWORD(lParam);
\r
8157 MenuPopup(hwnd, pt, hmenu, -1);
\r
8161 switch (LOWORD(wParam)) {
\r
8163 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8165 case IDM_SelectAll:
\r
8167 sel.cpMax = -1; /*999999?*/
\r
8168 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8171 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8174 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8177 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8182 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8185 #define CO_MAX 100000
\r
8186 #define CO_TRIM 1000
\r
8189 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8191 static SnapData sd;
\r
8192 static HWND hText, hInput /*, hFocus*/;
\r
8193 // InputSource *is = consoleInputSource;
\r
8195 static int sizeX, sizeY;
\r
8196 int newSizeX, newSizeY;
\r
8199 switch (message) {
\r
8200 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8201 hwndConsole = hDlg;
\r
8202 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8203 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8205 consoleTextWindowProc = (WNDPROC)
\r
8206 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8207 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8208 consoleInputWindowProc = (WNDPROC)
\r
8209 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8210 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8211 Colorize(ColorNormal, TRUE);
\r
8212 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8213 ChangedConsoleFont();
\r
8214 GetClientRect(hDlg, &rect);
\r
8215 sizeX = rect.right;
\r
8216 sizeY = rect.bottom;
\r
8217 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8218 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8219 WINDOWPLACEMENT wp;
\r
8220 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8221 wp.length = sizeof(WINDOWPLACEMENT);
\r
8223 wp.showCmd = SW_SHOW;
\r
8224 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8225 wp.rcNormalPosition.left = wpConsole.x;
\r
8226 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8227 wp.rcNormalPosition.top = wpConsole.y;
\r
8228 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8229 SetWindowPlacement(hDlg, &wp);
\r
8232 // [HGM] Chessknight's change 2004-07-13
\r
8233 else { /* Determine Defaults */
\r
8234 WINDOWPLACEMENT wp;
\r
8235 wpConsole.x = winWidth + 1;
\r
8236 wpConsole.y = boardY;
\r
8237 wpConsole.width = screenWidth - winWidth;
\r
8238 wpConsole.height = winHeight;
\r
8239 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8240 wp.length = sizeof(WINDOWPLACEMENT);
\r
8242 wp.showCmd = SW_SHOW;
\r
8243 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8244 wp.rcNormalPosition.left = wpConsole.x;
\r
8245 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8246 wp.rcNormalPosition.top = wpConsole.y;
\r
8247 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8248 SetWindowPlacement(hDlg, &wp);
\r
8263 if (IsIconic(hDlg)) break;
\r
8264 newSizeX = LOWORD(lParam);
\r
8265 newSizeY = HIWORD(lParam);
\r
8266 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8267 RECT rectText, rectInput;
\r
8269 int newTextHeight, newTextWidth;
\r
8270 GetWindowRect(hText, &rectText);
\r
8271 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8272 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8273 if (newTextHeight < 0) {
\r
8274 newSizeY += -newTextHeight;
\r
8275 newTextHeight = 0;
\r
8277 SetWindowPos(hText, NULL, 0, 0,
\r
8278 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8279 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8280 pt.x = rectInput.left;
\r
8281 pt.y = rectInput.top + newSizeY - sizeY;
\r
8282 ScreenToClient(hDlg, &pt);
\r
8283 SetWindowPos(hInput, NULL,
\r
8284 pt.x, pt.y, /* needs client coords */
\r
8285 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8286 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8292 case WM_GETMINMAXINFO:
\r
8293 /* Prevent resizing window too small */
\r
8294 mmi = (MINMAXINFO *) lParam;
\r
8295 mmi->ptMinTrackSize.x = 100;
\r
8296 mmi->ptMinTrackSize.y = 100;
\r
8299 /* [AS] Snapping */
\r
8300 case WM_ENTERSIZEMOVE:
\r
8301 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8304 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8307 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8309 case WM_EXITSIZEMOVE:
\r
8310 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8313 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8321 if (hwndConsole) return;
\r
8322 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8323 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8328 ConsoleOutput(char* data, int length, int forceVisible)
\r
8333 char buf[CO_MAX+1];
\r
8336 static int delayLF = 0;
\r
8337 CHARRANGE savesel, sel;
\r
8339 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8347 while (length--) {
\r
8355 } else if (*p == '\007') {
\r
8356 MyPlaySound(&sounds[(int)SoundBell]);
\r
8363 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8364 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8365 /* Save current selection */
\r
8366 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8367 exlen = GetWindowTextLength(hText);
\r
8368 /* Find out whether current end of text is visible */
\r
8369 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8370 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8371 /* Trim existing text if it's too long */
\r
8372 if (exlen + (q - buf) > CO_MAX) {
\r
8373 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8376 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8377 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8379 savesel.cpMin -= trim;
\r
8380 savesel.cpMax -= trim;
\r
8381 if (exlen < 0) exlen = 0;
\r
8382 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8383 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8385 /* Append the new text */
\r
8386 sel.cpMin = exlen;
\r
8387 sel.cpMax = exlen;
\r
8388 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8389 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8390 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8391 if (forceVisible || exlen == 0 ||
\r
8392 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8393 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8394 /* Scroll to make new end of text visible if old end of text
\r
8395 was visible or new text is an echo of user typein */
\r
8396 sel.cpMin = 9999999;
\r
8397 sel.cpMax = 9999999;
\r
8398 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8399 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8400 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8401 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8403 if (savesel.cpMax == exlen || forceVisible) {
\r
8404 /* Move insert point to new end of text if it was at the old
\r
8405 end of text or if the new text is an echo of user typein */
\r
8406 sel.cpMin = 9999999;
\r
8407 sel.cpMax = 9999999;
\r
8408 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8410 /* Restore previous selection */
\r
8411 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8413 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8420 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8424 COLORREF oldFg, oldBg;
\r
8428 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8430 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8431 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8432 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8435 rect.right = x + squareSize;
\r
8437 rect.bottom = y + squareSize;
\r
8440 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8441 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8442 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8443 &rect, str, strlen(str), NULL);
\r
8445 (void) SetTextColor(hdc, oldFg);
\r
8446 (void) SetBkColor(hdc, oldBg);
\r
8447 (void) SelectObject(hdc, oldFont);
\r
8451 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8452 RECT *rect, char *color, char *flagFell)
\r
8456 COLORREF oldFg, oldBg;
\r
8459 if (appData.clockMode) {
\r
8461 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8463 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8470 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8471 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8473 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8474 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8476 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8480 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8481 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8482 rect, str, strlen(str), NULL);
\r
8483 if(logoHeight > 0 && appData.clockMode) {
\r
8485 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8486 r.top = rect->top + logoHeight/2;
\r
8487 r.left = rect->left;
\r
8488 r.right = rect->right;
\r
8489 r.bottom = rect->bottom;
\r
8490 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8491 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8492 &r, str, strlen(str), NULL);
\r
8494 (void) SetTextColor(hdc, oldFg);
\r
8495 (void) SetBkColor(hdc, oldBg);
\r
8496 (void) SelectObject(hdc, oldFont);
\r
8501 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8507 if( count <= 0 ) {
\r
8508 if (appData.debugMode) {
\r
8509 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8512 return ERROR_INVALID_USER_BUFFER;
\r
8515 ResetEvent(ovl->hEvent);
\r
8516 ovl->Offset = ovl->OffsetHigh = 0;
\r
8517 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8521 err = GetLastError();
\r
8522 if (err == ERROR_IO_PENDING) {
\r
8523 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8527 err = GetLastError();
\r
8534 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8539 ResetEvent(ovl->hEvent);
\r
8540 ovl->Offset = ovl->OffsetHigh = 0;
\r
8541 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8545 err = GetLastError();
\r
8546 if (err == ERROR_IO_PENDING) {
\r
8547 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8551 err = GetLastError();
\r
8557 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8558 void CheckForInputBufferFull( InputSource * is )
\r
8560 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8561 /* Look for end of line */
\r
8562 char * p = is->buf;
\r
8564 while( p < is->next && *p != '\n' ) {
\r
8568 if( p >= is->next ) {
\r
8569 if (appData.debugMode) {
\r
8570 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8573 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8574 is->count = (DWORD) -1;
\r
8575 is->next = is->buf;
\r
8581 InputThread(LPVOID arg)
\r
8586 is = (InputSource *) arg;
\r
8587 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8588 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8589 while (is->hThread != NULL) {
\r
8590 is->error = DoReadFile(is->hFile, is->next,
\r
8591 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8592 &is->count, &ovl);
\r
8593 if (is->error == NO_ERROR) {
\r
8594 is->next += is->count;
\r
8596 if (is->error == ERROR_BROKEN_PIPE) {
\r
8597 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8600 is->count = (DWORD) -1;
\r
8601 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8606 CheckForInputBufferFull( is );
\r
8608 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8610 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8612 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8615 CloseHandle(ovl.hEvent);
\r
8616 CloseHandle(is->hFile);
\r
8618 if (appData.debugMode) {
\r
8619 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8626 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8628 NonOvlInputThread(LPVOID arg)
\r
8635 is = (InputSource *) arg;
\r
8636 while (is->hThread != NULL) {
\r
8637 is->error = ReadFile(is->hFile, is->next,
\r
8638 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8639 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8640 if (is->error == NO_ERROR) {
\r
8641 /* Change CRLF to LF */
\r
8642 if (is->next > is->buf) {
\r
8644 i = is->count + 1;
\r
8652 if (prev == '\r' && *p == '\n') {
\r
8664 if (is->error == ERROR_BROKEN_PIPE) {
\r
8665 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8668 is->count = (DWORD) -1;
\r
8672 CheckForInputBufferFull( is );
\r
8674 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8676 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8678 if (is->count < 0) break; /* Quit on error */
\r
8680 CloseHandle(is->hFile);
\r
8685 SocketInputThread(LPVOID arg)
\r
8689 is = (InputSource *) arg;
\r
8690 while (is->hThread != NULL) {
\r
8691 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8692 if ((int)is->count == SOCKET_ERROR) {
\r
8693 is->count = (DWORD) -1;
\r
8694 is->error = WSAGetLastError();
\r
8696 is->error = NO_ERROR;
\r
8697 is->next += is->count;
\r
8698 if (is->count == 0 && is->second == is) {
\r
8699 /* End of file on stderr; quit with no message */
\r
8703 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8705 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8707 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8713 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8717 is = (InputSource *) lParam;
\r
8718 if (is->lineByLine) {
\r
8719 /* Feed in lines one by one */
\r
8720 char *p = is->buf;
\r
8722 while (q < is->next) {
\r
8723 if (*q++ == '\n') {
\r
8724 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8729 /* Move any partial line to the start of the buffer */
\r
8731 while (p < is->next) {
\r
8736 if (is->error != NO_ERROR || is->count == 0) {
\r
8737 /* Notify backend of the error. Note: If there was a partial
\r
8738 line at the end, it is not flushed through. */
\r
8739 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8742 /* Feed in the whole chunk of input at once */
\r
8743 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8744 is->next = is->buf;
\r
8748 /*---------------------------------------------------------------------------*\
\r
8750 * Menu enables. Used when setting various modes.
\r
8752 \*---------------------------------------------------------------------------*/
\r
8760 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8762 while (enab->item > 0) {
\r
8763 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8768 Enables gnuEnables[] = {
\r
8769 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8770 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8771 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8772 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8773 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8774 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8775 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8776 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8777 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8778 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8782 Enables icsEnables[] = {
\r
8783 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8784 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8785 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8786 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8787 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8788 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8789 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8790 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8791 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8792 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8793 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8794 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8799 Enables zippyEnables[] = {
\r
8800 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8801 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8802 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8807 Enables ncpEnables[] = {
\r
8808 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8809 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8810 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8811 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8812 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8813 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8814 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8815 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8816 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8817 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8818 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8819 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8820 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8822 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8826 Enables trainingOnEnables[] = {
\r
8827 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8828 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8829 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8830 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8831 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8832 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8833 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8834 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8838 Enables trainingOffEnables[] = {
\r
8839 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8840 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8841 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8842 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8843 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8844 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8845 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8846 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8850 /* These modify either ncpEnables or gnuEnables */
\r
8851 Enables cmailEnables[] = {
\r
8852 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8853 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8854 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8855 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8856 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8857 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8858 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8862 Enables machineThinkingEnables[] = {
\r
8863 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8864 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8865 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8866 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8867 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8868 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8869 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8870 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8871 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8872 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8873 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8874 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8875 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8876 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8877 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8881 Enables userThinkingEnables[] = {
\r
8882 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8883 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8884 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8885 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8886 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8887 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8888 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8889 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8890 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8891 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8892 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8893 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8894 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8895 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8896 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8900 /*---------------------------------------------------------------------------*\
\r
8902 * Front-end interface functions exported by XBoard.
\r
8903 * Functions appear in same order as prototypes in frontend.h.
\r
8905 \*---------------------------------------------------------------------------*/
\r
8909 static UINT prevChecked = 0;
\r
8910 static int prevPausing = 0;
\r
8913 if (pausing != prevPausing) {
\r
8914 prevPausing = pausing;
\r
8915 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8916 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8917 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8920 switch (gameMode) {
\r
8921 case BeginningOfGame:
\r
8922 if (appData.icsActive)
\r
8923 nowChecked = IDM_IcsClient;
\r
8924 else if (appData.noChessProgram)
\r
8925 nowChecked = IDM_EditGame;
\r
8927 nowChecked = IDM_MachineBlack;
\r
8929 case MachinePlaysBlack:
\r
8930 nowChecked = IDM_MachineBlack;
\r
8932 case MachinePlaysWhite:
\r
8933 nowChecked = IDM_MachineWhite;
\r
8935 case TwoMachinesPlay:
\r
8936 nowChecked = IDM_TwoMachines;
\r
8939 nowChecked = IDM_AnalysisMode;
\r
8942 nowChecked = IDM_AnalyzeFile;
\r
8945 nowChecked = IDM_EditGame;
\r
8947 case PlayFromGameFile:
\r
8948 nowChecked = IDM_LoadGame;
\r
8950 case EditPosition:
\r
8951 nowChecked = IDM_EditPosition;
\r
8954 nowChecked = IDM_Training;
\r
8956 case IcsPlayingWhite:
\r
8957 case IcsPlayingBlack:
\r
8958 case IcsObserving:
\r
8960 nowChecked = IDM_IcsClient;
\r
8967 if (prevChecked != 0)
\r
8968 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8969 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8970 if (nowChecked != 0)
\r
8971 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8972 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8974 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8975 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8976 MF_BYCOMMAND|MF_ENABLED);
\r
8978 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8979 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8982 prevChecked = nowChecked;
\r
8984 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8985 if (appData.icsActive) {
\r
8986 if (appData.icsEngineAnalyze) {
\r
8987 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8988 MF_BYCOMMAND|MF_CHECKED);
\r
8990 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8991 MF_BYCOMMAND|MF_UNCHECKED);
\r
8999 HMENU hmenu = GetMenu(hwndMain);
\r
9000 SetMenuEnables(hmenu, icsEnables);
\r
9001 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9002 MF_BYPOSITION|MF_ENABLED);
\r
9004 if (appData.zippyPlay) {
\r
9005 SetMenuEnables(hmenu, zippyEnables);
\r
9006 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9007 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9008 MF_BYCOMMAND|MF_ENABLED);
\r
9016 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9022 HMENU hmenu = GetMenu(hwndMain);
\r
9023 SetMenuEnables(hmenu, ncpEnables);
\r
9024 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9025 MF_BYPOSITION|MF_GRAYED);
\r
9026 DrawMenuBar(hwndMain);
\r
9032 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9036 SetTrainingModeOn()
\r
9039 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9040 for (i = 0; i < N_BUTTONS; i++) {
\r
9041 if (buttonDesc[i].hwnd != NULL)
\r
9042 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9047 VOID SetTrainingModeOff()
\r
9050 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9051 for (i = 0; i < N_BUTTONS; i++) {
\r
9052 if (buttonDesc[i].hwnd != NULL)
\r
9053 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9059 SetUserThinkingEnables()
\r
9061 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9065 SetMachineThinkingEnables()
\r
9067 HMENU hMenu = GetMenu(hwndMain);
\r
9068 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9070 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9072 if (gameMode == MachinePlaysBlack) {
\r
9073 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9074 } else if (gameMode == MachinePlaysWhite) {
\r
9075 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9076 } else if (gameMode == TwoMachinesPlay) {
\r
9077 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9083 DisplayTitle(char *str)
\r
9085 char title[MSG_SIZ], *host;
\r
9086 if (str[0] != NULLCHAR) {
\r
9087 strcpy(title, str);
\r
9088 } else if (appData.icsActive) {
\r
9089 if (appData.icsCommPort[0] != NULLCHAR)
\r
9092 host = appData.icsHost;
\r
9093 sprintf(title, "%s: %s", szTitle, host);
\r
9094 } else if (appData.noChessProgram) {
\r
9095 strcpy(title, szTitle);
\r
9097 strcpy(title, szTitle);
\r
9098 strcat(title, ": ");
\r
9099 strcat(title, first.tidy);
\r
9101 SetWindowText(hwndMain, title);
\r
9106 DisplayMessage(char *str1, char *str2)
\r
9110 int remain = MESSAGE_TEXT_MAX - 1;
\r
9113 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9114 messageText[0] = NULLCHAR;
\r
9116 len = strlen(str1);
\r
9117 if (len > remain) len = remain;
\r
9118 strncpy(messageText, str1, len);
\r
9119 messageText[len] = NULLCHAR;
\r
9122 if (*str2 && remain >= 2) {
\r
9124 strcat(messageText, " ");
\r
9127 len = strlen(str2);
\r
9128 if (len > remain) len = remain;
\r
9129 strncat(messageText, str2, len);
\r
9131 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9133 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9137 hdc = GetDC(hwndMain);
\r
9138 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9139 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9140 &messageRect, messageText, strlen(messageText), NULL);
\r
9141 (void) SelectObject(hdc, oldFont);
\r
9142 (void) ReleaseDC(hwndMain, hdc);
\r
9146 DisplayError(char *str, int error)
\r
9148 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9154 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9155 NULL, error, LANG_NEUTRAL,
\r
9156 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9158 sprintf(buf, "%s:\n%s", str, buf2);
\r
9160 ErrorMap *em = errmap;
\r
9161 while (em->err != 0 && em->err != error) em++;
\r
9162 if (em->err != 0) {
\r
9163 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9165 sprintf(buf, "%s:\nError code %d", str, error);
\r
9170 ErrorPopUp("Error", buf);
\r
9175 DisplayMoveError(char *str)
\r
9177 fromX = fromY = -1;
\r
9178 ClearHighlights();
\r
9179 DrawPosition(FALSE, NULL);
\r
9180 if (appData.popupMoveErrors) {
\r
9181 ErrorPopUp("Error", str);
\r
9183 DisplayMessage(str, "");
\r
9184 moveErrorMessageUp = TRUE;
\r
9189 DisplayFatalError(char *str, int error, int exitStatus)
\r
9191 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9193 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9196 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9197 NULL, error, LANG_NEUTRAL,
\r
9198 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9200 sprintf(buf, "%s:\n%s", str, buf2);
\r
9202 ErrorMap *em = errmap;
\r
9203 while (em->err != 0 && em->err != error) em++;
\r
9204 if (em->err != 0) {
\r
9205 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9207 sprintf(buf, "%s:\nError code %d", str, error);
\r
9212 if (appData.debugMode) {
\r
9213 fprintf(debugFP, "%s: %s\n", label, str);
\r
9215 if (appData.popupExitMessage) {
\r
9216 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9217 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9219 ExitEvent(exitStatus);
\r
9224 DisplayInformation(char *str)
\r
9226 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9231 DisplayNote(char *str)
\r
9233 ErrorPopUp("Note", str);
\r
9238 char *title, *question, *replyPrefix;
\r
9243 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9245 static QuestionParams *qp;
\r
9246 char reply[MSG_SIZ];
\r
9249 switch (message) {
\r
9250 case WM_INITDIALOG:
\r
9251 qp = (QuestionParams *) lParam;
\r
9252 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9253 SetWindowText(hDlg, qp->title);
\r
9254 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9255 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9259 switch (LOWORD(wParam)) {
\r
9261 strcpy(reply, qp->replyPrefix);
\r
9262 if (*reply) strcat(reply, " ");
\r
9263 len = strlen(reply);
\r
9264 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9265 strcat(reply, "\n");
\r
9266 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9267 EndDialog(hDlg, TRUE);
\r
9268 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9271 EndDialog(hDlg, FALSE);
\r
9282 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9284 QuestionParams qp;
\r
9288 qp.question = question;
\r
9289 qp.replyPrefix = replyPrefix;
\r
9291 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9292 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9293 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9294 FreeProcInstance(lpProc);
\r
9297 /* [AS] Pick FRC position */
\r
9298 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9300 static int * lpIndexFRC;
\r
9306 case WM_INITDIALOG:
\r
9307 lpIndexFRC = (int *) lParam;
\r
9309 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9311 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9312 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9313 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9314 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9319 switch( LOWORD(wParam) ) {
\r
9321 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9322 EndDialog( hDlg, 0 );
\r
9323 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9326 EndDialog( hDlg, 1 );
\r
9328 case IDC_NFG_Edit:
\r
9329 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9330 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9332 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9335 case IDC_NFG_Random:
\r
9336 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9337 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9350 int index = appData.defaultFrcPosition;
\r
9351 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9353 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9355 if( result == 0 ) {
\r
9356 appData.defaultFrcPosition = index;
\r
9362 /* [AS] Game list options */
\r
9368 static GLT_Item GLT_ItemInfo[] = {
\r
9369 { GLT_EVENT, "Event" },
\r
9370 { GLT_SITE, "Site" },
\r
9371 { GLT_DATE, "Date" },
\r
9372 { GLT_ROUND, "Round" },
\r
9373 { GLT_PLAYERS, "Players" },
\r
9374 { GLT_RESULT, "Result" },
\r
9375 { GLT_WHITE_ELO, "White Rating" },
\r
9376 { GLT_BLACK_ELO, "Black Rating" },
\r
9377 { GLT_TIME_CONTROL,"Time Control" },
\r
9378 { GLT_VARIANT, "Variant" },
\r
9379 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9383 const char * GLT_FindItem( char id )
\r
9385 const char * result = 0;
\r
9387 GLT_Item * list = GLT_ItemInfo;
\r
9389 while( list->id != 0 ) {
\r
9390 if( list->id == id ) {
\r
9391 result = list->name;
\r
9401 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9403 const char * name = GLT_FindItem( id );
\r
9406 if( index >= 0 ) {
\r
9407 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9410 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9415 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9419 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9422 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9426 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9428 pc = GLT_ALL_TAGS;
\r
9431 if( strchr( tags, *pc ) == 0 ) {
\r
9432 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9437 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9440 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9442 char result = '\0';
\r
9445 GLT_Item * list = GLT_ItemInfo;
\r
9447 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9448 while( list->id != 0 ) {
\r
9449 if( strcmp( list->name, name ) == 0 ) {
\r
9450 result = list->id;
\r
9461 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9463 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9464 int idx2 = idx1 + delta;
\r
9465 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9467 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9470 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9471 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9472 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9473 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9477 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9479 static char glt[64];
\r
9480 static char * lpUserGLT;
\r
9484 case WM_INITDIALOG:
\r
9485 lpUserGLT = (char *) lParam;
\r
9487 strcpy( glt, lpUserGLT );
\r
9489 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9491 /* Initialize list */
\r
9492 GLT_TagsToList( hDlg, glt );
\r
9494 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9499 switch( LOWORD(wParam) ) {
\r
9502 char * pc = lpUserGLT;
\r
9504 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9508 id = GLT_ListItemToTag( hDlg, idx );
\r
9512 } while( id != '\0' );
\r
9514 EndDialog( hDlg, 0 );
\r
9517 EndDialog( hDlg, 1 );
\r
9520 case IDC_GLT_Default:
\r
9521 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9522 GLT_TagsToList( hDlg, glt );
\r
9525 case IDC_GLT_Restore:
\r
9526 strcpy( glt, lpUserGLT );
\r
9527 GLT_TagsToList( hDlg, glt );
\r
9531 GLT_MoveSelection( hDlg, -1 );
\r
9534 case IDC_GLT_Down:
\r
9535 GLT_MoveSelection( hDlg, +1 );
\r
9545 int GameListOptions()
\r
9549 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9551 strcpy( glt, appData.gameListTags );
\r
9553 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9555 if( result == 0 ) {
\r
9556 /* [AS] Memory leak here! */
\r
9557 appData.gameListTags = strdup( glt );
\r
9565 DisplayIcsInteractionTitle(char *str)
\r
9567 char consoleTitle[MSG_SIZ];
\r
9569 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9570 SetWindowText(hwndConsole, consoleTitle);
\r
9574 DrawPosition(int fullRedraw, Board board)
\r
9576 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9583 fromX = fromY = -1;
\r
9584 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9585 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9586 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9587 dragInfo.lastpos = dragInfo.pos;
\r
9588 dragInfo.start.x = dragInfo.start.y = -1;
\r
9589 dragInfo.from = dragInfo.start;
\r
9591 DrawPosition(TRUE, NULL);
\r
9597 CommentPopUp(char *title, char *str)
\r
9599 HWND hwnd = GetActiveWindow();
\r
9600 EitherCommentPopUp(0, title, str, FALSE);
\r
9601 SetActiveWindow(hwnd);
\r
9605 CommentPopDown(void)
\r
9607 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9608 if (commentDialog) {
\r
9609 ShowWindow(commentDialog, SW_HIDE);
\r
9611 commentDialogUp = FALSE;
\r
9615 EditCommentPopUp(int index, char *title, char *str)
\r
9617 EitherCommentPopUp(index, title, str, TRUE);
\r
9624 MyPlaySound(&sounds[(int)SoundMove]);
\r
9627 VOID PlayIcsWinSound()
\r
9629 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9632 VOID PlayIcsLossSound()
\r
9634 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9637 VOID PlayIcsDrawSound()
\r
9639 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9642 VOID PlayIcsUnfinishedSound()
\r
9644 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9650 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9658 consoleEcho = TRUE;
\r
9659 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9660 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9661 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9670 consoleEcho = FALSE;
\r
9671 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9672 /* This works OK: set text and background both to the same color */
\r
9674 cf.crTextColor = COLOR_ECHOOFF;
\r
9675 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9676 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9679 /* No Raw()...? */
\r
9681 void Colorize(ColorClass cc, int continuation)
\r
9683 currentColorClass = cc;
\r
9684 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9685 consoleCF.crTextColor = textAttribs[cc].color;
\r
9686 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9687 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9693 static char buf[MSG_SIZ];
\r
9694 DWORD bufsiz = MSG_SIZ;
\r
9696 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9697 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9699 if (!GetUserName(buf, &bufsiz)) {
\r
9700 /*DisplayError("Error getting user name", GetLastError());*/
\r
9701 strcpy(buf, "User");
\r
9709 static char buf[MSG_SIZ];
\r
9710 DWORD bufsiz = MSG_SIZ;
\r
9712 if (!GetComputerName(buf, &bufsiz)) {
\r
9713 /*DisplayError("Error getting host name", GetLastError());*/
\r
9714 strcpy(buf, "Unknown");
\r
9721 ClockTimerRunning()
\r
9723 return clockTimerEvent != 0;
\r
9729 if (clockTimerEvent == 0) return FALSE;
\r
9730 KillTimer(hwndMain, clockTimerEvent);
\r
9731 clockTimerEvent = 0;
\r
9736 StartClockTimer(long millisec)
\r
9738 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9739 (UINT) millisec, NULL);
\r
9743 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9746 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9748 if(appData.noGUI) return;
\r
9749 hdc = GetDC(hwndMain);
\r
9750 if (!IsIconic(hwndMain)) {
\r
9751 DisplayAClock(hdc, timeRemaining, highlight,
\r
9752 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9754 if (highlight && iconCurrent == iconBlack) {
\r
9755 iconCurrent = iconWhite;
\r
9756 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9757 if (IsIconic(hwndMain)) {
\r
9758 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9761 (void) ReleaseDC(hwndMain, hdc);
\r
9763 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9767 DisplayBlackClock(long timeRemaining, int highlight)
\r
9770 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9772 if(appData.noGUI) return;
\r
9773 hdc = GetDC(hwndMain);
\r
9774 if (!IsIconic(hwndMain)) {
\r
9775 DisplayAClock(hdc, timeRemaining, highlight,
\r
9776 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9778 if (highlight && iconCurrent == iconWhite) {
\r
9779 iconCurrent = iconBlack;
\r
9780 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9781 if (IsIconic(hwndMain)) {
\r
9782 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9785 (void) ReleaseDC(hwndMain, hdc);
\r
9787 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9792 LoadGameTimerRunning()
\r
9794 return loadGameTimerEvent != 0;
\r
9798 StopLoadGameTimer()
\r
9800 if (loadGameTimerEvent == 0) return FALSE;
\r
9801 KillTimer(hwndMain, loadGameTimerEvent);
\r
9802 loadGameTimerEvent = 0;
\r
9807 StartLoadGameTimer(long millisec)
\r
9809 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9810 (UINT) millisec, NULL);
\r
9818 char fileTitle[MSG_SIZ];
\r
9820 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9821 f = OpenFileDialog(hwndMain, "a", defName,
\r
9822 appData.oldSaveStyle ? "gam" : "pgn",
\r
9824 "Save Game to File", NULL, fileTitle, NULL);
\r
9826 SaveGame(f, 0, "");
\r
9833 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9835 if (delayedTimerEvent != 0) {
\r
9836 if (appData.debugMode) {
\r
9837 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9839 KillTimer(hwndMain, delayedTimerEvent);
\r
9840 delayedTimerEvent = 0;
\r
9841 delayedTimerCallback();
\r
9843 delayedTimerCallback = cb;
\r
9844 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9845 (UINT) millisec, NULL);
\r
9848 DelayedEventCallback
\r
9851 if (delayedTimerEvent) {
\r
9852 return delayedTimerCallback;
\r
9859 CancelDelayedEvent()
\r
9861 if (delayedTimerEvent) {
\r
9862 KillTimer(hwndMain, delayedTimerEvent);
\r
9863 delayedTimerEvent = 0;
\r
9867 DWORD GetWin32Priority(int nice)
\r
9868 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9870 REALTIME_PRIORITY_CLASS 0x00000100
\r
9871 HIGH_PRIORITY_CLASS 0x00000080
\r
9872 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9873 NORMAL_PRIORITY_CLASS 0x00000020
\r
9874 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9875 IDLE_PRIORITY_CLASS 0x00000040
\r
9877 if (nice < -15) return 0x00000080;
\r
9878 if (nice < 0) return 0x00008000;
\r
9879 if (nice == 0) return 0x00000020;
\r
9880 if (nice < 15) return 0x00004000;
\r
9881 return 0x00000040;
\r
9884 /* Start a child process running the given program.
\r
9885 The process's standard output can be read from "from", and its
\r
9886 standard input can be written to "to".
\r
9887 Exit with fatal error if anything goes wrong.
\r
9888 Returns an opaque pointer that can be used to destroy the process
\r
9892 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9894 #define BUFSIZE 4096
\r
9896 HANDLE hChildStdinRd, hChildStdinWr,
\r
9897 hChildStdoutRd, hChildStdoutWr;
\r
9898 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9899 SECURITY_ATTRIBUTES saAttr;
\r
9901 PROCESS_INFORMATION piProcInfo;
\r
9902 STARTUPINFO siStartInfo;
\r
9904 char buf[MSG_SIZ];
\r
9907 if (appData.debugMode) {
\r
9908 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9913 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9914 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9915 saAttr.bInheritHandle = TRUE;
\r
9916 saAttr.lpSecurityDescriptor = NULL;
\r
9919 * The steps for redirecting child's STDOUT:
\r
9920 * 1. Create anonymous pipe to be STDOUT for child.
\r
9921 * 2. Create a noninheritable duplicate of read handle,
\r
9922 * and close the inheritable read handle.
\r
9925 /* Create a pipe for the child's STDOUT. */
\r
9926 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9927 return GetLastError();
\r
9930 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9931 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9932 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9933 FALSE, /* not inherited */
\r
9934 DUPLICATE_SAME_ACCESS);
\r
9936 return GetLastError();
\r
9938 CloseHandle(hChildStdoutRd);
\r
9941 * The steps for redirecting child's STDIN:
\r
9942 * 1. Create anonymous pipe to be STDIN for child.
\r
9943 * 2. Create a noninheritable duplicate of write handle,
\r
9944 * and close the inheritable write handle.
\r
9947 /* Create a pipe for the child's STDIN. */
\r
9948 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9949 return GetLastError();
\r
9952 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9953 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9954 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9955 FALSE, /* not inherited */
\r
9956 DUPLICATE_SAME_ACCESS);
\r
9958 return GetLastError();
\r
9960 CloseHandle(hChildStdinWr);
\r
9962 /* Arrange to (1) look in dir for the child .exe file, and
\r
9963 * (2) have dir be the child's working directory. Interpret
\r
9964 * dir relative to the directory WinBoard loaded from. */
\r
9965 GetCurrentDirectory(MSG_SIZ, buf);
\r
9966 SetCurrentDirectory(installDir);
\r
9967 SetCurrentDirectory(dir);
\r
9969 /* Now create the child process. */
\r
9971 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9972 siStartInfo.lpReserved = NULL;
\r
9973 siStartInfo.lpDesktop = NULL;
\r
9974 siStartInfo.lpTitle = NULL;
\r
9975 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9976 siStartInfo.cbReserved2 = 0;
\r
9977 siStartInfo.lpReserved2 = NULL;
\r
9978 siStartInfo.hStdInput = hChildStdinRd;
\r
9979 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9980 siStartInfo.hStdError = hChildStdoutWr;
\r
9982 fSuccess = CreateProcess(NULL,
\r
9983 cmdLine, /* command line */
\r
9984 NULL, /* process security attributes */
\r
9985 NULL, /* primary thread security attrs */
\r
9986 TRUE, /* handles are inherited */
\r
9987 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9988 NULL, /* use parent's environment */
\r
9990 &siStartInfo, /* STARTUPINFO pointer */
\r
9991 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9993 err = GetLastError();
\r
9994 SetCurrentDirectory(buf); /* return to prev directory */
\r
9999 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10000 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10001 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10004 /* Close the handles we don't need in the parent */
\r
10005 CloseHandle(piProcInfo.hThread);
\r
10006 CloseHandle(hChildStdinRd);
\r
10007 CloseHandle(hChildStdoutWr);
\r
10009 /* Prepare return value */
\r
10010 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10011 cp->kind = CPReal;
\r
10012 cp->hProcess = piProcInfo.hProcess;
\r
10013 cp->pid = piProcInfo.dwProcessId;
\r
10014 cp->hFrom = hChildStdoutRdDup;
\r
10015 cp->hTo = hChildStdinWrDup;
\r
10017 *pr = (void *) cp;
\r
10019 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10020 2000 where engines sometimes don't see the initial command(s)
\r
10021 from WinBoard and hang. I don't understand how that can happen,
\r
10022 but the Sleep is harmless, so I've put it in. Others have also
\r
10023 reported what may be the same problem, so hopefully this will fix
\r
10024 it for them too. */
\r
10032 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10034 ChildProc *cp; int result;
\r
10036 cp = (ChildProc *) pr;
\r
10037 if (cp == NULL) return;
\r
10039 switch (cp->kind) {
\r
10041 /* TerminateProcess is considered harmful, so... */
\r
10042 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10043 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10044 /* The following doesn't work because the chess program
\r
10045 doesn't "have the same console" as WinBoard. Maybe
\r
10046 we could arrange for this even though neither WinBoard
\r
10047 nor the chess program uses a console for stdio? */
\r
10048 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10050 /* [AS] Special termination modes for misbehaving programs... */
\r
10051 if( signal == 9 ) {
\r
10052 result = TerminateProcess( cp->hProcess, 0 );
\r
10054 if ( appData.debugMode) {
\r
10055 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10058 else if( signal == 10 ) {
\r
10059 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10061 if( dw != WAIT_OBJECT_0 ) {
\r
10062 result = TerminateProcess( cp->hProcess, 0 );
\r
10064 if ( appData.debugMode) {
\r
10065 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10071 CloseHandle(cp->hProcess);
\r
10075 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10079 closesocket(cp->sock);
\r
10084 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10085 closesocket(cp->sock);
\r
10086 closesocket(cp->sock2);
\r
10094 InterruptChildProcess(ProcRef pr)
\r
10098 cp = (ChildProc *) pr;
\r
10099 if (cp == NULL) return;
\r
10100 switch (cp->kind) {
\r
10102 /* The following doesn't work because the chess program
\r
10103 doesn't "have the same console" as WinBoard. Maybe
\r
10104 we could arrange for this even though neither WinBoard
\r
10105 nor the chess program uses a console for stdio */
\r
10106 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10111 /* Can't interrupt */
\r
10115 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10122 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10124 char cmdLine[MSG_SIZ];
\r
10126 if (port[0] == NULLCHAR) {
\r
10127 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10129 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10131 return StartChildProcess(cmdLine, "", pr);
\r
10135 /* Code to open TCP sockets */
\r
10138 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10143 struct sockaddr_in sa, mysa;
\r
10144 struct hostent FAR *hp;
\r
10145 unsigned short uport;
\r
10146 WORD wVersionRequested;
\r
10149 /* Initialize socket DLL */
\r
10150 wVersionRequested = MAKEWORD(1, 1);
\r
10151 err = WSAStartup(wVersionRequested, &wsaData);
\r
10152 if (err != 0) return err;
\r
10154 /* Make socket */
\r
10155 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10156 err = WSAGetLastError();
\r
10161 /* Bind local address using (mostly) don't-care values.
\r
10163 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10164 mysa.sin_family = AF_INET;
\r
10165 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10166 uport = (unsigned short) 0;
\r
10167 mysa.sin_port = htons(uport);
\r
10168 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10169 == SOCKET_ERROR) {
\r
10170 err = WSAGetLastError();
\r
10175 /* Resolve remote host name */
\r
10176 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10177 if (!(hp = gethostbyname(host))) {
\r
10178 unsigned int b0, b1, b2, b3;
\r
10180 err = WSAGetLastError();
\r
10182 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10183 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10184 hp->h_addrtype = AF_INET;
\r
10185 hp->h_length = 4;
\r
10186 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10187 hp->h_addr_list[0] = (char *) malloc(4);
\r
10188 hp->h_addr_list[0][0] = (char) b0;
\r
10189 hp->h_addr_list[0][1] = (char) b1;
\r
10190 hp->h_addr_list[0][2] = (char) b2;
\r
10191 hp->h_addr_list[0][3] = (char) b3;
\r
10197 sa.sin_family = hp->h_addrtype;
\r
10198 uport = (unsigned short) atoi(port);
\r
10199 sa.sin_port = htons(uport);
\r
10200 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10202 /* Make connection */
\r
10203 if (connect(s, (struct sockaddr *) &sa,
\r
10204 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10205 err = WSAGetLastError();
\r
10210 /* Prepare return value */
\r
10211 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10212 cp->kind = CPSock;
\r
10214 *pr = (ProcRef *) cp;
\r
10220 OpenCommPort(char *name, ProcRef *pr)
\r
10225 char fullname[MSG_SIZ];
\r
10227 if (*name != '\\')
\r
10228 sprintf(fullname, "\\\\.\\%s", name);
\r
10230 strcpy(fullname, name);
\r
10232 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10233 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10234 if (h == (HANDLE) -1) {
\r
10235 return GetLastError();
\r
10239 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10241 /* Accumulate characters until a 100ms pause, then parse */
\r
10242 ct.ReadIntervalTimeout = 100;
\r
10243 ct.ReadTotalTimeoutMultiplier = 0;
\r
10244 ct.ReadTotalTimeoutConstant = 0;
\r
10245 ct.WriteTotalTimeoutMultiplier = 0;
\r
10246 ct.WriteTotalTimeoutConstant = 0;
\r
10247 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10249 /* Prepare return value */
\r
10250 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10251 cp->kind = CPComm;
\r
10254 *pr = (ProcRef *) cp;
\r
10260 OpenLoopback(ProcRef *pr)
\r
10262 DisplayFatalError("Not implemented", 0, 1);
\r
10268 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10272 SOCKET s, s2, s3;
\r
10273 struct sockaddr_in sa, mysa;
\r
10274 struct hostent FAR *hp;
\r
10275 unsigned short uport;
\r
10276 WORD wVersionRequested;
\r
10279 char stderrPortStr[MSG_SIZ];
\r
10281 /* Initialize socket DLL */
\r
10282 wVersionRequested = MAKEWORD(1, 1);
\r
10283 err = WSAStartup(wVersionRequested, &wsaData);
\r
10284 if (err != 0) return err;
\r
10286 /* Resolve remote host name */
\r
10287 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10288 if (!(hp = gethostbyname(host))) {
\r
10289 unsigned int b0, b1, b2, b3;
\r
10291 err = WSAGetLastError();
\r
10293 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10294 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10295 hp->h_addrtype = AF_INET;
\r
10296 hp->h_length = 4;
\r
10297 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10298 hp->h_addr_list[0] = (char *) malloc(4);
\r
10299 hp->h_addr_list[0][0] = (char) b0;
\r
10300 hp->h_addr_list[0][1] = (char) b1;
\r
10301 hp->h_addr_list[0][2] = (char) b2;
\r
10302 hp->h_addr_list[0][3] = (char) b3;
\r
10308 sa.sin_family = hp->h_addrtype;
\r
10309 uport = (unsigned short) 514;
\r
10310 sa.sin_port = htons(uport);
\r
10311 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10313 /* Bind local socket to unused "privileged" port address
\r
10315 s = INVALID_SOCKET;
\r
10316 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10317 mysa.sin_family = AF_INET;
\r
10318 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10319 for (fromPort = 1023;; fromPort--) {
\r
10320 if (fromPort < 0) {
\r
10322 return WSAEADDRINUSE;
\r
10324 if (s == INVALID_SOCKET) {
\r
10325 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10326 err = WSAGetLastError();
\r
10331 uport = (unsigned short) fromPort;
\r
10332 mysa.sin_port = htons(uport);
\r
10333 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10334 == SOCKET_ERROR) {
\r
10335 err = WSAGetLastError();
\r
10336 if (err == WSAEADDRINUSE) continue;
\r
10340 if (connect(s, (struct sockaddr *) &sa,
\r
10341 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10342 err = WSAGetLastError();
\r
10343 if (err == WSAEADDRINUSE) {
\r
10354 /* Bind stderr local socket to unused "privileged" port address
\r
10356 s2 = INVALID_SOCKET;
\r
10357 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10358 mysa.sin_family = AF_INET;
\r
10359 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10360 for (fromPort = 1023;; fromPort--) {
\r
10361 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10362 if (fromPort < 0) {
\r
10363 (void) closesocket(s);
\r
10365 return WSAEADDRINUSE;
\r
10367 if (s2 == INVALID_SOCKET) {
\r
10368 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10369 err = WSAGetLastError();
\r
10375 uport = (unsigned short) fromPort;
\r
10376 mysa.sin_port = htons(uport);
\r
10377 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10378 == SOCKET_ERROR) {
\r
10379 err = WSAGetLastError();
\r
10380 if (err == WSAEADDRINUSE) continue;
\r
10381 (void) closesocket(s);
\r
10385 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10386 err = WSAGetLastError();
\r
10387 if (err == WSAEADDRINUSE) {
\r
10389 s2 = INVALID_SOCKET;
\r
10392 (void) closesocket(s);
\r
10393 (void) closesocket(s2);
\r
10399 prevStderrPort = fromPort; // remember port used
\r
10400 sprintf(stderrPortStr, "%d", fromPort);
\r
10402 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10403 err = WSAGetLastError();
\r
10404 (void) closesocket(s);
\r
10405 (void) closesocket(s2);
\r
10410 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10411 err = WSAGetLastError();
\r
10412 (void) closesocket(s);
\r
10413 (void) closesocket(s2);
\r
10417 if (*user == NULLCHAR) user = UserName();
\r
10418 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10419 err = WSAGetLastError();
\r
10420 (void) closesocket(s);
\r
10421 (void) closesocket(s2);
\r
10425 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10426 err = WSAGetLastError();
\r
10427 (void) closesocket(s);
\r
10428 (void) closesocket(s2);
\r
10433 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10434 err = WSAGetLastError();
\r
10435 (void) closesocket(s);
\r
10436 (void) closesocket(s2);
\r
10440 (void) closesocket(s2); /* Stop listening */
\r
10442 /* Prepare return value */
\r
10443 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10444 cp->kind = CPRcmd;
\r
10447 *pr = (ProcRef *) cp;
\r
10454 AddInputSource(ProcRef pr, int lineByLine,
\r
10455 InputCallback func, VOIDSTAR closure)
\r
10457 InputSource *is, *is2 = NULL;
\r
10458 ChildProc *cp = (ChildProc *) pr;
\r
10460 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10461 is->lineByLine = lineByLine;
\r
10463 is->closure = closure;
\r
10464 is->second = NULL;
\r
10465 is->next = is->buf;
\r
10466 if (pr == NoProc) {
\r
10467 is->kind = CPReal;
\r
10468 consoleInputSource = is;
\r
10470 is->kind = cp->kind;
\r
10472 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10473 we create all threads suspended so that the is->hThread variable can be
\r
10474 safely assigned, then let the threads start with ResumeThread.
\r
10476 switch (cp->kind) {
\r
10478 is->hFile = cp->hFrom;
\r
10479 cp->hFrom = NULL; /* now owned by InputThread */
\r
10481 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10482 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10486 is->hFile = cp->hFrom;
\r
10487 cp->hFrom = NULL; /* now owned by InputThread */
\r
10489 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10490 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10494 is->sock = cp->sock;
\r
10496 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10497 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10501 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10503 is->sock = cp->sock;
\r
10504 is->second = is2;
\r
10505 is2->sock = cp->sock2;
\r
10506 is2->second = is2;
\r
10508 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10509 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10511 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10512 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10516 if( is->hThread != NULL ) {
\r
10517 ResumeThread( is->hThread );
\r
10520 if( is2 != NULL && is2->hThread != NULL ) {
\r
10521 ResumeThread( is2->hThread );
\r
10525 return (InputSourceRef) is;
\r
10529 RemoveInputSource(InputSourceRef isr)
\r
10533 is = (InputSource *) isr;
\r
10534 is->hThread = NULL; /* tell thread to stop */
\r
10535 CloseHandle(is->hThread);
\r
10536 if (is->second != NULL) {
\r
10537 is->second->hThread = NULL;
\r
10538 CloseHandle(is->second->hThread);
\r
10544 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10547 int outCount = SOCKET_ERROR;
\r
10548 ChildProc *cp = (ChildProc *) pr;
\r
10549 static OVERLAPPED ovl;
\r
10551 if (pr == NoProc) {
\r
10552 ConsoleOutput(message, count, FALSE);
\r
10556 if (ovl.hEvent == NULL) {
\r
10557 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10559 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10561 switch (cp->kind) {
\r
10564 outCount = send(cp->sock, message, count, 0);
\r
10565 if (outCount == SOCKET_ERROR) {
\r
10566 *outError = WSAGetLastError();
\r
10568 *outError = NO_ERROR;
\r
10573 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10574 &dOutCount, NULL)) {
\r
10575 *outError = NO_ERROR;
\r
10576 outCount = (int) dOutCount;
\r
10578 *outError = GetLastError();
\r
10583 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10584 &dOutCount, &ovl);
\r
10585 if (*outError == NO_ERROR) {
\r
10586 outCount = (int) dOutCount;
\r
10594 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10597 /* Ignore delay, not implemented for WinBoard */
\r
10598 return OutputToProcess(pr, message, count, outError);
\r
10603 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10604 char *buf, int count, int error)
\r
10606 DisplayFatalError("Not implemented", 0, 1);
\r
10609 /* see wgamelist.c for Game List functions */
\r
10610 /* see wedittags.c for Edit Tags functions */
\r
10617 char buf[MSG_SIZ];
\r
10620 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10621 f = fopen(buf, "r");
\r
10623 ProcessICSInitScript(f);
\r
10631 StartAnalysisClock()
\r
10633 if (analysisTimerEvent) return;
\r
10634 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10635 (UINT) 2000, NULL);
\r
10639 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10641 static HANDLE hwndText;
\r
10643 static int sizeX, sizeY;
\r
10644 int newSizeX, newSizeY, flags;
\r
10647 switch (message) {
\r
10648 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10649 /* Initialize the dialog items */
\r
10650 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10651 SetWindowText(hDlg, analysisTitle);
\r
10652 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10653 /* Size and position the dialog */
\r
10654 if (!analysisDialog) {
\r
10655 analysisDialog = hDlg;
\r
10656 flags = SWP_NOZORDER;
\r
10657 GetClientRect(hDlg, &rect);
\r
10658 sizeX = rect.right;
\r
10659 sizeY = rect.bottom;
\r
10660 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10661 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10662 WINDOWPLACEMENT wp;
\r
10663 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10664 wp.length = sizeof(WINDOWPLACEMENT);
\r
10666 wp.showCmd = SW_SHOW;
\r
10667 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10668 wp.rcNormalPosition.left = analysisX;
\r
10669 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10670 wp.rcNormalPosition.top = analysisY;
\r
10671 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10672 SetWindowPlacement(hDlg, &wp);
\r
10674 GetClientRect(hDlg, &rect);
\r
10675 newSizeX = rect.right;
\r
10676 newSizeY = rect.bottom;
\r
10677 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10678 newSizeX, newSizeY);
\r
10679 sizeX = newSizeX;
\r
10680 sizeY = newSizeY;
\r
10685 case WM_COMMAND: /* message: received a command */
\r
10686 switch (LOWORD(wParam)) {
\r
10688 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10689 ExitAnalyzeMode();
\r
10701 newSizeX = LOWORD(lParam);
\r
10702 newSizeY = HIWORD(lParam);
\r
10703 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10704 sizeX = newSizeX;
\r
10705 sizeY = newSizeY;
\r
10708 case WM_GETMINMAXINFO:
\r
10709 /* Prevent resizing window too small */
\r
10710 mmi = (MINMAXINFO *) lParam;
\r
10711 mmi->ptMinTrackSize.x = 100;
\r
10712 mmi->ptMinTrackSize.y = 100;
\r
10719 AnalysisPopUp(char* title, char* str)
\r
10725 EngineOutputPopUp();
\r
10728 if (str == NULL) str = "";
\r
10729 p = (char *) malloc(2 * strlen(str) + 2);
\r
10732 if (*str == '\n') *q++ = '\r';
\r
10736 if (analysisText != NULL) free(analysisText);
\r
10737 analysisText = p;
\r
10739 if (analysisDialog) {
\r
10740 SetWindowText(analysisDialog, title);
\r
10741 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10742 ShowWindow(analysisDialog, SW_SHOW);
\r
10744 analysisTitle = title;
\r
10745 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10746 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10747 hwndMain, (DLGPROC)lpProc);
\r
10748 FreeProcInstance(lpProc);
\r
10750 analysisDialogUp = TRUE;
\r
10754 AnalysisPopDown()
\r
10756 if (analysisDialog) {
\r
10757 ShowWindow(analysisDialog, SW_HIDE);
\r
10759 analysisDialogUp = FALSE;
\r
10764 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10766 highlightInfo.sq[0].x = fromX;
\r
10767 highlightInfo.sq[0].y = fromY;
\r
10768 highlightInfo.sq[1].x = toX;
\r
10769 highlightInfo.sq[1].y = toY;
\r
10773 ClearHighlights()
\r
10775 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10776 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10780 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10782 premoveHighlightInfo.sq[0].x = fromX;
\r
10783 premoveHighlightInfo.sq[0].y = fromY;
\r
10784 premoveHighlightInfo.sq[1].x = toX;
\r
10785 premoveHighlightInfo.sq[1].y = toY;
\r
10789 ClearPremoveHighlights()
\r
10791 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10792 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10796 ShutDownFrontEnd()
\r
10798 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10799 DeleteClipboardTempFiles();
\r
10805 if (IsIconic(hwndMain))
\r
10806 ShowWindow(hwndMain, SW_RESTORE);
\r
10808 SetActiveWindow(hwndMain);
\r
10812 * Prototypes for animation support routines
\r
10814 static void ScreenSquare(int column, int row, POINT * pt);
\r
10815 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10816 POINT frames[], int * nFrames);
\r
10820 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10821 { // [HGM] atomic: animate blast wave
\r
10823 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10824 explodeInfo.fromX = fromX;
\r
10825 explodeInfo.fromY = fromY;
\r
10826 explodeInfo.toX = toX;
\r
10827 explodeInfo.toY = toY;
\r
10828 for(i=1; i<nFrames; i++) {
\r
10829 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10830 DrawPosition(FALSE, NULL);
\r
10831 Sleep(appData.animSpeed);
\r
10833 explodeInfo.radius = 0;
\r
10834 DrawPosition(TRUE, NULL);
\r
10837 #define kFactor 4
\r
10840 AnimateMove(board, fromX, fromY, toX, toY)
\r
10847 ChessSquare piece;
\r
10848 POINT start, finish, mid;
\r
10849 POINT frames[kFactor * 2 + 1];
\r
10852 if (!appData.animate) return;
\r
10853 if (doingSizing) return;
\r
10854 if (fromY < 0 || fromX < 0) return;
\r
10855 piece = board[fromY][fromX];
\r
10856 if (piece >= EmptySquare) return;
\r
10858 ScreenSquare(fromX, fromY, &start);
\r
10859 ScreenSquare(toX, toY, &finish);
\r
10861 /* All pieces except knights move in straight line */
\r
10862 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10863 mid.x = start.x + (finish.x - start.x) / 2;
\r
10864 mid.y = start.y + (finish.y - start.y) / 2;
\r
10866 /* Knight: make diagonal movement then straight */
\r
10867 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10868 mid.x = start.x + (finish.x - start.x) / 2;
\r
10869 mid.y = finish.y;
\r
10871 mid.x = finish.x;
\r
10872 mid.y = start.y + (finish.y - start.y) / 2;
\r
10876 /* Don't use as many frames for very short moves */
\r
10877 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10878 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10880 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10882 animInfo.from.x = fromX;
\r
10883 animInfo.from.y = fromY;
\r
10884 animInfo.to.x = toX;
\r
10885 animInfo.to.y = toY;
\r
10886 animInfo.lastpos = start;
\r
10887 animInfo.piece = piece;
\r
10888 for (n = 0; n < nFrames; n++) {
\r
10889 animInfo.pos = frames[n];
\r
10890 DrawPosition(FALSE, NULL);
\r
10891 animInfo.lastpos = animInfo.pos;
\r
10892 Sleep(appData.animSpeed);
\r
10894 animInfo.pos = finish;
\r
10895 DrawPosition(FALSE, NULL);
\r
10896 animInfo.piece = EmptySquare;
\r
10897 if(gameInfo.variant == VariantAtomic &&
\r
10898 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10899 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10902 /* Convert board position to corner of screen rect and color */
\r
10905 ScreenSquare(column, row, pt)
\r
10906 int column; int row; POINT * pt;
\r
10909 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10910 pt->y = lineGap + row * (squareSize + lineGap);
\r
10912 pt->x = lineGap + column * (squareSize + lineGap);
\r
10913 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10917 /* Generate a series of frame coords from start->mid->finish.
\r
10918 The movement rate doubles until the half way point is
\r
10919 reached, then halves back down to the final destination,
\r
10920 which gives a nice slow in/out effect. The algorithmn
\r
10921 may seem to generate too many intermediates for short
\r
10922 moves, but remember that the purpose is to attract the
\r
10923 viewers attention to the piece about to be moved and
\r
10924 then to where it ends up. Too few frames would be less
\r
10928 Tween(start, mid, finish, factor, frames, nFrames)
\r
10929 POINT * start; POINT * mid;
\r
10930 POINT * finish; int factor;
\r
10931 POINT frames[]; int * nFrames;
\r
10933 int n, fraction = 1, count = 0;
\r
10935 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10936 for (n = 0; n < factor; n++)
\r
10938 for (n = 0; n < factor; n++) {
\r
10939 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10940 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10942 fraction = fraction / 2;
\r
10946 frames[count] = *mid;
\r
10949 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10951 for (n = 0; n < factor; n++) {
\r
10952 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10953 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10955 fraction = fraction * 2;
\r
10957 *nFrames = count;
\r
10961 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10966 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10967 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10969 OutputDebugString( buf );
\r
10972 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10974 EvalGraphSet( first, last, current, pvInfoList );
\r
10977 void SetProgramStats( FrontEndProgramStats * stats )
\r
10982 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10983 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10985 OutputDebugString( buf );
\r
10988 EngineOutputUpdate( stats );
\r