2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
83 #include "winboard.h"
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
87 #include "wclipbrd.h"
\r
88 #include "wgamelist.h"
\r
89 #include "wedittags.h"
\r
90 #include "woptions.h"
\r
91 #include "wsockerr.h"
\r
92 #include "defaults.h"
\r
96 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
99 void mysrandom(unsigned int seed);
\r
101 extern int whiteFlag, blackFlag;
\r
102 Boolean flipClock = FALSE;
\r
104 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
105 VOID NewVariantPopup(HWND hwnd);
\r
106 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
107 /*char*/int promoChar));
\r
108 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
109 void DisplayMove P((int moveNumber));
\r
110 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
112 ChessSquare piece;
\r
113 POINT pos; /* window coordinates of current pos */
\r
114 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
115 POINT from; /* board coordinates of the piece's orig pos */
\r
116 POINT to; /* board coordinates of the piece's new pos */
\r
119 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
122 POINT start; /* window coordinates of start pos */
\r
123 POINT pos; /* window coordinates of current pos */
\r
124 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
125 POINT from; /* board coordinates of the piece's orig pos */
\r
128 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
131 POINT sq[2]; /* board coordinates of from, to squares */
\r
134 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
135 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
137 typedef struct { // [HGM] atomic
\r
138 int fromX, fromY, toX, toY, radius;
\r
141 static ExplodeInfo explodeInfo;
\r
143 /* Window class names */
\r
144 char szAppName[] = "WinBoard";
\r
145 char szConsoleName[] = "WBConsole";
\r
147 /* Title bar text */
\r
148 char szTitle[] = "WinBoard";
\r
149 char szConsoleTitle[] = "I C S Interaction";
\r
152 char *settingsFileName;
\r
153 BOOLEAN saveSettingsOnExit;
\r
154 char installDir[MSG_SIZ];
\r
156 BoardSize boardSize;
\r
157 BOOLEAN chessProgram;
\r
158 static int boardX, boardY;
\r
159 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
160 static int squareSize, lineGap, minorSize;
\r
161 static int winWidth, winHeight, winW, winH;
\r
162 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
163 static int logoHeight = 0;
\r
164 static char messageText[MESSAGE_TEXT_MAX];
\r
165 static int clockTimerEvent = 0;
\r
166 static int loadGameTimerEvent = 0;
\r
167 static int analysisTimerEvent = 0;
\r
168 static DelayedEventCallback delayedTimerCallback;
\r
169 static int delayedTimerEvent = 0;
\r
170 static int buttonCount = 2;
\r
171 char *icsTextMenuString;
\r
173 char *firstChessProgramNames;
\r
174 char *secondChessProgramNames;
\r
176 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
178 #define PALETTESIZE 256
\r
180 HINSTANCE hInst; /* current instance */
\r
181 HWND hwndMain = NULL; /* root window*/
\r
182 HWND hwndConsole = NULL;
\r
183 BOOLEAN alwaysOnTop = FALSE;
\r
185 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
186 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
188 ColorClass currentColorClass;
\r
190 HWND hCommPort = NULL; /* currently open comm port */
\r
191 static HWND hwndPause; /* pause button */
\r
192 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
193 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
194 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
195 explodeBrush, /* [HGM] atomic */
\r
196 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
197 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
198 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
199 static HPEN gridPen = NULL;
\r
200 static HPEN highlightPen = NULL;
\r
201 static HPEN premovePen = NULL;
\r
202 static NPLOGPALETTE pLogPal;
\r
203 static BOOL paletteChanged = FALSE;
\r
204 static HICON iconWhite, iconBlack, iconCurrent;
\r
205 static int doingSizing = FALSE;
\r
206 static int lastSizing = 0;
\r
207 static int prevStderrPort;
\r
208 static HBITMAP userLogo;
\r
210 /* [AS] Support for background textures */
\r
211 #define BACK_TEXTURE_MODE_DISABLED 0
\r
212 #define BACK_TEXTURE_MODE_PLAIN 1
\r
213 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
215 static HBITMAP liteBackTexture = NULL;
\r
216 static HBITMAP darkBackTexture = NULL;
\r
217 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
218 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
219 static int backTextureSquareSize = 0;
\r
220 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
222 #if __GNUC__ && !defined(_winmajor)
\r
223 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
225 #define oldDialog (_winmajor < 4)
\r
228 char *defaultTextAttribs[] =
\r
230 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
231 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
241 int cliWidth, cliHeight;
\r
244 SizeInfo sizeInfo[] =
\r
246 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
247 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
248 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
249 { "petite", 33, 1, 1, 1, 0, 0 },
\r
250 { "slim", 37, 2, 1, 0, 0, 0 },
\r
251 { "small", 40, 2, 1, 0, 0, 0 },
\r
252 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
253 { "middling", 49, 2, 0, 0, 0, 0 },
\r
254 { "average", 54, 2, 0, 0, 0, 0 },
\r
255 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
256 { "medium", 64, 3, 0, 0, 0, 0 },
\r
257 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
258 { "large", 80, 3, 0, 0, 0, 0 },
\r
259 { "big", 87, 3, 0, 0, 0, 0 },
\r
260 { "huge", 95, 3, 0, 0, 0, 0 },
\r
261 { "giant", 108, 3, 0, 0, 0, 0 },
\r
262 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
263 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
264 { NULL, 0, 0, 0, 0, 0, 0 }
\r
267 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
268 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
270 { 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
271 { 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
272 { 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
273 { 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
274 { 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
275 { 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
276 { 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
277 { 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
278 { 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
279 { 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
280 { 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
281 { 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
282 { 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
283 { 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
284 { 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
285 { 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
286 { 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
287 { 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
290 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
299 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
300 #define N_BUTTONS 5
\r
302 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
304 {"<<", IDM_ToStart, NULL, NULL},
\r
305 {"<", IDM_Backward, NULL, NULL},
\r
306 {"P", IDM_Pause, NULL, NULL},
\r
307 {">", IDM_Forward, NULL, NULL},
\r
308 {">>", IDM_ToEnd, NULL, NULL},
\r
311 int tinyLayout = 0, smallLayout = 0;
\r
312 #define MENU_BAR_ITEMS 7
\r
313 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
314 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
315 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
319 MySound sounds[(int)NSoundClasses];
\r
320 MyTextAttribs textAttribs[(int)NColorClasses];
\r
322 MyColorizeAttribs colorizeAttribs[] = {
\r
323 { (COLORREF)0, 0, "Shout Text" },
\r
324 { (COLORREF)0, 0, "SShout/CShout" },
\r
325 { (COLORREF)0, 0, "Channel 1 Text" },
\r
326 { (COLORREF)0, 0, "Channel Text" },
\r
327 { (COLORREF)0, 0, "Kibitz Text" },
\r
328 { (COLORREF)0, 0, "Tell Text" },
\r
329 { (COLORREF)0, 0, "Challenge Text" },
\r
330 { (COLORREF)0, 0, "Request Text" },
\r
331 { (COLORREF)0, 0, "Seek Text" },
\r
332 { (COLORREF)0, 0, "Normal Text" },
\r
333 { (COLORREF)0, 0, "None" }
\r
338 static char *commentTitle;
\r
339 static char *commentText;
\r
340 static int commentIndex;
\r
341 static Boolean editComment = FALSE;
\r
342 HWND commentDialog = NULL;
\r
343 BOOLEAN commentDialogUp = FALSE;
\r
344 static int commentX, commentY, commentH, commentW;
\r
346 static char *analysisTitle;
\r
347 static char *analysisText;
\r
348 HWND analysisDialog = NULL;
\r
349 BOOLEAN analysisDialogUp = FALSE;
\r
350 static int analysisX, analysisY, analysisH, analysisW;
\r
352 char errorTitle[MSG_SIZ];
\r
353 char errorMessage[2*MSG_SIZ];
\r
354 HWND errorDialog = NULL;
\r
355 BOOLEAN moveErrorMessageUp = FALSE;
\r
356 BOOLEAN consoleEcho = TRUE;
\r
357 CHARFORMAT consoleCF;
\r
358 COLORREF consoleBackgroundColor;
\r
360 char *programVersion;
\r
366 typedef int CPKind;
\r
375 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
378 #define INPUT_SOURCE_BUF_SIZE 4096
\r
380 typedef struct _InputSource {
\r
387 char buf[INPUT_SOURCE_BUF_SIZE];
\r
391 InputCallback func;
\r
392 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
396 InputSource *consoleInputSource;
\r
401 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
402 VOID ConsoleCreate();
\r
404 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
405 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
406 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
407 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
409 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
410 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
411 void ParseIcsTextMenu(char *icsTextMenuString);
\r
412 VOID PopUpMoveDialog(char firstchar);
\r
413 VOID PopUpNameDialog(char firstchar);
\r
414 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
418 int GameListOptions();
\r
420 HWND moveHistoryDialog = NULL;
\r
421 BOOLEAN moveHistoryDialogUp = FALSE;
\r
423 WindowPlacement wpMoveHistory;
\r
425 HWND evalGraphDialog = NULL;
\r
426 BOOLEAN evalGraphDialogUp = FALSE;
\r
428 WindowPlacement wpEvalGraph;
\r
430 HWND engineOutputDialog = NULL;
\r
431 BOOLEAN engineOutputDialogUp = FALSE;
\r
433 WindowPlacement wpEngineOutput;
\r
434 WindowPlacement wpGameList;
\r
435 WindowPlacement wpConsole;
\r
437 VOID MoveHistoryPopUp();
\r
438 VOID MoveHistoryPopDown();
\r
439 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
440 BOOL MoveHistoryIsUp();
\r
442 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
443 VOID EvalGraphPopUp();
\r
444 VOID EvalGraphPopDown();
\r
445 BOOL EvalGraphIsUp();
\r
447 VOID EngineOutputPopUp();
\r
448 VOID EngineOutputPopDown();
\r
449 BOOL EngineOutputIsUp();
\r
450 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
452 VOID GothicPopUp(char *title, VariantClass variant);
\r
454 * Setting "frozen" should disable all user input other than deleting
\r
455 * the window. We do this while engines are initializing themselves.
\r
457 static int frozen = 0;
\r
458 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
464 if (frozen) return;
\r
466 hmenu = GetMenu(hwndMain);
\r
467 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
468 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
470 DrawMenuBar(hwndMain);
\r
473 /* Undo a FreezeUI */
\r
479 if (!frozen) return;
\r
481 hmenu = GetMenu(hwndMain);
\r
482 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
483 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
485 DrawMenuBar(hwndMain);
\r
488 static int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
490 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
495 #define JAWS_ALT_INTERCEPT
\r
496 #define JAWS_KB_NAVIGATION
\r
497 #define JAWS_MENU_ITEMS
\r
498 #define JAWS_SILENCE
\r
499 #define JAWS_REPLAY
\r
501 #define JAWS_COPYRIGHT
\r
502 #define JAWS_DELETE(X) X
\r
503 #define SAYMACHINEMOVE()
\r
507 /*---------------------------------------------------------------------------*\
\r
511 \*---------------------------------------------------------------------------*/
\r
514 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
515 LPSTR lpCmdLine, int nCmdShow)
\r
518 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
519 // INITCOMMONCONTROLSEX ex;
\r
523 LoadLibrary("RICHED32.DLL");
\r
524 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
526 if (!InitApplication(hInstance)) {
\r
529 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
535 // InitCommonControlsEx(&ex);
\r
536 InitCommonControls();
\r
538 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
539 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
540 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
542 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
544 while (GetMessage(&msg, /* message structure */
\r
545 NULL, /* handle of window receiving the message */
\r
546 0, /* lowest message to examine */
\r
547 0)) /* highest message to examine */
\r
550 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
551 // [HGM] navigate: switch between all windows with tab
\r
552 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
553 int i, currentElement = 0;
\r
555 // first determine what element of the chain we come from (if any)
\r
556 if(appData.icsActive) {
\r
557 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
558 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
560 if(engineOutputDialog && EngineOutputIsUp()) {
\r
561 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
562 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
564 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
565 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
567 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
568 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
569 if(msg.hwnd == e1) currentElement = 2; else
\r
570 if(msg.hwnd == e2) currentElement = 3; else
\r
571 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
572 if(msg.hwnd == mh) currentElement = 4; else
\r
573 if(msg.hwnd == evalGraphDialog) currentElement = 7; else
\r
574 if(msg.hwnd == hText) currentElement = 5; else
\r
575 if(msg.hwnd == hInput) currentElement = 6; else
\r
576 for (i = 0; i < N_BUTTONS; i++) {
\r
577 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
580 // determine where to go to
\r
581 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
583 currentElement = (currentElement + direction) % 7;
\r
584 switch(currentElement) {
\r
586 h = hwndMain; break; // passing this case always makes the loop exit
\r
588 h = buttonDesc[0].hwnd; break; // could be NULL
\r
590 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
593 if(!EngineOutputIsUp()) continue;
\r
596 if(!MoveHistoryIsUp()) continue;
\r
598 // case 5: // input to eval graph does not seem to get here!
\r
599 // if(!EvalGraphIsUp()) continue;
\r
600 // h = evalGraphDialog; break;
\r
602 if(!appData.icsActive) continue;
\r
606 if(!appData.icsActive) continue;
\r
612 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
613 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
616 continue; // this message now has been processed
\r
620 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
621 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
622 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
623 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
624 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
625 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
626 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
627 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
628 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
629 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
630 TranslateMessage(&msg); /* Translates virtual key codes */
\r
631 DispatchMessage(&msg); /* Dispatches message to window */
\r
636 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
639 /*---------------------------------------------------------------------------*\
\r
641 * Initialization functions
\r
643 \*---------------------------------------------------------------------------*/
\r
647 { // update user logo if necessary
\r
648 static char oldUserName[MSG_SIZ], *curName;
\r
650 if(appData.autoLogo) {
\r
651 curName = UserName();
\r
652 if(strcmp(curName, oldUserName)) {
\r
653 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
654 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
655 strcpy(oldUserName, curName);
\r
661 InitApplication(HINSTANCE hInstance)
\r
665 /* Fill in window class structure with parameters that describe the */
\r
668 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
669 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
670 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
671 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
672 wc.hInstance = hInstance; /* Owner of this class */
\r
673 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
674 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
675 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
676 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
677 wc.lpszClassName = szAppName; /* Name to register as */
\r
679 /* Register the window class and return success/failure code. */
\r
680 if (!RegisterClass(&wc)) return FALSE;
\r
682 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
683 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
685 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
686 wc.hInstance = hInstance;
\r
687 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
688 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
689 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
690 wc.lpszMenuName = NULL;
\r
691 wc.lpszClassName = szConsoleName;
\r
693 if (!RegisterClass(&wc)) return FALSE;
\r
698 /* Set by InitInstance, used by EnsureOnScreen */
\r
699 int screenHeight, screenWidth;
\r
702 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
704 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
705 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
706 if (*x > screenWidth - 32) *x = 0;
\r
707 if (*y > screenHeight - 32) *y = 0;
\r
708 if (*x < minX) *x = minX;
\r
709 if (*y < minY) *y = minY;
\r
713 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
715 HWND hwnd; /* Main window handle. */
\r
717 WINDOWPLACEMENT wp;
\r
720 hInst = hInstance; /* Store instance handle in our global variable */
\r
722 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
723 *filepart = NULLCHAR;
\r
725 GetCurrentDirectory(MSG_SIZ, installDir);
\r
727 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
728 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
729 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
730 if (appData.debugMode) {
\r
731 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
732 setbuf(debugFP, NULL);
\r
737 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
738 // InitEngineUCI( installDir, &second );
\r
740 /* Create a main window for this application instance. */
\r
741 hwnd = CreateWindow(szAppName, szTitle,
\r
742 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
743 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
744 NULL, NULL, hInstance, NULL);
\r
747 /* If window could not be created, return "failure" */
\r
752 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
753 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
754 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
756 if (first.programLogo == NULL && appData.debugMode) {
\r
757 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
759 } else if(appData.autoLogo) {
\r
760 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
762 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
763 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
767 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
768 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
770 if (second.programLogo == NULL && appData.debugMode) {
\r
771 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
773 } else if(appData.autoLogo) {
\r
775 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
776 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
777 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
779 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
780 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
781 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
787 iconWhite = LoadIcon(hInstance, "icon_white");
\r
788 iconBlack = LoadIcon(hInstance, "icon_black");
\r
789 iconCurrent = iconWhite;
\r
790 InitDrawingColors();
\r
791 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
792 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
793 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
794 /* Compute window size for each board size, and use the largest
\r
795 size that fits on this screen as the default. */
\r
796 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
797 if (boardSize == (BoardSize)-1 &&
\r
798 winH <= screenHeight
\r
799 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
800 && winW <= screenWidth) {
\r
801 boardSize = (BoardSize)ibs;
\r
805 InitDrawingSizes(boardSize, 0);
\r
807 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
809 /* [AS] Load textures if specified */
\r
810 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
812 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
813 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
814 liteBackTextureMode = appData.liteBackTextureMode;
\r
816 if (liteBackTexture == NULL && appData.debugMode) {
\r
817 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
821 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
822 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
823 darkBackTextureMode = appData.darkBackTextureMode;
\r
825 if (darkBackTexture == NULL && appData.debugMode) {
\r
826 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
830 mysrandom( (unsigned) time(NULL) );
\r
832 /* [AS] Restore layout */
\r
833 if( wpMoveHistory.visible ) {
\r
834 MoveHistoryPopUp();
\r
837 if( wpEvalGraph.visible ) {
\r
841 if( wpEngineOutput.visible ) {
\r
842 EngineOutputPopUp();
\r
847 /* Make the window visible; update its client area; and return "success" */
\r
848 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
849 wp.length = sizeof(WINDOWPLACEMENT);
\r
851 wp.showCmd = nCmdShow;
\r
852 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
853 wp.rcNormalPosition.left = boardX;
\r
854 wp.rcNormalPosition.right = boardX + winWidth;
\r
855 wp.rcNormalPosition.top = boardY;
\r
856 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
857 SetWindowPlacement(hwndMain, &wp);
\r
859 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
860 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
864 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
865 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
867 ShowWindow(hwndConsole, nCmdShow);
\r
869 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
877 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
878 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
879 ArgSettingsFilename,
\r
880 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
888 String *pString; // ArgString
\r
889 int *pInt; // ArgInt
\r
890 float *pFloat; // ArgFloat
\r
891 Boolean *pBoolean; // ArgBoolean
\r
892 COLORREF *pColor; // ArgColor
\r
893 ColorClass cc; // ArgAttribs
\r
894 String *pFilename; // ArgFilename
\r
895 BoardSize *pBoardSize; // ArgBoardSize
\r
896 int whichFont; // ArgFont
\r
897 DCB *pDCB; // ArgCommSettings
\r
898 String *pFilename; // ArgSettingsFilename
\r
906 ArgDescriptor argDescriptors[] = {
\r
907 /* positional arguments */
\r
908 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
909 { "", ArgNone, NULL },
\r
910 /* keyword arguments */
\r
911 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
912 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
913 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
914 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
915 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
916 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
917 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
918 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
919 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
920 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
921 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
922 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
923 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
924 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
925 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
926 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
927 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
928 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
930 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
932 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
934 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
935 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
937 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
938 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
939 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
940 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
941 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
942 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
943 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
944 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
945 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
946 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
947 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
948 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
949 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
950 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
951 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
952 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
953 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
954 /*!!bitmapDirectory?*/
\r
955 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
956 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
957 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
958 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
959 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
960 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
961 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
962 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
963 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
964 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
965 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
966 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
967 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
968 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
969 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
970 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
971 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
972 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
973 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
974 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
975 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
976 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
977 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
978 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
979 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
980 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
981 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
982 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
983 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
984 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
985 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
986 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
987 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
988 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
989 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
990 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
991 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
992 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
993 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
994 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
995 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
996 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
997 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
998 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
999 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1000 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1001 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1002 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1003 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1004 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1005 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1006 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1007 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1008 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1009 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1010 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1011 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1012 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1013 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1014 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1015 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1016 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1017 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1018 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1019 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1020 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1021 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1022 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1023 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1024 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1025 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1026 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1027 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1028 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1029 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1030 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1031 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1032 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1033 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1034 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1035 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1036 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1037 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1038 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1039 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1040 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1041 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1042 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1043 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1044 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1045 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1046 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1047 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1048 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1049 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1050 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1051 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1052 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1053 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1054 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1055 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1056 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1057 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1058 TRUE }, /* must come after all fonts */
\r
1059 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1060 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1061 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1062 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1063 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1064 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1065 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1066 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1067 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1068 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1069 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1070 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1071 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1072 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1073 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1074 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1075 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1076 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1077 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1078 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1079 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1080 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1081 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1082 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1083 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1084 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1085 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1086 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1087 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1088 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1089 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1091 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1092 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1094 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1095 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1096 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1097 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1098 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1099 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1100 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1101 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1102 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1103 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1104 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1105 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1106 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1107 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1108 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1109 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1110 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1111 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1112 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1113 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1114 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1115 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1116 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1117 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1118 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1119 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1120 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1121 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1122 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1123 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1124 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1125 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1126 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1127 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1128 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1129 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1130 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1131 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1132 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1133 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1134 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1135 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1136 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1137 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1138 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1139 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1140 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1141 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1142 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1143 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1144 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1145 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1146 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1147 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1148 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1149 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1150 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1151 { "highlightLastMove", ArgBoolean,
\r
1152 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1153 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1154 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1155 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1156 { "highlightDragging", ArgBoolean,
\r
1157 (LPVOID) &appData.highlightDragging, TRUE },
\r
1158 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1159 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1160 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1161 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1162 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1163 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1164 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1165 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1166 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1167 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1168 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1169 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1170 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1171 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1172 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1173 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1174 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1175 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1176 { "soundShout", ArgFilename,
\r
1177 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1178 { "soundSShout", ArgFilename,
\r
1179 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1180 { "soundChannel1", ArgFilename,
\r
1181 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1182 { "soundChannel", ArgFilename,
\r
1183 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1184 { "soundKibitz", ArgFilename,
\r
1185 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1186 { "soundTell", ArgFilename,
\r
1187 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1188 { "soundChallenge", ArgFilename,
\r
1189 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1190 { "soundRequest", ArgFilename,
\r
1191 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1192 { "soundSeek", ArgFilename,
\r
1193 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1194 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1195 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1196 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1197 { "soundIcsLoss", ArgFilename,
\r
1198 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1199 { "soundIcsDraw", ArgFilename,
\r
1200 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1201 { "soundIcsUnfinished", ArgFilename,
\r
1202 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1203 { "soundIcsAlarm", ArgFilename,
\r
1204 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1205 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1206 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1207 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1208 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1209 { "reuseChessPrograms", ArgBoolean,
\r
1210 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1211 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1212 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1213 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1214 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1215 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1216 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1217 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1218 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1219 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1220 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1221 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1222 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1223 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1224 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1225 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1227 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1229 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1230 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1231 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1232 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1233 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1234 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1235 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1236 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1237 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1238 /* [AS] New features */
\r
1239 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1240 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1241 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1242 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1243 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1244 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1245 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1246 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1247 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1248 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1249 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1250 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1251 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1252 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1253 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1254 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1255 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1256 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1257 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1258 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1259 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1260 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1261 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1262 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1263 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1264 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1265 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1266 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1267 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1268 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1269 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1270 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1271 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1272 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1273 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1274 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1275 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1276 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1277 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1278 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1279 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1280 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1281 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1282 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1283 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1284 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1285 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1286 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1287 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1288 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1290 /* [HGM] board-size, adjudication and misc. options */
\r
1291 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1292 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1293 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1294 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1295 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1296 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1297 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1298 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1299 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1300 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1301 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1302 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1303 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1304 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1305 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1306 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1307 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1308 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1309 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1310 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1311 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1312 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1313 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1314 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1315 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1316 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1317 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1318 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1319 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1320 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1321 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1324 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1325 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1326 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1327 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1328 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1329 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1330 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1331 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1332 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1333 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1334 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1335 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1336 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1338 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1339 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1340 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1341 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1342 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1343 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1344 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1346 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1347 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1348 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1349 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1350 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1351 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1352 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1353 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1354 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1355 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1356 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1357 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1358 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1359 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1360 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1361 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1362 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1363 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1364 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1366 /* [HGM] options for broadcasting and time odds */
\r
1367 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1368 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1369 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1370 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1371 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1372 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1373 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1374 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1375 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1376 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1377 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1379 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1380 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1381 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1382 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1383 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1384 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1385 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1386 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1387 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1388 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1389 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1390 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1391 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1392 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1393 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1394 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1395 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1396 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1397 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1398 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1399 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1400 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1401 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1402 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1403 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1404 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1405 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1406 /* [AS] Layout stuff */
\r
1407 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1408 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1409 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1410 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1411 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1413 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1414 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1415 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1416 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1417 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1419 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1420 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1421 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1422 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1423 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1425 { NULL, ArgNone, NULL, FALSE }
\r
1429 /* Kludge for indirection files on command line */
\r
1430 char* lastIndirectionFilename;
\r
1431 ArgDescriptor argDescriptorIndirection =
\r
1432 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1436 ExitArgError(char *msg, char *badArg)
\r
1438 char buf[MSG_SIZ];
\r
1440 sprintf(buf, "%s %s", msg, badArg);
\r
1441 DisplayFatalError(buf, 0, 2);
\r
1445 /* Command line font name parser. NULL name means do nothing.
\r
1446 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1447 For backward compatibility, syntax without the colon is also
\r
1448 accepted, but font names with digits in them won't work in that case.
\r
1451 ParseFontName(char *name, MyFontParams *mfp)
\r
1454 if (name == NULL) return;
\r
1456 q = strchr(p, ':');
\r
1458 if (q - p >= sizeof(mfp->faceName))
\r
1459 ExitArgError("Font name too long:", name);
\r
1460 memcpy(mfp->faceName, p, q - p);
\r
1461 mfp->faceName[q - p] = NULLCHAR;
\r
1464 q = mfp->faceName;
\r
1465 while (*p && !isdigit(*p)) {
\r
1467 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1468 ExitArgError("Font name too long:", name);
\r
1470 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1473 if (!*p) ExitArgError("Font point size missing:", name);
\r
1474 mfp->pointSize = (float) atof(p);
\r
1475 mfp->bold = (strchr(p, 'b') != NULL);
\r
1476 mfp->italic = (strchr(p, 'i') != NULL);
\r
1477 mfp->underline = (strchr(p, 'u') != NULL);
\r
1478 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1481 /* Color name parser.
\r
1482 X version accepts X color names, but this one
\r
1483 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1485 ParseColorName(char *name)
\r
1487 int red, green, blue, count;
\r
1488 char buf[MSG_SIZ];
\r
1490 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1492 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1493 &red, &green, &blue);
\r
1496 sprintf(buf, "Can't parse color name %s", name);
\r
1497 DisplayError(buf, 0);
\r
1498 return RGB(0, 0, 0);
\r
1500 return PALETTERGB(red, green, blue);
\r
1504 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1506 char *e = argValue;
\r
1510 if (*e == 'b') eff |= CFE_BOLD;
\r
1511 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1512 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1513 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1514 else if (*e == '#' || isdigit(*e)) break;
\r
1518 *color = ParseColorName(e);
\r
1523 ParseBoardSize(char *name)
\r
1525 BoardSize bs = SizeTiny;
\r
1526 while (sizeInfo[bs].name != NULL) {
\r
1527 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1530 ExitArgError("Unrecognized board size value", name);
\r
1531 return bs; /* not reached */
\r
1536 StringGet(void *getClosure)
\r
1538 char **p = (char **) getClosure;
\r
1543 FileGet(void *getClosure)
\r
1546 FILE* f = (FILE*) getClosure;
\r
1549 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1556 /* Parse settings file named "name". If file found, return the
\r
1557 full name in fullname and return TRUE; else return FALSE */
\r
1559 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1563 int ok; char buf[MSG_SIZ];
\r
1565 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1566 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1567 sprintf(buf, "%s.ini", name);
\r
1568 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1571 f = fopen(fullname, "r");
\r
1573 ParseArgs(FileGet, f);
\r
1582 ParseArgs(GetFunc get, void *cl)
\r
1584 char argName[ARG_MAX];
\r
1585 char argValue[ARG_MAX];
\r
1586 ArgDescriptor *ad;
\r
1595 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1596 if (ch == NULLCHAR) break;
\r
1598 /* Comment to end of line */
\r
1600 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1602 } else if (ch == '/' || ch == '-') {
\r
1605 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1606 ch != '\n' && ch != '\t') {
\r
1612 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1613 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1615 if (ad->argName == NULL)
\r
1616 ExitArgError("Unrecognized argument", argName);
\r
1618 } else if (ch == '@') {
\r
1619 /* Indirection file */
\r
1620 ad = &argDescriptorIndirection;
\r
1623 /* Positional argument */
\r
1624 ad = &argDescriptors[posarg++];
\r
1625 strcpy(argName, ad->argName);
\r
1628 if (ad->argType == ArgTrue) {
\r
1629 *(Boolean *) ad->argLoc = TRUE;
\r
1632 if (ad->argType == ArgFalse) {
\r
1633 *(Boolean *) ad->argLoc = FALSE;
\r
1637 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1638 if (ch == NULLCHAR || ch == '\n') {
\r
1639 ExitArgError("No value provided for argument", argName);
\r
1643 // Quoting with { }. No characters have to (or can) be escaped.
\r
1644 // Thus the string cannot contain a '}' character.
\r
1664 } else if (ch == '\'' || ch == '"') {
\r
1665 // Quoting with ' ' or " ", with \ as escape character.
\r
1666 // Inconvenient for long strings that may contain Windows filenames.
\r
1683 if (ch == start) {
\r
1692 if (ad->argType == ArgFilename
\r
1693 || ad->argType == ArgSettingsFilename) {
\r
1699 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1723 for (i = 0; i < 3; i++) {
\r
1724 if (ch >= '0' && ch <= '7') {
\r
1725 octval = octval*8 + (ch - '0');
\r
1732 *q++ = (char) octval;
\r
1743 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1750 switch (ad->argType) {
\r
1752 *(int *) ad->argLoc = atoi(argValue);
\r
1756 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1760 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1764 *(int *) ad->argLoc = atoi(argValue);
\r
1765 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1769 *(float *) ad->argLoc = (float) atof(argValue);
\r
1774 *(char **) ad->argLoc = strdup(argValue);
\r
1777 case ArgSettingsFilename:
\r
1779 char fullname[MSG_SIZ];
\r
1780 if (ParseSettingsFile(argValue, fullname)) {
\r
1781 if (ad->argLoc != NULL) {
\r
1782 *(char **) ad->argLoc = strdup(fullname);
\r
1785 if (ad->argLoc != NULL) {
\r
1787 ExitArgError("Failed to open indirection file", argValue);
\r
1794 switch (argValue[0]) {
\r
1797 *(Boolean *) ad->argLoc = TRUE;
\r
1801 *(Boolean *) ad->argLoc = FALSE;
\r
1804 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1810 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1813 case ArgAttribs: {
\r
1814 ColorClass cc = (ColorClass)ad->argLoc;
\r
1815 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1819 case ArgBoardSize:
\r
1820 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1824 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1827 case ArgCommSettings:
\r
1828 ParseCommSettings(argValue, &dcb);
\r
1832 ExitArgError("Unrecognized argument", argValue);
\r
1841 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1843 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1844 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1847 lf->lfEscapement = 0;
\r
1848 lf->lfOrientation = 0;
\r
1849 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1850 lf->lfItalic = mfp->italic;
\r
1851 lf->lfUnderline = mfp->underline;
\r
1852 lf->lfStrikeOut = mfp->strikeout;
\r
1853 lf->lfCharSet = DEFAULT_CHARSET;
\r
1854 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1855 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1856 lf->lfQuality = DEFAULT_QUALITY;
\r
1857 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1858 strcpy(lf->lfFaceName, mfp->faceName);
\r
1862 CreateFontInMF(MyFont *mf)
\r
1864 LFfromMFP(&mf->lf, &mf->mfp);
\r
1865 if (mf->hf) DeleteObject(mf->hf);
\r
1866 mf->hf = CreateFontIndirect(&mf->lf);
\r
1870 SetDefaultTextAttribs()
\r
1873 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1874 ParseAttribs(&textAttribs[cc].color,
\r
1875 &textAttribs[cc].effects,
\r
1876 defaultTextAttribs[cc]);
\r
1881 SetDefaultSounds()
\r
1885 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1886 textAttribs[cc].sound.name = strdup("");
\r
1887 textAttribs[cc].sound.data = NULL;
\r
1889 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1890 sounds[sc].name = strdup("");
\r
1891 sounds[sc].data = NULL;
\r
1893 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1901 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1902 MyLoadSound(&textAttribs[cc].sound);
\r
1904 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1905 MyLoadSound(&sounds[sc]);
\r
1910 InitAppData(LPSTR lpCmdLine)
\r
1913 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1916 programName = szAppName;
\r
1918 /* Initialize to defaults */
\r
1919 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1920 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1921 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1922 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1923 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1924 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1925 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1926 SetDefaultTextAttribs();
\r
1927 SetDefaultSounds();
\r
1928 appData.movesPerSession = MOVES_PER_SESSION;
\r
1929 appData.initString = INIT_STRING;
\r
1930 appData.secondInitString = INIT_STRING;
\r
1931 appData.firstComputerString = COMPUTER_STRING;
\r
1932 appData.secondComputerString = COMPUTER_STRING;
\r
1933 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1934 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1935 appData.firstPlaysBlack = FALSE;
\r
1936 appData.noChessProgram = FALSE;
\r
1937 chessProgram = FALSE;
\r
1938 appData.firstHost = FIRST_HOST;
\r
1939 appData.secondHost = SECOND_HOST;
\r
1940 appData.firstDirectory = FIRST_DIRECTORY;
\r
1941 appData.secondDirectory = SECOND_DIRECTORY;
\r
1942 appData.bitmapDirectory = "";
\r
1943 appData.remoteShell = REMOTE_SHELL;
\r
1944 appData.remoteUser = "";
\r
1945 appData.timeDelay = TIME_DELAY;
\r
1946 appData.timeControl = TIME_CONTROL;
\r
1947 appData.timeIncrement = TIME_INCREMENT;
\r
1948 appData.icsActive = FALSE;
\r
1949 appData.icsHost = "";
\r
1950 appData.icsPort = ICS_PORT;
\r
1951 appData.icsCommPort = ICS_COMM_PORT;
\r
1952 appData.icsLogon = ICS_LOGON;
\r
1953 appData.icsHelper = "";
\r
1954 appData.useTelnet = FALSE;
\r
1955 appData.telnetProgram = TELNET_PROGRAM;
\r
1956 appData.gateway = "";
\r
1957 appData.loadGameFile = "";
\r
1958 appData.loadGameIndex = 0;
\r
1959 appData.saveGameFile = "";
\r
1960 appData.autoSaveGames = FALSE;
\r
1961 appData.loadPositionFile = "";
\r
1962 appData.loadPositionIndex = 1;
\r
1963 appData.savePositionFile = "";
\r
1964 appData.matchMode = FALSE;
\r
1965 appData.matchGames = 0;
\r
1966 appData.monoMode = FALSE;
\r
1967 appData.debugMode = FALSE;
\r
1968 appData.clockMode = TRUE;
\r
1969 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1970 appData.Iconic = FALSE; /*unused*/
\r
1971 appData.searchTime = "";
\r
1972 appData.searchDepth = 0;
\r
1973 appData.showCoords = FALSE;
\r
1974 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1975 appData.autoCallFlag = FALSE;
\r
1976 appData.flipView = FALSE;
\r
1977 appData.autoFlipView = TRUE;
\r
1978 appData.cmailGameName = "";
\r
1979 appData.alwaysPromoteToQueen = FALSE;
\r
1980 appData.oldSaveStyle = FALSE;
\r
1981 appData.quietPlay = FALSE;
\r
1982 appData.showThinking = FALSE;
\r
1983 appData.ponderNextMove = TRUE;
\r
1984 appData.periodicUpdates = TRUE;
\r
1985 appData.popupExitMessage = TRUE;
\r
1986 appData.popupMoveErrors = FALSE;
\r
1987 appData.autoObserve = FALSE;
\r
1988 appData.autoComment = FALSE;
\r
1989 appData.animate = TRUE;
\r
1990 appData.animSpeed = 10;
\r
1991 appData.animateDragging = TRUE;
\r
1992 appData.highlightLastMove = TRUE;
\r
1993 appData.getMoveList = TRUE;
\r
1994 appData.testLegality = TRUE;
\r
1995 appData.premove = TRUE;
\r
1996 appData.premoveWhite = FALSE;
\r
1997 appData.premoveWhiteText = "";
\r
1998 appData.premoveBlack = FALSE;
\r
1999 appData.premoveBlackText = "";
\r
2000 appData.icsAlarm = TRUE;
\r
2001 appData.icsAlarmTime = 5000;
\r
2002 appData.autoRaiseBoard = TRUE;
\r
2003 appData.localLineEditing = TRUE;
\r
2004 appData.colorize = TRUE;
\r
2005 appData.reuseFirst = TRUE;
\r
2006 appData.reuseSecond = TRUE;
\r
2007 appData.blindfold = FALSE;
\r
2008 appData.icsEngineAnalyze = FALSE;
\r
2009 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2010 dcb.DCBlength = sizeof(DCB);
\r
2011 dcb.BaudRate = 9600;
\r
2012 dcb.fBinary = TRUE;
\r
2013 dcb.fParity = FALSE;
\r
2014 dcb.fOutxCtsFlow = FALSE;
\r
2015 dcb.fOutxDsrFlow = FALSE;
\r
2016 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2017 dcb.fDsrSensitivity = FALSE;
\r
2018 dcb.fTXContinueOnXoff = TRUE;
\r
2019 dcb.fOutX = FALSE;
\r
2021 dcb.fNull = FALSE;
\r
2022 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2023 dcb.fAbortOnError = FALSE;
\r
2025 dcb.Parity = SPACEPARITY;
\r
2026 dcb.StopBits = ONESTOPBIT;
\r
2027 settingsFileName = SETTINGS_FILE;
\r
2028 saveSettingsOnExit = TRUE;
\r
2029 boardX = CW_USEDEFAULT;
\r
2030 boardY = CW_USEDEFAULT;
\r
2031 analysisX = CW_USEDEFAULT;
\r
2032 analysisY = CW_USEDEFAULT;
\r
2033 analysisW = CW_USEDEFAULT;
\r
2034 analysisH = CW_USEDEFAULT;
\r
2035 commentX = CW_USEDEFAULT;
\r
2036 commentY = CW_USEDEFAULT;
\r
2037 commentW = CW_USEDEFAULT;
\r
2038 commentH = CW_USEDEFAULT;
\r
2039 editTagsX = CW_USEDEFAULT;
\r
2040 editTagsY = CW_USEDEFAULT;
\r
2041 editTagsW = CW_USEDEFAULT;
\r
2042 editTagsH = CW_USEDEFAULT;
\r
2043 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2044 icsNames = ICS_NAMES;
\r
2045 firstChessProgramNames = FCP_NAMES;
\r
2046 secondChessProgramNames = SCP_NAMES;
\r
2047 appData.initialMode = "";
\r
2048 appData.variant = "normal";
\r
2049 appData.firstProtocolVersion = PROTOVER;
\r
2050 appData.secondProtocolVersion = PROTOVER;
\r
2051 appData.showButtonBar = TRUE;
\r
2053 /* [AS] New properties (see comments in header file) */
\r
2054 appData.firstScoreIsAbsolute = FALSE;
\r
2055 appData.secondScoreIsAbsolute = FALSE;
\r
2056 appData.saveExtendedInfoInPGN = FALSE;
\r
2057 appData.hideThinkingFromHuman = FALSE;
\r
2058 appData.liteBackTextureFile = "";
\r
2059 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2060 appData.darkBackTextureFile = "";
\r
2061 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2062 appData.renderPiecesWithFont = "";
\r
2063 appData.fontToPieceTable = "";
\r
2064 appData.fontBackColorWhite = 0;
\r
2065 appData.fontForeColorWhite = 0;
\r
2066 appData.fontBackColorBlack = 0;
\r
2067 appData.fontForeColorBlack = 0;
\r
2068 appData.fontPieceSize = 80;
\r
2069 appData.overrideLineGap = 1;
\r
2070 appData.adjudicateLossThreshold = 0;
\r
2071 appData.delayBeforeQuit = 0;
\r
2072 appData.delayAfterQuit = 0;
\r
2073 appData.nameOfDebugFile = "winboard.debug";
\r
2074 appData.pgnEventHeader = "Computer Chess Game";
\r
2075 appData.defaultFrcPosition = -1;
\r
2076 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2077 appData.saveOutOfBookInfo = TRUE;
\r
2078 appData.showEvalInMoveHistory = TRUE;
\r
2079 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2080 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2081 appData.highlightMoveWithArrow = FALSE;
\r
2082 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2083 appData.useStickyWindows = TRUE;
\r
2084 appData.adjudicateDrawMoves = 0;
\r
2085 appData.autoDisplayComment = TRUE;
\r
2086 appData.autoDisplayTags = TRUE;
\r
2087 appData.firstIsUCI = FALSE;
\r
2088 appData.secondIsUCI = FALSE;
\r
2089 appData.firstHasOwnBookUCI = TRUE;
\r
2090 appData.secondHasOwnBookUCI = TRUE;
\r
2091 appData.polyglotDir = "";
\r
2092 appData.usePolyglotBook = FALSE;
\r
2093 appData.polyglotBook = "";
\r
2094 appData.defaultHashSize = 64;
\r
2095 appData.defaultCacheSizeEGTB = 4;
\r
2096 appData.defaultPathEGTB = "c:\\egtb";
\r
2097 appData.firstOptions = "";
\r
2098 appData.secondOptions = "";
\r
2100 InitWindowPlacement( &wpGameList );
\r
2101 InitWindowPlacement( &wpMoveHistory );
\r
2102 InitWindowPlacement( &wpEvalGraph );
\r
2103 InitWindowPlacement( &wpEngineOutput );
\r
2104 InitWindowPlacement( &wpConsole );
\r
2106 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2107 appData.NrFiles = -1;
\r
2108 appData.NrRanks = -1;
\r
2109 appData.holdingsSize = -1;
\r
2110 appData.testClaims = FALSE;
\r
2111 appData.checkMates = FALSE;
\r
2112 appData.materialDraws= FALSE;
\r
2113 appData.trivialDraws = FALSE;
\r
2114 appData.ruleMoves = 51;
\r
2115 appData.drawRepeats = 6;
\r
2116 appData.matchPause = 10000;
\r
2117 appData.alphaRank = FALSE;
\r
2118 appData.allWhite = FALSE;
\r
2119 appData.upsideDown = FALSE;
\r
2120 appData.serverPause = 15;
\r
2121 appData.serverMovesName = NULL;
\r
2122 appData.suppressLoadMoves = FALSE;
\r
2123 appData.firstTimeOdds = 1;
\r
2124 appData.secondTimeOdds = 1;
\r
2125 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2126 appData.secondAccumulateTC = 1;
\r
2127 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2128 appData.secondNPS = -1;
\r
2129 appData.engineComments = 1;
\r
2130 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2131 appData.egtFormats = "";
\r
2134 appData.zippyTalk = ZIPPY_TALK;
\r
2135 appData.zippyPlay = ZIPPY_PLAY;
\r
2136 appData.zippyLines = ZIPPY_LINES;
\r
2137 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2138 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2139 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2140 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2141 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2142 appData.zippyUseI = ZIPPY_USE_I;
\r
2143 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2144 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2145 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2146 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2147 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2148 appData.zippyAbort = ZIPPY_ABORT;
\r
2149 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2150 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2151 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2154 /* Point font array elements to structures and
\r
2155 parse default font names */
\r
2156 for (i=0; i<NUM_FONTS; i++) {
\r
2157 for (j=0; j<NUM_SIZES; j++) {
\r
2158 font[j][i] = &fontRec[j][i];
\r
2159 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2163 /* Parse default settings file if any */
\r
2164 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2165 settingsFileName = strdup(buf);
\r
2168 /* Parse command line */
\r
2169 ParseArgs(StringGet, &lpCmdLine);
\r
2171 /* [HGM] make sure board size is acceptable */
\r
2172 if(appData.NrFiles > BOARD_SIZE ||
\r
2173 appData.NrRanks > BOARD_SIZE )
\r
2174 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2176 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2177 * with options from the command line, we now make an even higher priority
\r
2178 * overrule by WB options attached to the engine command line. This so that
\r
2179 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2182 if(appData.firstChessProgram != NULL) {
\r
2183 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2184 static char *f = "first";
\r
2185 char buf[MSG_SIZ], *q = buf;
\r
2186 if(p != NULL) { // engine command line contains WinBoard options
\r
2187 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2188 ParseArgs(StringGet, &q);
\r
2189 p[-1] = 0; // cut them offengine command line
\r
2192 // now do same for second chess program
\r
2193 if(appData.secondChessProgram != NULL) {
\r
2194 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2195 static char *s = "second";
\r
2196 char buf[MSG_SIZ], *q = buf;
\r
2197 if(p != NULL) { // engine command line contains WinBoard options
\r
2198 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2199 ParseArgs(StringGet, &q);
\r
2200 p[-1] = 0; // cut them offengine command line
\r
2205 /* Propagate options that affect others */
\r
2206 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2207 if (appData.icsActive || appData.noChessProgram) {
\r
2208 chessProgram = FALSE; /* not local chess program mode */
\r
2211 /* Open startup dialog if needed */
\r
2212 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2213 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2214 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2215 *appData.secondChessProgram == NULLCHAR))) {
\r
2218 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2219 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2220 FreeProcInstance(lpProc);
\r
2223 /* Make sure save files land in the right (?) directory */
\r
2224 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2225 appData.saveGameFile = strdup(buf);
\r
2227 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2228 appData.savePositionFile = strdup(buf);
\r
2231 /* Finish initialization for fonts and sounds */
\r
2232 for (i=0; i<NUM_FONTS; i++) {
\r
2233 for (j=0; j<NUM_SIZES; j++) {
\r
2234 CreateFontInMF(font[j][i]);
\r
2237 /* xboard, and older WinBoards, controlled the move sound with the
\r
2238 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2239 always turn the option on (so that the backend will call us),
\r
2240 then let the user turn the sound off by setting it to silence if
\r
2241 desired. To accommodate old winboard.ini files saved by old
\r
2242 versions of WinBoard, we also turn off the sound if the option
\r
2243 was initially set to false. */
\r
2244 if (!appData.ringBellAfterMoves) {
\r
2245 sounds[(int)SoundMove].name = strdup("");
\r
2246 appData.ringBellAfterMoves = TRUE;
\r
2248 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2249 SetCurrentDirectory(installDir);
\r
2251 SetCurrentDirectory(currDir);
\r
2253 p = icsTextMenuString;
\r
2254 if (p[0] == '@') {
\r
2255 FILE* f = fopen(p + 1, "r");
\r
2257 DisplayFatalError(p + 1, errno, 2);
\r
2260 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2262 buf[i] = NULLCHAR;
\r
2265 ParseIcsTextMenu(strdup(p));
\r
2272 HMENU hmenu = GetMenu(hwndMain);
\r
2274 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2275 MF_BYCOMMAND|((appData.icsActive &&
\r
2276 *appData.icsCommPort != NULLCHAR) ?
\r
2277 MF_ENABLED : MF_GRAYED));
\r
2278 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2279 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2280 MF_CHECKED : MF_UNCHECKED));
\r
2285 SaveSettings(char* name)
\r
2288 ArgDescriptor *ad;
\r
2289 WINDOWPLACEMENT wp;
\r
2290 char dir[MSG_SIZ];
\r
2292 if (!hwndMain) return;
\r
2294 GetCurrentDirectory(MSG_SIZ, dir);
\r
2295 SetCurrentDirectory(installDir);
\r
2296 f = fopen(name, "w");
\r
2297 SetCurrentDirectory(dir);
\r
2299 DisplayError(name, errno);
\r
2302 fprintf(f, ";\n");
\r
2303 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2304 fprintf(f, ";\n");
\r
2305 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2306 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2307 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2308 fprintf(f, ";\n");
\r
2310 wp.length = sizeof(WINDOWPLACEMENT);
\r
2311 GetWindowPlacement(hwndMain, &wp);
\r
2312 boardX = wp.rcNormalPosition.left;
\r
2313 boardY = wp.rcNormalPosition.top;
\r
2315 if (hwndConsole) {
\r
2316 GetWindowPlacement(hwndConsole, &wp);
\r
2317 wpConsole.x = wp.rcNormalPosition.left;
\r
2318 wpConsole.y = wp.rcNormalPosition.top;
\r
2319 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2320 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2323 if (analysisDialog) {
\r
2324 GetWindowPlacement(analysisDialog, &wp);
\r
2325 analysisX = wp.rcNormalPosition.left;
\r
2326 analysisY = wp.rcNormalPosition.top;
\r
2327 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2328 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2331 if (commentDialog) {
\r
2332 GetWindowPlacement(commentDialog, &wp);
\r
2333 commentX = wp.rcNormalPosition.left;
\r
2334 commentY = wp.rcNormalPosition.top;
\r
2335 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2336 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2339 if (editTagsDialog) {
\r
2340 GetWindowPlacement(editTagsDialog, &wp);
\r
2341 editTagsX = wp.rcNormalPosition.left;
\r
2342 editTagsY = wp.rcNormalPosition.top;
\r
2343 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2344 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2347 if (gameListDialog) {
\r
2348 GetWindowPlacement(gameListDialog, &wp);
\r
2349 wpGameList.x = wp.rcNormalPosition.left;
\r
2350 wpGameList.y = wp.rcNormalPosition.top;
\r
2351 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2352 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2355 /* [AS] Move history */
\r
2356 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2358 if( moveHistoryDialog ) {
\r
2359 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2360 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2361 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2362 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2363 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2366 /* [AS] Eval graph */
\r
2367 wpEvalGraph.visible = EvalGraphIsUp();
\r
2369 if( evalGraphDialog ) {
\r
2370 GetWindowPlacement(evalGraphDialog, &wp);
\r
2371 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2372 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2373 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2374 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2377 /* [AS] Engine output */
\r
2378 wpEngineOutput.visible = EngineOutputIsUp();
\r
2380 if( engineOutputDialog ) {
\r
2381 GetWindowPlacement(engineOutputDialog, &wp);
\r
2382 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2383 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2384 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2385 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2388 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2389 if (!ad->save) continue;
\r
2390 switch (ad->argType) {
\r
2393 char *p = *(char **)ad->argLoc;
\r
2394 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2395 /* Quote multiline values or \-containing values
\r
2396 with { } if possible */
\r
2397 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2399 /* Else quote with " " */
\r
2400 fprintf(f, "/%s=\"", ad->argName);
\r
2402 if (*p == '\n') fprintf(f, "\n");
\r
2403 else if (*p == '\r') fprintf(f, "\\r");
\r
2404 else if (*p == '\t') fprintf(f, "\\t");
\r
2405 else if (*p == '\b') fprintf(f, "\\b");
\r
2406 else if (*p == '\f') fprintf(f, "\\f");
\r
2407 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2408 else if (*p == '\"') fprintf(f, "\\\"");
\r
2409 else if (*p == '\\') fprintf(f, "\\\\");
\r
2413 fprintf(f, "\"\n");
\r
2419 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2422 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2425 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2428 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2431 fprintf(f, "/%s=%s\n", ad->argName,
\r
2432 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2435 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2438 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2442 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2443 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2444 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2449 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2450 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2451 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2452 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2453 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2454 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2455 (ta->effects) ? " " : "",
\r
2456 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2460 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2461 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2463 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2466 case ArgBoardSize:
\r
2467 fprintf(f, "/%s=%s\n", ad->argName,
\r
2468 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2473 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2474 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2475 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2476 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2477 ad->argName, mfp->faceName, mfp->pointSize,
\r
2478 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2479 mfp->bold ? "b" : "",
\r
2480 mfp->italic ? "i" : "",
\r
2481 mfp->underline ? "u" : "",
\r
2482 mfp->strikeout ? "s" : "");
\r
2486 case ArgCommSettings:
\r
2487 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2489 case ArgSettingsFilename: ;
\r
2497 /*---------------------------------------------------------------------------*\
\r
2499 * GDI board drawing routines
\r
2501 \*---------------------------------------------------------------------------*/
\r
2503 /* [AS] Draw square using background texture */
\r
2504 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2509 return; /* Should never happen! */
\r
2512 SetGraphicsMode( dst, GM_ADVANCED );
\r
2519 /* X reflection */
\r
2524 x.eDx = (FLOAT) dw + dx - 1;
\r
2527 SetWorldTransform( dst, &x );
\r
2530 /* Y reflection */
\r
2536 x.eDy = (FLOAT) dh + dy - 1;
\r
2538 SetWorldTransform( dst, &x );
\r
2546 x.eDx = (FLOAT) dx;
\r
2547 x.eDy = (FLOAT) dy;
\r
2550 SetWorldTransform( dst, &x );
\r
2554 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2562 SetWorldTransform( dst, &x );
\r
2564 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2567 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2569 PM_WP = (int) WhitePawn,
\r
2570 PM_WN = (int) WhiteKnight,
\r
2571 PM_WB = (int) WhiteBishop,
\r
2572 PM_WR = (int) WhiteRook,
\r
2573 PM_WQ = (int) WhiteQueen,
\r
2574 PM_WF = (int) WhiteFerz,
\r
2575 PM_WW = (int) WhiteWazir,
\r
2576 PM_WE = (int) WhiteAlfil,
\r
2577 PM_WM = (int) WhiteMan,
\r
2578 PM_WO = (int) WhiteCannon,
\r
2579 PM_WU = (int) WhiteUnicorn,
\r
2580 PM_WH = (int) WhiteNightrider,
\r
2581 PM_WA = (int) WhiteAngel,
\r
2582 PM_WC = (int) WhiteMarshall,
\r
2583 PM_WAB = (int) WhiteCardinal,
\r
2584 PM_WD = (int) WhiteDragon,
\r
2585 PM_WL = (int) WhiteLance,
\r
2586 PM_WS = (int) WhiteCobra,
\r
2587 PM_WV = (int) WhiteFalcon,
\r
2588 PM_WSG = (int) WhiteSilver,
\r
2589 PM_WG = (int) WhiteGrasshopper,
\r
2590 PM_WK = (int) WhiteKing,
\r
2591 PM_BP = (int) BlackPawn,
\r
2592 PM_BN = (int) BlackKnight,
\r
2593 PM_BB = (int) BlackBishop,
\r
2594 PM_BR = (int) BlackRook,
\r
2595 PM_BQ = (int) BlackQueen,
\r
2596 PM_BF = (int) BlackFerz,
\r
2597 PM_BW = (int) BlackWazir,
\r
2598 PM_BE = (int) BlackAlfil,
\r
2599 PM_BM = (int) BlackMan,
\r
2600 PM_BO = (int) BlackCannon,
\r
2601 PM_BU = (int) BlackUnicorn,
\r
2602 PM_BH = (int) BlackNightrider,
\r
2603 PM_BA = (int) BlackAngel,
\r
2604 PM_BC = (int) BlackMarshall,
\r
2605 PM_BG = (int) BlackGrasshopper,
\r
2606 PM_BAB = (int) BlackCardinal,
\r
2607 PM_BD = (int) BlackDragon,
\r
2608 PM_BL = (int) BlackLance,
\r
2609 PM_BS = (int) BlackCobra,
\r
2610 PM_BV = (int) BlackFalcon,
\r
2611 PM_BSG = (int) BlackSilver,
\r
2612 PM_BK = (int) BlackKing
\r
2615 static HFONT hPieceFont = NULL;
\r
2616 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2617 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2618 static int fontBitmapSquareSize = 0;
\r
2619 static char pieceToFontChar[(int) EmptySquare] =
\r
2620 { 'p', 'n', 'b', 'r', 'q',
\r
2621 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2622 'k', 'o', 'm', 'v', 't', 'w',
\r
2623 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2626 extern BOOL SetCharTable( char *table, const char * map );
\r
2627 /* [HGM] moved to backend.c */
\r
2629 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2632 BYTE r1 = GetRValue( color );
\r
2633 BYTE g1 = GetGValue( color );
\r
2634 BYTE b1 = GetBValue( color );
\r
2640 /* Create a uniform background first */
\r
2641 hbrush = CreateSolidBrush( color );
\r
2642 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2643 FillRect( hdc, &rc, hbrush );
\r
2644 DeleteObject( hbrush );
\r
2647 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2648 int steps = squareSize / 2;
\r
2651 for( i=0; i<steps; i++ ) {
\r
2652 BYTE r = r1 - (r1-r2) * i / steps;
\r
2653 BYTE g = g1 - (g1-g2) * i / steps;
\r
2654 BYTE b = b1 - (b1-b2) * i / steps;
\r
2656 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2657 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2658 FillRect( hdc, &rc, hbrush );
\r
2659 DeleteObject(hbrush);
\r
2662 else if( mode == 2 ) {
\r
2663 /* Diagonal gradient, good more or less for every piece */
\r
2664 POINT triangle[3];
\r
2665 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2666 HBRUSH hbrush_old;
\r
2667 int steps = squareSize;
\r
2670 triangle[0].x = squareSize - steps;
\r
2671 triangle[0].y = squareSize;
\r
2672 triangle[1].x = squareSize;
\r
2673 triangle[1].y = squareSize;
\r
2674 triangle[2].x = squareSize;
\r
2675 triangle[2].y = squareSize - steps;
\r
2677 for( i=0; i<steps; i++ ) {
\r
2678 BYTE r = r1 - (r1-r2) * i / steps;
\r
2679 BYTE g = g1 - (g1-g2) * i / steps;
\r
2680 BYTE b = b1 - (b1-b2) * i / steps;
\r
2682 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2683 hbrush_old = SelectObject( hdc, hbrush );
\r
2684 Polygon( hdc, triangle, 3 );
\r
2685 SelectObject( hdc, hbrush_old );
\r
2686 DeleteObject(hbrush);
\r
2691 SelectObject( hdc, hpen );
\r
2696 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2697 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2698 piece: follow the steps as explained below.
\r
2700 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2704 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2708 int backColor = whitePieceColor;
\r
2709 int foreColor = blackPieceColor;
\r
2711 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2712 backColor = appData.fontBackColorWhite;
\r
2713 foreColor = appData.fontForeColorWhite;
\r
2715 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2716 backColor = appData.fontBackColorBlack;
\r
2717 foreColor = appData.fontForeColorBlack;
\r
2721 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2723 hbm_old = SelectObject( hdc, hbm );
\r
2727 rc.right = squareSize;
\r
2728 rc.bottom = squareSize;
\r
2730 /* Step 1: background is now black */
\r
2731 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2733 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2735 pt.x = (squareSize - sz.cx) / 2;
\r
2736 pt.y = (squareSize - sz.cy) / 2;
\r
2738 SetBkMode( hdc, TRANSPARENT );
\r
2739 SetTextColor( hdc, chroma );
\r
2740 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2741 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2743 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2744 /* Step 3: the area outside the piece is filled with white */
\r
2745 // FloodFill( hdc, 0, 0, chroma );
\r
2746 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2747 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2748 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2749 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2750 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2752 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2753 but if the start point is not inside the piece we're lost!
\r
2754 There should be a better way to do this... if we could create a region or path
\r
2755 from the fill operation we would be fine for example.
\r
2757 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2758 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2760 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2761 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2762 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2764 SelectObject( dc2, bm2 );
\r
2765 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2766 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2767 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2768 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2769 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2772 DeleteObject( bm2 );
\r
2775 SetTextColor( hdc, 0 );
\r
2777 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2778 draw the piece again in black for safety.
\r
2780 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2782 SelectObject( hdc, hbm_old );
\r
2784 if( hPieceMask[index] != NULL ) {
\r
2785 DeleteObject( hPieceMask[index] );
\r
2788 hPieceMask[index] = hbm;
\r
2791 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2793 SelectObject( hdc, hbm );
\r
2796 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2797 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2798 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2800 SelectObject( dc1, hPieceMask[index] );
\r
2801 SelectObject( dc2, bm2 );
\r
2802 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2803 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2806 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2807 the piece background and deletes (makes transparent) the rest.
\r
2808 Thanks to that mask, we are free to paint the background with the greates
\r
2809 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2810 We use this, to make gradients and give the pieces a "roundish" look.
\r
2812 SetPieceBackground( hdc, backColor, 2 );
\r
2813 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2817 DeleteObject( bm2 );
\r
2820 SetTextColor( hdc, foreColor );
\r
2821 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2823 SelectObject( hdc, hbm_old );
\r
2825 if( hPieceFace[index] != NULL ) {
\r
2826 DeleteObject( hPieceFace[index] );
\r
2829 hPieceFace[index] = hbm;
\r
2832 static int TranslatePieceToFontPiece( int piece )
\r
2862 case BlackMarshall:
\r
2866 case BlackNightrider:
\r
2872 case BlackUnicorn:
\r
2876 case BlackGrasshopper:
\r
2888 case BlackCardinal:
\r
2895 case WhiteMarshall:
\r
2899 case WhiteNightrider:
\r
2905 case WhiteUnicorn:
\r
2909 case WhiteGrasshopper:
\r
2921 case WhiteCardinal:
\r
2930 void CreatePiecesFromFont()
\r
2933 HDC hdc_window = NULL;
\r
2939 if( fontBitmapSquareSize < 0 ) {
\r
2940 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2944 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2945 fontBitmapSquareSize = -1;
\r
2949 if( fontBitmapSquareSize != squareSize ) {
\r
2950 hdc_window = GetDC( hwndMain );
\r
2951 hdc = CreateCompatibleDC( hdc_window );
\r
2953 if( hPieceFont != NULL ) {
\r
2954 DeleteObject( hPieceFont );
\r
2957 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2958 hPieceMask[i] = NULL;
\r
2959 hPieceFace[i] = NULL;
\r
2965 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2966 fontHeight = appData.fontPieceSize;
\r
2969 fontHeight = (fontHeight * squareSize) / 100;
\r
2971 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2973 lf.lfEscapement = 0;
\r
2974 lf.lfOrientation = 0;
\r
2975 lf.lfWeight = FW_NORMAL;
\r
2977 lf.lfUnderline = 0;
\r
2978 lf.lfStrikeOut = 0;
\r
2979 lf.lfCharSet = DEFAULT_CHARSET;
\r
2980 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2981 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2982 lf.lfQuality = PROOF_QUALITY;
\r
2983 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2984 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2985 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2987 hPieceFont = CreateFontIndirect( &lf );
\r
2989 if( hPieceFont == NULL ) {
\r
2990 fontBitmapSquareSize = -2;
\r
2993 /* Setup font-to-piece character table */
\r
2994 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2995 /* No (or wrong) global settings, try to detect the font */
\r
2996 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2998 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3000 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3001 /* DiagramTT* family */
\r
3002 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3004 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3005 /* Fairy symbols */
\r
3006 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3008 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3009 /* Good Companion (Some characters get warped as literal :-( */
\r
3010 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3011 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3012 SetCharTable(pieceToFontChar, s);
\r
3015 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3016 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3020 /* Create bitmaps */
\r
3021 hfont_old = SelectObject( hdc, hPieceFont );
\r
3023 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3024 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3025 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3026 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3027 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3028 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3029 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3030 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3031 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3032 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3033 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3034 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3036 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3037 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3038 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3039 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3040 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3042 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3043 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3048 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3050 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3051 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3055 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3056 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3063 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3064 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3065 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3066 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3067 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3069 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3070 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3071 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3073 SelectObject( hdc, hfont_old );
\r
3075 fontBitmapSquareSize = squareSize;
\r
3079 if( hdc != NULL ) {
\r
3083 if( hdc_window != NULL ) {
\r
3084 ReleaseDC( hwndMain, hdc_window );
\r
3089 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3093 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3094 if (gameInfo.event &&
\r
3095 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3096 strcmp(name, "k80s") == 0) {
\r
3097 strcpy(name, "tim");
\r
3099 return LoadBitmap(hinst, name);
\r
3103 /* Insert a color into the program's logical palette
\r
3104 structure. This code assumes the given color is
\r
3105 the result of the RGB or PALETTERGB macro, and it
\r
3106 knows how those macros work (which is documented).
\r
3109 InsertInPalette(COLORREF color)
\r
3111 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3113 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3114 DisplayFatalError("Too many colors", 0, 1);
\r
3115 pLogPal->palNumEntries--;
\r
3119 pe->peFlags = (char) 0;
\r
3120 pe->peRed = (char) (0xFF & color);
\r
3121 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3122 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3128 InitDrawingColors()
\r
3130 if (pLogPal == NULL) {
\r
3131 /* Allocate enough memory for a logical palette with
\r
3132 * PALETTESIZE entries and set the size and version fields
\r
3133 * of the logical palette structure.
\r
3135 pLogPal = (NPLOGPALETTE)
\r
3136 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3137 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3138 pLogPal->palVersion = 0x300;
\r
3140 pLogPal->palNumEntries = 0;
\r
3142 InsertInPalette(lightSquareColor);
\r
3143 InsertInPalette(darkSquareColor);
\r
3144 InsertInPalette(whitePieceColor);
\r
3145 InsertInPalette(blackPieceColor);
\r
3146 InsertInPalette(highlightSquareColor);
\r
3147 InsertInPalette(premoveHighlightColor);
\r
3149 /* create a logical color palette according the information
\r
3150 * in the LOGPALETTE structure.
\r
3152 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3154 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3155 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3156 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3157 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3158 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3159 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3160 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3161 /* [AS] Force rendering of the font-based pieces */
\r
3162 if( fontBitmapSquareSize > 0 ) {
\r
3163 fontBitmapSquareSize = 0;
\r
3169 BoardWidth(int boardSize, int n)
\r
3170 { /* [HGM] argument n added to allow different width and height */
\r
3171 int lineGap = sizeInfo[boardSize].lineGap;
\r
3173 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3174 lineGap = appData.overrideLineGap;
\r
3177 return (n + 1) * lineGap +
\r
3178 n * sizeInfo[boardSize].squareSize;
\r
3181 /* Respond to board resize by dragging edge */
\r
3183 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3185 BoardSize newSize = NUM_SIZES - 1;
\r
3186 static int recurse = 0;
\r
3187 if (IsIconic(hwndMain)) return;
\r
3188 if (recurse > 0) return;
\r
3190 while (newSize > 0) {
\r
3191 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3192 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3193 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3196 boardSize = newSize;
\r
3197 InitDrawingSizes(boardSize, flags);
\r
3204 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3206 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3207 ChessSquare piece;
\r
3208 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3210 SIZE clockSize, messageSize;
\r
3212 char buf[MSG_SIZ];
\r
3214 HMENU hmenu = GetMenu(hwndMain);
\r
3215 RECT crect, wrect, oldRect;
\r
3217 LOGBRUSH logbrush;
\r
3219 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3220 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3222 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3223 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3225 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3226 oldRect.top = boardY;
\r
3227 oldRect.right = boardX + winWidth;
\r
3228 oldRect.bottom = boardY + winHeight;
\r
3230 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3231 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3232 squareSize = sizeInfo[boardSize].squareSize;
\r
3233 lineGap = sizeInfo[boardSize].lineGap;
\r
3234 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3236 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3237 lineGap = appData.overrideLineGap;
\r
3240 if (tinyLayout != oldTinyLayout) {
\r
3241 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3243 style &= ~WS_SYSMENU;
\r
3244 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3245 "&Minimize\tCtrl+F4");
\r
3247 style |= WS_SYSMENU;
\r
3248 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3250 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3252 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3253 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3254 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3256 DrawMenuBar(hwndMain);
\r
3259 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3260 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3262 /* Get text area sizes */
\r
3263 hdc = GetDC(hwndMain);
\r
3264 if (appData.clockMode) {
\r
3265 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3267 sprintf(buf, "White");
\r
3269 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3270 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3271 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3272 str = "We only care about the height here";
\r
3273 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3274 SelectObject(hdc, oldFont);
\r
3275 ReleaseDC(hwndMain, hdc);
\r
3277 /* Compute where everything goes */
\r
3278 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3279 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3280 logoHeight = 2*clockSize.cy;
\r
3281 leftLogoRect.left = OUTER_MARGIN;
\r
3282 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3283 leftLogoRect.top = OUTER_MARGIN;
\r
3284 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3286 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3287 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3288 rightLogoRect.top = OUTER_MARGIN;
\r
3289 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3292 whiteRect.left = leftLogoRect.right;
\r
3293 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3294 whiteRect.top = OUTER_MARGIN;
\r
3295 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3297 blackRect.right = rightLogoRect.left;
\r
3298 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3299 blackRect.top = whiteRect.top;
\r
3300 blackRect.bottom = whiteRect.bottom;
\r
3302 whiteRect.left = OUTER_MARGIN;
\r
3303 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3304 whiteRect.top = OUTER_MARGIN;
\r
3305 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3307 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3308 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3309 blackRect.top = whiteRect.top;
\r
3310 blackRect.bottom = whiteRect.bottom;
\r
3313 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3314 if (appData.showButtonBar) {
\r
3315 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3316 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3318 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3320 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3321 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3323 boardRect.left = OUTER_MARGIN;
\r
3324 boardRect.right = boardRect.left + boardWidth;
\r
3325 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3326 boardRect.bottom = boardRect.top + boardHeight;
\r
3328 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3329 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3330 oldBoardSize = boardSize;
\r
3331 oldTinyLayout = tinyLayout;
\r
3332 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3333 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3334 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3335 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3336 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3337 winHeight = winH; // without disturbing window attachments
\r
3338 GetWindowRect(hwndMain, &wrect);
\r
3339 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3340 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3342 // [HGM] placement: let attached windows follow size change.
\r
3343 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3344 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3345 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3346 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3347 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3349 /* compensate if menu bar wrapped */
\r
3350 GetClientRect(hwndMain, &crect);
\r
3351 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3352 winHeight += offby;
\r
3354 case WMSZ_TOPLEFT:
\r
3355 SetWindowPos(hwndMain, NULL,
\r
3356 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3357 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3360 case WMSZ_TOPRIGHT:
\r
3362 SetWindowPos(hwndMain, NULL,
\r
3363 wrect.left, wrect.bottom - winHeight,
\r
3364 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3367 case WMSZ_BOTTOMLEFT:
\r
3369 SetWindowPos(hwndMain, NULL,
\r
3370 wrect.right - winWidth, wrect.top,
\r
3371 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3374 case WMSZ_BOTTOMRIGHT:
\r
3378 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3379 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3384 for (i = 0; i < N_BUTTONS; i++) {
\r
3385 if (buttonDesc[i].hwnd != NULL) {
\r
3386 DestroyWindow(buttonDesc[i].hwnd);
\r
3387 buttonDesc[i].hwnd = NULL;
\r
3389 if (appData.showButtonBar) {
\r
3390 buttonDesc[i].hwnd =
\r
3391 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3392 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3393 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3394 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3395 (HMENU) buttonDesc[i].id,
\r
3396 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3398 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3399 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3400 MAKELPARAM(FALSE, 0));
\r
3402 if (buttonDesc[i].id == IDM_Pause)
\r
3403 hwndPause = buttonDesc[i].hwnd;
\r
3404 buttonDesc[i].wndproc = (WNDPROC)
\r
3405 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3408 if (gridPen != NULL) DeleteObject(gridPen);
\r
3409 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3410 if (premovePen != NULL) DeleteObject(premovePen);
\r
3411 if (lineGap != 0) {
\r
3412 logbrush.lbStyle = BS_SOLID;
\r
3413 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3415 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3416 lineGap, &logbrush, 0, NULL);
\r
3417 logbrush.lbColor = highlightSquareColor;
\r
3419 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3420 lineGap, &logbrush, 0, NULL);
\r
3422 logbrush.lbColor = premoveHighlightColor;
\r
3424 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3425 lineGap, &logbrush, 0, NULL);
\r
3427 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3428 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3429 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3430 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3431 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3432 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3433 BOARD_WIDTH * (squareSize + lineGap);
\r
3434 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3436 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3437 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3438 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3439 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3440 lineGap / 2 + (i * (squareSize + lineGap));
\r
3441 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3442 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3443 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3447 /* [HGM] Licensing requirement */
\r
3449 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3452 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3454 GothicPopUp( "", VariantNormal);
\r
3457 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3459 /* Load piece bitmaps for this board size */
\r
3460 for (i=0; i<=2; i++) {
\r
3461 for (piece = WhitePawn;
\r
3462 (int) piece < (int) BlackPawn;
\r
3463 piece = (ChessSquare) ((int) piece + 1)) {
\r
3464 if (pieceBitmap[i][piece] != NULL)
\r
3465 DeleteObject(pieceBitmap[i][piece]);
\r
3469 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3470 // Orthodox Chess pieces
\r
3471 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3472 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3473 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3474 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3475 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3476 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3477 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3478 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3479 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3480 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3481 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3482 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3483 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3484 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3485 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3486 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3487 // in Shogi, Hijack the unused Queen for Lance
\r
3488 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3489 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3490 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3492 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3493 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3494 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3497 if(squareSize <= 72 && squareSize >= 33) {
\r
3498 /* A & C are available in most sizes now */
\r
3499 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3500 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3501 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3502 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3503 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3504 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3505 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3506 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3507 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3508 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3509 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3510 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3511 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3512 } else { // Smirf-like
\r
3513 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3514 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3515 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3517 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3518 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3519 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3520 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3521 } else { // WinBoard standard
\r
3522 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3523 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3524 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3529 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3530 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3531 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3532 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3533 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3534 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3535 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3536 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3537 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3538 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3539 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3540 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3541 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3542 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3543 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3544 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3545 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3546 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3547 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3548 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3549 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3550 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3551 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3552 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3553 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3554 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3555 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3556 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3557 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3558 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3559 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3561 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3562 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3563 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3564 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3565 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3566 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3567 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3568 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3569 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3570 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3571 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3572 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3573 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3575 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3576 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3577 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3578 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3579 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3580 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3581 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3582 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3583 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3584 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3585 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3586 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3589 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3590 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3591 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3592 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3593 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3594 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3595 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3596 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3597 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3598 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3599 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3600 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3601 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3602 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3603 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3607 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3608 /* special Shogi support in this size */
\r
3609 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3610 for (piece = WhitePawn;
\r
3611 (int) piece < (int) BlackPawn;
\r
3612 piece = (ChessSquare) ((int) piece + 1)) {
\r
3613 if (pieceBitmap[i][piece] != NULL)
\r
3614 DeleteObject(pieceBitmap[i][piece]);
\r
3617 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3618 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3619 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3620 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3621 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3622 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3623 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3624 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3625 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3626 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3627 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3628 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3629 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3630 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3631 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3632 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3633 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3634 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3635 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3636 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3637 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3638 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3639 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3640 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3641 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3642 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3643 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3644 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3645 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3646 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3647 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3648 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3649 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3650 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3651 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3652 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3653 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3654 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3655 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3656 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3657 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3658 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3664 PieceBitmap(ChessSquare p, int kind)
\r
3666 if ((int) p >= (int) BlackPawn)
\r
3667 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3669 return pieceBitmap[kind][(int) p];
\r
3672 /***************************************************************/
\r
3674 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3675 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3677 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3678 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3682 SquareToPos(int row, int column, int * x, int * y)
\r
3685 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3686 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3688 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3689 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3694 DrawCoordsOnDC(HDC hdc)
\r
3696 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
3697 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
3698 char str[2] = { NULLCHAR, NULLCHAR };
\r
3699 int oldMode, oldAlign, x, y, start, i;
\r
3703 if (!appData.showCoords)
\r
3706 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3708 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3709 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3710 oldAlign = GetTextAlign(hdc);
\r
3711 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3713 y = boardRect.top + lineGap;
\r
3714 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3716 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3717 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3718 str[0] = files[start + i];
\r
3719 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3720 y += squareSize + lineGap;
\r
3723 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3725 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3726 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3727 str[0] = ranks[start + i];
\r
3728 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3729 x += squareSize + lineGap;
\r
3732 SelectObject(hdc, oldBrush);
\r
3733 SetBkMode(hdc, oldMode);
\r
3734 SetTextAlign(hdc, oldAlign);
\r
3735 SelectObject(hdc, oldFont);
\r
3739 DrawGridOnDC(HDC hdc)
\r
3743 if (lineGap != 0) {
\r
3744 oldPen = SelectObject(hdc, gridPen);
\r
3745 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3746 SelectObject(hdc, oldPen);
\r
3750 #define HIGHLIGHT_PEN 0
\r
3751 #define PREMOVE_PEN 1
\r
3754 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3757 HPEN oldPen, hPen;
\r
3758 if (lineGap == 0) return;
\r
3760 x1 = boardRect.left +
\r
3761 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3762 y1 = boardRect.top +
\r
3763 lineGap/2 + y * (squareSize + lineGap);
\r
3765 x1 = boardRect.left +
\r
3766 lineGap/2 + x * (squareSize + lineGap);
\r
3767 y1 = boardRect.top +
\r
3768 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3770 hPen = pen ? premovePen : highlightPen;
\r
3771 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3772 MoveToEx(hdc, x1, y1, NULL);
\r
3773 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3774 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3775 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3776 LineTo(hdc, x1, y1);
\r
3777 SelectObject(hdc, oldPen);
\r
3781 DrawHighlightsOnDC(HDC hdc)
\r
3784 for (i=0; i<2; i++) {
\r
3785 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3786 DrawHighlightOnDC(hdc, TRUE,
\r
3787 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3790 for (i=0; i<2; i++) {
\r
3791 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3792 premoveHighlightInfo.sq[i].y >= 0) {
\r
3793 DrawHighlightOnDC(hdc, TRUE,
\r
3794 premoveHighlightInfo.sq[i].x,
\r
3795 premoveHighlightInfo.sq[i].y,
\r
3801 /* Note: sqcolor is used only in monoMode */
\r
3802 /* Note that this code is largely duplicated in woptions.c,
\r
3803 function DrawSampleSquare, so that needs to be updated too */
\r
3805 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3807 HBITMAP oldBitmap;
\r
3811 if (appData.blindfold) return;
\r
3813 /* [AS] Use font-based pieces if needed */
\r
3814 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3815 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3816 CreatePiecesFromFont();
\r
3818 if( fontBitmapSquareSize == squareSize ) {
\r
3819 int index = TranslatePieceToFontPiece(piece);
\r
3821 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3825 squareSize, squareSize,
\r
3830 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3834 squareSize, squareSize,
\r
3843 if (appData.monoMode) {
\r
3844 SelectObject(tmphdc, PieceBitmap(piece,
\r
3845 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3846 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3847 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3849 tmpSize = squareSize;
\r
3851 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3852 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3853 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3854 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3855 x += (squareSize - minorSize)>>1;
\r
3856 y += squareSize - minorSize - 2;
\r
3857 tmpSize = minorSize;
\r
3859 if (color || appData.allWhite ) {
\r
3860 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3862 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3863 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3864 if(appData.upsideDown && color==flipView)
\r
3865 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3867 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3869 /* Use black piece color for outline of white pieces */
\r
3870 /* Not sure this looks really good (though xboard does it).
\r
3871 Maybe better to have another selectable color, default black */
\r
3872 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3873 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3874 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3876 /* Use black for outline of white pieces */
\r
3877 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3878 if(appData.upsideDown && color==flipView)
\r
3879 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3881 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3885 /* Use white piece color for details of black pieces */
\r
3886 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3887 WHITE_PIECE ones aren't always the right shape. */
\r
3888 /* Not sure this looks really good (though xboard does it).
\r
3889 Maybe better to have another selectable color, default medium gray? */
\r
3890 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3891 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3892 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3893 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3894 SelectObject(hdc, blackPieceBrush);
\r
3895 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3897 /* Use square color for details of black pieces */
\r
3898 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3899 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3900 if(appData.upsideDown && !flipView)
\r
3901 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3903 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3906 SelectObject(hdc, oldBrush);
\r
3907 SelectObject(tmphdc, oldBitmap);
\r
3911 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3912 int GetBackTextureMode( int algo )
\r
3914 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3918 case BACK_TEXTURE_MODE_PLAIN:
\r
3919 result = 1; /* Always use identity map */
\r
3921 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3922 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3930 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3931 to handle redraws cleanly (as random numbers would always be different).
\r
3933 VOID RebuildTextureSquareInfo()
\r
3943 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3945 if( liteBackTexture != NULL ) {
\r
3946 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3947 lite_w = bi.bmWidth;
\r
3948 lite_h = bi.bmHeight;
\r
3952 if( darkBackTexture != NULL ) {
\r
3953 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3954 dark_w = bi.bmWidth;
\r
3955 dark_h = bi.bmHeight;
\r
3959 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3960 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3961 if( (col + row) & 1 ) {
\r
3963 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3964 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3965 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3966 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3971 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3972 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3973 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3974 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3981 /* [AS] Arrow highlighting support */
\r
3983 static int A_WIDTH = 5; /* Width of arrow body */
\r
3985 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3986 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3988 static double Sqr( double x )
\r
3993 static int Round( double x )
\r
3995 return (int) (x + 0.5);
\r
3998 /* Draw an arrow between two points using current settings */
\r
3999 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
4002 double dx, dy, j, k, x, y;
\r
4004 if( d_x == s_x ) {
\r
4005 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4007 arrow[0].x = s_x + A_WIDTH;
\r
4010 arrow[1].x = s_x + A_WIDTH;
\r
4011 arrow[1].y = d_y - h;
\r
4013 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4014 arrow[2].y = d_y - h;
\r
4019 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4020 arrow[4].y = d_y - h;
\r
4022 arrow[5].x = s_x - A_WIDTH;
\r
4023 arrow[5].y = d_y - h;
\r
4025 arrow[6].x = s_x - A_WIDTH;
\r
4028 else if( d_y == s_y ) {
\r
4029 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4032 arrow[0].y = s_y + A_WIDTH;
\r
4034 arrow[1].x = d_x - w;
\r
4035 arrow[1].y = s_y + A_WIDTH;
\r
4037 arrow[2].x = d_x - w;
\r
4038 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4043 arrow[4].x = d_x - w;
\r
4044 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4046 arrow[5].x = d_x - w;
\r
4047 arrow[5].y = s_y - A_WIDTH;
\r
4050 arrow[6].y = s_y - A_WIDTH;
\r
4053 /* [AS] Needed a lot of paper for this! :-) */
\r
4054 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4055 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4057 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4059 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4064 arrow[0].x = Round(x - j);
\r
4065 arrow[0].y = Round(y + j*dx);
\r
4067 arrow[1].x = Round(x + j);
\r
4068 arrow[1].y = Round(y - j*dx);
\r
4071 x = (double) d_x - k;
\r
4072 y = (double) d_y - k*dy;
\r
4075 x = (double) d_x + k;
\r
4076 y = (double) d_y + k*dy;
\r
4079 arrow[2].x = Round(x + j);
\r
4080 arrow[2].y = Round(y - j*dx);
\r
4082 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4083 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4088 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4089 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4091 arrow[6].x = Round(x - j);
\r
4092 arrow[6].y = Round(y + j*dx);
\r
4095 Polygon( hdc, arrow, 7 );
\r
4098 /* [AS] Draw an arrow between two squares */
\r
4099 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4101 int s_x, s_y, d_x, d_y;
\r
4108 if( s_col == d_col && s_row == d_row ) {
\r
4112 /* Get source and destination points */
\r
4113 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4114 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4117 d_y += squareSize / 4;
\r
4119 else if( d_y < s_y ) {
\r
4120 d_y += 3 * squareSize / 4;
\r
4123 d_y += squareSize / 2;
\r
4127 d_x += squareSize / 4;
\r
4129 else if( d_x < s_x ) {
\r
4130 d_x += 3 * squareSize / 4;
\r
4133 d_x += squareSize / 2;
\r
4136 s_x += squareSize / 2;
\r
4137 s_y += squareSize / 2;
\r
4139 /* Adjust width */
\r
4140 A_WIDTH = squareSize / 14;
\r
4143 stLB.lbStyle = BS_SOLID;
\r
4144 stLB.lbColor = appData.highlightArrowColor;
\r
4147 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4148 holdpen = SelectObject( hdc, hpen );
\r
4149 hbrush = CreateBrushIndirect( &stLB );
\r
4150 holdbrush = SelectObject( hdc, hbrush );
\r
4152 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4154 SelectObject( hdc, holdpen );
\r
4155 SelectObject( hdc, holdbrush );
\r
4156 DeleteObject( hpen );
\r
4157 DeleteObject( hbrush );
\r
4160 BOOL HasHighlightInfo()
\r
4162 BOOL result = FALSE;
\r
4164 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4165 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4173 BOOL IsDrawArrowEnabled()
\r
4175 BOOL result = FALSE;
\r
4177 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4184 VOID DrawArrowHighlight( HDC hdc )
\r
4186 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4187 DrawArrowBetweenSquares( hdc,
\r
4188 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4189 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4193 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4195 HRGN result = NULL;
\r
4197 if( HasHighlightInfo() ) {
\r
4198 int x1, y1, x2, y2;
\r
4199 int sx, sy, dx, dy;
\r
4201 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4202 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4204 sx = MIN( x1, x2 );
\r
4205 sy = MIN( y1, y2 );
\r
4206 dx = MAX( x1, x2 ) + squareSize;
\r
4207 dy = MAX( y1, y2 ) + squareSize;
\r
4209 result = CreateRectRgn( sx, sy, dx, dy );
\r
4216 Warning: this function modifies the behavior of several other functions.
\r
4218 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4219 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4220 repaint is scattered all over the place, which is not good for features such as
\r
4221 "arrow highlighting" that require a full repaint of the board.
\r
4223 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4224 user interaction, when speed is not so important) but especially to avoid errors
\r
4225 in the displayed graphics.
\r
4227 In such patched places, I always try refer to this function so there is a single
\r
4228 place to maintain knowledge.
\r
4230 To restore the original behavior, just return FALSE unconditionally.
\r
4232 BOOL IsFullRepaintPreferrable()
\r
4234 BOOL result = FALSE;
\r
4236 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4237 /* Arrow may appear on the board */
\r
4245 This function is called by DrawPosition to know whether a full repaint must
\r
4248 Only DrawPosition may directly call this function, which makes use of
\r
4249 some state information. Other function should call DrawPosition specifying
\r
4250 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4252 BOOL DrawPositionNeedsFullRepaint()
\r
4254 BOOL result = FALSE;
\r
4257 Probably a slightly better policy would be to trigger a full repaint
\r
4258 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4259 but animation is fast enough that it's difficult to notice.
\r
4261 if( animInfo.piece == EmptySquare ) {
\r
4262 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4271 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4273 int row, column, x, y, square_color, piece_color;
\r
4274 ChessSquare piece;
\r
4276 HDC texture_hdc = NULL;
\r
4278 /* [AS] Initialize background textures if needed */
\r
4279 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4280 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4281 if( backTextureSquareSize != squareSize
\r
4282 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4283 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4284 backTextureSquareSize = squareSize;
\r
4285 RebuildTextureSquareInfo();
\r
4288 texture_hdc = CreateCompatibleDC( hdc );
\r
4291 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4292 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4294 SquareToPos(row, column, &x, &y);
\r
4296 piece = board[row][column];
\r
4298 square_color = ((column + row) % 2) == 1;
\r
4299 if( gameInfo.variant == VariantXiangqi ) {
\r
4300 square_color = !InPalace(row, column);
\r
4301 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4302 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4304 piece_color = (int) piece < (int) BlackPawn;
\r
4307 /* [HGM] holdings file: light square or black */
\r
4308 if(column == BOARD_LEFT-2) {
\r
4309 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4312 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4316 if(column == BOARD_RGHT + 1 ) {
\r
4317 if( row < gameInfo.holdingsSize )
\r
4320 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4324 if(column == BOARD_LEFT-1 ) /* left align */
\r
4325 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4326 else if( column == BOARD_RGHT) /* right align */
\r
4327 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4329 if (appData.monoMode) {
\r
4330 if (piece == EmptySquare) {
\r
4331 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4332 square_color ? WHITENESS : BLACKNESS);
\r
4334 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4337 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4338 /* [AS] Draw the square using a texture bitmap */
\r
4339 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4340 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4341 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4344 squareSize, squareSize,
\r
4347 backTextureSquareInfo[r][c].mode,
\r
4348 backTextureSquareInfo[r][c].x,
\r
4349 backTextureSquareInfo[r][c].y );
\r
4351 SelectObject( texture_hdc, hbm );
\r
4353 if (piece != EmptySquare) {
\r
4354 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4358 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4360 oldBrush = SelectObject(hdc, brush );
\r
4361 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4362 SelectObject(hdc, oldBrush);
\r
4363 if (piece != EmptySquare)
\r
4364 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4369 if( texture_hdc != NULL ) {
\r
4370 DeleteDC( texture_hdc );
\r
4374 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4375 void fputDW(FILE *f, int x)
\r
4377 fputc(x & 255, f);
\r
4378 fputc(x>>8 & 255, f);
\r
4379 fputc(x>>16 & 255, f);
\r
4380 fputc(x>>24 & 255, f);
\r
4383 #define MAX_CLIPS 200 /* more than enough */
\r
4386 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4388 // HBITMAP bufferBitmap;
\r
4393 int w = 100, h = 50;
\r
4395 if(logo == NULL) return;
\r
4396 // GetClientRect(hwndMain, &Rect);
\r
4397 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4398 // Rect.bottom-Rect.top+1);
\r
4399 tmphdc = CreateCompatibleDC(hdc);
\r
4400 hbm = SelectObject(tmphdc, logo);
\r
4401 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4405 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4406 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4407 SelectObject(tmphdc, hbm);
\r
4412 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4414 static Board lastReq, lastDrawn;
\r
4415 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4416 static int lastDrawnFlipView = 0;
\r
4417 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4418 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4421 HBITMAP bufferBitmap;
\r
4422 HBITMAP oldBitmap;
\r
4424 HRGN clips[MAX_CLIPS];
\r
4425 ChessSquare dragged_piece = EmptySquare;
\r
4427 /* I'm undecided on this - this function figures out whether a full
\r
4428 * repaint is necessary on its own, so there's no real reason to have the
\r
4429 * caller tell it that. I think this can safely be set to FALSE - but
\r
4430 * if we trust the callers not to request full repaints unnessesarily, then
\r
4431 * we could skip some clipping work. In other words, only request a full
\r
4432 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4433 * gamestart and similar) --Hawk
\r
4435 Boolean fullrepaint = repaint;
\r
4437 if( DrawPositionNeedsFullRepaint() ) {
\r
4438 fullrepaint = TRUE;
\r
4442 if( fullrepaint ) {
\r
4443 static int repaint_count = 0;
\r
4447 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4448 OutputDebugString( buf );
\r
4452 if (board == NULL) {
\r
4453 if (!lastReqValid) {
\r
4458 CopyBoard(lastReq, board);
\r
4462 if (doingSizing) {
\r
4466 if (IsIconic(hwndMain)) {
\r
4470 if (hdc == NULL) {
\r
4471 hdc = GetDC(hwndMain);
\r
4472 if (!appData.monoMode) {
\r
4473 SelectPalette(hdc, hPal, FALSE);
\r
4474 RealizePalette(hdc);
\r
4478 releaseDC = FALSE;
\r
4482 fprintf(debugFP, "*******************************\n"
\r
4484 "dragInfo.from (%d,%d)\n"
\r
4485 "dragInfo.start (%d,%d)\n"
\r
4486 "dragInfo.pos (%d,%d)\n"
\r
4487 "dragInfo.lastpos (%d,%d)\n",
\r
4488 repaint ? "TRUE" : "FALSE",
\r
4489 dragInfo.from.x, dragInfo.from.y,
\r
4490 dragInfo.start.x, dragInfo.start.y,
\r
4491 dragInfo.pos.x, dragInfo.pos.y,
\r
4492 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4493 fprintf(debugFP, "prev: ");
\r
4494 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4495 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4496 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4499 fprintf(debugFP, "\n");
\r
4500 fprintf(debugFP, "board: ");
\r
4501 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4502 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4503 fprintf(debugFP, "%d ", board[row][column]);
\r
4506 fprintf(debugFP, "\n");
\r
4510 /* Create some work-DCs */
\r
4511 hdcmem = CreateCompatibleDC(hdc);
\r
4512 tmphdc = CreateCompatibleDC(hdc);
\r
4514 /* If dragging is in progress, we temporarely remove the piece */
\r
4515 /* [HGM] or temporarily decrease count if stacked */
\r
4516 /* !! Moved to before board compare !! */
\r
4517 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4518 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4519 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4520 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4521 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4523 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4524 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4525 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4527 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4530 /* Figure out which squares need updating by comparing the
\r
4531 * newest board with the last drawn board and checking if
\r
4532 * flipping has changed.
\r
4534 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4535 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4536 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4537 if (lastDrawn[row][column] != board[row][column]) {
\r
4538 SquareToPos(row, column, &x, &y);
\r
4539 clips[num_clips++] =
\r
4540 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4544 for (i=0; i<2; i++) {
\r
4545 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4546 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4547 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4548 lastDrawnHighlight.sq[i].y >= 0) {
\r
4549 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4550 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4551 clips[num_clips++] =
\r
4552 CreateRectRgn(x - lineGap, y - lineGap,
\r
4553 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4555 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4556 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4557 clips[num_clips++] =
\r
4558 CreateRectRgn(x - lineGap, y - lineGap,
\r
4559 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4563 for (i=0; i<2; i++) {
\r
4564 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4565 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4566 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4567 lastDrawnPremove.sq[i].y >= 0) {
\r
4568 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4569 lastDrawnPremove.sq[i].x, &x, &y);
\r
4570 clips[num_clips++] =
\r
4571 CreateRectRgn(x - lineGap, y - lineGap,
\r
4572 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4574 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4575 premoveHighlightInfo.sq[i].y >= 0) {
\r
4576 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4577 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4578 clips[num_clips++] =
\r
4579 CreateRectRgn(x - lineGap, y - lineGap,
\r
4580 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4585 fullrepaint = TRUE;
\r
4588 /* Create a buffer bitmap - this is the actual bitmap
\r
4589 * being written to. When all the work is done, we can
\r
4590 * copy it to the real DC (the screen). This avoids
\r
4591 * the problems with flickering.
\r
4593 GetClientRect(hwndMain, &Rect);
\r
4594 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4595 Rect.bottom-Rect.top+1);
\r
4596 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4597 if (!appData.monoMode) {
\r
4598 SelectPalette(hdcmem, hPal, FALSE);
\r
4601 /* Create clips for dragging */
\r
4602 if (!fullrepaint) {
\r
4603 if (dragInfo.from.x >= 0) {
\r
4604 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4605 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4607 if (dragInfo.start.x >= 0) {
\r
4608 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4609 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4611 if (dragInfo.pos.x >= 0) {
\r
4612 x = dragInfo.pos.x - squareSize / 2;
\r
4613 y = dragInfo.pos.y - squareSize / 2;
\r
4614 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4616 if (dragInfo.lastpos.x >= 0) {
\r
4617 x = dragInfo.lastpos.x - squareSize / 2;
\r
4618 y = dragInfo.lastpos.y - squareSize / 2;
\r
4619 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4623 /* Are we animating a move?
\r
4625 * - remove the piece from the board (temporarely)
\r
4626 * - calculate the clipping region
\r
4628 if (!fullrepaint) {
\r
4629 if (animInfo.piece != EmptySquare) {
\r
4630 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4631 x = boardRect.left + animInfo.lastpos.x;
\r
4632 y = boardRect.top + animInfo.lastpos.y;
\r
4633 x2 = boardRect.left + animInfo.pos.x;
\r
4634 y2 = boardRect.top + animInfo.pos.y;
\r
4635 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4636 /* Slight kludge. The real problem is that after AnimateMove is
\r
4637 done, the position on the screen does not match lastDrawn.
\r
4638 This currently causes trouble only on e.p. captures in
\r
4639 atomic, where the piece moves to an empty square and then
\r
4640 explodes. The old and new positions both had an empty square
\r
4641 at the destination, but animation has drawn a piece there and
\r
4642 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4643 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4647 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4648 if (num_clips == 0)
\r
4649 fullrepaint = TRUE;
\r
4651 /* Set clipping on the memory DC */
\r
4652 if (!fullrepaint) {
\r
4653 SelectClipRgn(hdcmem, clips[0]);
\r
4654 for (x = 1; x < num_clips; x++) {
\r
4655 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4656 abort(); // this should never ever happen!
\r
4660 /* Do all the drawing to the memory DC */
\r
4661 if(explodeInfo.radius) { // [HGM] atomic
\r
4663 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4664 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4665 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4666 x += squareSize/2;
\r
4667 y += squareSize/2;
\r
4668 if(!fullrepaint) {
\r
4669 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4670 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4672 DrawGridOnDC(hdcmem);
\r
4673 DrawHighlightsOnDC(hdcmem);
\r
4674 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4675 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4676 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4677 SelectObject(hdcmem, oldBrush);
\r
4679 DrawGridOnDC(hdcmem);
\r
4680 DrawHighlightsOnDC(hdcmem);
\r
4681 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4684 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4685 if(appData.autoLogo) {
\r
4687 switch(gameMode) { // pick logos based on game mode
\r
4688 case IcsObserving:
\r
4689 whiteLogo = second.programLogo; // ICS logo
\r
4690 blackLogo = second.programLogo;
\r
4693 case IcsPlayingWhite:
\r
4694 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4695 blackLogo = second.programLogo; // ICS logo
\r
4697 case IcsPlayingBlack:
\r
4698 whiteLogo = second.programLogo; // ICS logo
\r
4699 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4701 case TwoMachinesPlay:
\r
4702 if(first.twoMachinesColor[0] == 'b') {
\r
4703 whiteLogo = second.programLogo;
\r
4704 blackLogo = first.programLogo;
\r
4707 case MachinePlaysWhite:
\r
4708 blackLogo = userLogo;
\r
4710 case MachinePlaysBlack:
\r
4711 whiteLogo = userLogo;
\r
4712 blackLogo = first.programLogo;
\r
4715 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4716 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4719 if( appData.highlightMoveWithArrow ) {
\r
4720 DrawArrowHighlight(hdcmem);
\r
4723 DrawCoordsOnDC(hdcmem);
\r
4725 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4726 /* to make sure lastDrawn contains what is actually drawn */
\r
4728 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4729 if (dragged_piece != EmptySquare) {
\r
4730 /* [HGM] or restack */
\r
4731 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4732 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4734 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4735 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4736 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4737 x = dragInfo.pos.x - squareSize / 2;
\r
4738 y = dragInfo.pos.y - squareSize / 2;
\r
4739 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4740 ((int) dragged_piece < (int) BlackPawn),
\r
4741 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4744 /* Put the animated piece back into place and draw it */
\r
4745 if (animInfo.piece != EmptySquare) {
\r
4746 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4747 x = boardRect.left + animInfo.pos.x;
\r
4748 y = boardRect.top + animInfo.pos.y;
\r
4749 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4750 ((int) animInfo.piece < (int) BlackPawn),
\r
4751 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4754 /* Release the bufferBitmap by selecting in the old bitmap
\r
4755 * and delete the memory DC
\r
4757 SelectObject(hdcmem, oldBitmap);
\r
4760 /* Set clipping on the target DC */
\r
4761 if (!fullrepaint) {
\r
4762 SelectClipRgn(hdc, clips[0]);
\r
4763 for (x = 1; x < num_clips; x++) {
\r
4764 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4765 abort(); // this should never ever happen!
\r
4769 /* Copy the new bitmap onto the screen in one go.
\r
4770 * This way we avoid any flickering
\r
4772 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4773 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4774 boardRect.right - boardRect.left,
\r
4775 boardRect.bottom - boardRect.top,
\r
4776 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4777 if(saveDiagFlag) {
\r
4778 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4779 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4781 GetObject(bufferBitmap, sizeof(b), &b);
\r
4782 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4783 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4784 bih.biWidth = b.bmWidth;
\r
4785 bih.biHeight = b.bmHeight;
\r
4787 bih.biBitCount = b.bmBitsPixel;
\r
4788 bih.biCompression = 0;
\r
4789 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4790 bih.biXPelsPerMeter = 0;
\r
4791 bih.biYPelsPerMeter = 0;
\r
4792 bih.biClrUsed = 0;
\r
4793 bih.biClrImportant = 0;
\r
4794 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4795 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4796 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4797 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4800 wb = b.bmWidthBytes;
\r
4802 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4803 int k = ((int*) pData)[i];
\r
4804 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4805 if(j >= 16) break;
\r
4807 if(j >= nrColors) nrColors = j+1;
\r
4809 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4811 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4812 for(w=0; w<(wb>>2); w+=2) {
\r
4813 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4814 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4815 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4816 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4817 pData[p++] = m | j<<4;
\r
4819 while(p&3) pData[p++] = 0;
\r
4822 wb = ((wb+31)>>5)<<2;
\r
4824 // write BITMAPFILEHEADER
\r
4825 fprintf(diagFile, "BM");
\r
4826 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4827 fputDW(diagFile, 0);
\r
4828 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4829 // write BITMAPINFOHEADER
\r
4830 fputDW(diagFile, 40);
\r
4831 fputDW(diagFile, b.bmWidth);
\r
4832 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4833 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4834 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4835 fputDW(diagFile, 0);
\r
4836 fputDW(diagFile, 0);
\r
4837 fputDW(diagFile, 0);
\r
4838 fputDW(diagFile, 0);
\r
4839 fputDW(diagFile, 0);
\r
4840 fputDW(diagFile, 0);
\r
4841 // write color table
\r
4843 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4844 // write bitmap data
\r
4845 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4846 fputc(pData[i], diagFile);
\r
4851 SelectObject(tmphdc, oldBitmap);
\r
4853 /* Massive cleanup */
\r
4854 for (x = 0; x < num_clips; x++)
\r
4855 DeleteObject(clips[x]);
\r
4858 DeleteObject(bufferBitmap);
\r
4861 ReleaseDC(hwndMain, hdc);
\r
4863 if (lastDrawnFlipView != flipView) {
\r
4865 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4867 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4870 /* CopyBoard(lastDrawn, board);*/
\r
4871 lastDrawnHighlight = highlightInfo;
\r
4872 lastDrawnPremove = premoveHighlightInfo;
\r
4873 lastDrawnFlipView = flipView;
\r
4874 lastDrawnValid = 1;
\r
4877 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4882 saveDiagFlag = 1; diagFile = f;
\r
4883 HDCDrawPosition(NULL, TRUE, NULL);
\r
4887 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4894 /*---------------------------------------------------------------------------*\
\r
4895 | CLIENT PAINT PROCEDURE
\r
4896 | This is the main event-handler for the WM_PAINT message.
\r
4898 \*---------------------------------------------------------------------------*/
\r
4900 PaintProc(HWND hwnd)
\r
4906 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4907 if (IsIconic(hwnd)) {
\r
4908 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4910 if (!appData.monoMode) {
\r
4911 SelectPalette(hdc, hPal, FALSE);
\r
4912 RealizePalette(hdc);
\r
4914 HDCDrawPosition(hdc, 1, NULL);
\r
4916 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4917 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4918 ETO_CLIPPED|ETO_OPAQUE,
\r
4919 &messageRect, messageText, strlen(messageText), NULL);
\r
4920 SelectObject(hdc, oldFont);
\r
4921 DisplayBothClocks();
\r
4923 EndPaint(hwnd,&ps);
\r
4931 * If the user selects on a border boundary, return -1; if off the board,
\r
4932 * return -2. Otherwise map the event coordinate to the square.
\r
4933 * The offset boardRect.left or boardRect.top must already have been
\r
4934 * subtracted from x.
\r
4937 EventToSquare(int x)
\r
4944 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4946 x /= (squareSize + lineGap);
\r
4947 if (x >= BOARD_SIZE)
\r
4958 DropEnable dropEnables[] = {
\r
4959 { 'P', DP_Pawn, "Pawn" },
\r
4960 { 'N', DP_Knight, "Knight" },
\r
4961 { 'B', DP_Bishop, "Bishop" },
\r
4962 { 'R', DP_Rook, "Rook" },
\r
4963 { 'Q', DP_Queen, "Queen" },
\r
4967 SetupDropMenu(HMENU hmenu)
\r
4969 int i, count, enable;
\r
4971 extern char white_holding[], black_holding[];
\r
4972 char item[MSG_SIZ];
\r
4974 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4975 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4976 dropEnables[i].piece);
\r
4978 while (p && *p++ == dropEnables[i].piece) count++;
\r
4979 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4980 enable = count > 0 || !appData.testLegality
\r
4981 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4982 && !appData.icsActive);
\r
4983 ModifyMenu(hmenu, dropEnables[i].command,
\r
4984 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4985 dropEnables[i].command, item);
\r
4989 /* Event handler for mouse messages */
\r
4991 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4995 static int recursive = 0;
\r
4997 // BOOLEAN needsRedraw = FALSE;
\r
4998 BOOLEAN saveAnimate;
\r
4999 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
5000 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
5001 ChessMove moveType;
\r
5004 if (message == WM_MBUTTONUP) {
\r
5005 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5006 to the middle button: we simulate pressing the left button too!
\r
5008 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5009 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5015 pt.x = LOWORD(lParam);
\r
5016 pt.y = HIWORD(lParam);
\r
5017 x = EventToSquare(pt.x - boardRect.left);
\r
5018 y = EventToSquare(pt.y - boardRect.top);
\r
5019 if (!flipView && y >= 0) {
\r
5020 y = BOARD_HEIGHT - 1 - y;
\r
5022 if (flipView && x >= 0) {
\r
5023 x = BOARD_WIDTH - 1 - x;
\r
5026 switch (message) {
\r
5027 case WM_LBUTTONDOWN:
\r
5028 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5029 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5030 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5031 if(gameInfo.holdingsWidth &&
\r
5032 (WhiteOnMove(currentMove)
\r
5033 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5034 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5035 // click in right holdings, for determining promotion piece
\r
5036 ChessSquare p = boards[currentMove][y][x];
\r
5037 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5038 if(p != EmptySquare) {
\r
5039 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5040 fromX = fromY = -1;
\r
5044 DrawPosition(FALSE, boards[currentMove]);
\r
5048 sameAgain = FALSE;
\r
5050 /* Downclick vertically off board; check if on clock */
\r
5051 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5052 if (gameMode == EditPosition) {
\r
5053 SetWhiteToPlayEvent();
\r
5054 } else if (gameMode == IcsPlayingBlack ||
\r
5055 gameMode == MachinePlaysWhite) {
\r
5057 } else if (gameMode == EditGame) {
\r
5058 AdjustClock(flipClock, -1);
\r
5060 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5061 if (gameMode == EditPosition) {
\r
5062 SetBlackToPlayEvent();
\r
5063 } else if (gameMode == IcsPlayingWhite ||
\r
5064 gameMode == MachinePlaysBlack) {
\r
5066 } else if (gameMode == EditGame) {
\r
5067 AdjustClock(!flipClock, -1);
\r
5070 if (!appData.highlightLastMove) {
\r
5071 ClearHighlights();
\r
5072 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5074 fromX = fromY = -1;
\r
5075 dragInfo.start.x = dragInfo.start.y = -1;
\r
5076 dragInfo.from = dragInfo.start;
\r
5078 } else if (x < 0 || y < 0
\r
5079 /* [HGM] block clicks between board and holdings */
\r
5080 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5081 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5082 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5083 /* EditPosition, empty square, or different color piece;
\r
5084 click-click move is possible */
\r
5087 } else if (fromX == x && fromY == y) {
\r
5088 /* Downclick on same square again */
\r
5089 ClearHighlights();
\r
5090 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5091 sameAgain = TRUE;
\r
5092 } else if (fromX != -1 &&
\r
5093 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5095 /* Downclick on different square. */
\r
5096 /* [HGM] if on holdings file, should count as new first click ! */
\r
5097 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5100 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5101 to make sure move is legal before showing promotion popup */
\r
5102 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5103 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5104 fromX = fromY = -1;
\r
5105 ClearHighlights();
\r
5106 DrawPosition(FALSE, boards[currentMove]);
\r
5109 if(moveType != ImpossibleMove) {
\r
5110 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5111 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5112 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5113 appData.alwaysPromoteToQueen)) {
\r
5114 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5115 if (!appData.highlightLastMove) {
\r
5116 ClearHighlights();
\r
5117 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5120 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5121 SetHighlights(fromX, fromY, toX, toY);
\r
5122 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5123 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5124 If promotion to Q is legal, all are legal! */
\r
5125 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5126 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5127 // kludge to temporarily execute move on display, wthout promotng yet
\r
5128 promotionChoice = TRUE;
\r
5129 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5130 boards[currentMove][toY][toX] = p;
\r
5131 DrawPosition(FALSE, boards[currentMove]);
\r
5132 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5133 boards[currentMove][toY][toX] = q;
\r
5135 PromotionPopup(hwnd);
\r
5136 } else { /* not a promotion */
\r
5137 if (appData.animate || appData.highlightLastMove) {
\r
5138 SetHighlights(fromX, fromY, toX, toY);
\r
5140 ClearHighlights();
\r
5142 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5143 if (appData.animate && !appData.highlightLastMove) {
\r
5144 ClearHighlights();
\r
5145 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5148 fromX = fromY = -1;
\r
5152 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5153 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5154 } else ClearHighlights();
\r
5155 fromX = fromY = -1;
\r
5156 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5158 /* First downclick, or restart on a square with same color piece */
\r
5159 if (!frozen && OKToStartUserMove(x, y)) {
\r
5162 dragInfo.lastpos = pt;
\r
5163 dragInfo.from.x = fromX;
\r
5164 dragInfo.from.y = fromY;
\r
5165 dragInfo.start = dragInfo.from;
\r
5166 SetCapture(hwndMain);
\r
5168 fromX = fromY = -1;
\r
5169 dragInfo.start.x = dragInfo.start.y = -1;
\r
5170 dragInfo.from = dragInfo.start;
\r
5171 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5175 case WM_LBUTTONUP:
\r
5177 if (fromX == -1) break;
\r
5178 if (x == fromX && y == fromY) {
\r
5179 dragInfo.from.x = dragInfo.from.y = -1;
\r
5180 /* Upclick on same square */
\r
5182 /* Clicked same square twice: abort click-click move */
\r
5183 fromX = fromY = -1;
\r
5185 ClearPremoveHighlights();
\r
5187 /* First square clicked: start click-click move */
\r
5188 SetHighlights(fromX, fromY, -1, -1);
\r
5190 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5191 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5192 /* Errant click; ignore */
\r
5195 /* Finish drag move. */
\r
5196 if (appData.debugMode) {
\r
5197 fprintf(debugFP, "release\n");
\r
5199 dragInfo.from.x = dragInfo.from.y = -1;
\r
5202 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5203 appData.animate = appData.animate && !appData.animateDragging;
\r
5204 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5205 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5206 fromX = fromY = -1;
\r
5207 ClearHighlights();
\r
5208 DrawPosition(FALSE, boards[currentMove]);
\r
5209 appData.animate = saveAnimate;
\r
5212 if(moveType != ImpossibleMove) {
\r
5213 /* [HGM] use move type to determine if move is promotion.
\r
5214 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5215 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5216 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5217 appData.alwaysPromoteToQueen))
\r
5218 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5220 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5221 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5222 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5223 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5224 // kludge to temporarily execute move on display, wthout promotng yet
\r
5225 promotionChoice = TRUE;
\r
5226 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5227 boards[currentMove][toY][toX] = p;
\r
5228 DrawPosition(FALSE, boards[currentMove]);
\r
5229 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5230 boards[currentMove][toY][toX] = q;
\r
5231 appData.animate = saveAnimate;
\r
5234 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5236 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5237 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5238 moveType == WhiteCapturesEnPassant ||
\r
5239 moveType == BlackCapturesEnPassant ) )
\r
5240 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5241 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5244 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5245 appData.animate = saveAnimate;
\r
5246 fromX = fromY = -1;
\r
5247 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5248 ClearHighlights();
\r
5250 if (appData.animate || appData.animateDragging ||
\r
5251 appData.highlightDragging || gotPremove) {
\r
5252 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5255 dragInfo.start.x = dragInfo.start.y = -1;
\r
5256 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5259 case WM_MOUSEMOVE:
\r
5260 if ((appData.animateDragging || appData.highlightDragging)
\r
5261 && (wParam & MK_LBUTTON)
\r
5262 && dragInfo.from.x >= 0)
\r
5264 BOOL full_repaint = FALSE;
\r
5266 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5267 if (appData.animateDragging) {
\r
5268 dragInfo.pos = pt;
\r
5270 if (appData.highlightDragging) {
\r
5271 SetHighlights(fromX, fromY, x, y);
\r
5272 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5273 full_repaint = TRUE;
\r
5277 DrawPosition( full_repaint, NULL);
\r
5279 dragInfo.lastpos = dragInfo.pos;
\r
5283 case WM_MOUSEWHEEL: // [DM]
\r
5284 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5285 /* Mouse Wheel is being rolled forward
\r
5286 * Play moves forward
\r
5288 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5289 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5290 /* Mouse Wheel is being rolled backward
\r
5291 * Play moves backward
\r
5293 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5294 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5298 case WM_MBUTTONDOWN:
\r
5299 case WM_RBUTTONDOWN:
\r
5302 fromX = fromY = -1;
\r
5303 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5304 dragInfo.start.x = dragInfo.start.y = -1;
\r
5305 dragInfo.from = dragInfo.start;
\r
5306 dragInfo.lastpos = dragInfo.pos;
\r
5307 if (appData.highlightDragging) {
\r
5308 ClearHighlights();
\r
5311 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5312 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5313 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5314 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5315 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5318 DrawPosition(TRUE, NULL);
\r
5320 switch (gameMode) {
\r
5321 case EditPosition:
\r
5322 case IcsExamining:
\r
5323 if (x < 0 || y < 0) break;
\r
5326 if (message == WM_MBUTTONDOWN) {
\r
5327 buttonCount = 3; /* even if system didn't think so */
\r
5328 if (wParam & MK_SHIFT)
\r
5329 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5331 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5332 } else { /* message == WM_RBUTTONDOWN */
\r
5334 if (buttonCount == 3) {
\r
5335 if (wParam & MK_SHIFT)
\r
5336 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5338 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5340 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5343 /* Just have one menu, on the right button. Windows users don't
\r
5344 think to try the middle one, and sometimes other software steals
\r
5345 it, or it doesn't really exist. */
\r
5346 if(gameInfo.variant != VariantShogi)
\r
5347 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5349 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5353 case IcsPlayingWhite:
\r
5354 case IcsPlayingBlack:
\r
5356 case MachinePlaysWhite:
\r
5357 case MachinePlaysBlack:
\r
5358 if (appData.testLegality &&
\r
5359 gameInfo.variant != VariantBughouse &&
\r
5360 gameInfo.variant != VariantCrazyhouse) break;
\r
5361 if (x < 0 || y < 0) break;
\r
5364 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5365 SetupDropMenu(hmenu);
\r
5366 MenuPopup(hwnd, pt, hmenu, -1);
\r
5377 /* Preprocess messages for buttons in main window */
\r
5379 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5381 int id = GetWindowLong(hwnd, GWL_ID);
\r
5384 for (i=0; i<N_BUTTONS; i++) {
\r
5385 if (buttonDesc[i].id == id) break;
\r
5387 if (i == N_BUTTONS) return 0;
\r
5388 switch (message) {
\r
5393 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5394 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5401 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5404 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5405 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5406 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5407 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5409 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5411 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5412 PopUpMoveDialog((char)wParam);
\r
5418 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5421 /* Process messages for Promotion dialog box */
\r
5423 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5427 switch (message) {
\r
5428 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5429 /* Center the dialog over the application window */
\r
5430 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5431 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5432 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5433 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5434 SW_SHOW : SW_HIDE);
\r
5435 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5436 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5437 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5438 PieceToChar(WhiteAngel) != '~') ||
\r
5439 (PieceToChar(BlackAngel) >= 'A' &&
\r
5440 PieceToChar(BlackAngel) != '~') ) ?
\r
5441 SW_SHOW : SW_HIDE);
\r
5442 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5443 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5444 PieceToChar(WhiteMarshall) != '~') ||
\r
5445 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5446 PieceToChar(BlackMarshall) != '~') ) ?
\r
5447 SW_SHOW : SW_HIDE);
\r
5448 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5449 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5450 gameInfo.variant != VariantShogi ?
\r
5451 SW_SHOW : SW_HIDE);
\r
5452 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5453 gameInfo.variant != VariantShogi ?
\r
5454 SW_SHOW : SW_HIDE);
\r
5455 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5456 gameInfo.variant == VariantShogi ?
\r
5457 SW_SHOW : SW_HIDE);
\r
5458 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5459 gameInfo.variant == VariantShogi ?
\r
5460 SW_SHOW : SW_HIDE);
\r
5461 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5462 gameInfo.variant == VariantSuper ?
\r
5463 SW_SHOW : SW_HIDE);
\r
5466 case WM_COMMAND: /* message: received a command */
\r
5467 switch (LOWORD(wParam)) {
\r
5469 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5470 ClearHighlights();
\r
5471 DrawPosition(FALSE, NULL);
\r
5474 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5477 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5480 promoChar = PieceToChar(BlackRook);
\r
5483 promoChar = PieceToChar(BlackBishop);
\r
5485 case PB_Chancellor:
\r
5486 promoChar = PieceToChar(BlackMarshall);
\r
5488 case PB_Archbishop:
\r
5489 promoChar = PieceToChar(BlackAngel);
\r
5492 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5497 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5498 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5499 only show the popup when we are already sure the move is valid or
\r
5500 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5501 will figure out it is a promotion from the promoChar. */
\r
5502 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5503 if (!appData.highlightLastMove) {
\r
5504 ClearHighlights();
\r
5505 DrawPosition(FALSE, NULL);
\r
5512 /* Pop up promotion dialog */
\r
5514 PromotionPopup(HWND hwnd)
\r
5518 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5519 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5520 hwnd, (DLGPROC)lpProc);
\r
5521 FreeProcInstance(lpProc);
\r
5524 /* Toggle ShowThinking */
\r
5526 ToggleShowThinking()
\r
5528 appData.showThinking = !appData.showThinking;
\r
5529 ShowThinkingEvent();
\r
5533 LoadGameDialog(HWND hwnd, char* title)
\r
5537 char fileTitle[MSG_SIZ];
\r
5538 f = OpenFileDialog(hwnd, "rb", "",
\r
5539 appData.oldSaveStyle ? "gam" : "pgn",
\r
5541 title, &number, fileTitle, NULL);
\r
5543 cmailMsgLoaded = FALSE;
\r
5544 if (number == 0) {
\r
5545 int error = GameListBuild(f);
\r
5547 DisplayError("Cannot build game list", error);
\r
5548 } else if (!ListEmpty(&gameList) &&
\r
5549 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5550 GameListPopUp(f, fileTitle);
\r
5553 GameListDestroy();
\r
5556 LoadGame(f, number, fileTitle, FALSE);
\r
5561 ChangedConsoleFont()
\r
5564 CHARRANGE tmpsel, sel;
\r
5565 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5566 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5567 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5570 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5571 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5572 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5573 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5574 * size. This was undocumented in the version of MSVC++ that I had
\r
5575 * when I wrote the code, but is apparently documented now.
\r
5577 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5578 cfmt.bCharSet = f->lf.lfCharSet;
\r
5579 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5580 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5581 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5582 /* Why are the following seemingly needed too? */
\r
5583 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5584 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5585 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5587 tmpsel.cpMax = -1; /*999999?*/
\r
5588 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5589 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5590 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5591 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5593 paraf.cbSize = sizeof(paraf);
\r
5594 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5595 paraf.dxStartIndent = 0;
\r
5596 paraf.dxOffset = WRAP_INDENT;
\r
5597 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5598 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5601 /*---------------------------------------------------------------------------*\
\r
5603 * Window Proc for main window
\r
5605 \*---------------------------------------------------------------------------*/
\r
5607 /* Process messages for main window, etc. */
\r
5609 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5612 int wmId, wmEvent;
\r
5616 char fileTitle[MSG_SIZ];
\r
5617 char buf[MSG_SIZ];
\r
5618 static SnapData sd;
\r
5620 switch (message) {
\r
5622 case WM_PAINT: /* message: repaint portion of window */
\r
5626 case WM_ERASEBKGND:
\r
5627 if (IsIconic(hwnd)) {
\r
5628 /* Cheat; change the message */
\r
5629 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5631 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5635 case WM_LBUTTONDOWN:
\r
5636 case WM_MBUTTONDOWN:
\r
5637 case WM_RBUTTONDOWN:
\r
5638 case WM_LBUTTONUP:
\r
5639 case WM_MBUTTONUP:
\r
5640 case WM_RBUTTONUP:
\r
5641 case WM_MOUSEMOVE:
\r
5642 case WM_MOUSEWHEEL:
\r
5643 MouseEvent(hwnd, message, wParam, lParam);
\r
5646 JAWS_KB_NAVIGATION
\r
5650 JAWS_ALT_INTERCEPT
\r
5652 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5653 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5654 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5655 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5657 SendMessage(h, message, wParam, lParam);
\r
5658 } else if(lParam != KF_REPEAT) {
\r
5659 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5660 PopUpMoveDialog((char)wParam);
\r
5661 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5662 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5667 case WM_PALETTECHANGED:
\r
5668 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5670 HDC hdc = GetDC(hwndMain);
\r
5671 SelectPalette(hdc, hPal, TRUE);
\r
5672 nnew = RealizePalette(hdc);
\r
5674 paletteChanged = TRUE;
\r
5676 UpdateColors(hdc);
\r
5678 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5681 ReleaseDC(hwnd, hdc);
\r
5685 case WM_QUERYNEWPALETTE:
\r
5686 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5688 HDC hdc = GetDC(hwndMain);
\r
5689 paletteChanged = FALSE;
\r
5690 SelectPalette(hdc, hPal, FALSE);
\r
5691 nnew = RealizePalette(hdc);
\r
5693 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5695 ReleaseDC(hwnd, hdc);
\r
5700 case WM_COMMAND: /* message: command from application menu */
\r
5701 wmId = LOWORD(wParam);
\r
5702 wmEvent = HIWORD(wParam);
\r
5707 AnalysisPopDown();
\r
5708 SAY("new game enter a move to play against the computer with white");
\r
5711 case IDM_NewGameFRC:
\r
5712 if( NewGameFRC() == 0 ) {
\r
5714 AnalysisPopDown();
\r
5718 case IDM_NewVariant:
\r
5719 NewVariantPopup(hwnd);
\r
5722 case IDM_LoadGame:
\r
5723 LoadGameDialog(hwnd, "Load Game from File");
\r
5726 case IDM_LoadNextGame:
\r
5730 case IDM_LoadPrevGame:
\r
5734 case IDM_ReloadGame:
\r
5738 case IDM_LoadPosition:
\r
5739 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5740 Reset(FALSE, TRUE);
\r
5743 f = OpenFileDialog(hwnd, "rb", "",
\r
5744 appData.oldSaveStyle ? "pos" : "fen",
\r
5746 "Load Position from File", &number, fileTitle, NULL);
\r
5748 LoadPosition(f, number, fileTitle);
\r
5752 case IDM_LoadNextPosition:
\r
5753 ReloadPosition(1);
\r
5756 case IDM_LoadPrevPosition:
\r
5757 ReloadPosition(-1);
\r
5760 case IDM_ReloadPosition:
\r
5761 ReloadPosition(0);
\r
5764 case IDM_SaveGame:
\r
5765 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5766 f = OpenFileDialog(hwnd, "a", defName,
\r
5767 appData.oldSaveStyle ? "gam" : "pgn",
\r
5769 "Save Game to File", NULL, fileTitle, NULL);
\r
5771 SaveGame(f, 0, "");
\r
5775 case IDM_SavePosition:
\r
5776 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5777 f = OpenFileDialog(hwnd, "a", defName,
\r
5778 appData.oldSaveStyle ? "pos" : "fen",
\r
5780 "Save Position to File", NULL, fileTitle, NULL);
\r
5782 SavePosition(f, 0, "");
\r
5786 case IDM_SaveDiagram:
\r
5787 defName = "diagram";
\r
5788 f = OpenFileDialog(hwnd, "wb", defName,
\r
5791 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5797 case IDM_CopyGame:
\r
5798 CopyGameToClipboard();
\r
5801 case IDM_PasteGame:
\r
5802 PasteGameFromClipboard();
\r
5805 case IDM_CopyGameListToClipboard:
\r
5806 CopyGameListToClipboard();
\r
5809 /* [AS] Autodetect FEN or PGN data */
\r
5810 case IDM_PasteAny:
\r
5811 PasteGameOrFENFromClipboard();
\r
5814 /* [AS] Move history */
\r
5815 case IDM_ShowMoveHistory:
\r
5816 if( MoveHistoryIsUp() ) {
\r
5817 MoveHistoryPopDown();
\r
5820 MoveHistoryPopUp();
\r
5824 /* [AS] Eval graph */
\r
5825 case IDM_ShowEvalGraph:
\r
5826 if( EvalGraphIsUp() ) {
\r
5827 EvalGraphPopDown();
\r
5831 SetFocus(hwndMain);
\r
5835 /* [AS] Engine output */
\r
5836 case IDM_ShowEngineOutput:
\r
5837 if( EngineOutputIsUp() ) {
\r
5838 EngineOutputPopDown();
\r
5841 EngineOutputPopUp();
\r
5845 /* [AS] User adjudication */
\r
5846 case IDM_UserAdjudication_White:
\r
5847 UserAdjudicationEvent( +1 );
\r
5850 case IDM_UserAdjudication_Black:
\r
5851 UserAdjudicationEvent( -1 );
\r
5854 case IDM_UserAdjudication_Draw:
\r
5855 UserAdjudicationEvent( 0 );
\r
5858 /* [AS] Game list options dialog */
\r
5859 case IDM_GameListOptions:
\r
5860 GameListOptions();
\r
5863 case IDM_CopyPosition:
\r
5864 CopyFENToClipboard();
\r
5867 case IDM_PastePosition:
\r
5868 PasteFENFromClipboard();
\r
5871 case IDM_MailMove:
\r
5875 case IDM_ReloadCMailMsg:
\r
5876 Reset(TRUE, TRUE);
\r
5877 ReloadCmailMsgEvent(FALSE);
\r
5880 case IDM_Minimize:
\r
5881 ShowWindow(hwnd, SW_MINIMIZE);
\r
5888 case IDM_MachineWhite:
\r
5889 MachineWhiteEvent();
\r
5891 * refresh the tags dialog only if it's visible
\r
5893 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5895 tags = PGNTags(&gameInfo);
\r
5896 TagsPopUp(tags, CmailMsg());
\r
5899 SAY("computer starts playing white");
\r
5902 case IDM_MachineBlack:
\r
5903 MachineBlackEvent();
\r
5905 * refresh the tags dialog only if it's visible
\r
5907 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5909 tags = PGNTags(&gameInfo);
\r
5910 TagsPopUp(tags, CmailMsg());
\r
5913 SAY("computer starts playing black");
\r
5916 case IDM_TwoMachines:
\r
5917 TwoMachinesEvent();
\r
5919 * refresh the tags dialog only if it's visible
\r
5921 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5923 tags = PGNTags(&gameInfo);
\r
5924 TagsPopUp(tags, CmailMsg());
\r
5927 SAY("programs start playing each other");
\r
5930 case IDM_AnalysisMode:
\r
5931 if (!first.analysisSupport) {
\r
5932 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5933 DisplayError(buf, 0);
\r
5935 SAY("analyzing current position");
\r
5936 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5937 if (appData.icsActive) {
\r
5938 if (gameMode != IcsObserving) {
\r
5939 sprintf(buf, "You are not observing a game");
\r
5940 DisplayError(buf, 0);
\r
5941 /* secure check */
\r
5942 if (appData.icsEngineAnalyze) {
\r
5943 if (appData.debugMode)
\r
5944 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5945 ExitAnalyzeMode();
\r
5951 /* if enable, user want disable icsEngineAnalyze */
\r
5952 if (appData.icsEngineAnalyze) {
\r
5953 ExitAnalyzeMode();
\r
5957 appData.icsEngineAnalyze = TRUE;
\r
5958 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5961 if (!appData.showThinking) ToggleShowThinking();
\r
5962 AnalyzeModeEvent();
\r
5966 case IDM_AnalyzeFile:
\r
5967 if (!first.analysisSupport) {
\r
5968 char buf[MSG_SIZ];
\r
5969 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5970 DisplayError(buf, 0);
\r
5972 if (!appData.showThinking) ToggleShowThinking();
\r
5973 AnalyzeFileEvent();
\r
5974 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5975 AnalysisPeriodicEvent(1);
\r
5979 case IDM_IcsClient:
\r
5983 case IDM_EditGame:
\r
5988 case IDM_EditPosition:
\r
5989 EditPositionEvent();
\r
5990 SAY("to set up a position type a FEN");
\r
5993 case IDM_Training:
\r
5997 case IDM_ShowGameList:
\r
5998 ShowGameListProc();
\r
6001 case IDM_EditTags:
\r
6005 case IDM_EditComment:
\r
6006 if (commentDialogUp && editComment) {
\r
6009 EditCommentEvent();
\r
6029 case IDM_CallFlag:
\r
6049 case IDM_StopObserving:
\r
6050 StopObservingEvent();
\r
6053 case IDM_StopExamining:
\r
6054 StopExaminingEvent();
\r
6057 case IDM_TypeInMove:
\r
6058 PopUpMoveDialog('\000');
\r
6061 case IDM_TypeInName:
\r
6062 PopUpNameDialog('\000');
\r
6065 case IDM_Backward:
\r
6067 SetFocus(hwndMain);
\r
6074 SetFocus(hwndMain);
\r
6079 SetFocus(hwndMain);
\r
6084 SetFocus(hwndMain);
\r
6091 case IDM_TruncateGame:
\r
6092 TruncateGameEvent();
\r
6099 case IDM_RetractMove:
\r
6100 RetractMoveEvent();
\r
6103 case IDM_FlipView:
\r
6104 flipView = !flipView;
\r
6105 DrawPosition(FALSE, NULL);
\r
6108 case IDM_FlipClock:
\r
6109 flipClock = !flipClock;
\r
6110 DisplayBothClocks();
\r
6111 DrawPosition(FALSE, NULL);
\r
6114 case IDM_GeneralOptions:
\r
6115 GeneralOptionsPopup(hwnd);
\r
6116 DrawPosition(TRUE, NULL);
\r
6119 case IDM_BoardOptions:
\r
6120 BoardOptionsPopup(hwnd);
\r
6123 case IDM_EnginePlayOptions:
\r
6124 EnginePlayOptionsPopup(hwnd);
\r
6127 case IDM_Engine1Options:
\r
6128 EngineOptionsPopup(hwnd, &first);
\r
6131 case IDM_Engine2Options:
\r
6132 EngineOptionsPopup(hwnd, &second);
\r
6135 case IDM_OptionsUCI:
\r
6136 UciOptionsPopup(hwnd);
\r
6139 case IDM_IcsOptions:
\r
6140 IcsOptionsPopup(hwnd);
\r
6144 FontsOptionsPopup(hwnd);
\r
6148 SoundOptionsPopup(hwnd);
\r
6151 case IDM_CommPort:
\r
6152 CommPortOptionsPopup(hwnd);
\r
6155 case IDM_LoadOptions:
\r
6156 LoadOptionsPopup(hwnd);
\r
6159 case IDM_SaveOptions:
\r
6160 SaveOptionsPopup(hwnd);
\r
6163 case IDM_TimeControl:
\r
6164 TimeControlOptionsPopup(hwnd);
\r
6167 case IDM_SaveSettings:
\r
6168 SaveSettings(settingsFileName);
\r
6171 case IDM_SaveSettingsOnExit:
\r
6172 saveSettingsOnExit = !saveSettingsOnExit;
\r
6173 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6174 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6175 MF_CHECKED : MF_UNCHECKED));
\r
6186 case IDM_AboutGame:
\r
6191 appData.debugMode = !appData.debugMode;
\r
6192 if (appData.debugMode) {
\r
6193 char dir[MSG_SIZ];
\r
6194 GetCurrentDirectory(MSG_SIZ, dir);
\r
6195 SetCurrentDirectory(installDir);
\r
6196 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6197 SetCurrentDirectory(dir);
\r
6198 setbuf(debugFP, NULL);
\r
6205 case IDM_HELPCONTENTS:
\r
6206 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6207 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6208 MessageBox (GetFocus(),
\r
6209 "Unable to activate help",
\r
6210 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6214 case IDM_HELPSEARCH:
\r
6215 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6216 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6217 MessageBox (GetFocus(),
\r
6218 "Unable to activate help",
\r
6219 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6223 case IDM_HELPHELP:
\r
6224 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6225 MessageBox (GetFocus(),
\r
6226 "Unable to activate help",
\r
6227 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6232 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6234 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6235 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6236 FreeProcInstance(lpProc);
\r
6239 case IDM_DirectCommand1:
\r
6240 AskQuestionEvent("Direct Command",
\r
6241 "Send to chess program:", "", "1");
\r
6243 case IDM_DirectCommand2:
\r
6244 AskQuestionEvent("Direct Command",
\r
6245 "Send to second chess program:", "", "2");
\r
6248 case EP_WhitePawn:
\r
6249 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6250 fromX = fromY = -1;
\r
6253 case EP_WhiteKnight:
\r
6254 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6255 fromX = fromY = -1;
\r
6258 case EP_WhiteBishop:
\r
6259 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6260 fromX = fromY = -1;
\r
6263 case EP_WhiteRook:
\r
6264 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6265 fromX = fromY = -1;
\r
6268 case EP_WhiteQueen:
\r
6269 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6270 fromX = fromY = -1;
\r
6273 case EP_WhiteFerz:
\r
6274 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6275 fromX = fromY = -1;
\r
6278 case EP_WhiteWazir:
\r
6279 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6280 fromX = fromY = -1;
\r
6283 case EP_WhiteAlfil:
\r
6284 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6285 fromX = fromY = -1;
\r
6288 case EP_WhiteCannon:
\r
6289 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6290 fromX = fromY = -1;
\r
6293 case EP_WhiteCardinal:
\r
6294 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6295 fromX = fromY = -1;
\r
6298 case EP_WhiteMarshall:
\r
6299 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6300 fromX = fromY = -1;
\r
6303 case EP_WhiteKing:
\r
6304 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6305 fromX = fromY = -1;
\r
6308 case EP_BlackPawn:
\r
6309 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6310 fromX = fromY = -1;
\r
6313 case EP_BlackKnight:
\r
6314 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6315 fromX = fromY = -1;
\r
6318 case EP_BlackBishop:
\r
6319 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6320 fromX = fromY = -1;
\r
6323 case EP_BlackRook:
\r
6324 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6325 fromX = fromY = -1;
\r
6328 case EP_BlackQueen:
\r
6329 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6330 fromX = fromY = -1;
\r
6333 case EP_BlackFerz:
\r
6334 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6335 fromX = fromY = -1;
\r
6338 case EP_BlackWazir:
\r
6339 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6340 fromX = fromY = -1;
\r
6343 case EP_BlackAlfil:
\r
6344 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6345 fromX = fromY = -1;
\r
6348 case EP_BlackCannon:
\r
6349 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6350 fromX = fromY = -1;
\r
6353 case EP_BlackCardinal:
\r
6354 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6355 fromX = fromY = -1;
\r
6358 case EP_BlackMarshall:
\r
6359 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6360 fromX = fromY = -1;
\r
6363 case EP_BlackKing:
\r
6364 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6365 fromX = fromY = -1;
\r
6368 case EP_EmptySquare:
\r
6369 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6370 fromX = fromY = -1;
\r
6373 case EP_ClearBoard:
\r
6374 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6375 fromX = fromY = -1;
\r
6379 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6380 fromX = fromY = -1;
\r
6384 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6385 fromX = fromY = -1;
\r
6389 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6390 fromX = fromY = -1;
\r
6394 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6395 fromX = fromY = -1;
\r
6399 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6400 fromX = fromY = -1;
\r
6404 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6405 fromX = fromY = -1;
\r
6409 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6410 fromX = fromY = -1;
\r
6414 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6415 fromX = fromY = -1;
\r
6419 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6420 fromX = fromY = -1;
\r
6424 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6430 case CLOCK_TIMER_ID:
\r
6431 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6432 clockTimerEvent = 0;
\r
6433 DecrementClocks(); /* call into back end */
\r
6435 case LOAD_GAME_TIMER_ID:
\r
6436 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6437 loadGameTimerEvent = 0;
\r
6438 AutoPlayGameLoop(); /* call into back end */
\r
6440 case ANALYSIS_TIMER_ID:
\r
6441 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6442 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6443 AnalysisPeriodicEvent(0);
\r
6445 KillTimer(hwnd, analysisTimerEvent);
\r
6446 analysisTimerEvent = 0;
\r
6449 case DELAYED_TIMER_ID:
\r
6450 KillTimer(hwnd, delayedTimerEvent);
\r
6451 delayedTimerEvent = 0;
\r
6452 delayedTimerCallback();
\r
6457 case WM_USER_Input:
\r
6458 InputEvent(hwnd, message, wParam, lParam);
\r
6461 /* [AS] Also move "attached" child windows */
\r
6462 case WM_WINDOWPOSCHANGING:
\r
6464 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6465 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6467 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6468 /* Window is moving */
\r
6471 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6472 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6473 rcMain.right = boardX + winWidth;
\r
6474 rcMain.top = boardY;
\r
6475 rcMain.bottom = boardY + winHeight;
\r
6477 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6478 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6479 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6480 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6481 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6488 /* [AS] Snapping */
\r
6489 case WM_ENTERSIZEMOVE:
\r
6490 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6491 if (hwnd == hwndMain) {
\r
6492 doingSizing = TRUE;
\r
6495 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6499 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6500 if (hwnd == hwndMain) {
\r
6501 lastSizing = wParam;
\r
6506 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6507 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6509 case WM_EXITSIZEMOVE:
\r
6510 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6511 if (hwnd == hwndMain) {
\r
6513 doingSizing = FALSE;
\r
6514 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6515 GetClientRect(hwnd, &client);
\r
6516 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6518 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6520 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6523 case WM_DESTROY: /* message: window being destroyed */
\r
6524 PostQuitMessage(0);
\r
6528 if (hwnd == hwndMain) {
\r
6533 default: /* Passes it on if unprocessed */
\r
6534 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6539 /*---------------------------------------------------------------------------*\
\r
6541 * Misc utility routines
\r
6543 \*---------------------------------------------------------------------------*/
\r
6546 * Decent random number generator, at least not as bad as Windows
\r
6547 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6549 unsigned int randstate;
\r
6554 randstate = randstate * 1664525 + 1013904223;
\r
6555 return (int) randstate & 0x7fffffff;
\r
6559 mysrandom(unsigned int seed)
\r
6566 * returns TRUE if user selects a different color, FALSE otherwise
\r
6570 ChangeColor(HWND hwnd, COLORREF *which)
\r
6572 static BOOL firstTime = TRUE;
\r
6573 static DWORD customColors[16];
\r
6575 COLORREF newcolor;
\r
6580 /* Make initial colors in use available as custom colors */
\r
6581 /* Should we put the compiled-in defaults here instead? */
\r
6583 customColors[i++] = lightSquareColor & 0xffffff;
\r
6584 customColors[i++] = darkSquareColor & 0xffffff;
\r
6585 customColors[i++] = whitePieceColor & 0xffffff;
\r
6586 customColors[i++] = blackPieceColor & 0xffffff;
\r
6587 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6588 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6590 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6591 customColors[i++] = textAttribs[ccl].color;
\r
6593 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6594 firstTime = FALSE;
\r
6597 cc.lStructSize = sizeof(cc);
\r
6598 cc.hwndOwner = hwnd;
\r
6599 cc.hInstance = NULL;
\r
6600 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6601 cc.lpCustColors = (LPDWORD) customColors;
\r
6602 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6604 if (!ChooseColor(&cc)) return FALSE;
\r
6606 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6607 if (newcolor == *which) return FALSE;
\r
6608 *which = newcolor;
\r
6612 InitDrawingColors();
\r
6613 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6618 MyLoadSound(MySound *ms)
\r
6624 if (ms->data) free(ms->data);
\r
6627 switch (ms->name[0]) {
\r
6633 /* System sound from Control Panel. Don't preload here. */
\r
6637 if (ms->name[1] == NULLCHAR) {
\r
6638 /* "!" alone = silence */
\r
6641 /* Builtin wave resource. Error if not found. */
\r
6642 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6643 if (h == NULL) break;
\r
6644 ms->data = (void *)LoadResource(hInst, h);
\r
6645 if (h == NULL) break;
\r
6650 /* .wav file. Error if not found. */
\r
6651 f = fopen(ms->name, "rb");
\r
6652 if (f == NULL) break;
\r
6653 if (fstat(fileno(f), &st) < 0) break;
\r
6654 ms->data = malloc(st.st_size);
\r
6655 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6661 char buf[MSG_SIZ];
\r
6662 sprintf(buf, "Error loading sound %s", ms->name);
\r
6663 DisplayError(buf, GetLastError());
\r
6669 MyPlaySound(MySound *ms)
\r
6671 BOOLEAN ok = FALSE;
\r
6673 switch (ms->name[0]) {
\r
6675 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6680 /* System sound from Control Panel (deprecated feature).
\r
6681 "$" alone or an unset sound name gets default beep (still in use). */
\r
6682 if (ms->name[1]) {
\r
6683 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6685 if (!ok) ok = MessageBeep(MB_OK);
\r
6688 /* Builtin wave resource, or "!" alone for silence */
\r
6689 if (ms->name[1]) {
\r
6690 if (ms->data == NULL) return FALSE;
\r
6691 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6697 /* .wav file. Error if not found. */
\r
6698 if (ms->data == NULL) return FALSE;
\r
6699 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6702 /* Don't print an error: this can happen innocently if the sound driver
\r
6703 is busy; for instance, if another instance of WinBoard is playing
\r
6704 a sound at about the same time. */
\r
6707 char buf[MSG_SIZ];
\r
6708 sprintf(buf, "Error playing sound %s", ms->name);
\r
6709 DisplayError(buf, GetLastError());
\r
6717 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6720 OPENFILENAME *ofn;
\r
6721 static UINT *number; /* gross that this is static */
\r
6723 switch (message) {
\r
6724 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6725 /* Center the dialog over the application window */
\r
6726 ofn = (OPENFILENAME *) lParam;
\r
6727 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6728 number = (UINT *) ofn->lCustData;
\r
6729 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6733 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6734 return FALSE; /* Allow for further processing */
\r
6737 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6738 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6740 return FALSE; /* Allow for further processing */
\r
6746 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6748 static UINT *number;
\r
6749 OPENFILENAME *ofname;
\r
6752 case WM_INITDIALOG:
\r
6753 ofname = (OPENFILENAME *)lParam;
\r
6754 number = (UINT *)(ofname->lCustData);
\r
6757 ofnot = (OFNOTIFY *)lParam;
\r
6758 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6759 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6768 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6769 char *nameFilt, char *dlgTitle, UINT *number,
\r
6770 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6772 OPENFILENAME openFileName;
\r
6773 char buf1[MSG_SIZ];
\r
6776 if (fileName == NULL) fileName = buf1;
\r
6777 if (defName == NULL) {
\r
6778 strcpy(fileName, "*.");
\r
6779 strcat(fileName, defExt);
\r
6781 strcpy(fileName, defName);
\r
6783 if (fileTitle) strcpy(fileTitle, "");
\r
6784 if (number) *number = 0;
\r
6786 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6787 openFileName.hwndOwner = hwnd;
\r
6788 openFileName.hInstance = (HANDLE) hInst;
\r
6789 openFileName.lpstrFilter = nameFilt;
\r
6790 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6791 openFileName.nMaxCustFilter = 0L;
\r
6792 openFileName.nFilterIndex = 1L;
\r
6793 openFileName.lpstrFile = fileName;
\r
6794 openFileName.nMaxFile = MSG_SIZ;
\r
6795 openFileName.lpstrFileTitle = fileTitle;
\r
6796 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6797 openFileName.lpstrInitialDir = NULL;
\r
6798 openFileName.lpstrTitle = dlgTitle;
\r
6799 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6800 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6801 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6802 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6803 openFileName.nFileOffset = 0;
\r
6804 openFileName.nFileExtension = 0;
\r
6805 openFileName.lpstrDefExt = defExt;
\r
6806 openFileName.lCustData = (LONG) number;
\r
6807 openFileName.lpfnHook = oldDialog ?
\r
6808 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6809 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6811 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6812 GetOpenFileName(&openFileName)) {
\r
6813 /* open the file */
\r
6814 f = fopen(openFileName.lpstrFile, write);
\r
6816 MessageBox(hwnd, "File open failed", NULL,
\r
6817 MB_OK|MB_ICONEXCLAMATION);
\r
6821 int err = CommDlgExtendedError();
\r
6822 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6831 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6833 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6836 * Get the first pop-up menu in the menu template. This is the
\r
6837 * menu that TrackPopupMenu displays.
\r
6839 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6841 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6844 * TrackPopup uses screen coordinates, so convert the
\r
6845 * coordinates of the mouse click to screen coordinates.
\r
6847 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6849 /* Draw and track the floating pop-up menu. */
\r
6850 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6851 pt.x, pt.y, 0, hwnd, NULL);
\r
6853 /* Destroy the menu.*/
\r
6854 DestroyMenu(hmenu);
\r
6859 int sizeX, sizeY, newSizeX, newSizeY;
\r
6861 } ResizeEditPlusButtonsClosure;
\r
6864 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6866 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6870 if (hChild == cl->hText) return TRUE;
\r
6871 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6872 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6873 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6874 ScreenToClient(cl->hDlg, &pt);
\r
6875 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6876 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6880 /* Resize a dialog that has a (rich) edit field filling most of
\r
6881 the top, with a row of buttons below */
\r
6883 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6886 int newTextHeight, newTextWidth;
\r
6887 ResizeEditPlusButtonsClosure cl;
\r
6889 /*if (IsIconic(hDlg)) return;*/
\r
6890 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6892 cl.hdwp = BeginDeferWindowPos(8);
\r
6894 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6895 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6896 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6897 if (newTextHeight < 0) {
\r
6898 newSizeY += -newTextHeight;
\r
6899 newTextHeight = 0;
\r
6901 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6902 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6908 cl.newSizeX = newSizeX;
\r
6909 cl.newSizeY = newSizeY;
\r
6910 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6912 EndDeferWindowPos(cl.hdwp);
\r
6915 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6917 RECT rChild, rParent;
\r
6918 int wChild, hChild, wParent, hParent;
\r
6919 int wScreen, hScreen, xNew, yNew;
\r
6922 /* Get the Height and Width of the child window */
\r
6923 GetWindowRect (hwndChild, &rChild);
\r
6924 wChild = rChild.right - rChild.left;
\r
6925 hChild = rChild.bottom - rChild.top;
\r
6927 /* Get the Height and Width of the parent window */
\r
6928 GetWindowRect (hwndParent, &rParent);
\r
6929 wParent = rParent.right - rParent.left;
\r
6930 hParent = rParent.bottom - rParent.top;
\r
6932 /* Get the display limits */
\r
6933 hdc = GetDC (hwndChild);
\r
6934 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6935 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6936 ReleaseDC(hwndChild, hdc);
\r
6938 /* Calculate new X position, then adjust for screen */
\r
6939 xNew = rParent.left + ((wParent - wChild) /2);
\r
6942 } else if ((xNew+wChild) > wScreen) {
\r
6943 xNew = wScreen - wChild;
\r
6946 /* Calculate new Y position, then adjust for screen */
\r
6948 yNew = rParent.top + ((hParent - hChild) /2);
\r
6951 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6956 } else if ((yNew+hChild) > hScreen) {
\r
6957 yNew = hScreen - hChild;
\r
6960 /* Set it, and return */
\r
6961 return SetWindowPos (hwndChild, NULL,
\r
6962 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6965 /* Center one window over another */
\r
6966 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6968 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6971 /*---------------------------------------------------------------------------*\
\r
6973 * Startup Dialog functions
\r
6975 \*---------------------------------------------------------------------------*/
\r
6977 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6979 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6981 while (*cd != NULL) {
\r
6982 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6988 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6990 char buf1[ARG_MAX];
\r
6993 if (str[0] == '@') {
\r
6994 FILE* f = fopen(str + 1, "r");
\r
6996 DisplayFatalError(str + 1, errno, 2);
\r
6999 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
7001 buf1[len] = NULLCHAR;
\r
7005 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7008 char buf[MSG_SIZ];
\r
7009 char *end = strchr(str, '\n');
\r
7010 if (end == NULL) return;
\r
7011 memcpy(buf, str, end - str);
\r
7012 buf[end - str] = NULLCHAR;
\r
7013 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7019 SetStartupDialogEnables(HWND hDlg)
\r
7021 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7022 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7023 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7024 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7025 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7026 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7027 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7028 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7029 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7030 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7031 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7032 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7033 IsDlgButtonChecked(hDlg, OPT_View));
\r
7037 QuoteForFilename(char *filename)
\r
7039 int dquote, space;
\r
7040 dquote = strchr(filename, '"') != NULL;
\r
7041 space = strchr(filename, ' ') != NULL;
\r
7042 if (dquote || space) {
\r
7054 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7056 char buf[MSG_SIZ];
\r
7059 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7060 q = QuoteForFilename(nthcp);
\r
7061 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7062 if (*nthdir != NULLCHAR) {
\r
7063 q = QuoteForFilename(nthdir);
\r
7064 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7066 if (*nthcp == NULLCHAR) {
\r
7067 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7068 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7069 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7070 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7075 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7077 char buf[MSG_SIZ];
\r
7081 switch (message) {
\r
7082 case WM_INITDIALOG:
\r
7083 /* Center the dialog */
\r
7084 CenterWindow (hDlg, GetDesktopWindow());
\r
7085 /* Initialize the dialog items */
\r
7086 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7087 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7088 firstChessProgramNames);
\r
7089 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7090 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7091 secondChessProgramNames);
\r
7092 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7093 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7094 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7095 if (*appData.icsHelper != NULLCHAR) {
\r
7096 char *q = QuoteForFilename(appData.icsHelper);
\r
7097 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7099 if (*appData.icsHost == NULLCHAR) {
\r
7100 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7101 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7102 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7103 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7104 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7107 if (appData.icsActive) {
\r
7108 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7110 else if (appData.noChessProgram) {
\r
7111 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7114 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7117 SetStartupDialogEnables(hDlg);
\r
7121 switch (LOWORD(wParam)) {
\r
7123 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7124 strcpy(buf, "/fcp=");
\r
7125 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7127 ParseArgs(StringGet, &p);
\r
7128 strcpy(buf, "/scp=");
\r
7129 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7131 ParseArgs(StringGet, &p);
\r
7132 appData.noChessProgram = FALSE;
\r
7133 appData.icsActive = FALSE;
\r
7134 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7135 strcpy(buf, "/ics /icshost=");
\r
7136 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7138 ParseArgs(StringGet, &p);
\r
7139 if (appData.zippyPlay) {
\r
7140 strcpy(buf, "/fcp=");
\r
7141 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7143 ParseArgs(StringGet, &p);
\r
7145 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7146 appData.noChessProgram = TRUE;
\r
7147 appData.icsActive = FALSE;
\r
7149 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7150 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7153 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7154 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7156 ParseArgs(StringGet, &p);
\r
7158 EndDialog(hDlg, TRUE);
\r
7165 case IDM_HELPCONTENTS:
\r
7166 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7167 MessageBox (GetFocus(),
\r
7168 "Unable to activate help",
\r
7169 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7174 SetStartupDialogEnables(hDlg);
\r
7182 /*---------------------------------------------------------------------------*\
\r
7184 * About box dialog functions
\r
7186 \*---------------------------------------------------------------------------*/
\r
7188 /* Process messages for "About" dialog box */
\r
7190 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7192 switch (message) {
\r
7193 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7194 /* Center the dialog over the application window */
\r
7195 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7196 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7200 case WM_COMMAND: /* message: received a command */
\r
7201 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7202 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7203 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7211 /*---------------------------------------------------------------------------*\
\r
7213 * Comment Dialog functions
\r
7215 \*---------------------------------------------------------------------------*/
\r
7218 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7220 static HANDLE hwndText = NULL;
\r
7221 int len, newSizeX, newSizeY, flags;
\r
7222 static int sizeX, sizeY;
\r
7227 switch (message) {
\r
7228 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7229 /* Initialize the dialog items */
\r
7230 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7231 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7232 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7233 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7234 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7235 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7236 SetWindowText(hDlg, commentTitle);
\r
7237 if (editComment) {
\r
7238 SetFocus(hwndText);
\r
7240 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7242 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7243 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7244 MAKELPARAM(FALSE, 0));
\r
7245 /* Size and position the dialog */
\r
7246 if (!commentDialog) {
\r
7247 commentDialog = hDlg;
\r
7248 flags = SWP_NOZORDER;
\r
7249 GetClientRect(hDlg, &rect);
\r
7250 sizeX = rect.right;
\r
7251 sizeY = rect.bottom;
\r
7252 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7253 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7254 WINDOWPLACEMENT wp;
\r
7255 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7256 wp.length = sizeof(WINDOWPLACEMENT);
\r
7258 wp.showCmd = SW_SHOW;
\r
7259 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7260 wp.rcNormalPosition.left = commentX;
\r
7261 wp.rcNormalPosition.right = commentX + commentW;
\r
7262 wp.rcNormalPosition.top = commentY;
\r
7263 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7264 SetWindowPlacement(hDlg, &wp);
\r
7266 GetClientRect(hDlg, &rect);
\r
7267 newSizeX = rect.right;
\r
7268 newSizeY = rect.bottom;
\r
7269 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7270 newSizeX, newSizeY);
\r
7277 case WM_COMMAND: /* message: received a command */
\r
7278 switch (LOWORD(wParam)) {
\r
7280 if (editComment) {
\r
7282 /* Read changed options from the dialog box */
\r
7283 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7284 len = GetWindowTextLength(hwndText);
\r
7285 str = (char *) malloc(len + 1);
\r
7286 GetWindowText(hwndText, str, len + 1);
\r
7295 ReplaceComment(commentIndex, str);
\r
7302 case OPT_CancelComment:
\r
7306 case OPT_ClearComment:
\r
7307 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7310 case OPT_EditComment:
\r
7311 EditCommentEvent();
\r
7320 newSizeX = LOWORD(lParam);
\r
7321 newSizeY = HIWORD(lParam);
\r
7322 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7327 case WM_GETMINMAXINFO:
\r
7328 /* Prevent resizing window too small */
\r
7329 mmi = (MINMAXINFO *) lParam;
\r
7330 mmi->ptMinTrackSize.x = 100;
\r
7331 mmi->ptMinTrackSize.y = 100;
\r
7338 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7343 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7345 if (str == NULL) str = "";
\r
7346 p = (char *) malloc(2 * strlen(str) + 2);
\r
7349 if (*str == '\n') *q++ = '\r';
\r
7353 if (commentText != NULL) free(commentText);
\r
7355 commentIndex = index;
\r
7356 commentTitle = title;
\r
7358 editComment = edit;
\r
7360 if (commentDialog) {
\r
7361 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7362 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7364 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7365 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7366 hwndMain, (DLGPROC)lpProc);
\r
7367 FreeProcInstance(lpProc);
\r
7369 commentDialogUp = TRUE;
\r
7373 /*---------------------------------------------------------------------------*\
\r
7375 * Type-in move dialog functions
\r
7377 \*---------------------------------------------------------------------------*/
\r
7380 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7382 char move[MSG_SIZ];
\r
7384 ChessMove moveType;
\r
7385 int fromX, fromY, toX, toY;
\r
7388 switch (message) {
\r
7389 case WM_INITDIALOG:
\r
7390 move[0] = (char) lParam;
\r
7391 move[1] = NULLCHAR;
\r
7392 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7393 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7394 SetWindowText(hInput, move);
\r
7396 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7400 switch (LOWORD(wParam)) {
\r
7402 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7403 { int n; Board board;
\r
7405 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7406 EditPositionPasteFEN(move);
\r
7407 EndDialog(hDlg, TRUE);
\r
7410 // [HGM] movenum: allow move number to be typed in any mode
\r
7411 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7412 currentMove = 2*n-1;
\r
7413 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7414 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7415 EndDialog(hDlg, TRUE);
\r
7416 DrawPosition(TRUE, boards[currentMove]);
\r
7417 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7418 else DisplayMessage("", "");
\r
7422 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7423 gameMode != Training) {
\r
7424 DisplayMoveError("Displayed move is not current");
\r
7426 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7427 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7428 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7429 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7430 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7431 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7432 if (gameMode != Training)
\r
7433 forwardMostMove = currentMove;
\r
7434 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7436 DisplayMoveError("Could not parse move");
\r
7439 EndDialog(hDlg, TRUE);
\r
7442 EndDialog(hDlg, FALSE);
\r
7453 PopUpMoveDialog(char firstchar)
\r
7457 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7458 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7459 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7460 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7461 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7462 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7463 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7464 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7465 gameMode == Training) {
\r
7466 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7467 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7468 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7469 FreeProcInstance(lpProc);
\r
7473 /*---------------------------------------------------------------------------*\
\r
7475 * Type-in name dialog functions
\r
7477 \*---------------------------------------------------------------------------*/
\r
7480 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7482 char move[MSG_SIZ];
\r
7485 switch (message) {
\r
7486 case WM_INITDIALOG:
\r
7487 move[0] = (char) lParam;
\r
7488 move[1] = NULLCHAR;
\r
7489 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7490 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7491 SetWindowText(hInput, move);
\r
7493 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7497 switch (LOWORD(wParam)) {
\r
7499 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7500 appData.userName = strdup(move);
\r
7503 EndDialog(hDlg, TRUE);
\r
7506 EndDialog(hDlg, FALSE);
\r
7517 PopUpNameDialog(char firstchar)
\r
7521 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7522 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7523 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7524 FreeProcInstance(lpProc);
\r
7527 /*---------------------------------------------------------------------------*\
\r
7531 \*---------------------------------------------------------------------------*/
\r
7533 /* Nonmodal error box */
\r
7534 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7535 WPARAM wParam, LPARAM lParam);
\r
7538 ErrorPopUp(char *title, char *content)
\r
7542 BOOLEAN modal = hwndMain == NULL;
\r
7560 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7561 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7564 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7566 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7567 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7568 hwndMain, (DLGPROC)lpProc);
\r
7569 FreeProcInstance(lpProc);
\r
7576 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7577 if (errorDialog == NULL) return;
\r
7578 DestroyWindow(errorDialog);
\r
7579 errorDialog = NULL;
\r
7583 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7588 switch (message) {
\r
7589 case WM_INITDIALOG:
\r
7590 GetWindowRect(hDlg, &rChild);
\r
7593 SetWindowPos(hDlg, NULL, rChild.left,
\r
7594 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7595 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7599 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7600 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7601 and it doesn't work when you resize the dialog.
\r
7602 For now, just give it a default position.
\r
7604 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7606 errorDialog = hDlg;
\r
7607 SetWindowText(hDlg, errorTitle);
\r
7608 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7609 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7613 switch (LOWORD(wParam)) {
\r
7616 if (errorDialog == hDlg) errorDialog = NULL;
\r
7617 DestroyWindow(hDlg);
\r
7629 HWND gothicDialog = NULL;
\r
7632 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7636 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7638 switch (message) {
\r
7639 case WM_INITDIALOG:
\r
7640 GetWindowRect(hDlg, &rChild);
\r
7642 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7646 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7647 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7648 and it doesn't work when you resize the dialog.
\r
7649 For now, just give it a default position.
\r
7651 gothicDialog = hDlg;
\r
7652 SetWindowText(hDlg, errorTitle);
\r
7653 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7654 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7658 switch (LOWORD(wParam)) {
\r
7661 if (errorDialog == hDlg) errorDialog = NULL;
\r
7662 DestroyWindow(hDlg);
\r
7674 GothicPopUp(char *title, VariantClass variant)
\r
7677 static char *lastTitle;
\r
7679 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7680 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7682 if(lastTitle != title && gothicDialog != NULL) {
\r
7683 DestroyWindow(gothicDialog);
\r
7684 gothicDialog = NULL;
\r
7686 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7687 title = lastTitle;
\r
7688 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7689 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7690 hwndMain, (DLGPROC)lpProc);
\r
7691 FreeProcInstance(lpProc);
\r
7696 /*---------------------------------------------------------------------------*\
\r
7698 * Ics Interaction console functions
\r
7700 \*---------------------------------------------------------------------------*/
\r
7702 #define HISTORY_SIZE 64
\r
7703 static char *history[HISTORY_SIZE];
\r
7704 int histIn = 0, histP = 0;
\r
7707 SaveInHistory(char *cmd)
\r
7709 if (history[histIn] != NULL) {
\r
7710 free(history[histIn]);
\r
7711 history[histIn] = NULL;
\r
7713 if (*cmd == NULLCHAR) return;
\r
7714 history[histIn] = StrSave(cmd);
\r
7715 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7716 if (history[histIn] != NULL) {
\r
7717 free(history[histIn]);
\r
7718 history[histIn] = NULL;
\r
7724 PrevInHistory(char *cmd)
\r
7727 if (histP == histIn) {
\r
7728 if (history[histIn] != NULL) free(history[histIn]);
\r
7729 history[histIn] = StrSave(cmd);
\r
7731 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7732 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7734 return history[histP];
\r
7740 if (histP == histIn) return NULL;
\r
7741 histP = (histP + 1) % HISTORY_SIZE;
\r
7742 return history[histP];
\r
7749 BOOLEAN immediate;
\r
7750 } IcsTextMenuEntry;
\r
7751 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7752 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7755 ParseIcsTextMenu(char *icsTextMenuString)
\r
7758 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7759 char *p = icsTextMenuString;
\r
7760 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7763 if (e->command != NULL) {
\r
7765 e->command = NULL;
\r
7769 e = icsTextMenuEntry;
\r
7770 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7771 if (*p == ';' || *p == '\n') {
\r
7772 e->item = strdup("-");
\r
7773 e->command = NULL;
\r
7775 } else if (*p == '-') {
\r
7776 e->item = strdup("-");
\r
7777 e->command = NULL;
\r
7781 char *q, *r, *s, *t;
\r
7783 q = strchr(p, ',');
\r
7784 if (q == NULL) break;
\r
7786 r = strchr(q + 1, ',');
\r
7787 if (r == NULL) break;
\r
7789 s = strchr(r + 1, ',');
\r
7790 if (s == NULL) break;
\r
7793 t = strchr(s + 1, c);
\r
7796 t = strchr(s + 1, c);
\r
7798 if (t != NULL) *t = NULLCHAR;
\r
7799 e->item = strdup(p);
\r
7800 e->command = strdup(q + 1);
\r
7801 e->getname = *(r + 1) != '0';
\r
7802 e->immediate = *(s + 1) != '0';
\r
7806 if (t == NULL) break;
\r
7815 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7819 hmenu = LoadMenu(hInst, "TextMenu");
\r
7820 h = GetSubMenu(hmenu, 0);
\r
7822 if (strcmp(e->item, "-") == 0) {
\r
7823 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7825 if (e->item[0] == '|') {
\r
7826 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7827 IDM_CommandX + i, &e->item[1]);
\r
7829 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7838 WNDPROC consoleTextWindowProc;
\r
7841 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7843 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7844 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7848 SetWindowText(hInput, command);
\r
7850 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7852 sel.cpMin = 999999;
\r
7853 sel.cpMax = 999999;
\r
7854 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7859 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7860 if (sel.cpMin == sel.cpMax) {
\r
7861 /* Expand to surrounding word */
\r
7864 tr.chrg.cpMax = sel.cpMin;
\r
7865 tr.chrg.cpMin = --sel.cpMin;
\r
7866 if (sel.cpMin < 0) break;
\r
7867 tr.lpstrText = name;
\r
7868 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7869 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7873 tr.chrg.cpMin = sel.cpMax;
\r
7874 tr.chrg.cpMax = ++sel.cpMax;
\r
7875 tr.lpstrText = name;
\r
7876 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7877 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7880 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7881 MessageBeep(MB_ICONEXCLAMATION);
\r
7885 tr.lpstrText = name;
\r
7886 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7888 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7889 MessageBeep(MB_ICONEXCLAMATION);
\r
7892 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7895 sprintf(buf, "%s %s", command, name);
\r
7896 SetWindowText(hInput, buf);
\r
7897 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7899 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7900 SetWindowText(hInput, buf);
\r
7901 sel.cpMin = 999999;
\r
7902 sel.cpMax = 999999;
\r
7903 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7909 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7914 switch (message) {
\r
7916 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7919 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7922 sel.cpMin = 999999;
\r
7923 sel.cpMax = 999999;
\r
7924 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7925 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7930 if(wParam != '\022') {
\r
7931 if (wParam == '\t') {
\r
7932 if (GetKeyState(VK_SHIFT) < 0) {
\r
7934 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7935 if (buttonDesc[0].hwnd) {
\r
7936 SetFocus(buttonDesc[0].hwnd);
\r
7938 SetFocus(hwndMain);
\r
7942 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7945 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7946 JAWS_DELETE( SetFocus(hInput); )
\r
7947 SendMessage(hInput, message, wParam, lParam);
\r
7950 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7951 case WM_RBUTTONUP:
\r
7952 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7953 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7954 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7957 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7958 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7959 if (sel.cpMin == sel.cpMax) {
\r
7960 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7961 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7963 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7964 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7966 pt.x = LOWORD(lParam);
\r
7967 pt.y = HIWORD(lParam);
\r
7968 MenuPopup(hwnd, pt, hmenu, -1);
\r
7972 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7974 return SendMessage(hInput, message, wParam, lParam);
\r
7975 case WM_MBUTTONDOWN:
\r
7976 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7977 case WM_RBUTTONDOWN:
\r
7978 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7979 /* Move selection here if it was empty */
\r
7981 pt.x = LOWORD(lParam);
\r
7982 pt.y = HIWORD(lParam);
\r
7983 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7984 if (sel.cpMin == sel.cpMax) {
\r
7985 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7986 sel.cpMax = sel.cpMin;
\r
7987 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7989 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7993 switch (LOWORD(wParam)) {
\r
7994 case IDM_QuickPaste:
\r
7996 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7997 if (sel.cpMin == sel.cpMax) {
\r
7998 MessageBeep(MB_ICONEXCLAMATION);
\r
8001 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8002 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8003 SendMessage(hInput, WM_PASTE, 0, 0);
\r
8008 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8011 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8014 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8018 int i = LOWORD(wParam) - IDM_CommandX;
\r
8019 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8020 icsTextMenuEntry[i].command != NULL) {
\r
8021 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8022 icsTextMenuEntry[i].getname,
\r
8023 icsTextMenuEntry[i].immediate);
\r
8031 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8034 WNDPROC consoleInputWindowProc;
\r
8037 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8039 char buf[MSG_SIZ];
\r
8041 static BOOL sendNextChar = FALSE;
\r
8042 static BOOL quoteNextChar = FALSE;
\r
8043 InputSource *is = consoleInputSource;
\r
8047 switch (message) {
\r
8049 if (!appData.localLineEditing || sendNextChar) {
\r
8050 is->buf[0] = (CHAR) wParam;
\r
8052 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8053 sendNextChar = FALSE;
\r
8056 if (quoteNextChar) {
\r
8057 buf[0] = (char) wParam;
\r
8058 buf[1] = NULLCHAR;
\r
8059 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8060 quoteNextChar = FALSE;
\r
8064 case '\r': /* Enter key */
\r
8065 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8066 if (consoleEcho) SaveInHistory(is->buf);
\r
8067 is->buf[is->count++] = '\n';
\r
8068 is->buf[is->count] = NULLCHAR;
\r
8069 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8070 if (consoleEcho) {
\r
8071 ConsoleOutput(is->buf, is->count, TRUE);
\r
8072 } else if (appData.localLineEditing) {
\r
8073 ConsoleOutput("\n", 1, TRUE);
\r
8076 case '\033': /* Escape key */
\r
8077 SetWindowText(hwnd, "");
\r
8078 cf.cbSize = sizeof(CHARFORMAT);
\r
8079 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8080 if (consoleEcho) {
\r
8081 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8083 cf.crTextColor = COLOR_ECHOOFF;
\r
8085 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8086 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8088 case '\t': /* Tab key */
\r
8089 if (GetKeyState(VK_SHIFT) < 0) {
\r
8091 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8094 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8095 if (buttonDesc[0].hwnd) {
\r
8096 SetFocus(buttonDesc[0].hwnd);
\r
8098 SetFocus(hwndMain);
\r
8102 case '\023': /* Ctrl+S */
\r
8103 sendNextChar = TRUE;
\r
8105 case '\021': /* Ctrl+Q */
\r
8106 quoteNextChar = TRUE;
\r
8116 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8117 p = PrevInHistory(buf);
\r
8119 SetWindowText(hwnd, p);
\r
8120 sel.cpMin = 999999;
\r
8121 sel.cpMax = 999999;
\r
8122 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8127 p = NextInHistory();
\r
8129 SetWindowText(hwnd, p);
\r
8130 sel.cpMin = 999999;
\r
8131 sel.cpMax = 999999;
\r
8132 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8138 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8142 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8146 case WM_MBUTTONDOWN:
\r
8147 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8148 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8150 case WM_RBUTTONUP:
\r
8151 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8152 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8153 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8157 hmenu = LoadMenu(hInst, "InputMenu");
\r
8158 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8159 if (sel.cpMin == sel.cpMax) {
\r
8160 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8161 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8163 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8164 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8166 pt.x = LOWORD(lParam);
\r
8167 pt.y = HIWORD(lParam);
\r
8168 MenuPopup(hwnd, pt, hmenu, -1);
\r
8172 switch (LOWORD(wParam)) {
\r
8174 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8176 case IDM_SelectAll:
\r
8178 sel.cpMax = -1; /*999999?*/
\r
8179 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8182 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8185 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8188 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8193 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8196 #define CO_MAX 100000
\r
8197 #define CO_TRIM 1000
\r
8200 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8202 static SnapData sd;
\r
8203 static HWND hText, hInput /*, hFocus*/;
\r
8204 // InputSource *is = consoleInputSource;
\r
8206 static int sizeX, sizeY;
\r
8207 int newSizeX, newSizeY;
\r
8210 switch (message) {
\r
8211 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8212 hwndConsole = hDlg;
\r
8213 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8214 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8216 consoleTextWindowProc = (WNDPROC)
\r
8217 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8218 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8219 consoleInputWindowProc = (WNDPROC)
\r
8220 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8221 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8222 Colorize(ColorNormal, TRUE);
\r
8223 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8224 ChangedConsoleFont();
\r
8225 GetClientRect(hDlg, &rect);
\r
8226 sizeX = rect.right;
\r
8227 sizeY = rect.bottom;
\r
8228 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8229 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8230 WINDOWPLACEMENT wp;
\r
8231 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8232 wp.length = sizeof(WINDOWPLACEMENT);
\r
8234 wp.showCmd = SW_SHOW;
\r
8235 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8236 wp.rcNormalPosition.left = wpConsole.x;
\r
8237 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8238 wp.rcNormalPosition.top = wpConsole.y;
\r
8239 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8240 SetWindowPlacement(hDlg, &wp);
\r
8243 // [HGM] Chessknight's change 2004-07-13
\r
8244 else { /* Determine Defaults */
\r
8245 WINDOWPLACEMENT wp;
\r
8246 wpConsole.x = winWidth + 1;
\r
8247 wpConsole.y = boardY;
\r
8248 wpConsole.width = screenWidth - winWidth;
\r
8249 wpConsole.height = winHeight;
\r
8250 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8251 wp.length = sizeof(WINDOWPLACEMENT);
\r
8253 wp.showCmd = SW_SHOW;
\r
8254 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8255 wp.rcNormalPosition.left = wpConsole.x;
\r
8256 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8257 wp.rcNormalPosition.top = wpConsole.y;
\r
8258 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8259 SetWindowPlacement(hDlg, &wp);
\r
8274 if (IsIconic(hDlg)) break;
\r
8275 newSizeX = LOWORD(lParam);
\r
8276 newSizeY = HIWORD(lParam);
\r
8277 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8278 RECT rectText, rectInput;
\r
8280 int newTextHeight, newTextWidth;
\r
8281 GetWindowRect(hText, &rectText);
\r
8282 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8283 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8284 if (newTextHeight < 0) {
\r
8285 newSizeY += -newTextHeight;
\r
8286 newTextHeight = 0;
\r
8288 SetWindowPos(hText, NULL, 0, 0,
\r
8289 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8290 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8291 pt.x = rectInput.left;
\r
8292 pt.y = rectInput.top + newSizeY - sizeY;
\r
8293 ScreenToClient(hDlg, &pt);
\r
8294 SetWindowPos(hInput, NULL,
\r
8295 pt.x, pt.y, /* needs client coords */
\r
8296 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8297 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8303 case WM_GETMINMAXINFO:
\r
8304 /* Prevent resizing window too small */
\r
8305 mmi = (MINMAXINFO *) lParam;
\r
8306 mmi->ptMinTrackSize.x = 100;
\r
8307 mmi->ptMinTrackSize.y = 100;
\r
8310 /* [AS] Snapping */
\r
8311 case WM_ENTERSIZEMOVE:
\r
8312 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8315 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8318 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8320 case WM_EXITSIZEMOVE:
\r
8321 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8324 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8332 if (hwndConsole) return;
\r
8333 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8334 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8339 ConsoleOutput(char* data, int length, int forceVisible)
\r
8344 char buf[CO_MAX+1];
\r
8347 static int delayLF = 0;
\r
8348 CHARRANGE savesel, sel;
\r
8350 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8358 while (length--) {
\r
8366 } else if (*p == '\007') {
\r
8367 MyPlaySound(&sounds[(int)SoundBell]);
\r
8374 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8375 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8376 /* Save current selection */
\r
8377 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8378 exlen = GetWindowTextLength(hText);
\r
8379 /* Find out whether current end of text is visible */
\r
8380 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8381 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8382 /* Trim existing text if it's too long */
\r
8383 if (exlen + (q - buf) > CO_MAX) {
\r
8384 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8387 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8388 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8390 savesel.cpMin -= trim;
\r
8391 savesel.cpMax -= trim;
\r
8392 if (exlen < 0) exlen = 0;
\r
8393 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8394 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8396 /* Append the new text */
\r
8397 sel.cpMin = exlen;
\r
8398 sel.cpMax = exlen;
\r
8399 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8400 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8401 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8402 if (forceVisible || exlen == 0 ||
\r
8403 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8404 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8405 /* Scroll to make new end of text visible if old end of text
\r
8406 was visible or new text is an echo of user typein */
\r
8407 sel.cpMin = 9999999;
\r
8408 sel.cpMax = 9999999;
\r
8409 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8410 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8411 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8412 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8414 if (savesel.cpMax == exlen || forceVisible) {
\r
8415 /* Move insert point to new end of text if it was at the old
\r
8416 end of text or if the new text is an echo of user typein */
\r
8417 sel.cpMin = 9999999;
\r
8418 sel.cpMax = 9999999;
\r
8419 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8421 /* Restore previous selection */
\r
8422 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8424 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8431 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8435 COLORREF oldFg, oldBg;
\r
8439 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8441 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8442 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8443 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8446 rect.right = x + squareSize;
\r
8448 rect.bottom = y + squareSize;
\r
8451 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8452 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8453 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8454 &rect, str, strlen(str), NULL);
\r
8456 (void) SetTextColor(hdc, oldFg);
\r
8457 (void) SetBkColor(hdc, oldBg);
\r
8458 (void) SelectObject(hdc, oldFont);
\r
8462 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8463 RECT *rect, char *color, char *flagFell)
\r
8467 COLORREF oldFg, oldBg;
\r
8470 if (appData.clockMode) {
\r
8472 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8474 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8481 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8482 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8484 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8485 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8487 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8491 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8492 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8493 rect, str, strlen(str), NULL);
\r
8494 if(logoHeight > 0 && appData.clockMode) {
\r
8496 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8497 r.top = rect->top + logoHeight/2;
\r
8498 r.left = rect->left;
\r
8499 r.right = rect->right;
\r
8500 r.bottom = rect->bottom;
\r
8501 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8502 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8503 &r, str, strlen(str), NULL);
\r
8505 (void) SetTextColor(hdc, oldFg);
\r
8506 (void) SetBkColor(hdc, oldBg);
\r
8507 (void) SelectObject(hdc, oldFont);
\r
8512 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8518 if( count <= 0 ) {
\r
8519 if (appData.debugMode) {
\r
8520 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8523 return ERROR_INVALID_USER_BUFFER;
\r
8526 ResetEvent(ovl->hEvent);
\r
8527 ovl->Offset = ovl->OffsetHigh = 0;
\r
8528 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8532 err = GetLastError();
\r
8533 if (err == ERROR_IO_PENDING) {
\r
8534 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8538 err = GetLastError();
\r
8545 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8550 ResetEvent(ovl->hEvent);
\r
8551 ovl->Offset = ovl->OffsetHigh = 0;
\r
8552 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8556 err = GetLastError();
\r
8557 if (err == ERROR_IO_PENDING) {
\r
8558 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8562 err = GetLastError();
\r
8568 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8569 void CheckForInputBufferFull( InputSource * is )
\r
8571 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8572 /* Look for end of line */
\r
8573 char * p = is->buf;
\r
8575 while( p < is->next && *p != '\n' ) {
\r
8579 if( p >= is->next ) {
\r
8580 if (appData.debugMode) {
\r
8581 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8584 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8585 is->count = (DWORD) -1;
\r
8586 is->next = is->buf;
\r
8592 InputThread(LPVOID arg)
\r
8597 is = (InputSource *) arg;
\r
8598 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8599 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8600 while (is->hThread != NULL) {
\r
8601 is->error = DoReadFile(is->hFile, is->next,
\r
8602 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8603 &is->count, &ovl);
\r
8604 if (is->error == NO_ERROR) {
\r
8605 is->next += is->count;
\r
8607 if (is->error == ERROR_BROKEN_PIPE) {
\r
8608 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8611 is->count = (DWORD) -1;
\r
8612 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8617 CheckForInputBufferFull( is );
\r
8619 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8621 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8623 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8626 CloseHandle(ovl.hEvent);
\r
8627 CloseHandle(is->hFile);
\r
8629 if (appData.debugMode) {
\r
8630 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8637 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8639 NonOvlInputThread(LPVOID arg)
\r
8646 is = (InputSource *) arg;
\r
8647 while (is->hThread != NULL) {
\r
8648 is->error = ReadFile(is->hFile, is->next,
\r
8649 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8650 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8651 if (is->error == NO_ERROR) {
\r
8652 /* Change CRLF to LF */
\r
8653 if (is->next > is->buf) {
\r
8655 i = is->count + 1;
\r
8663 if (prev == '\r' && *p == '\n') {
\r
8675 if (is->error == ERROR_BROKEN_PIPE) {
\r
8676 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8679 is->count = (DWORD) -1;
\r
8683 CheckForInputBufferFull( is );
\r
8685 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8687 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8689 if (is->count < 0) break; /* Quit on error */
\r
8691 CloseHandle(is->hFile);
\r
8696 SocketInputThread(LPVOID arg)
\r
8700 is = (InputSource *) arg;
\r
8701 while (is->hThread != NULL) {
\r
8702 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8703 if ((int)is->count == SOCKET_ERROR) {
\r
8704 is->count = (DWORD) -1;
\r
8705 is->error = WSAGetLastError();
\r
8707 is->error = NO_ERROR;
\r
8708 is->next += is->count;
\r
8709 if (is->count == 0 && is->second == is) {
\r
8710 /* End of file on stderr; quit with no message */
\r
8714 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8716 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8718 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8724 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8728 is = (InputSource *) lParam;
\r
8729 if (is->lineByLine) {
\r
8730 /* Feed in lines one by one */
\r
8731 char *p = is->buf;
\r
8733 while (q < is->next) {
\r
8734 if (*q++ == '\n') {
\r
8735 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8740 /* Move any partial line to the start of the buffer */
\r
8742 while (p < is->next) {
\r
8747 if (is->error != NO_ERROR || is->count == 0) {
\r
8748 /* Notify backend of the error. Note: If there was a partial
\r
8749 line at the end, it is not flushed through. */
\r
8750 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8753 /* Feed in the whole chunk of input at once */
\r
8754 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8755 is->next = is->buf;
\r
8759 /*---------------------------------------------------------------------------*\
\r
8761 * Menu enables. Used when setting various modes.
\r
8763 \*---------------------------------------------------------------------------*/
\r
8771 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8773 while (enab->item > 0) {
\r
8774 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8779 Enables gnuEnables[] = {
\r
8780 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8781 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8782 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8783 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8784 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8785 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8786 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8787 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8788 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8789 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8793 Enables icsEnables[] = {
\r
8794 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8795 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8796 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8797 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8798 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8799 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8800 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8801 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8802 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8803 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8804 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8805 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8810 Enables zippyEnables[] = {
\r
8811 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8812 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8813 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8818 Enables ncpEnables[] = {
\r
8819 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8820 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8822 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8823 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8824 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8825 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8826 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8827 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8828 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8829 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8830 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8831 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8832 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8833 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8837 Enables trainingOnEnables[] = {
\r
8838 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8839 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8840 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8841 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8842 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8843 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8844 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8845 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8849 Enables trainingOffEnables[] = {
\r
8850 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8851 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8852 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8853 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8854 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8855 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8856 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8857 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8861 /* These modify either ncpEnables or gnuEnables */
\r
8862 Enables cmailEnables[] = {
\r
8863 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8864 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8865 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8866 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8867 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8868 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8869 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8873 Enables machineThinkingEnables[] = {
\r
8874 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8875 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8876 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8877 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8878 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8879 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8880 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8881 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8882 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8883 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8884 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8885 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8886 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8887 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8888 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8892 Enables userThinkingEnables[] = {
\r
8893 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8894 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8895 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8896 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8897 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8898 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8899 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8900 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8901 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8902 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8903 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8904 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8905 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8906 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8907 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8911 /*---------------------------------------------------------------------------*\
\r
8913 * Front-end interface functions exported by XBoard.
\r
8914 * Functions appear in same order as prototypes in frontend.h.
\r
8916 \*---------------------------------------------------------------------------*/
\r
8920 static UINT prevChecked = 0;
\r
8921 static int prevPausing = 0;
\r
8924 if (pausing != prevPausing) {
\r
8925 prevPausing = pausing;
\r
8926 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8927 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8928 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8931 switch (gameMode) {
\r
8932 case BeginningOfGame:
\r
8933 if (appData.icsActive)
\r
8934 nowChecked = IDM_IcsClient;
\r
8935 else if (appData.noChessProgram)
\r
8936 nowChecked = IDM_EditGame;
\r
8938 nowChecked = IDM_MachineBlack;
\r
8940 case MachinePlaysBlack:
\r
8941 nowChecked = IDM_MachineBlack;
\r
8943 case MachinePlaysWhite:
\r
8944 nowChecked = IDM_MachineWhite;
\r
8946 case TwoMachinesPlay:
\r
8947 nowChecked = IDM_TwoMachines;
\r
8950 nowChecked = IDM_AnalysisMode;
\r
8953 nowChecked = IDM_AnalyzeFile;
\r
8956 nowChecked = IDM_EditGame;
\r
8958 case PlayFromGameFile:
\r
8959 nowChecked = IDM_LoadGame;
\r
8961 case EditPosition:
\r
8962 nowChecked = IDM_EditPosition;
\r
8965 nowChecked = IDM_Training;
\r
8967 case IcsPlayingWhite:
\r
8968 case IcsPlayingBlack:
\r
8969 case IcsObserving:
\r
8971 nowChecked = IDM_IcsClient;
\r
8978 if (prevChecked != 0)
\r
8979 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8980 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8981 if (nowChecked != 0)
\r
8982 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8983 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8985 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8986 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8987 MF_BYCOMMAND|MF_ENABLED);
\r
8989 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8990 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8993 prevChecked = nowChecked;
\r
8995 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8996 if (appData.icsActive) {
\r
8997 if (appData.icsEngineAnalyze) {
\r
8998 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8999 MF_BYCOMMAND|MF_CHECKED);
\r
9001 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9002 MF_BYCOMMAND|MF_UNCHECKED);
\r
9010 HMENU hmenu = GetMenu(hwndMain);
\r
9011 SetMenuEnables(hmenu, icsEnables);
\r
9012 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9013 MF_BYPOSITION|MF_ENABLED);
\r
9015 if (appData.zippyPlay) {
\r
9016 SetMenuEnables(hmenu, zippyEnables);
\r
9017 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9018 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9019 MF_BYCOMMAND|MF_ENABLED);
\r
9027 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9033 HMENU hmenu = GetMenu(hwndMain);
\r
9034 SetMenuEnables(hmenu, ncpEnables);
\r
9035 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9036 MF_BYPOSITION|MF_GRAYED);
\r
9037 DrawMenuBar(hwndMain);
\r
9043 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9047 SetTrainingModeOn()
\r
9050 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9051 for (i = 0; i < N_BUTTONS; i++) {
\r
9052 if (buttonDesc[i].hwnd != NULL)
\r
9053 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9058 VOID SetTrainingModeOff()
\r
9061 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9062 for (i = 0; i < N_BUTTONS; i++) {
\r
9063 if (buttonDesc[i].hwnd != NULL)
\r
9064 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9070 SetUserThinkingEnables()
\r
9072 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9076 SetMachineThinkingEnables()
\r
9078 HMENU hMenu = GetMenu(hwndMain);
\r
9079 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9081 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9083 if (gameMode == MachinePlaysBlack) {
\r
9084 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9085 } else if (gameMode == MachinePlaysWhite) {
\r
9086 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9087 } else if (gameMode == TwoMachinesPlay) {
\r
9088 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9094 DisplayTitle(char *str)
\r
9096 char title[MSG_SIZ], *host;
\r
9097 if (str[0] != NULLCHAR) {
\r
9098 strcpy(title, str);
\r
9099 } else if (appData.icsActive) {
\r
9100 if (appData.icsCommPort[0] != NULLCHAR)
\r
9103 host = appData.icsHost;
\r
9104 sprintf(title, "%s: %s", szTitle, host);
\r
9105 } else if (appData.noChessProgram) {
\r
9106 strcpy(title, szTitle);
\r
9108 strcpy(title, szTitle);
\r
9109 strcat(title, ": ");
\r
9110 strcat(title, first.tidy);
\r
9112 SetWindowText(hwndMain, title);
\r
9117 DisplayMessage(char *str1, char *str2)
\r
9121 int remain = MESSAGE_TEXT_MAX - 1;
\r
9124 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9125 messageText[0] = NULLCHAR;
\r
9127 len = strlen(str1);
\r
9128 if (len > remain) len = remain;
\r
9129 strncpy(messageText, str1, len);
\r
9130 messageText[len] = NULLCHAR;
\r
9133 if (*str2 && remain >= 2) {
\r
9135 strcat(messageText, " ");
\r
9138 len = strlen(str2);
\r
9139 if (len > remain) len = remain;
\r
9140 strncat(messageText, str2, len);
\r
9142 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9144 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9148 hdc = GetDC(hwndMain);
\r
9149 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9150 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9151 &messageRect, messageText, strlen(messageText), NULL);
\r
9152 (void) SelectObject(hdc, oldFont);
\r
9153 (void) ReleaseDC(hwndMain, hdc);
\r
9157 DisplayError(char *str, int error)
\r
9159 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9165 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9166 NULL, error, LANG_NEUTRAL,
\r
9167 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9169 sprintf(buf, "%s:\n%s", str, buf2);
\r
9171 ErrorMap *em = errmap;
\r
9172 while (em->err != 0 && em->err != error) em++;
\r
9173 if (em->err != 0) {
\r
9174 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9176 sprintf(buf, "%s:\nError code %d", str, error);
\r
9181 ErrorPopUp("Error", buf);
\r
9186 DisplayMoveError(char *str)
\r
9188 fromX = fromY = -1;
\r
9189 ClearHighlights();
\r
9190 DrawPosition(FALSE, NULL);
\r
9191 if (appData.popupMoveErrors) {
\r
9192 ErrorPopUp("Error", str);
\r
9194 DisplayMessage(str, "");
\r
9195 moveErrorMessageUp = TRUE;
\r
9200 DisplayFatalError(char *str, int error, int exitStatus)
\r
9202 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9204 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9207 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9208 NULL, error, LANG_NEUTRAL,
\r
9209 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9211 sprintf(buf, "%s:\n%s", str, buf2);
\r
9213 ErrorMap *em = errmap;
\r
9214 while (em->err != 0 && em->err != error) em++;
\r
9215 if (em->err != 0) {
\r
9216 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9218 sprintf(buf, "%s:\nError code %d", str, error);
\r
9223 if (appData.debugMode) {
\r
9224 fprintf(debugFP, "%s: %s\n", label, str);
\r
9226 if (appData.popupExitMessage) {
\r
9227 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9228 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9230 ExitEvent(exitStatus);
\r
9235 DisplayInformation(char *str)
\r
9237 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9242 DisplayNote(char *str)
\r
9244 ErrorPopUp("Note", str);
\r
9249 char *title, *question, *replyPrefix;
\r
9254 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9256 static QuestionParams *qp;
\r
9257 char reply[MSG_SIZ];
\r
9260 switch (message) {
\r
9261 case WM_INITDIALOG:
\r
9262 qp = (QuestionParams *) lParam;
\r
9263 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9264 SetWindowText(hDlg, qp->title);
\r
9265 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9266 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9270 switch (LOWORD(wParam)) {
\r
9272 strcpy(reply, qp->replyPrefix);
\r
9273 if (*reply) strcat(reply, " ");
\r
9274 len = strlen(reply);
\r
9275 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9276 strcat(reply, "\n");
\r
9277 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9278 EndDialog(hDlg, TRUE);
\r
9279 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9282 EndDialog(hDlg, FALSE);
\r
9293 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9295 QuestionParams qp;
\r
9299 qp.question = question;
\r
9300 qp.replyPrefix = replyPrefix;
\r
9302 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9303 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9304 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9305 FreeProcInstance(lpProc);
\r
9308 /* [AS] Pick FRC position */
\r
9309 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9311 static int * lpIndexFRC;
\r
9317 case WM_INITDIALOG:
\r
9318 lpIndexFRC = (int *) lParam;
\r
9320 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9322 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9323 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9324 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9325 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9330 switch( LOWORD(wParam) ) {
\r
9332 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9333 EndDialog( hDlg, 0 );
\r
9334 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9337 EndDialog( hDlg, 1 );
\r
9339 case IDC_NFG_Edit:
\r
9340 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9341 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9343 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9346 case IDC_NFG_Random:
\r
9347 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9348 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9361 int index = appData.defaultFrcPosition;
\r
9362 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9364 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9366 if( result == 0 ) {
\r
9367 appData.defaultFrcPosition = index;
\r
9373 /* [AS] Game list options */
\r
9379 static GLT_Item GLT_ItemInfo[] = {
\r
9380 { GLT_EVENT, "Event" },
\r
9381 { GLT_SITE, "Site" },
\r
9382 { GLT_DATE, "Date" },
\r
9383 { GLT_ROUND, "Round" },
\r
9384 { GLT_PLAYERS, "Players" },
\r
9385 { GLT_RESULT, "Result" },
\r
9386 { GLT_WHITE_ELO, "White Rating" },
\r
9387 { GLT_BLACK_ELO, "Black Rating" },
\r
9388 { GLT_TIME_CONTROL,"Time Control" },
\r
9389 { GLT_VARIANT, "Variant" },
\r
9390 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9394 const char * GLT_FindItem( char id )
\r
9396 const char * result = 0;
\r
9398 GLT_Item * list = GLT_ItemInfo;
\r
9400 while( list->id != 0 ) {
\r
9401 if( list->id == id ) {
\r
9402 result = list->name;
\r
9412 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9414 const char * name = GLT_FindItem( id );
\r
9417 if( index >= 0 ) {
\r
9418 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9421 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9426 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9430 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9433 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9437 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9439 pc = GLT_ALL_TAGS;
\r
9442 if( strchr( tags, *pc ) == 0 ) {
\r
9443 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9448 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9451 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9453 char result = '\0';
\r
9456 GLT_Item * list = GLT_ItemInfo;
\r
9458 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9459 while( list->id != 0 ) {
\r
9460 if( strcmp( list->name, name ) == 0 ) {
\r
9461 result = list->id;
\r
9472 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9474 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9475 int idx2 = idx1 + delta;
\r
9476 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9478 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9481 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9482 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9483 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9484 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9488 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9490 static char glt[64];
\r
9491 static char * lpUserGLT;
\r
9495 case WM_INITDIALOG:
\r
9496 lpUserGLT = (char *) lParam;
\r
9498 strcpy( glt, lpUserGLT );
\r
9500 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9502 /* Initialize list */
\r
9503 GLT_TagsToList( hDlg, glt );
\r
9505 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9510 switch( LOWORD(wParam) ) {
\r
9513 char * pc = lpUserGLT;
\r
9515 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9519 id = GLT_ListItemToTag( hDlg, idx );
\r
9523 } while( id != '\0' );
\r
9525 EndDialog( hDlg, 0 );
\r
9528 EndDialog( hDlg, 1 );
\r
9531 case IDC_GLT_Default:
\r
9532 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9533 GLT_TagsToList( hDlg, glt );
\r
9536 case IDC_GLT_Restore:
\r
9537 strcpy( glt, lpUserGLT );
\r
9538 GLT_TagsToList( hDlg, glt );
\r
9542 GLT_MoveSelection( hDlg, -1 );
\r
9545 case IDC_GLT_Down:
\r
9546 GLT_MoveSelection( hDlg, +1 );
\r
9556 int GameListOptions()
\r
9560 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9562 strcpy( glt, appData.gameListTags );
\r
9564 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9566 if( result == 0 ) {
\r
9567 /* [AS] Memory leak here! */
\r
9568 appData.gameListTags = strdup( glt );
\r
9576 DisplayIcsInteractionTitle(char *str)
\r
9578 char consoleTitle[MSG_SIZ];
\r
9580 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9581 SetWindowText(hwndConsole, consoleTitle);
\r
9585 DrawPosition(int fullRedraw, Board board)
\r
9587 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9594 fromX = fromY = -1;
\r
9595 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9596 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9597 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9598 dragInfo.lastpos = dragInfo.pos;
\r
9599 dragInfo.start.x = dragInfo.start.y = -1;
\r
9600 dragInfo.from = dragInfo.start;
\r
9602 DrawPosition(TRUE, NULL);
\r
9608 CommentPopUp(char *title, char *str)
\r
9610 HWND hwnd = GetActiveWindow();
\r
9611 EitherCommentPopUp(0, title, str, FALSE);
\r
9612 SetActiveWindow(hwnd);
\r
9616 CommentPopDown(void)
\r
9618 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9619 if (commentDialog) {
\r
9620 ShowWindow(commentDialog, SW_HIDE);
\r
9622 commentDialogUp = FALSE;
\r
9626 EditCommentPopUp(int index, char *title, char *str)
\r
9628 EitherCommentPopUp(index, title, str, TRUE);
\r
9635 MyPlaySound(&sounds[(int)SoundMove]);
\r
9638 VOID PlayIcsWinSound()
\r
9640 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9643 VOID PlayIcsLossSound()
\r
9645 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9648 VOID PlayIcsDrawSound()
\r
9650 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9653 VOID PlayIcsUnfinishedSound()
\r
9655 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9661 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9669 consoleEcho = TRUE;
\r
9670 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9671 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9672 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9681 consoleEcho = FALSE;
\r
9682 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9683 /* This works OK: set text and background both to the same color */
\r
9685 cf.crTextColor = COLOR_ECHOOFF;
\r
9686 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9687 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9690 /* No Raw()...? */
\r
9692 void Colorize(ColorClass cc, int continuation)
\r
9694 currentColorClass = cc;
\r
9695 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9696 consoleCF.crTextColor = textAttribs[cc].color;
\r
9697 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9698 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9704 static char buf[MSG_SIZ];
\r
9705 DWORD bufsiz = MSG_SIZ;
\r
9707 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9708 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9710 if (!GetUserName(buf, &bufsiz)) {
\r
9711 /*DisplayError("Error getting user name", GetLastError());*/
\r
9712 strcpy(buf, "User");
\r
9720 static char buf[MSG_SIZ];
\r
9721 DWORD bufsiz = MSG_SIZ;
\r
9723 if (!GetComputerName(buf, &bufsiz)) {
\r
9724 /*DisplayError("Error getting host name", GetLastError());*/
\r
9725 strcpy(buf, "Unknown");
\r
9732 ClockTimerRunning()
\r
9734 return clockTimerEvent != 0;
\r
9740 if (clockTimerEvent == 0) return FALSE;
\r
9741 KillTimer(hwndMain, clockTimerEvent);
\r
9742 clockTimerEvent = 0;
\r
9747 StartClockTimer(long millisec)
\r
9749 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9750 (UINT) millisec, NULL);
\r
9754 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9757 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9759 if(appData.noGUI) return;
\r
9760 hdc = GetDC(hwndMain);
\r
9761 if (!IsIconic(hwndMain)) {
\r
9762 DisplayAClock(hdc, timeRemaining, highlight,
\r
9763 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9765 if (highlight && iconCurrent == iconBlack) {
\r
9766 iconCurrent = iconWhite;
\r
9767 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9768 if (IsIconic(hwndMain)) {
\r
9769 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9772 (void) ReleaseDC(hwndMain, hdc);
\r
9774 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9778 DisplayBlackClock(long timeRemaining, int highlight)
\r
9781 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9783 if(appData.noGUI) return;
\r
9784 hdc = GetDC(hwndMain);
\r
9785 if (!IsIconic(hwndMain)) {
\r
9786 DisplayAClock(hdc, timeRemaining, highlight,
\r
9787 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9789 if (highlight && iconCurrent == iconWhite) {
\r
9790 iconCurrent = iconBlack;
\r
9791 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9792 if (IsIconic(hwndMain)) {
\r
9793 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9796 (void) ReleaseDC(hwndMain, hdc);
\r
9798 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9803 LoadGameTimerRunning()
\r
9805 return loadGameTimerEvent != 0;
\r
9809 StopLoadGameTimer()
\r
9811 if (loadGameTimerEvent == 0) return FALSE;
\r
9812 KillTimer(hwndMain, loadGameTimerEvent);
\r
9813 loadGameTimerEvent = 0;
\r
9818 StartLoadGameTimer(long millisec)
\r
9820 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9821 (UINT) millisec, NULL);
\r
9829 char fileTitle[MSG_SIZ];
\r
9831 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9832 f = OpenFileDialog(hwndMain, "a", defName,
\r
9833 appData.oldSaveStyle ? "gam" : "pgn",
\r
9835 "Save Game to File", NULL, fileTitle, NULL);
\r
9837 SaveGame(f, 0, "");
\r
9844 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9846 if (delayedTimerEvent != 0) {
\r
9847 if (appData.debugMode) {
\r
9848 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9850 KillTimer(hwndMain, delayedTimerEvent);
\r
9851 delayedTimerEvent = 0;
\r
9852 delayedTimerCallback();
\r
9854 delayedTimerCallback = cb;
\r
9855 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9856 (UINT) millisec, NULL);
\r
9859 DelayedEventCallback
\r
9862 if (delayedTimerEvent) {
\r
9863 return delayedTimerCallback;
\r
9870 CancelDelayedEvent()
\r
9872 if (delayedTimerEvent) {
\r
9873 KillTimer(hwndMain, delayedTimerEvent);
\r
9874 delayedTimerEvent = 0;
\r
9878 DWORD GetWin32Priority(int nice)
\r
9879 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9881 REALTIME_PRIORITY_CLASS 0x00000100
\r
9882 HIGH_PRIORITY_CLASS 0x00000080
\r
9883 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9884 NORMAL_PRIORITY_CLASS 0x00000020
\r
9885 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9886 IDLE_PRIORITY_CLASS 0x00000040
\r
9888 if (nice < -15) return 0x00000080;
\r
9889 if (nice < 0) return 0x00008000;
\r
9890 if (nice == 0) return 0x00000020;
\r
9891 if (nice < 15) return 0x00004000;
\r
9892 return 0x00000040;
\r
9895 /* Start a child process running the given program.
\r
9896 The process's standard output can be read from "from", and its
\r
9897 standard input can be written to "to".
\r
9898 Exit with fatal error if anything goes wrong.
\r
9899 Returns an opaque pointer that can be used to destroy the process
\r
9903 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9905 #define BUFSIZE 4096
\r
9907 HANDLE hChildStdinRd, hChildStdinWr,
\r
9908 hChildStdoutRd, hChildStdoutWr;
\r
9909 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9910 SECURITY_ATTRIBUTES saAttr;
\r
9912 PROCESS_INFORMATION piProcInfo;
\r
9913 STARTUPINFO siStartInfo;
\r
9915 char buf[MSG_SIZ];
\r
9918 if (appData.debugMode) {
\r
9919 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9924 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9925 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9926 saAttr.bInheritHandle = TRUE;
\r
9927 saAttr.lpSecurityDescriptor = NULL;
\r
9930 * The steps for redirecting child's STDOUT:
\r
9931 * 1. Create anonymous pipe to be STDOUT for child.
\r
9932 * 2. Create a noninheritable duplicate of read handle,
\r
9933 * and close the inheritable read handle.
\r
9936 /* Create a pipe for the child's STDOUT. */
\r
9937 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9938 return GetLastError();
\r
9941 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9942 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9943 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9944 FALSE, /* not inherited */
\r
9945 DUPLICATE_SAME_ACCESS);
\r
9947 return GetLastError();
\r
9949 CloseHandle(hChildStdoutRd);
\r
9952 * The steps for redirecting child's STDIN:
\r
9953 * 1. Create anonymous pipe to be STDIN for child.
\r
9954 * 2. Create a noninheritable duplicate of write handle,
\r
9955 * and close the inheritable write handle.
\r
9958 /* Create a pipe for the child's STDIN. */
\r
9959 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9960 return GetLastError();
\r
9963 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9964 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9965 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9966 FALSE, /* not inherited */
\r
9967 DUPLICATE_SAME_ACCESS);
\r
9969 return GetLastError();
\r
9971 CloseHandle(hChildStdinWr);
\r
9973 /* Arrange to (1) look in dir for the child .exe file, and
\r
9974 * (2) have dir be the child's working directory. Interpret
\r
9975 * dir relative to the directory WinBoard loaded from. */
\r
9976 GetCurrentDirectory(MSG_SIZ, buf);
\r
9977 SetCurrentDirectory(installDir);
\r
9978 SetCurrentDirectory(dir);
\r
9980 /* Now create the child process. */
\r
9982 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9983 siStartInfo.lpReserved = NULL;
\r
9984 siStartInfo.lpDesktop = NULL;
\r
9985 siStartInfo.lpTitle = NULL;
\r
9986 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9987 siStartInfo.cbReserved2 = 0;
\r
9988 siStartInfo.lpReserved2 = NULL;
\r
9989 siStartInfo.hStdInput = hChildStdinRd;
\r
9990 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9991 siStartInfo.hStdError = hChildStdoutWr;
\r
9993 fSuccess = CreateProcess(NULL,
\r
9994 cmdLine, /* command line */
\r
9995 NULL, /* process security attributes */
\r
9996 NULL, /* primary thread security attrs */
\r
9997 TRUE, /* handles are inherited */
\r
9998 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9999 NULL, /* use parent's environment */
\r
10001 &siStartInfo, /* STARTUPINFO pointer */
\r
10002 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
10004 err = GetLastError();
\r
10005 SetCurrentDirectory(buf); /* return to prev directory */
\r
10006 if (! fSuccess) {
\r
10010 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10011 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10012 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10015 /* Close the handles we don't need in the parent */
\r
10016 CloseHandle(piProcInfo.hThread);
\r
10017 CloseHandle(hChildStdinRd);
\r
10018 CloseHandle(hChildStdoutWr);
\r
10020 /* Prepare return value */
\r
10021 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10022 cp->kind = CPReal;
\r
10023 cp->hProcess = piProcInfo.hProcess;
\r
10024 cp->pid = piProcInfo.dwProcessId;
\r
10025 cp->hFrom = hChildStdoutRdDup;
\r
10026 cp->hTo = hChildStdinWrDup;
\r
10028 *pr = (void *) cp;
\r
10030 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10031 2000 where engines sometimes don't see the initial command(s)
\r
10032 from WinBoard and hang. I don't understand how that can happen,
\r
10033 but the Sleep is harmless, so I've put it in. Others have also
\r
10034 reported what may be the same problem, so hopefully this will fix
\r
10035 it for them too. */
\r
10043 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10045 ChildProc *cp; int result;
\r
10047 cp = (ChildProc *) pr;
\r
10048 if (cp == NULL) return;
\r
10050 switch (cp->kind) {
\r
10052 /* TerminateProcess is considered harmful, so... */
\r
10053 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10054 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10055 /* The following doesn't work because the chess program
\r
10056 doesn't "have the same console" as WinBoard. Maybe
\r
10057 we could arrange for this even though neither WinBoard
\r
10058 nor the chess program uses a console for stdio? */
\r
10059 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10061 /* [AS] Special termination modes for misbehaving programs... */
\r
10062 if( signal == 9 ) {
\r
10063 result = TerminateProcess( cp->hProcess, 0 );
\r
10065 if ( appData.debugMode) {
\r
10066 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10069 else if( signal == 10 ) {
\r
10070 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10072 if( dw != WAIT_OBJECT_0 ) {
\r
10073 result = TerminateProcess( cp->hProcess, 0 );
\r
10075 if ( appData.debugMode) {
\r
10076 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10082 CloseHandle(cp->hProcess);
\r
10086 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10090 closesocket(cp->sock);
\r
10095 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10096 closesocket(cp->sock);
\r
10097 closesocket(cp->sock2);
\r
10105 InterruptChildProcess(ProcRef pr)
\r
10109 cp = (ChildProc *) pr;
\r
10110 if (cp == NULL) return;
\r
10111 switch (cp->kind) {
\r
10113 /* The following doesn't work because the chess program
\r
10114 doesn't "have the same console" as WinBoard. Maybe
\r
10115 we could arrange for this even though neither WinBoard
\r
10116 nor the chess program uses a console for stdio */
\r
10117 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10122 /* Can't interrupt */
\r
10126 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10133 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10135 char cmdLine[MSG_SIZ];
\r
10137 if (port[0] == NULLCHAR) {
\r
10138 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10140 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10142 return StartChildProcess(cmdLine, "", pr);
\r
10146 /* Code to open TCP sockets */
\r
10149 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10154 struct sockaddr_in sa, mysa;
\r
10155 struct hostent FAR *hp;
\r
10156 unsigned short uport;
\r
10157 WORD wVersionRequested;
\r
10160 /* Initialize socket DLL */
\r
10161 wVersionRequested = MAKEWORD(1, 1);
\r
10162 err = WSAStartup(wVersionRequested, &wsaData);
\r
10163 if (err != 0) return err;
\r
10165 /* Make socket */
\r
10166 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10167 err = WSAGetLastError();
\r
10172 /* Bind local address using (mostly) don't-care values.
\r
10174 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10175 mysa.sin_family = AF_INET;
\r
10176 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10177 uport = (unsigned short) 0;
\r
10178 mysa.sin_port = htons(uport);
\r
10179 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10180 == SOCKET_ERROR) {
\r
10181 err = WSAGetLastError();
\r
10186 /* Resolve remote host name */
\r
10187 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10188 if (!(hp = gethostbyname(host))) {
\r
10189 unsigned int b0, b1, b2, b3;
\r
10191 err = WSAGetLastError();
\r
10193 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10194 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10195 hp->h_addrtype = AF_INET;
\r
10196 hp->h_length = 4;
\r
10197 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10198 hp->h_addr_list[0] = (char *) malloc(4);
\r
10199 hp->h_addr_list[0][0] = (char) b0;
\r
10200 hp->h_addr_list[0][1] = (char) b1;
\r
10201 hp->h_addr_list[0][2] = (char) b2;
\r
10202 hp->h_addr_list[0][3] = (char) b3;
\r
10208 sa.sin_family = hp->h_addrtype;
\r
10209 uport = (unsigned short) atoi(port);
\r
10210 sa.sin_port = htons(uport);
\r
10211 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10213 /* Make connection */
\r
10214 if (connect(s, (struct sockaddr *) &sa,
\r
10215 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10216 err = WSAGetLastError();
\r
10221 /* Prepare return value */
\r
10222 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10223 cp->kind = CPSock;
\r
10225 *pr = (ProcRef *) cp;
\r
10231 OpenCommPort(char *name, ProcRef *pr)
\r
10236 char fullname[MSG_SIZ];
\r
10238 if (*name != '\\')
\r
10239 sprintf(fullname, "\\\\.\\%s", name);
\r
10241 strcpy(fullname, name);
\r
10243 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10244 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10245 if (h == (HANDLE) -1) {
\r
10246 return GetLastError();
\r
10250 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10252 /* Accumulate characters until a 100ms pause, then parse */
\r
10253 ct.ReadIntervalTimeout = 100;
\r
10254 ct.ReadTotalTimeoutMultiplier = 0;
\r
10255 ct.ReadTotalTimeoutConstant = 0;
\r
10256 ct.WriteTotalTimeoutMultiplier = 0;
\r
10257 ct.WriteTotalTimeoutConstant = 0;
\r
10258 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10260 /* Prepare return value */
\r
10261 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10262 cp->kind = CPComm;
\r
10265 *pr = (ProcRef *) cp;
\r
10271 OpenLoopback(ProcRef *pr)
\r
10273 DisplayFatalError("Not implemented", 0, 1);
\r
10279 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10283 SOCKET s, s2, s3;
\r
10284 struct sockaddr_in sa, mysa;
\r
10285 struct hostent FAR *hp;
\r
10286 unsigned short uport;
\r
10287 WORD wVersionRequested;
\r
10290 char stderrPortStr[MSG_SIZ];
\r
10292 /* Initialize socket DLL */
\r
10293 wVersionRequested = MAKEWORD(1, 1);
\r
10294 err = WSAStartup(wVersionRequested, &wsaData);
\r
10295 if (err != 0) return err;
\r
10297 /* Resolve remote host name */
\r
10298 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10299 if (!(hp = gethostbyname(host))) {
\r
10300 unsigned int b0, b1, b2, b3;
\r
10302 err = WSAGetLastError();
\r
10304 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10305 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10306 hp->h_addrtype = AF_INET;
\r
10307 hp->h_length = 4;
\r
10308 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10309 hp->h_addr_list[0] = (char *) malloc(4);
\r
10310 hp->h_addr_list[0][0] = (char) b0;
\r
10311 hp->h_addr_list[0][1] = (char) b1;
\r
10312 hp->h_addr_list[0][2] = (char) b2;
\r
10313 hp->h_addr_list[0][3] = (char) b3;
\r
10319 sa.sin_family = hp->h_addrtype;
\r
10320 uport = (unsigned short) 514;
\r
10321 sa.sin_port = htons(uport);
\r
10322 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10324 /* Bind local socket to unused "privileged" port address
\r
10326 s = INVALID_SOCKET;
\r
10327 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10328 mysa.sin_family = AF_INET;
\r
10329 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10330 for (fromPort = 1023;; fromPort--) {
\r
10331 if (fromPort < 0) {
\r
10333 return WSAEADDRINUSE;
\r
10335 if (s == INVALID_SOCKET) {
\r
10336 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10337 err = WSAGetLastError();
\r
10342 uport = (unsigned short) fromPort;
\r
10343 mysa.sin_port = htons(uport);
\r
10344 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10345 == SOCKET_ERROR) {
\r
10346 err = WSAGetLastError();
\r
10347 if (err == WSAEADDRINUSE) continue;
\r
10351 if (connect(s, (struct sockaddr *) &sa,
\r
10352 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10353 err = WSAGetLastError();
\r
10354 if (err == WSAEADDRINUSE) {
\r
10365 /* Bind stderr local socket to unused "privileged" port address
\r
10367 s2 = INVALID_SOCKET;
\r
10368 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10369 mysa.sin_family = AF_INET;
\r
10370 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10371 for (fromPort = 1023;; fromPort--) {
\r
10372 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10373 if (fromPort < 0) {
\r
10374 (void) closesocket(s);
\r
10376 return WSAEADDRINUSE;
\r
10378 if (s2 == INVALID_SOCKET) {
\r
10379 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10380 err = WSAGetLastError();
\r
10386 uport = (unsigned short) fromPort;
\r
10387 mysa.sin_port = htons(uport);
\r
10388 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10389 == SOCKET_ERROR) {
\r
10390 err = WSAGetLastError();
\r
10391 if (err == WSAEADDRINUSE) continue;
\r
10392 (void) closesocket(s);
\r
10396 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10397 err = WSAGetLastError();
\r
10398 if (err == WSAEADDRINUSE) {
\r
10400 s2 = INVALID_SOCKET;
\r
10403 (void) closesocket(s);
\r
10404 (void) closesocket(s2);
\r
10410 prevStderrPort = fromPort; // remember port used
\r
10411 sprintf(stderrPortStr, "%d", fromPort);
\r
10413 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10414 err = WSAGetLastError();
\r
10415 (void) closesocket(s);
\r
10416 (void) closesocket(s2);
\r
10421 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10422 err = WSAGetLastError();
\r
10423 (void) closesocket(s);
\r
10424 (void) closesocket(s2);
\r
10428 if (*user == NULLCHAR) user = UserName();
\r
10429 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10430 err = WSAGetLastError();
\r
10431 (void) closesocket(s);
\r
10432 (void) closesocket(s2);
\r
10436 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10437 err = WSAGetLastError();
\r
10438 (void) closesocket(s);
\r
10439 (void) closesocket(s2);
\r
10444 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10445 err = WSAGetLastError();
\r
10446 (void) closesocket(s);
\r
10447 (void) closesocket(s2);
\r
10451 (void) closesocket(s2); /* Stop listening */
\r
10453 /* Prepare return value */
\r
10454 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10455 cp->kind = CPRcmd;
\r
10458 *pr = (ProcRef *) cp;
\r
10465 AddInputSource(ProcRef pr, int lineByLine,
\r
10466 InputCallback func, VOIDSTAR closure)
\r
10468 InputSource *is, *is2 = NULL;
\r
10469 ChildProc *cp = (ChildProc *) pr;
\r
10471 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10472 is->lineByLine = lineByLine;
\r
10474 is->closure = closure;
\r
10475 is->second = NULL;
\r
10476 is->next = is->buf;
\r
10477 if (pr == NoProc) {
\r
10478 is->kind = CPReal;
\r
10479 consoleInputSource = is;
\r
10481 is->kind = cp->kind;
\r
10483 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10484 we create all threads suspended so that the is->hThread variable can be
\r
10485 safely assigned, then let the threads start with ResumeThread.
\r
10487 switch (cp->kind) {
\r
10489 is->hFile = cp->hFrom;
\r
10490 cp->hFrom = NULL; /* now owned by InputThread */
\r
10492 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10493 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10497 is->hFile = cp->hFrom;
\r
10498 cp->hFrom = NULL; /* now owned by InputThread */
\r
10500 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10501 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10505 is->sock = cp->sock;
\r
10507 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10508 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10512 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10514 is->sock = cp->sock;
\r
10515 is->second = is2;
\r
10516 is2->sock = cp->sock2;
\r
10517 is2->second = is2;
\r
10519 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10520 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10522 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10523 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10527 if( is->hThread != NULL ) {
\r
10528 ResumeThread( is->hThread );
\r
10531 if( is2 != NULL && is2->hThread != NULL ) {
\r
10532 ResumeThread( is2->hThread );
\r
10536 return (InputSourceRef) is;
\r
10540 RemoveInputSource(InputSourceRef isr)
\r
10544 is = (InputSource *) isr;
\r
10545 is->hThread = NULL; /* tell thread to stop */
\r
10546 CloseHandle(is->hThread);
\r
10547 if (is->second != NULL) {
\r
10548 is->second->hThread = NULL;
\r
10549 CloseHandle(is->second->hThread);
\r
10555 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10558 int outCount = SOCKET_ERROR;
\r
10559 ChildProc *cp = (ChildProc *) pr;
\r
10560 static OVERLAPPED ovl;
\r
10562 if (pr == NoProc) {
\r
10563 ConsoleOutput(message, count, FALSE);
\r
10567 if (ovl.hEvent == NULL) {
\r
10568 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10570 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10572 switch (cp->kind) {
\r
10575 outCount = send(cp->sock, message, count, 0);
\r
10576 if (outCount == SOCKET_ERROR) {
\r
10577 *outError = WSAGetLastError();
\r
10579 *outError = NO_ERROR;
\r
10584 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10585 &dOutCount, NULL)) {
\r
10586 *outError = NO_ERROR;
\r
10587 outCount = (int) dOutCount;
\r
10589 *outError = GetLastError();
\r
10594 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10595 &dOutCount, &ovl);
\r
10596 if (*outError == NO_ERROR) {
\r
10597 outCount = (int) dOutCount;
\r
10605 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10608 /* Ignore delay, not implemented for WinBoard */
\r
10609 return OutputToProcess(pr, message, count, outError);
\r
10614 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10615 char *buf, int count, int error)
\r
10617 DisplayFatalError("Not implemented", 0, 1);
\r
10620 /* see wgamelist.c for Game List functions */
\r
10621 /* see wedittags.c for Edit Tags functions */
\r
10628 char buf[MSG_SIZ];
\r
10631 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10632 f = fopen(buf, "r");
\r
10634 ProcessICSInitScript(f);
\r
10642 StartAnalysisClock()
\r
10644 if (analysisTimerEvent) return;
\r
10645 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10646 (UINT) 2000, NULL);
\r
10650 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10652 static HANDLE hwndText;
\r
10654 static int sizeX, sizeY;
\r
10655 int newSizeX, newSizeY, flags;
\r
10658 switch (message) {
\r
10659 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10660 /* Initialize the dialog items */
\r
10661 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10662 SetWindowText(hDlg, analysisTitle);
\r
10663 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10664 /* Size and position the dialog */
\r
10665 if (!analysisDialog) {
\r
10666 analysisDialog = hDlg;
\r
10667 flags = SWP_NOZORDER;
\r
10668 GetClientRect(hDlg, &rect);
\r
10669 sizeX = rect.right;
\r
10670 sizeY = rect.bottom;
\r
10671 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10672 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10673 WINDOWPLACEMENT wp;
\r
10674 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10675 wp.length = sizeof(WINDOWPLACEMENT);
\r
10677 wp.showCmd = SW_SHOW;
\r
10678 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10679 wp.rcNormalPosition.left = analysisX;
\r
10680 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10681 wp.rcNormalPosition.top = analysisY;
\r
10682 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10683 SetWindowPlacement(hDlg, &wp);
\r
10685 GetClientRect(hDlg, &rect);
\r
10686 newSizeX = rect.right;
\r
10687 newSizeY = rect.bottom;
\r
10688 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10689 newSizeX, newSizeY);
\r
10690 sizeX = newSizeX;
\r
10691 sizeY = newSizeY;
\r
10696 case WM_COMMAND: /* message: received a command */
\r
10697 switch (LOWORD(wParam)) {
\r
10699 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10700 ExitAnalyzeMode();
\r
10712 newSizeX = LOWORD(lParam);
\r
10713 newSizeY = HIWORD(lParam);
\r
10714 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10715 sizeX = newSizeX;
\r
10716 sizeY = newSizeY;
\r
10719 case WM_GETMINMAXINFO:
\r
10720 /* Prevent resizing window too small */
\r
10721 mmi = (MINMAXINFO *) lParam;
\r
10722 mmi->ptMinTrackSize.x = 100;
\r
10723 mmi->ptMinTrackSize.y = 100;
\r
10730 AnalysisPopUp(char* title, char* str)
\r
10736 EngineOutputPopUp();
\r
10739 if (str == NULL) str = "";
\r
10740 p = (char *) malloc(2 * strlen(str) + 2);
\r
10743 if (*str == '\n') *q++ = '\r';
\r
10747 if (analysisText != NULL) free(analysisText);
\r
10748 analysisText = p;
\r
10750 if (analysisDialog) {
\r
10751 SetWindowText(analysisDialog, title);
\r
10752 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10753 ShowWindow(analysisDialog, SW_SHOW);
\r
10755 analysisTitle = title;
\r
10756 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10757 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10758 hwndMain, (DLGPROC)lpProc);
\r
10759 FreeProcInstance(lpProc);
\r
10761 analysisDialogUp = TRUE;
\r
10765 AnalysisPopDown()
\r
10767 if (analysisDialog) {
\r
10768 ShowWindow(analysisDialog, SW_HIDE);
\r
10770 analysisDialogUp = FALSE;
\r
10775 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10777 highlightInfo.sq[0].x = fromX;
\r
10778 highlightInfo.sq[0].y = fromY;
\r
10779 highlightInfo.sq[1].x = toX;
\r
10780 highlightInfo.sq[1].y = toY;
\r
10784 ClearHighlights()
\r
10786 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10787 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10791 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10793 premoveHighlightInfo.sq[0].x = fromX;
\r
10794 premoveHighlightInfo.sq[0].y = fromY;
\r
10795 premoveHighlightInfo.sq[1].x = toX;
\r
10796 premoveHighlightInfo.sq[1].y = toY;
\r
10800 ClearPremoveHighlights()
\r
10802 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10803 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10807 ShutDownFrontEnd()
\r
10809 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10810 DeleteClipboardTempFiles();
\r
10816 if (IsIconic(hwndMain))
\r
10817 ShowWindow(hwndMain, SW_RESTORE);
\r
10819 SetActiveWindow(hwndMain);
\r
10823 * Prototypes for animation support routines
\r
10825 static void ScreenSquare(int column, int row, POINT * pt);
\r
10826 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10827 POINT frames[], int * nFrames);
\r
10831 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10832 { // [HGM] atomic: animate blast wave
\r
10834 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10835 explodeInfo.fromX = fromX;
\r
10836 explodeInfo.fromY = fromY;
\r
10837 explodeInfo.toX = toX;
\r
10838 explodeInfo.toY = toY;
\r
10839 for(i=1; i<nFrames; i++) {
\r
10840 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10841 DrawPosition(FALSE, NULL);
\r
10842 Sleep(appData.animSpeed);
\r
10844 explodeInfo.radius = 0;
\r
10845 DrawPosition(TRUE, NULL);
\r
10848 #define kFactor 4
\r
10851 AnimateMove(board, fromX, fromY, toX, toY)
\r
10858 ChessSquare piece;
\r
10859 POINT start, finish, mid;
\r
10860 POINT frames[kFactor * 2 + 1];
\r
10863 if (!appData.animate) return;
\r
10864 if (doingSizing) return;
\r
10865 if (fromY < 0 || fromX < 0) return;
\r
10866 piece = board[fromY][fromX];
\r
10867 if (piece >= EmptySquare) return;
\r
10869 ScreenSquare(fromX, fromY, &start);
\r
10870 ScreenSquare(toX, toY, &finish);
\r
10872 /* All pieces except knights move in straight line */
\r
10873 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10874 mid.x = start.x + (finish.x - start.x) / 2;
\r
10875 mid.y = start.y + (finish.y - start.y) / 2;
\r
10877 /* Knight: make diagonal movement then straight */
\r
10878 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10879 mid.x = start.x + (finish.x - start.x) / 2;
\r
10880 mid.y = finish.y;
\r
10882 mid.x = finish.x;
\r
10883 mid.y = start.y + (finish.y - start.y) / 2;
\r
10887 /* Don't use as many frames for very short moves */
\r
10888 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10889 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10891 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10893 animInfo.from.x = fromX;
\r
10894 animInfo.from.y = fromY;
\r
10895 animInfo.to.x = toX;
\r
10896 animInfo.to.y = toY;
\r
10897 animInfo.lastpos = start;
\r
10898 animInfo.piece = piece;
\r
10899 for (n = 0; n < nFrames; n++) {
\r
10900 animInfo.pos = frames[n];
\r
10901 DrawPosition(FALSE, NULL);
\r
10902 animInfo.lastpos = animInfo.pos;
\r
10903 Sleep(appData.animSpeed);
\r
10905 animInfo.pos = finish;
\r
10906 DrawPosition(FALSE, NULL);
\r
10907 animInfo.piece = EmptySquare;
\r
10908 if(gameInfo.variant == VariantAtomic &&
\r
10909 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10910 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10913 /* Convert board position to corner of screen rect and color */
\r
10916 ScreenSquare(column, row, pt)
\r
10917 int column; int row; POINT * pt;
\r
10920 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10921 pt->y = lineGap + row * (squareSize + lineGap);
\r
10923 pt->x = lineGap + column * (squareSize + lineGap);
\r
10924 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10928 /* Generate a series of frame coords from start->mid->finish.
\r
10929 The movement rate doubles until the half way point is
\r
10930 reached, then halves back down to the final destination,
\r
10931 which gives a nice slow in/out effect. The algorithmn
\r
10932 may seem to generate too many intermediates for short
\r
10933 moves, but remember that the purpose is to attract the
\r
10934 viewers attention to the piece about to be moved and
\r
10935 then to where it ends up. Too few frames would be less
\r
10939 Tween(start, mid, finish, factor, frames, nFrames)
\r
10940 POINT * start; POINT * mid;
\r
10941 POINT * finish; int factor;
\r
10942 POINT frames[]; int * nFrames;
\r
10944 int n, fraction = 1, count = 0;
\r
10946 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10947 for (n = 0; n < factor; n++)
\r
10949 for (n = 0; n < factor; n++) {
\r
10950 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10951 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10953 fraction = fraction / 2;
\r
10957 frames[count] = *mid;
\r
10960 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10962 for (n = 0; n < factor; n++) {
\r
10963 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10964 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10966 fraction = fraction * 2;
\r
10968 *nFrames = count;
\r
10972 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10977 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10978 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10980 OutputDebugString( buf );
\r
10983 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10985 EvalGraphSet( first, last, current, pvInfoList );
\r
10988 void SetProgramStats( FrontEndProgramStats * stats )
\r
10993 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10994 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10996 OutputDebugString( buf );
\r
10999 EngineOutputUpdate( stats );
\r