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 EngineOptionsPopup(); // [HGM] settings
\r
454 VOID GothicPopUp(char *title, VariantClass variant);
\r
456 * Setting "frozen" should disable all user input other than deleting
\r
457 * the window. We do this while engines are initializing themselves.
\r
459 static int frozen = 0;
\r
460 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
466 if (frozen) return;
\r
468 hmenu = GetMenu(hwndMain);
\r
469 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
470 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
472 DrawMenuBar(hwndMain);
\r
475 /* Undo a FreezeUI */
\r
481 if (!frozen) return;
\r
483 hmenu = GetMenu(hwndMain);
\r
484 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
485 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
487 DrawMenuBar(hwndMain);
\r
490 static int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
492 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
497 #define JAWS_ALT_INTERCEPT
\r
498 #define JAWS_KB_NAVIGATION
\r
499 #define JAWS_MENU_ITEMS
\r
500 #define JAWS_SILENCE
\r
501 #define JAWS_REPLAY
\r
503 #define JAWS_COPYRIGHT
\r
504 #define JAWS_DELETE(X) X
\r
505 #define SAYMACHINEMOVE()
\r
509 /*---------------------------------------------------------------------------*\
\r
513 \*---------------------------------------------------------------------------*/
\r
516 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
517 LPSTR lpCmdLine, int nCmdShow)
\r
520 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
521 // INITCOMMONCONTROLSEX ex;
\r
525 LoadLibrary("RICHED32.DLL");
\r
526 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
528 if (!InitApplication(hInstance)) {
\r
531 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
537 // InitCommonControlsEx(&ex);
\r
538 InitCommonControls();
\r
540 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
541 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
542 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
544 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
546 while (GetMessage(&msg, /* message structure */
\r
547 NULL, /* handle of window receiving the message */
\r
548 0, /* lowest message to examine */
\r
549 0)) /* highest message to examine */
\r
552 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
553 // [HGM] navigate: switch between all windows with tab
\r
554 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
555 int i, currentElement = 0;
\r
557 // first determine what element of the chain we come from (if any)
\r
558 if(appData.icsActive) {
\r
559 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
560 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
562 if(engineOutputDialog && EngineOutputIsUp()) {
\r
563 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
564 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
566 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
567 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
569 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
570 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
571 if(msg.hwnd == e1) currentElement = 2; else
\r
572 if(msg.hwnd == e2) currentElement = 3; else
\r
573 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
574 if(msg.hwnd == mh) currentElement = 4; else
\r
575 if(msg.hwnd == evalGraphDialog) currentElement = 7; else
\r
576 if(msg.hwnd == hText) currentElement = 5; else
\r
577 if(msg.hwnd == hInput) currentElement = 6; else
\r
578 for (i = 0; i < N_BUTTONS; i++) {
\r
579 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
582 // determine where to go to
\r
583 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
585 currentElement = (currentElement + direction) % 7;
\r
586 switch(currentElement) {
\r
588 h = hwndMain; break; // passing this case always makes the loop exit
\r
590 h = buttonDesc[0].hwnd; break; // could be NULL
\r
592 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
595 if(!EngineOutputIsUp()) continue;
\r
598 if(!MoveHistoryIsUp()) continue;
\r
600 // case 5: // input to eval graph does not seem to get here!
\r
601 // if(!EvalGraphIsUp()) continue;
\r
602 // h = evalGraphDialog; break;
\r
604 if(!appData.icsActive) continue;
\r
608 if(!appData.icsActive) continue;
\r
614 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
615 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
618 continue; // this message now has been processed
\r
622 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
623 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
624 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
625 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
626 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
627 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
628 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
629 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
630 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
631 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
632 TranslateMessage(&msg); /* Translates virtual key codes */
\r
633 DispatchMessage(&msg); /* Dispatches message to window */
\r
638 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
641 /*---------------------------------------------------------------------------*\
\r
643 * Initialization functions
\r
645 \*---------------------------------------------------------------------------*/
\r
649 { // update user logo if necessary
\r
650 static char oldUserName[MSG_SIZ], *curName;
\r
652 if(appData.autoLogo) {
\r
653 curName = UserName();
\r
654 if(strcmp(curName, oldUserName)) {
\r
655 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
656 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
657 strcpy(oldUserName, curName);
\r
663 InitApplication(HINSTANCE hInstance)
\r
667 /* Fill in window class structure with parameters that describe the */
\r
670 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
671 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
672 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
673 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
674 wc.hInstance = hInstance; /* Owner of this class */
\r
675 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
676 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
677 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
678 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
679 wc.lpszClassName = szAppName; /* Name to register as */
\r
681 /* Register the window class and return success/failure code. */
\r
682 if (!RegisterClass(&wc)) return FALSE;
\r
684 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
685 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
687 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
688 wc.hInstance = hInstance;
\r
689 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
690 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
691 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
692 wc.lpszMenuName = NULL;
\r
693 wc.lpszClassName = szConsoleName;
\r
695 if (!RegisterClass(&wc)) return FALSE;
\r
700 /* Set by InitInstance, used by EnsureOnScreen */
\r
701 int screenHeight, screenWidth;
\r
704 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
706 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
707 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
708 if (*x > screenWidth - 32) *x = 0;
\r
709 if (*y > screenHeight - 32) *y = 0;
\r
710 if (*x < minX) *x = minX;
\r
711 if (*y < minY) *y = minY;
\r
715 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
717 HWND hwnd; /* Main window handle. */
\r
719 WINDOWPLACEMENT wp;
\r
722 hInst = hInstance; /* Store instance handle in our global variable */
\r
724 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
725 *filepart = NULLCHAR;
\r
727 GetCurrentDirectory(MSG_SIZ, installDir);
\r
729 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
730 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
731 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
732 if (appData.debugMode) {
\r
733 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
734 setbuf(debugFP, NULL);
\r
739 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
740 // InitEngineUCI( installDir, &second );
\r
742 /* Create a main window for this application instance. */
\r
743 hwnd = CreateWindow(szAppName, szTitle,
\r
744 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
745 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
746 NULL, NULL, hInstance, NULL);
\r
749 /* If window could not be created, return "failure" */
\r
754 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
755 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
756 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
758 if (first.programLogo == NULL && appData.debugMode) {
\r
759 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
761 } else if(appData.autoLogo) {
\r
762 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
764 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
765 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
769 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
770 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
772 if (second.programLogo == NULL && appData.debugMode) {
\r
773 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
775 } else if(appData.autoLogo) {
\r
777 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
778 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
779 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
781 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
782 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
783 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
789 iconWhite = LoadIcon(hInstance, "icon_white");
\r
790 iconBlack = LoadIcon(hInstance, "icon_black");
\r
791 iconCurrent = iconWhite;
\r
792 InitDrawingColors();
\r
793 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
794 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
795 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
796 /* Compute window size for each board size, and use the largest
\r
797 size that fits on this screen as the default. */
\r
798 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
799 if (boardSize == (BoardSize)-1 &&
\r
800 winH <= screenHeight
\r
801 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
802 && winW <= screenWidth) {
\r
803 boardSize = (BoardSize)ibs;
\r
807 InitDrawingSizes(boardSize, 0);
\r
809 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
811 /* [AS] Load textures if specified */
\r
812 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
814 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
815 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
816 liteBackTextureMode = appData.liteBackTextureMode;
\r
818 if (liteBackTexture == NULL && appData.debugMode) {
\r
819 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
823 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
824 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
825 darkBackTextureMode = appData.darkBackTextureMode;
\r
827 if (darkBackTexture == NULL && appData.debugMode) {
\r
828 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
832 mysrandom( (unsigned) time(NULL) );
\r
834 /* [AS] Restore layout */
\r
835 if( wpMoveHistory.visible ) {
\r
836 MoveHistoryPopUp();
\r
839 if( wpEvalGraph.visible ) {
\r
843 if( wpEngineOutput.visible ) {
\r
844 EngineOutputPopUp();
\r
849 /* Make the window visible; update its client area; and return "success" */
\r
850 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
851 wp.length = sizeof(WINDOWPLACEMENT);
\r
853 wp.showCmd = nCmdShow;
\r
854 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
855 wp.rcNormalPosition.left = boardX;
\r
856 wp.rcNormalPosition.right = boardX + winWidth;
\r
857 wp.rcNormalPosition.top = boardY;
\r
858 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
859 SetWindowPlacement(hwndMain, &wp);
\r
861 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
862 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
866 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
867 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
869 ShowWindow(hwndConsole, nCmdShow);
\r
871 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
879 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
880 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
881 ArgSettingsFilename,
\r
882 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
890 String *pString; // ArgString
\r
891 int *pInt; // ArgInt
\r
892 float *pFloat; // ArgFloat
\r
893 Boolean *pBoolean; // ArgBoolean
\r
894 COLORREF *pColor; // ArgColor
\r
895 ColorClass cc; // ArgAttribs
\r
896 String *pFilename; // ArgFilename
\r
897 BoardSize *pBoardSize; // ArgBoardSize
\r
898 int whichFont; // ArgFont
\r
899 DCB *pDCB; // ArgCommSettings
\r
900 String *pFilename; // ArgSettingsFilename
\r
908 ArgDescriptor argDescriptors[] = {
\r
909 /* positional arguments */
\r
910 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
911 { "", ArgNone, NULL },
\r
912 /* keyword arguments */
\r
913 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
914 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
915 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
916 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
917 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
918 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
919 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
920 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
921 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
922 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
923 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
924 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
925 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
926 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
927 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
928 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
929 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
930 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
932 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
934 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
936 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
937 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
939 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
940 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
941 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
942 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
943 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
944 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
945 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
946 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
947 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
948 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
949 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
950 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
951 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
952 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
953 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
954 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
955 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
956 /*!!bitmapDirectory?*/
\r
957 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
958 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
959 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
960 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
961 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
962 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
963 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
964 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
965 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
966 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
967 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
968 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
969 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
970 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
971 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
972 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
973 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
974 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
975 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
976 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
977 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
978 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
979 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
980 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
981 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
982 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
983 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
984 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
985 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
986 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
987 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
988 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
989 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
990 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
991 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
992 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
993 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
994 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
995 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
996 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
997 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
998 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
999 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1000 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1001 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1002 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1003 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1004 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1005 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1006 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1007 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1008 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1009 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1010 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1011 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1012 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1013 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1014 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1015 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1016 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1017 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1018 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1019 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1020 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1021 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1022 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1023 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1024 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1025 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1026 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1027 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1028 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1029 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1030 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1031 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1032 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1033 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1034 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1035 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1036 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1037 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1038 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1039 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1040 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1041 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1042 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1043 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1044 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1045 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1046 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1047 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1048 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1049 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1050 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1051 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1052 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1053 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1054 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1055 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1056 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1057 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1058 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1059 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1060 TRUE }, /* must come after all fonts */
\r
1061 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1062 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1063 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1064 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1065 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1066 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1067 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1068 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1069 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1070 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1071 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1072 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1073 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1074 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1075 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1076 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1077 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1078 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1079 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1080 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1081 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1082 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1083 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1084 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1085 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1086 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1087 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1088 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1089 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1090 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1091 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1093 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1094 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1096 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1097 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1098 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1099 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1100 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1101 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1102 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1103 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1104 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1105 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1106 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1107 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1108 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1109 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1110 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1111 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1112 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1113 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1114 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1115 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1116 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1117 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1118 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1119 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1120 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1121 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1122 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1123 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1124 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1125 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1126 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1127 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1128 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1129 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1130 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1131 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1132 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1133 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1134 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1135 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1136 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1137 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1138 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1139 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1140 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1141 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1142 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1143 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1144 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1145 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1146 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1147 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1148 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1149 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1150 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1151 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1152 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1153 { "highlightLastMove", ArgBoolean,
\r
1154 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1155 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1156 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1157 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1158 { "highlightDragging", ArgBoolean,
\r
1159 (LPVOID) &appData.highlightDragging, TRUE },
\r
1160 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1161 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1162 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1163 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1164 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1165 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1166 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1167 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1168 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1169 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1170 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1171 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1172 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1173 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1174 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1175 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1176 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1177 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1178 { "soundShout", ArgFilename,
\r
1179 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1180 { "soundSShout", ArgFilename,
\r
1181 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1182 { "soundChannel1", ArgFilename,
\r
1183 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1184 { "soundChannel", ArgFilename,
\r
1185 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1186 { "soundKibitz", ArgFilename,
\r
1187 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1188 { "soundTell", ArgFilename,
\r
1189 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1190 { "soundChallenge", ArgFilename,
\r
1191 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1192 { "soundRequest", ArgFilename,
\r
1193 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1194 { "soundSeek", ArgFilename,
\r
1195 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1196 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1197 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1198 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1199 { "soundIcsLoss", ArgFilename,
\r
1200 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1201 { "soundIcsDraw", ArgFilename,
\r
1202 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1203 { "soundIcsUnfinished", ArgFilename,
\r
1204 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1205 { "soundIcsAlarm", ArgFilename,
\r
1206 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1207 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1208 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1209 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1210 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1211 { "reuseChessPrograms", ArgBoolean,
\r
1212 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1213 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1214 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1215 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1216 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1217 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1218 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1219 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1220 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1221 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1222 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1223 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1224 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1225 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1226 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1227 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1229 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1231 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1232 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1233 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1234 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1235 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1236 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1237 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1238 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1239 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1240 /* [AS] New features */
\r
1241 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1242 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1243 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1244 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1245 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1246 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1247 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1248 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1249 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1250 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1251 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1252 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1253 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1254 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1255 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1256 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1257 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1258 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1259 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1260 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1261 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1262 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1263 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1264 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1265 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1266 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1267 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1268 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1269 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1270 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1271 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1272 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1273 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1274 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1275 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1276 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1277 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1278 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1279 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1280 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1281 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1282 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1283 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1284 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1285 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1286 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1287 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1288 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1289 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1290 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1292 /* [HGM] board-size, adjudication and misc. options */
\r
1293 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1294 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1295 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1296 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1297 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1298 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1299 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1300 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1301 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1302 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1303 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1304 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1305 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1306 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1307 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1308 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1309 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1310 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1311 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1312 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1313 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1314 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1315 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1316 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1317 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1318 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1319 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1320 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1321 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1322 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1323 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1326 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1327 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1328 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1329 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1330 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1331 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1332 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1333 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1334 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1335 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1336 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1337 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1338 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1340 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1341 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1342 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1343 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1344 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1345 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1346 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1348 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1349 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1350 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1351 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1352 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1353 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1354 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1355 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1356 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1357 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1358 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1359 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1360 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1361 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1362 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1363 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1364 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1365 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1366 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1368 /* [HGM] options for broadcasting and time odds */
\r
1369 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1370 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1371 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1372 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1373 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1374 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1375 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1376 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1377 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1378 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1379 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1381 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1382 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1383 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1384 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1385 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1386 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1387 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1388 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1389 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1390 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1391 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1392 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1393 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1394 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1395 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1396 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1397 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1398 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1399 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1400 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1401 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1402 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1403 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1404 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1405 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1406 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1407 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1408 /* [AS] Layout stuff */
\r
1409 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1410 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1411 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1412 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1413 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1415 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1416 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1417 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1418 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1419 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1421 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1422 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1423 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1424 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1425 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1427 { NULL, ArgNone, NULL, FALSE }
\r
1431 /* Kludge for indirection files on command line */
\r
1432 char* lastIndirectionFilename;
\r
1433 ArgDescriptor argDescriptorIndirection =
\r
1434 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1438 ExitArgError(char *msg, char *badArg)
\r
1440 char buf[MSG_SIZ];
\r
1442 sprintf(buf, "%s %s", msg, badArg);
\r
1443 DisplayFatalError(buf, 0, 2);
\r
1447 /* Command line font name parser. NULL name means do nothing.
\r
1448 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1449 For backward compatibility, syntax without the colon is also
\r
1450 accepted, but font names with digits in them won't work in that case.
\r
1453 ParseFontName(char *name, MyFontParams *mfp)
\r
1456 if (name == NULL) return;
\r
1458 q = strchr(p, ':');
\r
1460 if (q - p >= sizeof(mfp->faceName))
\r
1461 ExitArgError("Font name too long:", name);
\r
1462 memcpy(mfp->faceName, p, q - p);
\r
1463 mfp->faceName[q - p] = NULLCHAR;
\r
1466 q = mfp->faceName;
\r
1467 while (*p && !isdigit(*p)) {
\r
1469 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1470 ExitArgError("Font name too long:", name);
\r
1472 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1475 if (!*p) ExitArgError("Font point size missing:", name);
\r
1476 mfp->pointSize = (float) atof(p);
\r
1477 mfp->bold = (strchr(p, 'b') != NULL);
\r
1478 mfp->italic = (strchr(p, 'i') != NULL);
\r
1479 mfp->underline = (strchr(p, 'u') != NULL);
\r
1480 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1483 /* Color name parser.
\r
1484 X version accepts X color names, but this one
\r
1485 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1487 ParseColorName(char *name)
\r
1489 int red, green, blue, count;
\r
1490 char buf[MSG_SIZ];
\r
1492 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1494 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1495 &red, &green, &blue);
\r
1498 sprintf(buf, "Can't parse color name %s", name);
\r
1499 DisplayError(buf, 0);
\r
1500 return RGB(0, 0, 0);
\r
1502 return PALETTERGB(red, green, blue);
\r
1506 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1508 char *e = argValue;
\r
1512 if (*e == 'b') eff |= CFE_BOLD;
\r
1513 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1514 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1515 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1516 else if (*e == '#' || isdigit(*e)) break;
\r
1520 *color = ParseColorName(e);
\r
1525 ParseBoardSize(char *name)
\r
1527 BoardSize bs = SizeTiny;
\r
1528 while (sizeInfo[bs].name != NULL) {
\r
1529 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1532 ExitArgError("Unrecognized board size value", name);
\r
1533 return bs; /* not reached */
\r
1538 StringGet(void *getClosure)
\r
1540 char **p = (char **) getClosure;
\r
1545 FileGet(void *getClosure)
\r
1548 FILE* f = (FILE*) getClosure;
\r
1551 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1558 /* Parse settings file named "name". If file found, return the
\r
1559 full name in fullname and return TRUE; else return FALSE */
\r
1561 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1565 int ok; char buf[MSG_SIZ];
\r
1567 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1568 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1569 sprintf(buf, "%s.ini", name);
\r
1570 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1573 f = fopen(fullname, "r");
\r
1575 ParseArgs(FileGet, f);
\r
1584 ParseArgs(GetFunc get, void *cl)
\r
1586 char argName[ARG_MAX];
\r
1587 char argValue[ARG_MAX];
\r
1588 ArgDescriptor *ad;
\r
1597 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1598 if (ch == NULLCHAR) break;
\r
1600 /* Comment to end of line */
\r
1602 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1604 } else if (ch == '/' || ch == '-') {
\r
1607 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1608 ch != '\n' && ch != '\t') {
\r
1614 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1615 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1617 if (ad->argName == NULL)
\r
1618 ExitArgError("Unrecognized argument", argName);
\r
1620 } else if (ch == '@') {
\r
1621 /* Indirection file */
\r
1622 ad = &argDescriptorIndirection;
\r
1625 /* Positional argument */
\r
1626 ad = &argDescriptors[posarg++];
\r
1627 strcpy(argName, ad->argName);
\r
1630 if (ad->argType == ArgTrue) {
\r
1631 *(Boolean *) ad->argLoc = TRUE;
\r
1634 if (ad->argType == ArgFalse) {
\r
1635 *(Boolean *) ad->argLoc = FALSE;
\r
1639 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1640 if (ch == NULLCHAR || ch == '\n') {
\r
1641 ExitArgError("No value provided for argument", argName);
\r
1645 // Quoting with { }. No characters have to (or can) be escaped.
\r
1646 // Thus the string cannot contain a '}' character.
\r
1666 } else if (ch == '\'' || ch == '"') {
\r
1667 // Quoting with ' ' or " ", with \ as escape character.
\r
1668 // Inconvenient for long strings that may contain Windows filenames.
\r
1685 if (ch == start) {
\r
1694 if (ad->argType == ArgFilename
\r
1695 || ad->argType == ArgSettingsFilename) {
\r
1701 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1725 for (i = 0; i < 3; i++) {
\r
1726 if (ch >= '0' && ch <= '7') {
\r
1727 octval = octval*8 + (ch - '0');
\r
1734 *q++ = (char) octval;
\r
1745 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1752 switch (ad->argType) {
\r
1754 *(int *) ad->argLoc = atoi(argValue);
\r
1758 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1762 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1766 *(int *) ad->argLoc = atoi(argValue);
\r
1767 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1771 *(float *) ad->argLoc = (float) atof(argValue);
\r
1776 *(char **) ad->argLoc = strdup(argValue);
\r
1779 case ArgSettingsFilename:
\r
1781 char fullname[MSG_SIZ];
\r
1782 if (ParseSettingsFile(argValue, fullname)) {
\r
1783 if (ad->argLoc != NULL) {
\r
1784 *(char **) ad->argLoc = strdup(fullname);
\r
1787 if (ad->argLoc != NULL) {
\r
1789 ExitArgError("Failed to open indirection file", argValue);
\r
1796 switch (argValue[0]) {
\r
1799 *(Boolean *) ad->argLoc = TRUE;
\r
1803 *(Boolean *) ad->argLoc = FALSE;
\r
1806 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1812 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1815 case ArgAttribs: {
\r
1816 ColorClass cc = (ColorClass)ad->argLoc;
\r
1817 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1821 case ArgBoardSize:
\r
1822 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1826 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1829 case ArgCommSettings:
\r
1830 ParseCommSettings(argValue, &dcb);
\r
1834 ExitArgError("Unrecognized argument", argValue);
\r
1843 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1845 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1846 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1849 lf->lfEscapement = 0;
\r
1850 lf->lfOrientation = 0;
\r
1851 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1852 lf->lfItalic = mfp->italic;
\r
1853 lf->lfUnderline = mfp->underline;
\r
1854 lf->lfStrikeOut = mfp->strikeout;
\r
1855 lf->lfCharSet = DEFAULT_CHARSET;
\r
1856 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1857 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1858 lf->lfQuality = DEFAULT_QUALITY;
\r
1859 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1860 strcpy(lf->lfFaceName, mfp->faceName);
\r
1864 CreateFontInMF(MyFont *mf)
\r
1866 LFfromMFP(&mf->lf, &mf->mfp);
\r
1867 if (mf->hf) DeleteObject(mf->hf);
\r
1868 mf->hf = CreateFontIndirect(&mf->lf);
\r
1872 SetDefaultTextAttribs()
\r
1875 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1876 ParseAttribs(&textAttribs[cc].color,
\r
1877 &textAttribs[cc].effects,
\r
1878 defaultTextAttribs[cc]);
\r
1883 SetDefaultSounds()
\r
1887 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1888 textAttribs[cc].sound.name = strdup("");
\r
1889 textAttribs[cc].sound.data = NULL;
\r
1891 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1892 sounds[sc].name = strdup("");
\r
1893 sounds[sc].data = NULL;
\r
1895 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1903 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1904 MyLoadSound(&textAttribs[cc].sound);
\r
1906 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1907 MyLoadSound(&sounds[sc]);
\r
1912 InitAppData(LPSTR lpCmdLine)
\r
1915 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1918 programName = szAppName;
\r
1920 /* Initialize to defaults */
\r
1921 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1922 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1923 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1924 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1925 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1926 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1927 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1928 SetDefaultTextAttribs();
\r
1929 SetDefaultSounds();
\r
1930 appData.movesPerSession = MOVES_PER_SESSION;
\r
1931 appData.initString = INIT_STRING;
\r
1932 appData.secondInitString = INIT_STRING;
\r
1933 appData.firstComputerString = COMPUTER_STRING;
\r
1934 appData.secondComputerString = COMPUTER_STRING;
\r
1935 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1936 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1937 appData.firstPlaysBlack = FALSE;
\r
1938 appData.noChessProgram = FALSE;
\r
1939 chessProgram = FALSE;
\r
1940 appData.firstHost = FIRST_HOST;
\r
1941 appData.secondHost = SECOND_HOST;
\r
1942 appData.firstDirectory = FIRST_DIRECTORY;
\r
1943 appData.secondDirectory = SECOND_DIRECTORY;
\r
1944 appData.bitmapDirectory = "";
\r
1945 appData.remoteShell = REMOTE_SHELL;
\r
1946 appData.remoteUser = "";
\r
1947 appData.timeDelay = TIME_DELAY;
\r
1948 appData.timeControl = TIME_CONTROL;
\r
1949 appData.timeIncrement = TIME_INCREMENT;
\r
1950 appData.icsActive = FALSE;
\r
1951 appData.icsHost = "";
\r
1952 appData.icsPort = ICS_PORT;
\r
1953 appData.icsCommPort = ICS_COMM_PORT;
\r
1954 appData.icsLogon = ICS_LOGON;
\r
1955 appData.icsHelper = "";
\r
1956 appData.useTelnet = FALSE;
\r
1957 appData.telnetProgram = TELNET_PROGRAM;
\r
1958 appData.gateway = "";
\r
1959 appData.loadGameFile = "";
\r
1960 appData.loadGameIndex = 0;
\r
1961 appData.saveGameFile = "";
\r
1962 appData.autoSaveGames = FALSE;
\r
1963 appData.loadPositionFile = "";
\r
1964 appData.loadPositionIndex = 1;
\r
1965 appData.savePositionFile = "";
\r
1966 appData.matchMode = FALSE;
\r
1967 appData.matchGames = 0;
\r
1968 appData.monoMode = FALSE;
\r
1969 appData.debugMode = FALSE;
\r
1970 appData.clockMode = TRUE;
\r
1971 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1972 appData.Iconic = FALSE; /*unused*/
\r
1973 appData.searchTime = "";
\r
1974 appData.searchDepth = 0;
\r
1975 appData.showCoords = FALSE;
\r
1976 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1977 appData.autoCallFlag = FALSE;
\r
1978 appData.flipView = FALSE;
\r
1979 appData.autoFlipView = TRUE;
\r
1980 appData.cmailGameName = "";
\r
1981 appData.alwaysPromoteToQueen = FALSE;
\r
1982 appData.oldSaveStyle = FALSE;
\r
1983 appData.quietPlay = FALSE;
\r
1984 appData.showThinking = FALSE;
\r
1985 appData.ponderNextMove = TRUE;
\r
1986 appData.periodicUpdates = TRUE;
\r
1987 appData.popupExitMessage = TRUE;
\r
1988 appData.popupMoveErrors = FALSE;
\r
1989 appData.autoObserve = FALSE;
\r
1990 appData.autoComment = FALSE;
\r
1991 appData.animate = TRUE;
\r
1992 appData.animSpeed = 10;
\r
1993 appData.animateDragging = TRUE;
\r
1994 appData.highlightLastMove = TRUE;
\r
1995 appData.getMoveList = TRUE;
\r
1996 appData.testLegality = TRUE;
\r
1997 appData.premove = TRUE;
\r
1998 appData.premoveWhite = FALSE;
\r
1999 appData.premoveWhiteText = "";
\r
2000 appData.premoveBlack = FALSE;
\r
2001 appData.premoveBlackText = "";
\r
2002 appData.icsAlarm = TRUE;
\r
2003 appData.icsAlarmTime = 5000;
\r
2004 appData.autoRaiseBoard = TRUE;
\r
2005 appData.localLineEditing = TRUE;
\r
2006 appData.colorize = TRUE;
\r
2007 appData.reuseFirst = TRUE;
\r
2008 appData.reuseSecond = TRUE;
\r
2009 appData.blindfold = FALSE;
\r
2010 appData.icsEngineAnalyze = FALSE;
\r
2011 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2012 dcb.DCBlength = sizeof(DCB);
\r
2013 dcb.BaudRate = 9600;
\r
2014 dcb.fBinary = TRUE;
\r
2015 dcb.fParity = FALSE;
\r
2016 dcb.fOutxCtsFlow = FALSE;
\r
2017 dcb.fOutxDsrFlow = FALSE;
\r
2018 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2019 dcb.fDsrSensitivity = FALSE;
\r
2020 dcb.fTXContinueOnXoff = TRUE;
\r
2021 dcb.fOutX = FALSE;
\r
2023 dcb.fNull = FALSE;
\r
2024 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2025 dcb.fAbortOnError = FALSE;
\r
2027 dcb.Parity = SPACEPARITY;
\r
2028 dcb.StopBits = ONESTOPBIT;
\r
2029 settingsFileName = SETTINGS_FILE;
\r
2030 saveSettingsOnExit = TRUE;
\r
2031 boardX = CW_USEDEFAULT;
\r
2032 boardY = CW_USEDEFAULT;
\r
2033 analysisX = CW_USEDEFAULT;
\r
2034 analysisY = CW_USEDEFAULT;
\r
2035 analysisW = CW_USEDEFAULT;
\r
2036 analysisH = CW_USEDEFAULT;
\r
2037 commentX = CW_USEDEFAULT;
\r
2038 commentY = CW_USEDEFAULT;
\r
2039 commentW = CW_USEDEFAULT;
\r
2040 commentH = CW_USEDEFAULT;
\r
2041 editTagsX = CW_USEDEFAULT;
\r
2042 editTagsY = CW_USEDEFAULT;
\r
2043 editTagsW = CW_USEDEFAULT;
\r
2044 editTagsH = CW_USEDEFAULT;
\r
2045 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2046 icsNames = ICS_NAMES;
\r
2047 firstChessProgramNames = FCP_NAMES;
\r
2048 secondChessProgramNames = SCP_NAMES;
\r
2049 appData.initialMode = "";
\r
2050 appData.variant = "normal";
\r
2051 appData.firstProtocolVersion = PROTOVER;
\r
2052 appData.secondProtocolVersion = PROTOVER;
\r
2053 appData.showButtonBar = TRUE;
\r
2055 /* [AS] New properties (see comments in header file) */
\r
2056 appData.firstScoreIsAbsolute = FALSE;
\r
2057 appData.secondScoreIsAbsolute = FALSE;
\r
2058 appData.saveExtendedInfoInPGN = FALSE;
\r
2059 appData.hideThinkingFromHuman = FALSE;
\r
2060 appData.liteBackTextureFile = "";
\r
2061 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2062 appData.darkBackTextureFile = "";
\r
2063 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2064 appData.renderPiecesWithFont = "";
\r
2065 appData.fontToPieceTable = "";
\r
2066 appData.fontBackColorWhite = 0;
\r
2067 appData.fontForeColorWhite = 0;
\r
2068 appData.fontBackColorBlack = 0;
\r
2069 appData.fontForeColorBlack = 0;
\r
2070 appData.fontPieceSize = 80;
\r
2071 appData.overrideLineGap = 1;
\r
2072 appData.adjudicateLossThreshold = 0;
\r
2073 appData.delayBeforeQuit = 0;
\r
2074 appData.delayAfterQuit = 0;
\r
2075 appData.nameOfDebugFile = "winboard.debug";
\r
2076 appData.pgnEventHeader = "Computer Chess Game";
\r
2077 appData.defaultFrcPosition = -1;
\r
2078 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2079 appData.saveOutOfBookInfo = TRUE;
\r
2080 appData.showEvalInMoveHistory = TRUE;
\r
2081 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2082 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2083 appData.highlightMoveWithArrow = FALSE;
\r
2084 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2085 appData.useStickyWindows = TRUE;
\r
2086 appData.adjudicateDrawMoves = 0;
\r
2087 appData.autoDisplayComment = TRUE;
\r
2088 appData.autoDisplayTags = TRUE;
\r
2089 appData.firstIsUCI = FALSE;
\r
2090 appData.secondIsUCI = FALSE;
\r
2091 appData.firstHasOwnBookUCI = TRUE;
\r
2092 appData.secondHasOwnBookUCI = TRUE;
\r
2093 appData.polyglotDir = "";
\r
2094 appData.usePolyglotBook = FALSE;
\r
2095 appData.polyglotBook = "";
\r
2096 appData.defaultHashSize = 64;
\r
2097 appData.defaultCacheSizeEGTB = 4;
\r
2098 appData.defaultPathEGTB = "c:\\egtb";
\r
2099 appData.firstOptions = "";
\r
2100 appData.secondOptions = "";
\r
2102 InitWindowPlacement( &wpGameList );
\r
2103 InitWindowPlacement( &wpMoveHistory );
\r
2104 InitWindowPlacement( &wpEvalGraph );
\r
2105 InitWindowPlacement( &wpEngineOutput );
\r
2106 InitWindowPlacement( &wpConsole );
\r
2108 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2109 appData.NrFiles = -1;
\r
2110 appData.NrRanks = -1;
\r
2111 appData.holdingsSize = -1;
\r
2112 appData.testClaims = FALSE;
\r
2113 appData.checkMates = FALSE;
\r
2114 appData.materialDraws= FALSE;
\r
2115 appData.trivialDraws = FALSE;
\r
2116 appData.ruleMoves = 51;
\r
2117 appData.drawRepeats = 6;
\r
2118 appData.matchPause = 10000;
\r
2119 appData.alphaRank = FALSE;
\r
2120 appData.allWhite = FALSE;
\r
2121 appData.upsideDown = FALSE;
\r
2122 appData.serverPause = 15;
\r
2123 appData.serverMovesName = NULL;
\r
2124 appData.suppressLoadMoves = FALSE;
\r
2125 appData.firstTimeOdds = 1;
\r
2126 appData.secondTimeOdds = 1;
\r
2127 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2128 appData.secondAccumulateTC = 1;
\r
2129 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2130 appData.secondNPS = -1;
\r
2131 appData.engineComments = 1;
\r
2132 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2133 appData.egtFormats = "";
\r
2136 appData.zippyTalk = ZIPPY_TALK;
\r
2137 appData.zippyPlay = ZIPPY_PLAY;
\r
2138 appData.zippyLines = ZIPPY_LINES;
\r
2139 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2140 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2141 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2142 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2143 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2144 appData.zippyUseI = ZIPPY_USE_I;
\r
2145 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2146 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2147 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2148 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2149 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2150 appData.zippyAbort = ZIPPY_ABORT;
\r
2151 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2152 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2153 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2156 /* Point font array elements to structures and
\r
2157 parse default font names */
\r
2158 for (i=0; i<NUM_FONTS; i++) {
\r
2159 for (j=0; j<NUM_SIZES; j++) {
\r
2160 font[j][i] = &fontRec[j][i];
\r
2161 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2165 /* Parse default settings file if any */
\r
2166 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2167 settingsFileName = strdup(buf);
\r
2170 /* Parse command line */
\r
2171 ParseArgs(StringGet, &lpCmdLine);
\r
2173 /* [HGM] make sure board size is acceptable */
\r
2174 if(appData.NrFiles > BOARD_SIZE ||
\r
2175 appData.NrRanks > BOARD_SIZE )
\r
2176 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2178 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2179 * with options from the command line, we now make an even higher priority
\r
2180 * overrule by WB options attached to the engine command line. This so that
\r
2181 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2184 if(appData.firstChessProgram != NULL) {
\r
2185 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2186 static char *f = "first";
\r
2187 char buf[MSG_SIZ], *q = buf;
\r
2188 if(p != NULL) { // engine command line contains WinBoard options
\r
2189 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2190 ParseArgs(StringGet, &q);
\r
2191 p[-1] = 0; // cut them offengine command line
\r
2194 // now do same for second chess program
\r
2195 if(appData.secondChessProgram != NULL) {
\r
2196 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2197 static char *s = "second";
\r
2198 char buf[MSG_SIZ], *q = buf;
\r
2199 if(p != NULL) { // engine command line contains WinBoard options
\r
2200 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2201 ParseArgs(StringGet, &q);
\r
2202 p[-1] = 0; // cut them offengine command line
\r
2207 /* Propagate options that affect others */
\r
2208 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2209 if (appData.icsActive || appData.noChessProgram) {
\r
2210 chessProgram = FALSE; /* not local chess program mode */
\r
2213 /* Open startup dialog if needed */
\r
2214 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2215 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2216 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2217 *appData.secondChessProgram == NULLCHAR))) {
\r
2220 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2221 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2222 FreeProcInstance(lpProc);
\r
2225 /* Make sure save files land in the right (?) directory */
\r
2226 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2227 appData.saveGameFile = strdup(buf);
\r
2229 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2230 appData.savePositionFile = strdup(buf);
\r
2233 /* Finish initialization for fonts and sounds */
\r
2234 for (i=0; i<NUM_FONTS; i++) {
\r
2235 for (j=0; j<NUM_SIZES; j++) {
\r
2236 CreateFontInMF(font[j][i]);
\r
2239 /* xboard, and older WinBoards, controlled the move sound with the
\r
2240 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2241 always turn the option on (so that the backend will call us),
\r
2242 then let the user turn the sound off by setting it to silence if
\r
2243 desired. To accommodate old winboard.ini files saved by old
\r
2244 versions of WinBoard, we also turn off the sound if the option
\r
2245 was initially set to false. */
\r
2246 if (!appData.ringBellAfterMoves) {
\r
2247 sounds[(int)SoundMove].name = strdup("");
\r
2248 appData.ringBellAfterMoves = TRUE;
\r
2250 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2251 SetCurrentDirectory(installDir);
\r
2253 SetCurrentDirectory(currDir);
\r
2255 p = icsTextMenuString;
\r
2256 if (p[0] == '@') {
\r
2257 FILE* f = fopen(p + 1, "r");
\r
2259 DisplayFatalError(p + 1, errno, 2);
\r
2262 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2264 buf[i] = NULLCHAR;
\r
2267 ParseIcsTextMenu(strdup(p));
\r
2274 HMENU hmenu = GetMenu(hwndMain);
\r
2276 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2277 MF_BYCOMMAND|((appData.icsActive &&
\r
2278 *appData.icsCommPort != NULLCHAR) ?
\r
2279 MF_ENABLED : MF_GRAYED));
\r
2280 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2281 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2282 MF_CHECKED : MF_UNCHECKED));
\r
2287 SaveSettings(char* name)
\r
2290 ArgDescriptor *ad;
\r
2291 WINDOWPLACEMENT wp;
\r
2292 char dir[MSG_SIZ];
\r
2294 if (!hwndMain) return;
\r
2296 GetCurrentDirectory(MSG_SIZ, dir);
\r
2297 SetCurrentDirectory(installDir);
\r
2298 f = fopen(name, "w");
\r
2299 SetCurrentDirectory(dir);
\r
2301 DisplayError(name, errno);
\r
2304 fprintf(f, ";\n");
\r
2305 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2306 fprintf(f, ";\n");
\r
2307 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2308 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2309 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2310 fprintf(f, ";\n");
\r
2312 wp.length = sizeof(WINDOWPLACEMENT);
\r
2313 GetWindowPlacement(hwndMain, &wp);
\r
2314 boardX = wp.rcNormalPosition.left;
\r
2315 boardY = wp.rcNormalPosition.top;
\r
2317 if (hwndConsole) {
\r
2318 GetWindowPlacement(hwndConsole, &wp);
\r
2319 wpConsole.x = wp.rcNormalPosition.left;
\r
2320 wpConsole.y = wp.rcNormalPosition.top;
\r
2321 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2322 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2325 if (analysisDialog) {
\r
2326 GetWindowPlacement(analysisDialog, &wp);
\r
2327 analysisX = wp.rcNormalPosition.left;
\r
2328 analysisY = wp.rcNormalPosition.top;
\r
2329 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2330 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2333 if (commentDialog) {
\r
2334 GetWindowPlacement(commentDialog, &wp);
\r
2335 commentX = wp.rcNormalPosition.left;
\r
2336 commentY = wp.rcNormalPosition.top;
\r
2337 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2338 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2341 if (editTagsDialog) {
\r
2342 GetWindowPlacement(editTagsDialog, &wp);
\r
2343 editTagsX = wp.rcNormalPosition.left;
\r
2344 editTagsY = wp.rcNormalPosition.top;
\r
2345 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2346 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2349 if (gameListDialog) {
\r
2350 GetWindowPlacement(gameListDialog, &wp);
\r
2351 wpGameList.x = wp.rcNormalPosition.left;
\r
2352 wpGameList.y = wp.rcNormalPosition.top;
\r
2353 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2354 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2357 /* [AS] Move history */
\r
2358 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2360 if( moveHistoryDialog ) {
\r
2361 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2362 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2363 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2364 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2365 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2368 /* [AS] Eval graph */
\r
2369 wpEvalGraph.visible = EvalGraphIsUp();
\r
2371 if( evalGraphDialog ) {
\r
2372 GetWindowPlacement(evalGraphDialog, &wp);
\r
2373 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2374 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2375 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2376 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2379 /* [AS] Engine output */
\r
2380 wpEngineOutput.visible = EngineOutputIsUp();
\r
2382 if( engineOutputDialog ) {
\r
2383 GetWindowPlacement(engineOutputDialog, &wp);
\r
2384 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2385 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2386 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2387 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2390 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2391 if (!ad->save) continue;
\r
2392 switch (ad->argType) {
\r
2395 char *p = *(char **)ad->argLoc;
\r
2396 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2397 /* Quote multiline values or \-containing values
\r
2398 with { } if possible */
\r
2399 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2401 /* Else quote with " " */
\r
2402 fprintf(f, "/%s=\"", ad->argName);
\r
2404 if (*p == '\n') fprintf(f, "\n");
\r
2405 else if (*p == '\r') fprintf(f, "\\r");
\r
2406 else if (*p == '\t') fprintf(f, "\\t");
\r
2407 else if (*p == '\b') fprintf(f, "\\b");
\r
2408 else if (*p == '\f') fprintf(f, "\\f");
\r
2409 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2410 else if (*p == '\"') fprintf(f, "\\\"");
\r
2411 else if (*p == '\\') fprintf(f, "\\\\");
\r
2415 fprintf(f, "\"\n");
\r
2421 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2424 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2427 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2430 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2433 fprintf(f, "/%s=%s\n", ad->argName,
\r
2434 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2437 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2440 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2444 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2445 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2446 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2451 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2452 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2453 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2454 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2455 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2456 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2457 (ta->effects) ? " " : "",
\r
2458 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2462 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2463 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2465 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2468 case ArgBoardSize:
\r
2469 fprintf(f, "/%s=%s\n", ad->argName,
\r
2470 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2475 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2476 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2477 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2478 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2479 ad->argName, mfp->faceName, mfp->pointSize,
\r
2480 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2481 mfp->bold ? "b" : "",
\r
2482 mfp->italic ? "i" : "",
\r
2483 mfp->underline ? "u" : "",
\r
2484 mfp->strikeout ? "s" : "");
\r
2488 case ArgCommSettings:
\r
2489 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2491 case ArgSettingsFilename: ;
\r
2499 /*---------------------------------------------------------------------------*\
\r
2501 * GDI board drawing routines
\r
2503 \*---------------------------------------------------------------------------*/
\r
2505 /* [AS] Draw square using background texture */
\r
2506 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2511 return; /* Should never happen! */
\r
2514 SetGraphicsMode( dst, GM_ADVANCED );
\r
2521 /* X reflection */
\r
2526 x.eDx = (FLOAT) dw + dx - 1;
\r
2529 SetWorldTransform( dst, &x );
\r
2532 /* Y reflection */
\r
2538 x.eDy = (FLOAT) dh + dy - 1;
\r
2540 SetWorldTransform( dst, &x );
\r
2548 x.eDx = (FLOAT) dx;
\r
2549 x.eDy = (FLOAT) dy;
\r
2552 SetWorldTransform( dst, &x );
\r
2556 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2564 SetWorldTransform( dst, &x );
\r
2566 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2569 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2571 PM_WP = (int) WhitePawn,
\r
2572 PM_WN = (int) WhiteKnight,
\r
2573 PM_WB = (int) WhiteBishop,
\r
2574 PM_WR = (int) WhiteRook,
\r
2575 PM_WQ = (int) WhiteQueen,
\r
2576 PM_WF = (int) WhiteFerz,
\r
2577 PM_WW = (int) WhiteWazir,
\r
2578 PM_WE = (int) WhiteAlfil,
\r
2579 PM_WM = (int) WhiteMan,
\r
2580 PM_WO = (int) WhiteCannon,
\r
2581 PM_WU = (int) WhiteUnicorn,
\r
2582 PM_WH = (int) WhiteNightrider,
\r
2583 PM_WA = (int) WhiteAngel,
\r
2584 PM_WC = (int) WhiteMarshall,
\r
2585 PM_WAB = (int) WhiteCardinal,
\r
2586 PM_WD = (int) WhiteDragon,
\r
2587 PM_WL = (int) WhiteLance,
\r
2588 PM_WS = (int) WhiteCobra,
\r
2589 PM_WV = (int) WhiteFalcon,
\r
2590 PM_WSG = (int) WhiteSilver,
\r
2591 PM_WG = (int) WhiteGrasshopper,
\r
2592 PM_WK = (int) WhiteKing,
\r
2593 PM_BP = (int) BlackPawn,
\r
2594 PM_BN = (int) BlackKnight,
\r
2595 PM_BB = (int) BlackBishop,
\r
2596 PM_BR = (int) BlackRook,
\r
2597 PM_BQ = (int) BlackQueen,
\r
2598 PM_BF = (int) BlackFerz,
\r
2599 PM_BW = (int) BlackWazir,
\r
2600 PM_BE = (int) BlackAlfil,
\r
2601 PM_BM = (int) BlackMan,
\r
2602 PM_BO = (int) BlackCannon,
\r
2603 PM_BU = (int) BlackUnicorn,
\r
2604 PM_BH = (int) BlackNightrider,
\r
2605 PM_BA = (int) BlackAngel,
\r
2606 PM_BC = (int) BlackMarshall,
\r
2607 PM_BG = (int) BlackGrasshopper,
\r
2608 PM_BAB = (int) BlackCardinal,
\r
2609 PM_BD = (int) BlackDragon,
\r
2610 PM_BL = (int) BlackLance,
\r
2611 PM_BS = (int) BlackCobra,
\r
2612 PM_BV = (int) BlackFalcon,
\r
2613 PM_BSG = (int) BlackSilver,
\r
2614 PM_BK = (int) BlackKing
\r
2617 static HFONT hPieceFont = NULL;
\r
2618 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2619 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2620 static int fontBitmapSquareSize = 0;
\r
2621 static char pieceToFontChar[(int) EmptySquare] =
\r
2622 { 'p', 'n', 'b', 'r', 'q',
\r
2623 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2624 'k', 'o', 'm', 'v', 't', 'w',
\r
2625 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2628 extern BOOL SetCharTable( char *table, const char * map );
\r
2629 /* [HGM] moved to backend.c */
\r
2631 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2634 BYTE r1 = GetRValue( color );
\r
2635 BYTE g1 = GetGValue( color );
\r
2636 BYTE b1 = GetBValue( color );
\r
2642 /* Create a uniform background first */
\r
2643 hbrush = CreateSolidBrush( color );
\r
2644 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2645 FillRect( hdc, &rc, hbrush );
\r
2646 DeleteObject( hbrush );
\r
2649 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2650 int steps = squareSize / 2;
\r
2653 for( i=0; i<steps; i++ ) {
\r
2654 BYTE r = r1 - (r1-r2) * i / steps;
\r
2655 BYTE g = g1 - (g1-g2) * i / steps;
\r
2656 BYTE b = b1 - (b1-b2) * i / steps;
\r
2658 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2659 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2660 FillRect( hdc, &rc, hbrush );
\r
2661 DeleteObject(hbrush);
\r
2664 else if( mode == 2 ) {
\r
2665 /* Diagonal gradient, good more or less for every piece */
\r
2666 POINT triangle[3];
\r
2667 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2668 HBRUSH hbrush_old;
\r
2669 int steps = squareSize;
\r
2672 triangle[0].x = squareSize - steps;
\r
2673 triangle[0].y = squareSize;
\r
2674 triangle[1].x = squareSize;
\r
2675 triangle[1].y = squareSize;
\r
2676 triangle[2].x = squareSize;
\r
2677 triangle[2].y = squareSize - steps;
\r
2679 for( i=0; i<steps; i++ ) {
\r
2680 BYTE r = r1 - (r1-r2) * i / steps;
\r
2681 BYTE g = g1 - (g1-g2) * i / steps;
\r
2682 BYTE b = b1 - (b1-b2) * i / steps;
\r
2684 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2685 hbrush_old = SelectObject( hdc, hbrush );
\r
2686 Polygon( hdc, triangle, 3 );
\r
2687 SelectObject( hdc, hbrush_old );
\r
2688 DeleteObject(hbrush);
\r
2693 SelectObject( hdc, hpen );
\r
2698 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2699 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2700 piece: follow the steps as explained below.
\r
2702 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2706 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2710 int backColor = whitePieceColor;
\r
2711 int foreColor = blackPieceColor;
\r
2713 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2714 backColor = appData.fontBackColorWhite;
\r
2715 foreColor = appData.fontForeColorWhite;
\r
2717 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2718 backColor = appData.fontBackColorBlack;
\r
2719 foreColor = appData.fontForeColorBlack;
\r
2723 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2725 hbm_old = SelectObject( hdc, hbm );
\r
2729 rc.right = squareSize;
\r
2730 rc.bottom = squareSize;
\r
2732 /* Step 1: background is now black */
\r
2733 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2735 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2737 pt.x = (squareSize - sz.cx) / 2;
\r
2738 pt.y = (squareSize - sz.cy) / 2;
\r
2740 SetBkMode( hdc, TRANSPARENT );
\r
2741 SetTextColor( hdc, chroma );
\r
2742 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2743 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2745 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2746 /* Step 3: the area outside the piece is filled with white */
\r
2747 // FloodFill( hdc, 0, 0, chroma );
\r
2748 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2749 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2750 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2751 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2752 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2754 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2755 but if the start point is not inside the piece we're lost!
\r
2756 There should be a better way to do this... if we could create a region or path
\r
2757 from the fill operation we would be fine for example.
\r
2759 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2760 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2762 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2763 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2764 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2766 SelectObject( dc2, bm2 );
\r
2767 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2768 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2769 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2770 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2771 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2774 DeleteObject( bm2 );
\r
2777 SetTextColor( hdc, 0 );
\r
2779 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2780 draw the piece again in black for safety.
\r
2782 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2784 SelectObject( hdc, hbm_old );
\r
2786 if( hPieceMask[index] != NULL ) {
\r
2787 DeleteObject( hPieceMask[index] );
\r
2790 hPieceMask[index] = hbm;
\r
2793 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2795 SelectObject( hdc, hbm );
\r
2798 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2799 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2800 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2802 SelectObject( dc1, hPieceMask[index] );
\r
2803 SelectObject( dc2, bm2 );
\r
2804 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2805 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2808 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2809 the piece background and deletes (makes transparent) the rest.
\r
2810 Thanks to that mask, we are free to paint the background with the greates
\r
2811 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2812 We use this, to make gradients and give the pieces a "roundish" look.
\r
2814 SetPieceBackground( hdc, backColor, 2 );
\r
2815 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2819 DeleteObject( bm2 );
\r
2822 SetTextColor( hdc, foreColor );
\r
2823 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2825 SelectObject( hdc, hbm_old );
\r
2827 if( hPieceFace[index] != NULL ) {
\r
2828 DeleteObject( hPieceFace[index] );
\r
2831 hPieceFace[index] = hbm;
\r
2834 static int TranslatePieceToFontPiece( int piece )
\r
2864 case BlackMarshall:
\r
2868 case BlackNightrider:
\r
2874 case BlackUnicorn:
\r
2878 case BlackGrasshopper:
\r
2890 case BlackCardinal:
\r
2897 case WhiteMarshall:
\r
2901 case WhiteNightrider:
\r
2907 case WhiteUnicorn:
\r
2911 case WhiteGrasshopper:
\r
2923 case WhiteCardinal:
\r
2932 void CreatePiecesFromFont()
\r
2935 HDC hdc_window = NULL;
\r
2941 if( fontBitmapSquareSize < 0 ) {
\r
2942 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2946 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2947 fontBitmapSquareSize = -1;
\r
2951 if( fontBitmapSquareSize != squareSize ) {
\r
2952 hdc_window = GetDC( hwndMain );
\r
2953 hdc = CreateCompatibleDC( hdc_window );
\r
2955 if( hPieceFont != NULL ) {
\r
2956 DeleteObject( hPieceFont );
\r
2959 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2960 hPieceMask[i] = NULL;
\r
2961 hPieceFace[i] = NULL;
\r
2967 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2968 fontHeight = appData.fontPieceSize;
\r
2971 fontHeight = (fontHeight * squareSize) / 100;
\r
2973 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2975 lf.lfEscapement = 0;
\r
2976 lf.lfOrientation = 0;
\r
2977 lf.lfWeight = FW_NORMAL;
\r
2979 lf.lfUnderline = 0;
\r
2980 lf.lfStrikeOut = 0;
\r
2981 lf.lfCharSet = DEFAULT_CHARSET;
\r
2982 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2983 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2984 lf.lfQuality = PROOF_QUALITY;
\r
2985 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2986 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2987 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2989 hPieceFont = CreateFontIndirect( &lf );
\r
2991 if( hPieceFont == NULL ) {
\r
2992 fontBitmapSquareSize = -2;
\r
2995 /* Setup font-to-piece character table */
\r
2996 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2997 /* No (or wrong) global settings, try to detect the font */
\r
2998 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3000 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3002 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3003 /* DiagramTT* family */
\r
3004 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3006 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3007 /* Fairy symbols */
\r
3008 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3010 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3011 /* Good Companion (Some characters get warped as literal :-( */
\r
3012 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3013 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3014 SetCharTable(pieceToFontChar, s);
\r
3017 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3018 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3022 /* Create bitmaps */
\r
3023 hfont_old = SelectObject( hdc, hPieceFont );
\r
3025 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3026 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3027 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3028 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3029 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3030 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3031 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3032 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3033 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3034 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3035 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3036 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3038 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3039 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3040 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3042 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3043 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3048 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3050 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3051 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3055 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3056 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3063 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3064 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3065 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3066 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3067 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3068 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3069 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3071 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3072 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3073 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3075 SelectObject( hdc, hfont_old );
\r
3077 fontBitmapSquareSize = squareSize;
\r
3081 if( hdc != NULL ) {
\r
3085 if( hdc_window != NULL ) {
\r
3086 ReleaseDC( hwndMain, hdc_window );
\r
3091 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3095 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3096 if (gameInfo.event &&
\r
3097 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3098 strcmp(name, "k80s") == 0) {
\r
3099 strcpy(name, "tim");
\r
3101 return LoadBitmap(hinst, name);
\r
3105 /* Insert a color into the program's logical palette
\r
3106 structure. This code assumes the given color is
\r
3107 the result of the RGB or PALETTERGB macro, and it
\r
3108 knows how those macros work (which is documented).
\r
3111 InsertInPalette(COLORREF color)
\r
3113 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3115 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3116 DisplayFatalError("Too many colors", 0, 1);
\r
3117 pLogPal->palNumEntries--;
\r
3121 pe->peFlags = (char) 0;
\r
3122 pe->peRed = (char) (0xFF & color);
\r
3123 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3124 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3130 InitDrawingColors()
\r
3132 if (pLogPal == NULL) {
\r
3133 /* Allocate enough memory for a logical palette with
\r
3134 * PALETTESIZE entries and set the size and version fields
\r
3135 * of the logical palette structure.
\r
3137 pLogPal = (NPLOGPALETTE)
\r
3138 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3139 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3140 pLogPal->palVersion = 0x300;
\r
3142 pLogPal->palNumEntries = 0;
\r
3144 InsertInPalette(lightSquareColor);
\r
3145 InsertInPalette(darkSquareColor);
\r
3146 InsertInPalette(whitePieceColor);
\r
3147 InsertInPalette(blackPieceColor);
\r
3148 InsertInPalette(highlightSquareColor);
\r
3149 InsertInPalette(premoveHighlightColor);
\r
3151 /* create a logical color palette according the information
\r
3152 * in the LOGPALETTE structure.
\r
3154 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3156 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3157 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3158 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3159 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3160 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3161 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3162 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3163 /* [AS] Force rendering of the font-based pieces */
\r
3164 if( fontBitmapSquareSize > 0 ) {
\r
3165 fontBitmapSquareSize = 0;
\r
3171 BoardWidth(int boardSize, int n)
\r
3172 { /* [HGM] argument n added to allow different width and height */
\r
3173 int lineGap = sizeInfo[boardSize].lineGap;
\r
3175 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3176 lineGap = appData.overrideLineGap;
\r
3179 return (n + 1) * lineGap +
\r
3180 n * sizeInfo[boardSize].squareSize;
\r
3183 /* Respond to board resize by dragging edge */
\r
3185 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3187 BoardSize newSize = NUM_SIZES - 1;
\r
3188 static int recurse = 0;
\r
3189 if (IsIconic(hwndMain)) return;
\r
3190 if (recurse > 0) return;
\r
3192 while (newSize > 0) {
\r
3193 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3194 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3195 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3198 boardSize = newSize;
\r
3199 InitDrawingSizes(boardSize, flags);
\r
3206 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3208 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3209 ChessSquare piece;
\r
3210 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3212 SIZE clockSize, messageSize;
\r
3214 char buf[MSG_SIZ];
\r
3216 HMENU hmenu = GetMenu(hwndMain);
\r
3217 RECT crect, wrect, oldRect;
\r
3219 LOGBRUSH logbrush;
\r
3221 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3222 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3224 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3225 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3227 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3228 oldRect.top = boardY;
\r
3229 oldRect.right = boardX + winWidth;
\r
3230 oldRect.bottom = boardY + winHeight;
\r
3232 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3233 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3234 squareSize = sizeInfo[boardSize].squareSize;
\r
3235 lineGap = sizeInfo[boardSize].lineGap;
\r
3236 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3238 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3239 lineGap = appData.overrideLineGap;
\r
3242 if (tinyLayout != oldTinyLayout) {
\r
3243 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3245 style &= ~WS_SYSMENU;
\r
3246 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3247 "&Minimize\tCtrl+F4");
\r
3249 style |= WS_SYSMENU;
\r
3250 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3252 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3254 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3255 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3256 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3258 DrawMenuBar(hwndMain);
\r
3261 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3262 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3264 /* Get text area sizes */
\r
3265 hdc = GetDC(hwndMain);
\r
3266 if (appData.clockMode) {
\r
3267 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3269 sprintf(buf, "White");
\r
3271 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3272 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3273 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3274 str = "We only care about the height here";
\r
3275 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3276 SelectObject(hdc, oldFont);
\r
3277 ReleaseDC(hwndMain, hdc);
\r
3279 /* Compute where everything goes */
\r
3280 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3281 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3282 logoHeight = 2*clockSize.cy;
\r
3283 leftLogoRect.left = OUTER_MARGIN;
\r
3284 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3285 leftLogoRect.top = OUTER_MARGIN;
\r
3286 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3288 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3289 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3290 rightLogoRect.top = OUTER_MARGIN;
\r
3291 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3294 whiteRect.left = leftLogoRect.right;
\r
3295 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3296 whiteRect.top = OUTER_MARGIN;
\r
3297 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3299 blackRect.right = rightLogoRect.left;
\r
3300 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3301 blackRect.top = whiteRect.top;
\r
3302 blackRect.bottom = whiteRect.bottom;
\r
3304 whiteRect.left = OUTER_MARGIN;
\r
3305 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3306 whiteRect.top = OUTER_MARGIN;
\r
3307 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3309 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3310 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3311 blackRect.top = whiteRect.top;
\r
3312 blackRect.bottom = whiteRect.bottom;
\r
3315 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3316 if (appData.showButtonBar) {
\r
3317 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3318 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3320 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3322 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3323 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3325 boardRect.left = OUTER_MARGIN;
\r
3326 boardRect.right = boardRect.left + boardWidth;
\r
3327 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3328 boardRect.bottom = boardRect.top + boardHeight;
\r
3330 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3331 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3332 oldBoardSize = boardSize;
\r
3333 oldTinyLayout = tinyLayout;
\r
3334 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3335 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3336 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3337 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3338 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3339 winHeight = winH; // without disturbing window attachments
\r
3340 GetWindowRect(hwndMain, &wrect);
\r
3341 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3342 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3344 // [HGM] placement: let attached windows follow size change.
\r
3345 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3346 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3347 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3348 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3349 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3351 /* compensate if menu bar wrapped */
\r
3352 GetClientRect(hwndMain, &crect);
\r
3353 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3354 winHeight += offby;
\r
3356 case WMSZ_TOPLEFT:
\r
3357 SetWindowPos(hwndMain, NULL,
\r
3358 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3359 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3362 case WMSZ_TOPRIGHT:
\r
3364 SetWindowPos(hwndMain, NULL,
\r
3365 wrect.left, wrect.bottom - winHeight,
\r
3366 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3369 case WMSZ_BOTTOMLEFT:
\r
3371 SetWindowPos(hwndMain, NULL,
\r
3372 wrect.right - winWidth, wrect.top,
\r
3373 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3376 case WMSZ_BOTTOMRIGHT:
\r
3380 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3381 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3386 for (i = 0; i < N_BUTTONS; i++) {
\r
3387 if (buttonDesc[i].hwnd != NULL) {
\r
3388 DestroyWindow(buttonDesc[i].hwnd);
\r
3389 buttonDesc[i].hwnd = NULL;
\r
3391 if (appData.showButtonBar) {
\r
3392 buttonDesc[i].hwnd =
\r
3393 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3394 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3395 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3396 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3397 (HMENU) buttonDesc[i].id,
\r
3398 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3400 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3401 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3402 MAKELPARAM(FALSE, 0));
\r
3404 if (buttonDesc[i].id == IDM_Pause)
\r
3405 hwndPause = buttonDesc[i].hwnd;
\r
3406 buttonDesc[i].wndproc = (WNDPROC)
\r
3407 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3410 if (gridPen != NULL) DeleteObject(gridPen);
\r
3411 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3412 if (premovePen != NULL) DeleteObject(premovePen);
\r
3413 if (lineGap != 0) {
\r
3414 logbrush.lbStyle = BS_SOLID;
\r
3415 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3417 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3418 lineGap, &logbrush, 0, NULL);
\r
3419 logbrush.lbColor = highlightSquareColor;
\r
3421 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3422 lineGap, &logbrush, 0, NULL);
\r
3424 logbrush.lbColor = premoveHighlightColor;
\r
3426 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3427 lineGap, &logbrush, 0, NULL);
\r
3429 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3430 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3431 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3432 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3433 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3434 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3435 BOARD_WIDTH * (squareSize + lineGap);
\r
3436 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3438 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3439 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3440 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3441 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3442 lineGap / 2 + (i * (squareSize + lineGap));
\r
3443 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3444 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3445 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3449 /* [HGM] Licensing requirement */
\r
3451 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3454 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3456 GothicPopUp( "", VariantNormal);
\r
3459 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3461 /* Load piece bitmaps for this board size */
\r
3462 for (i=0; i<=2; i++) {
\r
3463 for (piece = WhitePawn;
\r
3464 (int) piece < (int) BlackPawn;
\r
3465 piece = (ChessSquare) ((int) piece + 1)) {
\r
3466 if (pieceBitmap[i][piece] != NULL)
\r
3467 DeleteObject(pieceBitmap[i][piece]);
\r
3471 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3472 // Orthodox Chess pieces
\r
3473 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3474 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3475 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3476 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3477 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3478 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3479 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3480 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3481 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3482 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3483 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3484 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3485 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3486 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3487 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3488 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3489 // in Shogi, Hijack the unused Queen for Lance
\r
3490 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3491 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3492 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3494 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3495 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3496 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3499 if(squareSize <= 72 && squareSize >= 33) {
\r
3500 /* A & C are available in most sizes now */
\r
3501 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3502 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3503 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3504 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3505 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3506 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3507 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3508 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3509 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3510 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3511 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3512 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3513 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3514 } else { // Smirf-like
\r
3515 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3516 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3517 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3519 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3520 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3521 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3522 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3523 } else { // WinBoard standard
\r
3524 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3525 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3526 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3531 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3532 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3533 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3534 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3535 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3536 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3537 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3538 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3539 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3540 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3541 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3542 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3543 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3544 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3545 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3546 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3547 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3548 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3549 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3550 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3551 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3552 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3553 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3554 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3555 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3556 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3557 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3558 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3559 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3560 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3561 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3563 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3564 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3565 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3566 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3567 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3568 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3569 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3570 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3571 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3572 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3573 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3574 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3575 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3577 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3578 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3579 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3580 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3581 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3582 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3583 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3584 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3585 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3586 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3587 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3588 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3591 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3592 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3593 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3594 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3595 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3596 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3597 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3598 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3599 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3600 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3601 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3602 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3603 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3604 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3605 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3609 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3610 /* special Shogi support in this size */
\r
3611 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3612 for (piece = WhitePawn;
\r
3613 (int) piece < (int) BlackPawn;
\r
3614 piece = (ChessSquare) ((int) piece + 1)) {
\r
3615 if (pieceBitmap[i][piece] != NULL)
\r
3616 DeleteObject(pieceBitmap[i][piece]);
\r
3619 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3620 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3621 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3622 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3623 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3624 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3625 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3626 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3627 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3628 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3629 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3630 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3631 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3632 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3633 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3634 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3635 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3636 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3637 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3638 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3639 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3640 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3641 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3642 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3643 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3644 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3645 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3646 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3647 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3648 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3649 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3650 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3651 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3652 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3653 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3654 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3655 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3656 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3657 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3658 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3659 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3660 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3666 PieceBitmap(ChessSquare p, int kind)
\r
3668 if ((int) p >= (int) BlackPawn)
\r
3669 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3671 return pieceBitmap[kind][(int) p];
\r
3674 /***************************************************************/
\r
3676 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3677 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3679 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3680 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3684 SquareToPos(int row, int column, int * x, int * y)
\r
3687 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3688 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3690 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3691 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3696 DrawCoordsOnDC(HDC hdc)
\r
3698 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
3699 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
3700 char str[2] = { NULLCHAR, NULLCHAR };
\r
3701 int oldMode, oldAlign, x, y, start, i;
\r
3705 if (!appData.showCoords)
\r
3708 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3710 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3711 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3712 oldAlign = GetTextAlign(hdc);
\r
3713 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3715 y = boardRect.top + lineGap;
\r
3716 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3718 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3719 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3720 str[0] = files[start + i];
\r
3721 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3722 y += squareSize + lineGap;
\r
3725 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3727 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3728 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3729 str[0] = ranks[start + i];
\r
3730 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3731 x += squareSize + lineGap;
\r
3734 SelectObject(hdc, oldBrush);
\r
3735 SetBkMode(hdc, oldMode);
\r
3736 SetTextAlign(hdc, oldAlign);
\r
3737 SelectObject(hdc, oldFont);
\r
3741 DrawGridOnDC(HDC hdc)
\r
3745 if (lineGap != 0) {
\r
3746 oldPen = SelectObject(hdc, gridPen);
\r
3747 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3748 SelectObject(hdc, oldPen);
\r
3752 #define HIGHLIGHT_PEN 0
\r
3753 #define PREMOVE_PEN 1
\r
3756 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3759 HPEN oldPen, hPen;
\r
3760 if (lineGap == 0) return;
\r
3762 x1 = boardRect.left +
\r
3763 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3764 y1 = boardRect.top +
\r
3765 lineGap/2 + y * (squareSize + lineGap);
\r
3767 x1 = boardRect.left +
\r
3768 lineGap/2 + x * (squareSize + lineGap);
\r
3769 y1 = boardRect.top +
\r
3770 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3772 hPen = pen ? premovePen : highlightPen;
\r
3773 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3774 MoveToEx(hdc, x1, y1, NULL);
\r
3775 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3776 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3777 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3778 LineTo(hdc, x1, y1);
\r
3779 SelectObject(hdc, oldPen);
\r
3783 DrawHighlightsOnDC(HDC hdc)
\r
3786 for (i=0; i<2; i++) {
\r
3787 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3788 DrawHighlightOnDC(hdc, TRUE,
\r
3789 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3792 for (i=0; i<2; i++) {
\r
3793 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3794 premoveHighlightInfo.sq[i].y >= 0) {
\r
3795 DrawHighlightOnDC(hdc, TRUE,
\r
3796 premoveHighlightInfo.sq[i].x,
\r
3797 premoveHighlightInfo.sq[i].y,
\r
3803 /* Note: sqcolor is used only in monoMode */
\r
3804 /* Note that this code is largely duplicated in woptions.c,
\r
3805 function DrawSampleSquare, so that needs to be updated too */
\r
3807 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3809 HBITMAP oldBitmap;
\r
3813 if (appData.blindfold) return;
\r
3815 /* [AS] Use font-based pieces if needed */
\r
3816 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3817 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3818 CreatePiecesFromFont();
\r
3820 if( fontBitmapSquareSize == squareSize ) {
\r
3821 int index = TranslatePieceToFontPiece(piece);
\r
3823 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3827 squareSize, squareSize,
\r
3832 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3836 squareSize, squareSize,
\r
3845 if (appData.monoMode) {
\r
3846 SelectObject(tmphdc, PieceBitmap(piece,
\r
3847 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3848 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3849 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3851 tmpSize = squareSize;
\r
3853 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3854 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3855 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3856 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3857 x += (squareSize - minorSize)>>1;
\r
3858 y += squareSize - minorSize - 2;
\r
3859 tmpSize = minorSize;
\r
3861 if (color || appData.allWhite ) {
\r
3862 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3864 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3865 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3866 if(appData.upsideDown && color==flipView)
\r
3867 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3869 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3871 /* Use black piece color for outline of white pieces */
\r
3872 /* Not sure this looks really good (though xboard does it).
\r
3873 Maybe better to have another selectable color, default black */
\r
3874 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3875 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3876 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3878 /* Use black for outline of white pieces */
\r
3879 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3880 if(appData.upsideDown && color==flipView)
\r
3881 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3883 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3887 /* Use white piece color for details of black pieces */
\r
3888 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3889 WHITE_PIECE ones aren't always the right shape. */
\r
3890 /* Not sure this looks really good (though xboard does it).
\r
3891 Maybe better to have another selectable color, default medium gray? */
\r
3892 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3893 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3894 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3895 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3896 SelectObject(hdc, blackPieceBrush);
\r
3897 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3899 /* Use square color for details of black pieces */
\r
3900 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3901 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3902 if(appData.upsideDown && !flipView)
\r
3903 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3905 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3908 SelectObject(hdc, oldBrush);
\r
3909 SelectObject(tmphdc, oldBitmap);
\r
3913 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3914 int GetBackTextureMode( int algo )
\r
3916 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3920 case BACK_TEXTURE_MODE_PLAIN:
\r
3921 result = 1; /* Always use identity map */
\r
3923 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3924 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3932 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3933 to handle redraws cleanly (as random numbers would always be different).
\r
3935 VOID RebuildTextureSquareInfo()
\r
3945 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3947 if( liteBackTexture != NULL ) {
\r
3948 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3949 lite_w = bi.bmWidth;
\r
3950 lite_h = bi.bmHeight;
\r
3954 if( darkBackTexture != NULL ) {
\r
3955 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3956 dark_w = bi.bmWidth;
\r
3957 dark_h = bi.bmHeight;
\r
3961 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3962 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3963 if( (col + row) & 1 ) {
\r
3965 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3966 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3967 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3968 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3973 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3974 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3975 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3976 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3983 /* [AS] Arrow highlighting support */
\r
3985 static int A_WIDTH = 5; /* Width of arrow body */
\r
3987 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3988 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3990 static double Sqr( double x )
\r
3995 static int Round( double x )
\r
3997 return (int) (x + 0.5);
\r
4000 /* Draw an arrow between two points using current settings */
\r
4001 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
4004 double dx, dy, j, k, x, y;
\r
4006 if( d_x == s_x ) {
\r
4007 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4009 arrow[0].x = s_x + A_WIDTH;
\r
4012 arrow[1].x = s_x + A_WIDTH;
\r
4013 arrow[1].y = d_y - h;
\r
4015 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4016 arrow[2].y = d_y - h;
\r
4021 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4022 arrow[4].y = d_y - h;
\r
4024 arrow[5].x = s_x - A_WIDTH;
\r
4025 arrow[5].y = d_y - h;
\r
4027 arrow[6].x = s_x - A_WIDTH;
\r
4030 else if( d_y == s_y ) {
\r
4031 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4034 arrow[0].y = s_y + A_WIDTH;
\r
4036 arrow[1].x = d_x - w;
\r
4037 arrow[1].y = s_y + A_WIDTH;
\r
4039 arrow[2].x = d_x - w;
\r
4040 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4045 arrow[4].x = d_x - w;
\r
4046 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4048 arrow[5].x = d_x - w;
\r
4049 arrow[5].y = s_y - A_WIDTH;
\r
4052 arrow[6].y = s_y - A_WIDTH;
\r
4055 /* [AS] Needed a lot of paper for this! :-) */
\r
4056 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4057 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4059 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4061 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4066 arrow[0].x = Round(x - j);
\r
4067 arrow[0].y = Round(y + j*dx);
\r
4069 arrow[1].x = Round(x + j);
\r
4070 arrow[1].y = Round(y - j*dx);
\r
4073 x = (double) d_x - k;
\r
4074 y = (double) d_y - k*dy;
\r
4077 x = (double) d_x + k;
\r
4078 y = (double) d_y + k*dy;
\r
4081 arrow[2].x = Round(x + j);
\r
4082 arrow[2].y = Round(y - j*dx);
\r
4084 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4085 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4090 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4091 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4093 arrow[6].x = Round(x - j);
\r
4094 arrow[6].y = Round(y + j*dx);
\r
4097 Polygon( hdc, arrow, 7 );
\r
4100 /* [AS] Draw an arrow between two squares */
\r
4101 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4103 int s_x, s_y, d_x, d_y;
\r
4110 if( s_col == d_col && s_row == d_row ) {
\r
4114 /* Get source and destination points */
\r
4115 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4116 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4119 d_y += squareSize / 4;
\r
4121 else if( d_y < s_y ) {
\r
4122 d_y += 3 * squareSize / 4;
\r
4125 d_y += squareSize / 2;
\r
4129 d_x += squareSize / 4;
\r
4131 else if( d_x < s_x ) {
\r
4132 d_x += 3 * squareSize / 4;
\r
4135 d_x += squareSize / 2;
\r
4138 s_x += squareSize / 2;
\r
4139 s_y += squareSize / 2;
\r
4141 /* Adjust width */
\r
4142 A_WIDTH = squareSize / 14;
\r
4145 stLB.lbStyle = BS_SOLID;
\r
4146 stLB.lbColor = appData.highlightArrowColor;
\r
4149 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4150 holdpen = SelectObject( hdc, hpen );
\r
4151 hbrush = CreateBrushIndirect( &stLB );
\r
4152 holdbrush = SelectObject( hdc, hbrush );
\r
4154 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4156 SelectObject( hdc, holdpen );
\r
4157 SelectObject( hdc, holdbrush );
\r
4158 DeleteObject( hpen );
\r
4159 DeleteObject( hbrush );
\r
4162 BOOL HasHighlightInfo()
\r
4164 BOOL result = FALSE;
\r
4166 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4167 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4175 BOOL IsDrawArrowEnabled()
\r
4177 BOOL result = FALSE;
\r
4179 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4186 VOID DrawArrowHighlight( HDC hdc )
\r
4188 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4189 DrawArrowBetweenSquares( hdc,
\r
4190 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4191 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4195 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4197 HRGN result = NULL;
\r
4199 if( HasHighlightInfo() ) {
\r
4200 int x1, y1, x2, y2;
\r
4201 int sx, sy, dx, dy;
\r
4203 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4204 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4206 sx = MIN( x1, x2 );
\r
4207 sy = MIN( y1, y2 );
\r
4208 dx = MAX( x1, x2 ) + squareSize;
\r
4209 dy = MAX( y1, y2 ) + squareSize;
\r
4211 result = CreateRectRgn( sx, sy, dx, dy );
\r
4218 Warning: this function modifies the behavior of several other functions.
\r
4220 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4221 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4222 repaint is scattered all over the place, which is not good for features such as
\r
4223 "arrow highlighting" that require a full repaint of the board.
\r
4225 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4226 user interaction, when speed is not so important) but especially to avoid errors
\r
4227 in the displayed graphics.
\r
4229 In such patched places, I always try refer to this function so there is a single
\r
4230 place to maintain knowledge.
\r
4232 To restore the original behavior, just return FALSE unconditionally.
\r
4234 BOOL IsFullRepaintPreferrable()
\r
4236 BOOL result = FALSE;
\r
4238 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4239 /* Arrow may appear on the board */
\r
4247 This function is called by DrawPosition to know whether a full repaint must
\r
4250 Only DrawPosition may directly call this function, which makes use of
\r
4251 some state information. Other function should call DrawPosition specifying
\r
4252 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4254 BOOL DrawPositionNeedsFullRepaint()
\r
4256 BOOL result = FALSE;
\r
4259 Probably a slightly better policy would be to trigger a full repaint
\r
4260 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4261 but animation is fast enough that it's difficult to notice.
\r
4263 if( animInfo.piece == EmptySquare ) {
\r
4264 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4273 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4275 int row, column, x, y, square_color, piece_color;
\r
4276 ChessSquare piece;
\r
4278 HDC texture_hdc = NULL;
\r
4280 /* [AS] Initialize background textures if needed */
\r
4281 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4282 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4283 if( backTextureSquareSize != squareSize
\r
4284 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4285 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4286 backTextureSquareSize = squareSize;
\r
4287 RebuildTextureSquareInfo();
\r
4290 texture_hdc = CreateCompatibleDC( hdc );
\r
4293 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4294 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4296 SquareToPos(row, column, &x, &y);
\r
4298 piece = board[row][column];
\r
4300 square_color = ((column + row) % 2) == 1;
\r
4301 if( gameInfo.variant == VariantXiangqi ) {
\r
4302 square_color = !InPalace(row, column);
\r
4303 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4304 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4306 piece_color = (int) piece < (int) BlackPawn;
\r
4309 /* [HGM] holdings file: light square or black */
\r
4310 if(column == BOARD_LEFT-2) {
\r
4311 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4314 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4318 if(column == BOARD_RGHT + 1 ) {
\r
4319 if( row < gameInfo.holdingsSize )
\r
4322 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4326 if(column == BOARD_LEFT-1 ) /* left align */
\r
4327 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4328 else if( column == BOARD_RGHT) /* right align */
\r
4329 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4331 if (appData.monoMode) {
\r
4332 if (piece == EmptySquare) {
\r
4333 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4334 square_color ? WHITENESS : BLACKNESS);
\r
4336 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4339 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4340 /* [AS] Draw the square using a texture bitmap */
\r
4341 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4342 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4343 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4346 squareSize, squareSize,
\r
4349 backTextureSquareInfo[r][c].mode,
\r
4350 backTextureSquareInfo[r][c].x,
\r
4351 backTextureSquareInfo[r][c].y );
\r
4353 SelectObject( texture_hdc, hbm );
\r
4355 if (piece != EmptySquare) {
\r
4356 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4360 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4362 oldBrush = SelectObject(hdc, brush );
\r
4363 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4364 SelectObject(hdc, oldBrush);
\r
4365 if (piece != EmptySquare)
\r
4366 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4371 if( texture_hdc != NULL ) {
\r
4372 DeleteDC( texture_hdc );
\r
4376 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4377 void fputDW(FILE *f, int x)
\r
4379 fputc(x & 255, f);
\r
4380 fputc(x>>8 & 255, f);
\r
4381 fputc(x>>16 & 255, f);
\r
4382 fputc(x>>24 & 255, f);
\r
4385 #define MAX_CLIPS 200 /* more than enough */
\r
4388 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4390 // HBITMAP bufferBitmap;
\r
4395 int w = 100, h = 50;
\r
4397 if(logo == NULL) return;
\r
4398 // GetClientRect(hwndMain, &Rect);
\r
4399 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4400 // Rect.bottom-Rect.top+1);
\r
4401 tmphdc = CreateCompatibleDC(hdc);
\r
4402 hbm = SelectObject(tmphdc, logo);
\r
4403 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4407 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4408 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4409 SelectObject(tmphdc, hbm);
\r
4414 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4416 static Board lastReq, lastDrawn;
\r
4417 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4418 static int lastDrawnFlipView = 0;
\r
4419 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4420 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4423 HBITMAP bufferBitmap;
\r
4424 HBITMAP oldBitmap;
\r
4426 HRGN clips[MAX_CLIPS];
\r
4427 ChessSquare dragged_piece = EmptySquare;
\r
4429 /* I'm undecided on this - this function figures out whether a full
\r
4430 * repaint is necessary on its own, so there's no real reason to have the
\r
4431 * caller tell it that. I think this can safely be set to FALSE - but
\r
4432 * if we trust the callers not to request full repaints unnessesarily, then
\r
4433 * we could skip some clipping work. In other words, only request a full
\r
4434 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4435 * gamestart and similar) --Hawk
\r
4437 Boolean fullrepaint = repaint;
\r
4439 if( DrawPositionNeedsFullRepaint() ) {
\r
4440 fullrepaint = TRUE;
\r
4444 if( fullrepaint ) {
\r
4445 static int repaint_count = 0;
\r
4449 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4450 OutputDebugString( buf );
\r
4454 if (board == NULL) {
\r
4455 if (!lastReqValid) {
\r
4460 CopyBoard(lastReq, board);
\r
4464 if (doingSizing) {
\r
4468 if (IsIconic(hwndMain)) {
\r
4472 if (hdc == NULL) {
\r
4473 hdc = GetDC(hwndMain);
\r
4474 if (!appData.monoMode) {
\r
4475 SelectPalette(hdc, hPal, FALSE);
\r
4476 RealizePalette(hdc);
\r
4480 releaseDC = FALSE;
\r
4484 fprintf(debugFP, "*******************************\n"
\r
4486 "dragInfo.from (%d,%d)\n"
\r
4487 "dragInfo.start (%d,%d)\n"
\r
4488 "dragInfo.pos (%d,%d)\n"
\r
4489 "dragInfo.lastpos (%d,%d)\n",
\r
4490 repaint ? "TRUE" : "FALSE",
\r
4491 dragInfo.from.x, dragInfo.from.y,
\r
4492 dragInfo.start.x, dragInfo.start.y,
\r
4493 dragInfo.pos.x, dragInfo.pos.y,
\r
4494 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4495 fprintf(debugFP, "prev: ");
\r
4496 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4497 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4498 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4501 fprintf(debugFP, "\n");
\r
4502 fprintf(debugFP, "board: ");
\r
4503 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4504 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4505 fprintf(debugFP, "%d ", board[row][column]);
\r
4508 fprintf(debugFP, "\n");
\r
4512 /* Create some work-DCs */
\r
4513 hdcmem = CreateCompatibleDC(hdc);
\r
4514 tmphdc = CreateCompatibleDC(hdc);
\r
4516 /* If dragging is in progress, we temporarely remove the piece */
\r
4517 /* [HGM] or temporarily decrease count if stacked */
\r
4518 /* !! Moved to before board compare !! */
\r
4519 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4520 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4521 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4522 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4523 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4525 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4526 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4527 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4529 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4532 /* Figure out which squares need updating by comparing the
\r
4533 * newest board with the last drawn board and checking if
\r
4534 * flipping has changed.
\r
4536 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4537 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4538 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4539 if (lastDrawn[row][column] != board[row][column]) {
\r
4540 SquareToPos(row, column, &x, &y);
\r
4541 clips[num_clips++] =
\r
4542 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4546 for (i=0; i<2; i++) {
\r
4547 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4548 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4549 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4550 lastDrawnHighlight.sq[i].y >= 0) {
\r
4551 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4552 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4553 clips[num_clips++] =
\r
4554 CreateRectRgn(x - lineGap, y - lineGap,
\r
4555 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4557 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4558 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4559 clips[num_clips++] =
\r
4560 CreateRectRgn(x - lineGap, y - lineGap,
\r
4561 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4565 for (i=0; i<2; i++) {
\r
4566 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4567 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4568 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4569 lastDrawnPremove.sq[i].y >= 0) {
\r
4570 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4571 lastDrawnPremove.sq[i].x, &x, &y);
\r
4572 clips[num_clips++] =
\r
4573 CreateRectRgn(x - lineGap, y - lineGap,
\r
4574 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4576 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4577 premoveHighlightInfo.sq[i].y >= 0) {
\r
4578 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4579 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4580 clips[num_clips++] =
\r
4581 CreateRectRgn(x - lineGap, y - lineGap,
\r
4582 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4587 fullrepaint = TRUE;
\r
4590 /* Create a buffer bitmap - this is the actual bitmap
\r
4591 * being written to. When all the work is done, we can
\r
4592 * copy it to the real DC (the screen). This avoids
\r
4593 * the problems with flickering.
\r
4595 GetClientRect(hwndMain, &Rect);
\r
4596 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4597 Rect.bottom-Rect.top+1);
\r
4598 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4599 if (!appData.monoMode) {
\r
4600 SelectPalette(hdcmem, hPal, FALSE);
\r
4603 /* Create clips for dragging */
\r
4604 if (!fullrepaint) {
\r
4605 if (dragInfo.from.x >= 0) {
\r
4606 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4607 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4609 if (dragInfo.start.x >= 0) {
\r
4610 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4611 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4613 if (dragInfo.pos.x >= 0) {
\r
4614 x = dragInfo.pos.x - squareSize / 2;
\r
4615 y = dragInfo.pos.y - squareSize / 2;
\r
4616 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4618 if (dragInfo.lastpos.x >= 0) {
\r
4619 x = dragInfo.lastpos.x - squareSize / 2;
\r
4620 y = dragInfo.lastpos.y - squareSize / 2;
\r
4621 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4625 /* Are we animating a move?
\r
4627 * - remove the piece from the board (temporarely)
\r
4628 * - calculate the clipping region
\r
4630 if (!fullrepaint) {
\r
4631 if (animInfo.piece != EmptySquare) {
\r
4632 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4633 x = boardRect.left + animInfo.lastpos.x;
\r
4634 y = boardRect.top + animInfo.lastpos.y;
\r
4635 x2 = boardRect.left + animInfo.pos.x;
\r
4636 y2 = boardRect.top + animInfo.pos.y;
\r
4637 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4638 /* Slight kludge. The real problem is that after AnimateMove is
\r
4639 done, the position on the screen does not match lastDrawn.
\r
4640 This currently causes trouble only on e.p. captures in
\r
4641 atomic, where the piece moves to an empty square and then
\r
4642 explodes. The old and new positions both had an empty square
\r
4643 at the destination, but animation has drawn a piece there and
\r
4644 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4645 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4649 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4650 if (num_clips == 0)
\r
4651 fullrepaint = TRUE;
\r
4653 /* Set clipping on the memory DC */
\r
4654 if (!fullrepaint) {
\r
4655 SelectClipRgn(hdcmem, clips[0]);
\r
4656 for (x = 1; x < num_clips; x++) {
\r
4657 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4658 abort(); // this should never ever happen!
\r
4662 /* Do all the drawing to the memory DC */
\r
4663 if(explodeInfo.radius) { // [HGM] atomic
\r
4665 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4666 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4667 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4668 x += squareSize/2;
\r
4669 y += squareSize/2;
\r
4670 if(!fullrepaint) {
\r
4671 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4672 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4674 DrawGridOnDC(hdcmem);
\r
4675 DrawHighlightsOnDC(hdcmem);
\r
4676 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4677 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4678 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4679 SelectObject(hdcmem, oldBrush);
\r
4681 DrawGridOnDC(hdcmem);
\r
4682 DrawHighlightsOnDC(hdcmem);
\r
4683 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4686 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4687 if(appData.autoLogo) {
\r
4689 switch(gameMode) { // pick logos based on game mode
\r
4690 case IcsObserving:
\r
4691 whiteLogo = second.programLogo; // ICS logo
\r
4692 blackLogo = second.programLogo;
\r
4695 case IcsPlayingWhite:
\r
4696 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4697 blackLogo = second.programLogo; // ICS logo
\r
4699 case IcsPlayingBlack:
\r
4700 whiteLogo = second.programLogo; // ICS logo
\r
4701 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4703 case TwoMachinesPlay:
\r
4704 if(first.twoMachinesColor[0] == 'b') {
\r
4705 whiteLogo = second.programLogo;
\r
4706 blackLogo = first.programLogo;
\r
4709 case MachinePlaysWhite:
\r
4710 blackLogo = userLogo;
\r
4712 case MachinePlaysBlack:
\r
4713 whiteLogo = userLogo;
\r
4714 blackLogo = first.programLogo;
\r
4717 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4718 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4721 if( appData.highlightMoveWithArrow ) {
\r
4722 DrawArrowHighlight(hdcmem);
\r
4725 DrawCoordsOnDC(hdcmem);
\r
4727 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4728 /* to make sure lastDrawn contains what is actually drawn */
\r
4730 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4731 if (dragged_piece != EmptySquare) {
\r
4732 /* [HGM] or restack */
\r
4733 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4734 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4736 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4737 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4738 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4739 x = dragInfo.pos.x - squareSize / 2;
\r
4740 y = dragInfo.pos.y - squareSize / 2;
\r
4741 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4742 ((int) dragged_piece < (int) BlackPawn),
\r
4743 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4746 /* Put the animated piece back into place and draw it */
\r
4747 if (animInfo.piece != EmptySquare) {
\r
4748 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4749 x = boardRect.left + animInfo.pos.x;
\r
4750 y = boardRect.top + animInfo.pos.y;
\r
4751 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4752 ((int) animInfo.piece < (int) BlackPawn),
\r
4753 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4756 /* Release the bufferBitmap by selecting in the old bitmap
\r
4757 * and delete the memory DC
\r
4759 SelectObject(hdcmem, oldBitmap);
\r
4762 /* Set clipping on the target DC */
\r
4763 if (!fullrepaint) {
\r
4764 SelectClipRgn(hdc, clips[0]);
\r
4765 for (x = 1; x < num_clips; x++) {
\r
4766 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4767 abort(); // this should never ever happen!
\r
4771 /* Copy the new bitmap onto the screen in one go.
\r
4772 * This way we avoid any flickering
\r
4774 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4775 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4776 boardRect.right - boardRect.left,
\r
4777 boardRect.bottom - boardRect.top,
\r
4778 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4779 if(saveDiagFlag) {
\r
4780 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4781 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4783 GetObject(bufferBitmap, sizeof(b), &b);
\r
4784 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4785 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4786 bih.biWidth = b.bmWidth;
\r
4787 bih.biHeight = b.bmHeight;
\r
4789 bih.biBitCount = b.bmBitsPixel;
\r
4790 bih.biCompression = 0;
\r
4791 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4792 bih.biXPelsPerMeter = 0;
\r
4793 bih.biYPelsPerMeter = 0;
\r
4794 bih.biClrUsed = 0;
\r
4795 bih.biClrImportant = 0;
\r
4796 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4797 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4798 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4799 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4802 wb = b.bmWidthBytes;
\r
4804 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4805 int k = ((int*) pData)[i];
\r
4806 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4807 if(j >= 16) break;
\r
4809 if(j >= nrColors) nrColors = j+1;
\r
4811 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4813 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4814 for(w=0; w<(wb>>2); w+=2) {
\r
4815 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4816 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4817 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4818 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4819 pData[p++] = m | j<<4;
\r
4821 while(p&3) pData[p++] = 0;
\r
4824 wb = ((wb+31)>>5)<<2;
\r
4826 // write BITMAPFILEHEADER
\r
4827 fprintf(diagFile, "BM");
\r
4828 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4829 fputDW(diagFile, 0);
\r
4830 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4831 // write BITMAPINFOHEADER
\r
4832 fputDW(diagFile, 40);
\r
4833 fputDW(diagFile, b.bmWidth);
\r
4834 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4835 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4836 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4837 fputDW(diagFile, 0);
\r
4838 fputDW(diagFile, 0);
\r
4839 fputDW(diagFile, 0);
\r
4840 fputDW(diagFile, 0);
\r
4841 fputDW(diagFile, 0);
\r
4842 fputDW(diagFile, 0);
\r
4843 // write color table
\r
4845 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4846 // write bitmap data
\r
4847 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4848 fputc(pData[i], diagFile);
\r
4853 SelectObject(tmphdc, oldBitmap);
\r
4855 /* Massive cleanup */
\r
4856 for (x = 0; x < num_clips; x++)
\r
4857 DeleteObject(clips[x]);
\r
4860 DeleteObject(bufferBitmap);
\r
4863 ReleaseDC(hwndMain, hdc);
\r
4865 if (lastDrawnFlipView != flipView) {
\r
4867 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4869 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4872 /* CopyBoard(lastDrawn, board);*/
\r
4873 lastDrawnHighlight = highlightInfo;
\r
4874 lastDrawnPremove = premoveHighlightInfo;
\r
4875 lastDrawnFlipView = flipView;
\r
4876 lastDrawnValid = 1;
\r
4879 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4884 saveDiagFlag = 1; diagFile = f;
\r
4885 HDCDrawPosition(NULL, TRUE, NULL);
\r
4889 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4896 /*---------------------------------------------------------------------------*\
\r
4897 | CLIENT PAINT PROCEDURE
\r
4898 | This is the main event-handler for the WM_PAINT message.
\r
4900 \*---------------------------------------------------------------------------*/
\r
4902 PaintProc(HWND hwnd)
\r
4908 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4909 if (IsIconic(hwnd)) {
\r
4910 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4912 if (!appData.monoMode) {
\r
4913 SelectPalette(hdc, hPal, FALSE);
\r
4914 RealizePalette(hdc);
\r
4916 HDCDrawPosition(hdc, 1, NULL);
\r
4918 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4919 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4920 ETO_CLIPPED|ETO_OPAQUE,
\r
4921 &messageRect, messageText, strlen(messageText), NULL);
\r
4922 SelectObject(hdc, oldFont);
\r
4923 DisplayBothClocks();
\r
4925 EndPaint(hwnd,&ps);
\r
4933 * If the user selects on a border boundary, return -1; if off the board,
\r
4934 * return -2. Otherwise map the event coordinate to the square.
\r
4935 * The offset boardRect.left or boardRect.top must already have been
\r
4936 * subtracted from x.
\r
4939 EventToSquare(int x)
\r
4946 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4948 x /= (squareSize + lineGap);
\r
4949 if (x >= BOARD_SIZE)
\r
4960 DropEnable dropEnables[] = {
\r
4961 { 'P', DP_Pawn, "Pawn" },
\r
4962 { 'N', DP_Knight, "Knight" },
\r
4963 { 'B', DP_Bishop, "Bishop" },
\r
4964 { 'R', DP_Rook, "Rook" },
\r
4965 { 'Q', DP_Queen, "Queen" },
\r
4969 SetupDropMenu(HMENU hmenu)
\r
4971 int i, count, enable;
\r
4973 extern char white_holding[], black_holding[];
\r
4974 char item[MSG_SIZ];
\r
4976 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4977 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4978 dropEnables[i].piece);
\r
4980 while (p && *p++ == dropEnables[i].piece) count++;
\r
4981 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4982 enable = count > 0 || !appData.testLegality
\r
4983 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4984 && !appData.icsActive);
\r
4985 ModifyMenu(hmenu, dropEnables[i].command,
\r
4986 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4987 dropEnables[i].command, item);
\r
4991 /* Event handler for mouse messages */
\r
4993 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4997 static int recursive = 0;
\r
4999 // BOOLEAN needsRedraw = FALSE;
\r
5000 BOOLEAN saveAnimate;
\r
5001 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
5002 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
5003 ChessMove moveType;
\r
5006 if (message == WM_MBUTTONUP) {
\r
5007 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5008 to the middle button: we simulate pressing the left button too!
\r
5010 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5011 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5017 pt.x = LOWORD(lParam);
\r
5018 pt.y = HIWORD(lParam);
\r
5019 x = EventToSquare(pt.x - boardRect.left);
\r
5020 y = EventToSquare(pt.y - boardRect.top);
\r
5021 if (!flipView && y >= 0) {
\r
5022 y = BOARD_HEIGHT - 1 - y;
\r
5024 if (flipView && x >= 0) {
\r
5025 x = BOARD_WIDTH - 1 - x;
\r
5028 switch (message) {
\r
5029 case WM_LBUTTONDOWN:
\r
5030 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5031 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5032 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5033 if(gameInfo.holdingsWidth &&
\r
5034 (WhiteOnMove(currentMove)
\r
5035 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5036 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5037 // click in right holdings, for determining promotion piece
\r
5038 ChessSquare p = boards[currentMove][y][x];
\r
5039 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5040 if(p != EmptySquare) {
\r
5041 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5042 fromX = fromY = -1;
\r
5046 DrawPosition(FALSE, boards[currentMove]);
\r
5050 sameAgain = FALSE;
\r
5052 /* Downclick vertically off board; check if on clock */
\r
5053 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5054 if (gameMode == EditPosition) {
\r
5055 SetWhiteToPlayEvent();
\r
5056 } else if (gameMode == IcsPlayingBlack ||
\r
5057 gameMode == MachinePlaysWhite) {
\r
5059 } else if (gameMode == EditGame) {
\r
5060 AdjustClock(flipClock, -1);
\r
5062 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5063 if (gameMode == EditPosition) {
\r
5064 SetBlackToPlayEvent();
\r
5065 } else if (gameMode == IcsPlayingWhite ||
\r
5066 gameMode == MachinePlaysBlack) {
\r
5068 } else if (gameMode == EditGame) {
\r
5069 AdjustClock(!flipClock, -1);
\r
5072 if (!appData.highlightLastMove) {
\r
5073 ClearHighlights();
\r
5074 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5076 fromX = fromY = -1;
\r
5077 dragInfo.start.x = dragInfo.start.y = -1;
\r
5078 dragInfo.from = dragInfo.start;
\r
5080 } else if (x < 0 || y < 0
\r
5081 /* [HGM] block clicks between board and holdings */
\r
5082 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5083 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5084 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5085 /* EditPosition, empty square, or different color piece;
\r
5086 click-click move is possible */
\r
5089 } else if (fromX == x && fromY == y) {
\r
5090 /* Downclick on same square again */
\r
5091 ClearHighlights();
\r
5092 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5093 sameAgain = TRUE;
\r
5094 } else if (fromX != -1 &&
\r
5095 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5097 /* Downclick on different square. */
\r
5098 /* [HGM] if on holdings file, should count as new first click ! */
\r
5099 /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5102 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5103 to make sure move is legal before showing promotion popup */
\r
5104 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5105 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5106 fromX = fromY = -1;
\r
5107 ClearHighlights();
\r
5108 DrawPosition(FALSE, boards[currentMove]);
\r
5111 if(moveType != ImpossibleMove) {
\r
5112 if(moveType == IllegalMove) {
\r
5115 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5116 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5117 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5118 appData.alwaysPromoteToQueen)) {
\r
5119 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5120 if (!appData.highlightLastMove) {
\r
5121 ClearHighlights();
\r
5122 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5125 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5126 SetHighlights(fromX, fromY, toX, toY);
\r
5127 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5128 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5129 If promotion to Q is legal, all are legal! */
\r
5130 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5131 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5132 // kludge to temporarily execute move on display, without promotng yet
\r
5133 promotionChoice = TRUE;
\r
5134 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5135 boards[currentMove][toY][toX] = p;
\r
5136 DrawPosition(FALSE, boards[currentMove]);
\r
5137 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5138 boards[currentMove][toY][toX] = q;
\r
5140 PromotionPopup(hwnd);
\r
5141 } else { /* not a promotion */
\r
5142 if (appData.animate || appData.highlightLastMove) {
\r
5143 SetHighlights(fromX, fromY, toX, toY);
\r
5145 ClearHighlights();
\r
5147 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5148 if (appData.animate && !appData.highlightLastMove) {
\r
5149 ClearHighlights();
\r
5150 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5153 fromX = fromY = -1;
\r
5157 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5158 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5159 } else ClearHighlights();
\r
5160 fromX = fromY = -1;
\r
5161 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5163 /* First downclick, or restart on a square with same color piece */
\r
5164 if (!frozen && OKToStartUserMove(x, y)) {
\r
5167 dragInfo.lastpos = pt;
\r
5168 dragInfo.from.x = fromX;
\r
5169 dragInfo.from.y = fromY;
\r
5170 dragInfo.start = dragInfo.from;
\r
5171 SetCapture(hwndMain);
\r
5173 fromX = fromY = -1;
\r
5174 dragInfo.start.x = dragInfo.start.y = -1;
\r
5175 dragInfo.from = dragInfo.start;
\r
5176 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5180 case WM_LBUTTONUP:
\r
5182 if (fromX == -1) break;
\r
5183 if (x == fromX && y == fromY) {
\r
5184 dragInfo.from.x = dragInfo.from.y = -1;
\r
5185 /* Upclick on same square */
\r
5187 /* Clicked same square twice: abort click-click move */
\r
5188 fromX = fromY = -1;
\r
5190 ClearPremoveHighlights();
\r
5192 /* First square clicked: start click-click move */
\r
5193 SetHighlights(fromX, fromY, -1, -1);
\r
5195 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5196 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5197 /* Errant click; ignore */
\r
5200 /* Finish drag move. */
\r
5201 if (appData.debugMode) {
\r
5202 fprintf(debugFP, "release\n");
\r
5204 dragInfo.from.x = dragInfo.from.y = -1;
\r
5207 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5208 appData.animate = appData.animate && !appData.animateDragging;
\r
5209 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5210 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5211 fromX = fromY = -1;
\r
5212 ClearHighlights();
\r
5213 DrawPosition(FALSE, boards[currentMove]);
\r
5214 appData.animate = saveAnimate;
\r
5217 if(moveType != ImpossibleMove) {
\r
5218 /* [HGM] use move type to determine if move is promotion.
\r
5219 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5220 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5221 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5222 appData.alwaysPromoteToQueen))
\r
5223 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5225 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5226 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5227 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5228 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5229 // kludge to temporarily execute move on display, wthout promotng yet
\r
5230 promotionChoice = TRUE;
\r
5231 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5232 boards[currentMove][toY][toX] = p;
\r
5233 DrawPosition(FALSE, boards[currentMove]);
\r
5234 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5235 boards[currentMove][toY][toX] = q;
\r
5236 appData.animate = saveAnimate;
\r
5239 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5241 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5242 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5243 moveType == WhiteCapturesEnPassant ||
\r
5244 moveType == BlackCapturesEnPassant ) )
\r
5245 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5246 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5249 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5250 appData.animate = saveAnimate;
\r
5251 fromX = fromY = -1;
\r
5252 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5253 ClearHighlights();
\r
5255 if (appData.animate || appData.animateDragging ||
\r
5256 appData.highlightDragging || gotPremove) {
\r
5257 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5260 dragInfo.start.x = dragInfo.start.y = -1;
\r
5261 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5264 case WM_MOUSEMOVE:
\r
5265 if ((appData.animateDragging || appData.highlightDragging)
\r
5266 && (wParam & MK_LBUTTON)
\r
5267 && dragInfo.from.x >= 0)
\r
5269 BOOL full_repaint = FALSE;
\r
5271 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5272 if (appData.animateDragging) {
\r
5273 dragInfo.pos = pt;
\r
5275 if (appData.highlightDragging) {
\r
5276 SetHighlights(fromX, fromY, x, y);
\r
5277 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5278 full_repaint = TRUE;
\r
5282 DrawPosition( full_repaint, NULL);
\r
5284 dragInfo.lastpos = dragInfo.pos;
\r
5288 case WM_MOUSEWHEEL: // [DM]
\r
5289 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5290 /* Mouse Wheel is being rolled forward
\r
5291 * Play moves forward
\r
5293 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5294 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5295 /* Mouse Wheel is being rolled backward
\r
5296 * Play moves backward
\r
5298 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5299 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5303 case WM_MBUTTONDOWN:
\r
5304 case WM_RBUTTONDOWN:
\r
5307 fromX = fromY = -1;
\r
5308 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5309 dragInfo.start.x = dragInfo.start.y = -1;
\r
5310 dragInfo.from = dragInfo.start;
\r
5311 dragInfo.lastpos = dragInfo.pos;
\r
5312 if (appData.highlightDragging) {
\r
5313 ClearHighlights();
\r
5316 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5317 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5318 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5319 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5320 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5323 DrawPosition(TRUE, NULL);
\r
5325 switch (gameMode) {
\r
5326 case EditPosition:
\r
5327 case IcsExamining:
\r
5328 if (x < 0 || y < 0) break;
\r
5331 if (message == WM_MBUTTONDOWN) {
\r
5332 buttonCount = 3; /* even if system didn't think so */
\r
5333 if (wParam & MK_SHIFT)
\r
5334 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5336 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5337 } else { /* message == WM_RBUTTONDOWN */
\r
5339 if (buttonCount == 3) {
\r
5340 if (wParam & MK_SHIFT)
\r
5341 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5343 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5345 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5348 /* Just have one menu, on the right button. Windows users don't
\r
5349 think to try the middle one, and sometimes other software steals
\r
5350 it, or it doesn't really exist. */
\r
5351 if(gameInfo.variant != VariantShogi)
\r
5352 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5354 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5358 case IcsPlayingWhite:
\r
5359 case IcsPlayingBlack:
\r
5361 case MachinePlaysWhite:
\r
5362 case MachinePlaysBlack:
\r
5363 if (appData.testLegality &&
\r
5364 gameInfo.variant != VariantBughouse &&
\r
5365 gameInfo.variant != VariantCrazyhouse) break;
\r
5366 if (x < 0 || y < 0) break;
\r
5369 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5370 SetupDropMenu(hmenu);
\r
5371 MenuPopup(hwnd, pt, hmenu, -1);
\r
5382 /* Preprocess messages for buttons in main window */
\r
5384 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5386 int id = GetWindowLong(hwnd, GWL_ID);
\r
5389 for (i=0; i<N_BUTTONS; i++) {
\r
5390 if (buttonDesc[i].id == id) break;
\r
5392 if (i == N_BUTTONS) return 0;
\r
5393 switch (message) {
\r
5398 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5399 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5406 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5409 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5410 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5411 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5412 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5414 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5416 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5417 PopUpMoveDialog((char)wParam);
\r
5423 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5426 /* Process messages for Promotion dialog box */
\r
5428 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5432 switch (message) {
\r
5433 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5434 /* Center the dialog over the application window */
\r
5435 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5436 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5437 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5438 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5439 SW_SHOW : SW_HIDE);
\r
5440 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5441 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5442 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5443 PieceToChar(WhiteAngel) != '~') ||
\r
5444 (PieceToChar(BlackAngel) >= 'A' &&
\r
5445 PieceToChar(BlackAngel) != '~') ) ?
\r
5446 SW_SHOW : SW_HIDE);
\r
5447 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5448 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5449 PieceToChar(WhiteMarshall) != '~') ||
\r
5450 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5451 PieceToChar(BlackMarshall) != '~') ) ?
\r
5452 SW_SHOW : SW_HIDE);
\r
5453 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5454 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5455 gameInfo.variant != VariantShogi ?
\r
5456 SW_SHOW : SW_HIDE);
\r
5457 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5458 gameInfo.variant != VariantShogi ?
\r
5459 SW_SHOW : SW_HIDE);
\r
5460 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5461 gameInfo.variant == VariantShogi ?
\r
5462 SW_SHOW : SW_HIDE);
\r
5463 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5464 gameInfo.variant == VariantShogi ?
\r
5465 SW_SHOW : SW_HIDE);
\r
5466 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5467 gameInfo.variant == VariantSuper ?
\r
5468 SW_SHOW : SW_HIDE);
\r
5471 case WM_COMMAND: /* message: received a command */
\r
5472 switch (LOWORD(wParam)) {
\r
5474 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5475 ClearHighlights();
\r
5476 DrawPosition(FALSE, NULL);
\r
5479 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5482 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5485 promoChar = PieceToChar(BlackRook);
\r
5488 promoChar = PieceToChar(BlackBishop);
\r
5490 case PB_Chancellor:
\r
5491 promoChar = PieceToChar(BlackMarshall);
\r
5493 case PB_Archbishop:
\r
5494 promoChar = PieceToChar(BlackAngel);
\r
5497 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5502 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5503 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5504 only show the popup when we are already sure the move is valid or
\r
5505 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5506 will figure out it is a promotion from the promoChar. */
\r
5507 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5508 if (!appData.highlightLastMove) {
\r
5509 ClearHighlights();
\r
5510 DrawPosition(FALSE, NULL);
\r
5517 /* Pop up promotion dialog */
\r
5519 PromotionPopup(HWND hwnd)
\r
5523 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5524 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5525 hwnd, (DLGPROC)lpProc);
\r
5526 FreeProcInstance(lpProc);
\r
5529 /* Toggle ShowThinking */
\r
5531 ToggleShowThinking()
\r
5533 appData.showThinking = !appData.showThinking;
\r
5534 ShowThinkingEvent();
\r
5538 LoadGameDialog(HWND hwnd, char* title)
\r
5542 char fileTitle[MSG_SIZ];
\r
5543 f = OpenFileDialog(hwnd, "rb", "",
\r
5544 appData.oldSaveStyle ? "gam" : "pgn",
\r
5546 title, &number, fileTitle, NULL);
\r
5548 cmailMsgLoaded = FALSE;
\r
5549 if (number == 0) {
\r
5550 int error = GameListBuild(f);
\r
5552 DisplayError("Cannot build game list", error);
\r
5553 } else if (!ListEmpty(&gameList) &&
\r
5554 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5555 GameListPopUp(f, fileTitle);
\r
5558 GameListDestroy();
\r
5561 LoadGame(f, number, fileTitle, FALSE);
\r
5566 ChangedConsoleFont()
\r
5569 CHARRANGE tmpsel, sel;
\r
5570 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5571 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5572 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5575 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5576 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5577 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5578 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5579 * size. This was undocumented in the version of MSVC++ that I had
\r
5580 * when I wrote the code, but is apparently documented now.
\r
5582 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5583 cfmt.bCharSet = f->lf.lfCharSet;
\r
5584 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5585 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5586 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5587 /* Why are the following seemingly needed too? */
\r
5588 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5589 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5590 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5592 tmpsel.cpMax = -1; /*999999?*/
\r
5593 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5594 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5595 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5596 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5598 paraf.cbSize = sizeof(paraf);
\r
5599 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5600 paraf.dxStartIndent = 0;
\r
5601 paraf.dxOffset = WRAP_INDENT;
\r
5602 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5603 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5606 /*---------------------------------------------------------------------------*\
\r
5608 * Window Proc for main window
\r
5610 \*---------------------------------------------------------------------------*/
\r
5612 /* Process messages for main window, etc. */
\r
5614 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5617 int wmId, wmEvent;
\r
5621 char fileTitle[MSG_SIZ];
\r
5622 char buf[MSG_SIZ];
\r
5623 static SnapData sd;
\r
5625 switch (message) {
\r
5627 case WM_PAINT: /* message: repaint portion of window */
\r
5631 case WM_ERASEBKGND:
\r
5632 if (IsIconic(hwnd)) {
\r
5633 /* Cheat; change the message */
\r
5634 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5636 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5640 case WM_LBUTTONDOWN:
\r
5641 case WM_MBUTTONDOWN:
\r
5642 case WM_RBUTTONDOWN:
\r
5643 case WM_LBUTTONUP:
\r
5644 case WM_MBUTTONUP:
\r
5645 case WM_RBUTTONUP:
\r
5646 case WM_MOUSEMOVE:
\r
5647 case WM_MOUSEWHEEL:
\r
5648 MouseEvent(hwnd, message, wParam, lParam);
\r
5651 JAWS_KB_NAVIGATION
\r
5655 JAWS_ALT_INTERCEPT
\r
5657 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5658 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5659 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5660 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5662 SendMessage(h, message, wParam, lParam);
\r
5663 } else if(lParam != KF_REPEAT) {
\r
5664 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5665 PopUpMoveDialog((char)wParam);
\r
5666 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5667 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5672 case WM_PALETTECHANGED:
\r
5673 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5675 HDC hdc = GetDC(hwndMain);
\r
5676 SelectPalette(hdc, hPal, TRUE);
\r
5677 nnew = RealizePalette(hdc);
\r
5679 paletteChanged = TRUE;
\r
5681 UpdateColors(hdc);
\r
5683 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5686 ReleaseDC(hwnd, hdc);
\r
5690 case WM_QUERYNEWPALETTE:
\r
5691 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5693 HDC hdc = GetDC(hwndMain);
\r
5694 paletteChanged = FALSE;
\r
5695 SelectPalette(hdc, hPal, FALSE);
\r
5696 nnew = RealizePalette(hdc);
\r
5698 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5700 ReleaseDC(hwnd, hdc);
\r
5705 case WM_COMMAND: /* message: command from application menu */
\r
5706 wmId = LOWORD(wParam);
\r
5707 wmEvent = HIWORD(wParam);
\r
5712 AnalysisPopDown();
\r
5713 SAY("new game enter a move to play against the computer with white");
\r
5716 case IDM_NewGameFRC:
\r
5717 if( NewGameFRC() == 0 ) {
\r
5719 AnalysisPopDown();
\r
5723 case IDM_NewVariant:
\r
5724 NewVariantPopup(hwnd);
\r
5727 case IDM_LoadGame:
\r
5728 LoadGameDialog(hwnd, "Load Game from File");
\r
5731 case IDM_LoadNextGame:
\r
5735 case IDM_LoadPrevGame:
\r
5739 case IDM_ReloadGame:
\r
5743 case IDM_LoadPosition:
\r
5744 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5745 Reset(FALSE, TRUE);
\r
5748 f = OpenFileDialog(hwnd, "rb", "",
\r
5749 appData.oldSaveStyle ? "pos" : "fen",
\r
5751 "Load Position from File", &number, fileTitle, NULL);
\r
5753 LoadPosition(f, number, fileTitle);
\r
5757 case IDM_LoadNextPosition:
\r
5758 ReloadPosition(1);
\r
5761 case IDM_LoadPrevPosition:
\r
5762 ReloadPosition(-1);
\r
5765 case IDM_ReloadPosition:
\r
5766 ReloadPosition(0);
\r
5769 case IDM_SaveGame:
\r
5770 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5771 f = OpenFileDialog(hwnd, "a", defName,
\r
5772 appData.oldSaveStyle ? "gam" : "pgn",
\r
5774 "Save Game to File", NULL, fileTitle, NULL);
\r
5776 SaveGame(f, 0, "");
\r
5780 case IDM_SavePosition:
\r
5781 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5782 f = OpenFileDialog(hwnd, "a", defName,
\r
5783 appData.oldSaveStyle ? "pos" : "fen",
\r
5785 "Save Position to File", NULL, fileTitle, NULL);
\r
5787 SavePosition(f, 0, "");
\r
5791 case IDM_SaveDiagram:
\r
5792 defName = "diagram";
\r
5793 f = OpenFileDialog(hwnd, "wb", defName,
\r
5796 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5802 case IDM_CopyGame:
\r
5803 CopyGameToClipboard();
\r
5806 case IDM_PasteGame:
\r
5807 PasteGameFromClipboard();
\r
5810 case IDM_CopyGameListToClipboard:
\r
5811 CopyGameListToClipboard();
\r
5814 /* [AS] Autodetect FEN or PGN data */
\r
5815 case IDM_PasteAny:
\r
5816 PasteGameOrFENFromClipboard();
\r
5819 /* [AS] Move history */
\r
5820 case IDM_ShowMoveHistory:
\r
5821 if( MoveHistoryIsUp() ) {
\r
5822 MoveHistoryPopDown();
\r
5825 MoveHistoryPopUp();
\r
5829 /* [AS] Eval graph */
\r
5830 case IDM_ShowEvalGraph:
\r
5831 if( EvalGraphIsUp() ) {
\r
5832 EvalGraphPopDown();
\r
5836 SetFocus(hwndMain);
\r
5840 /* [AS] Engine output */
\r
5841 case IDM_ShowEngineOutput:
\r
5842 if( EngineOutputIsUp() ) {
\r
5843 EngineOutputPopDown();
\r
5846 EngineOutputPopUp();
\r
5850 /* [AS] User adjudication */
\r
5851 case IDM_UserAdjudication_White:
\r
5852 UserAdjudicationEvent( +1 );
\r
5855 case IDM_UserAdjudication_Black:
\r
5856 UserAdjudicationEvent( -1 );
\r
5859 case IDM_UserAdjudication_Draw:
\r
5860 UserAdjudicationEvent( 0 );
\r
5863 /* [AS] Game list options dialog */
\r
5864 case IDM_GameListOptions:
\r
5865 GameListOptions();
\r
5868 case IDM_CopyPosition:
\r
5869 CopyFENToClipboard();
\r
5872 case IDM_PastePosition:
\r
5873 PasteFENFromClipboard();
\r
5876 case IDM_MailMove:
\r
5880 case IDM_ReloadCMailMsg:
\r
5881 Reset(TRUE, TRUE);
\r
5882 ReloadCmailMsgEvent(FALSE);
\r
5885 case IDM_Minimize:
\r
5886 ShowWindow(hwnd, SW_MINIMIZE);
\r
5893 case IDM_MachineWhite:
\r
5894 MachineWhiteEvent();
\r
5896 * refresh the tags dialog only if it's visible
\r
5898 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5900 tags = PGNTags(&gameInfo);
\r
5901 TagsPopUp(tags, CmailMsg());
\r
5904 SAY("computer starts playing white");
\r
5907 case IDM_MachineBlack:
\r
5908 MachineBlackEvent();
\r
5910 * refresh the tags dialog only if it's visible
\r
5912 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5914 tags = PGNTags(&gameInfo);
\r
5915 TagsPopUp(tags, CmailMsg());
\r
5918 SAY("computer starts playing black");
\r
5921 case IDM_TwoMachines:
\r
5922 TwoMachinesEvent();
\r
5924 * refresh the tags dialog only if it's visible
\r
5926 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5928 tags = PGNTags(&gameInfo);
\r
5929 TagsPopUp(tags, CmailMsg());
\r
5932 SAY("programs start playing each other");
\r
5935 case IDM_AnalysisMode:
\r
5936 if (!first.analysisSupport) {
\r
5937 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5938 DisplayError(buf, 0);
\r
5940 SAY("analyzing current position");
\r
5941 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5942 if (appData.icsActive) {
\r
5943 if (gameMode != IcsObserving) {
\r
5944 sprintf(buf, "You are not observing a game");
\r
5945 DisplayError(buf, 0);
\r
5946 /* secure check */
\r
5947 if (appData.icsEngineAnalyze) {
\r
5948 if (appData.debugMode)
\r
5949 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5950 ExitAnalyzeMode();
\r
5956 /* if enable, user want disable icsEngineAnalyze */
\r
5957 if (appData.icsEngineAnalyze) {
\r
5958 ExitAnalyzeMode();
\r
5962 appData.icsEngineAnalyze = TRUE;
\r
5963 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5966 if (!appData.showThinking) ToggleShowThinking();
\r
5967 AnalyzeModeEvent();
\r
5971 case IDM_AnalyzeFile:
\r
5972 if (!first.analysisSupport) {
\r
5973 char buf[MSG_SIZ];
\r
5974 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5975 DisplayError(buf, 0);
\r
5977 if (!appData.showThinking) ToggleShowThinking();
\r
5978 AnalyzeFileEvent();
\r
5979 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5980 AnalysisPeriodicEvent(1);
\r
5984 case IDM_IcsClient:
\r
5988 case IDM_EditGame:
\r
5993 case IDM_EditPosition:
\r
5994 EditPositionEvent();
\r
5995 SAY("to set up a position type a FEN");
\r
5998 case IDM_Training:
\r
6002 case IDM_ShowGameList:
\r
6003 ShowGameListProc();
\r
6006 case IDM_EditTags:
\r
6010 case IDM_EditComment:
\r
6011 if (commentDialogUp && editComment) {
\r
6014 EditCommentEvent();
\r
6034 case IDM_CallFlag:
\r
6054 case IDM_StopObserving:
\r
6055 StopObservingEvent();
\r
6058 case IDM_StopExamining:
\r
6059 StopExaminingEvent();
\r
6062 case IDM_TypeInMove:
\r
6063 PopUpMoveDialog('\000');
\r
6066 case IDM_TypeInName:
\r
6067 PopUpNameDialog('\000');
\r
6070 case IDM_Backward:
\r
6072 SetFocus(hwndMain);
\r
6079 SetFocus(hwndMain);
\r
6084 SetFocus(hwndMain);
\r
6089 SetFocus(hwndMain);
\r
6096 case IDM_TruncateGame:
\r
6097 TruncateGameEvent();
\r
6104 case IDM_RetractMove:
\r
6105 RetractMoveEvent();
\r
6108 case IDM_FlipView:
\r
6109 flipView = !flipView;
\r
6110 DrawPosition(FALSE, NULL);
\r
6113 case IDM_FlipClock:
\r
6114 flipClock = !flipClock;
\r
6115 DisplayBothClocks();
\r
6116 DrawPosition(FALSE, NULL);
\r
6119 case IDM_GeneralOptions:
\r
6120 GeneralOptionsPopup(hwnd);
\r
6121 DrawPosition(TRUE, NULL);
\r
6124 case IDM_BoardOptions:
\r
6125 BoardOptionsPopup(hwnd);
\r
6128 case IDM_EnginePlayOptions:
\r
6129 EnginePlayOptionsPopup(hwnd);
\r
6132 case IDM_Engine1Options:
\r
6133 EngineOptionsPopup(hwnd, &first);
\r
6136 case IDM_Engine2Options:
\r
6137 EngineOptionsPopup(hwnd, &second);
\r
6140 case IDM_OptionsUCI:
\r
6141 UciOptionsPopup(hwnd);
\r
6144 case IDM_IcsOptions:
\r
6145 IcsOptionsPopup(hwnd);
\r
6149 FontsOptionsPopup(hwnd);
\r
6153 SoundOptionsPopup(hwnd);
\r
6156 case IDM_CommPort:
\r
6157 CommPortOptionsPopup(hwnd);
\r
6160 case IDM_LoadOptions:
\r
6161 LoadOptionsPopup(hwnd);
\r
6164 case IDM_SaveOptions:
\r
6165 SaveOptionsPopup(hwnd);
\r
6168 case IDM_TimeControl:
\r
6169 TimeControlOptionsPopup(hwnd);
\r
6172 case IDM_SaveSettings:
\r
6173 SaveSettings(settingsFileName);
\r
6176 case IDM_SaveSettingsOnExit:
\r
6177 saveSettingsOnExit = !saveSettingsOnExit;
\r
6178 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6179 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6180 MF_CHECKED : MF_UNCHECKED));
\r
6191 case IDM_AboutGame:
\r
6196 appData.debugMode = !appData.debugMode;
\r
6197 if (appData.debugMode) {
\r
6198 char dir[MSG_SIZ];
\r
6199 GetCurrentDirectory(MSG_SIZ, dir);
\r
6200 SetCurrentDirectory(installDir);
\r
6201 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6202 SetCurrentDirectory(dir);
\r
6203 setbuf(debugFP, NULL);
\r
6210 case IDM_HELPCONTENTS:
\r
6211 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6212 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6213 MessageBox (GetFocus(),
\r
6214 "Unable to activate help",
\r
6215 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6219 case IDM_HELPSEARCH:
\r
6220 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6221 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6222 MessageBox (GetFocus(),
\r
6223 "Unable to activate help",
\r
6224 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6228 case IDM_HELPHELP:
\r
6229 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6230 MessageBox (GetFocus(),
\r
6231 "Unable to activate help",
\r
6232 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6237 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6239 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6240 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6241 FreeProcInstance(lpProc);
\r
6244 case IDM_DirectCommand1:
\r
6245 AskQuestionEvent("Direct Command",
\r
6246 "Send to chess program:", "", "1");
\r
6248 case IDM_DirectCommand2:
\r
6249 AskQuestionEvent("Direct Command",
\r
6250 "Send to second chess program:", "", "2");
\r
6253 case EP_WhitePawn:
\r
6254 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6255 fromX = fromY = -1;
\r
6258 case EP_WhiteKnight:
\r
6259 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6260 fromX = fromY = -1;
\r
6263 case EP_WhiteBishop:
\r
6264 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6265 fromX = fromY = -1;
\r
6268 case EP_WhiteRook:
\r
6269 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6270 fromX = fromY = -1;
\r
6273 case EP_WhiteQueen:
\r
6274 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6275 fromX = fromY = -1;
\r
6278 case EP_WhiteFerz:
\r
6279 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6280 fromX = fromY = -1;
\r
6283 case EP_WhiteWazir:
\r
6284 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6285 fromX = fromY = -1;
\r
6288 case EP_WhiteAlfil:
\r
6289 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6290 fromX = fromY = -1;
\r
6293 case EP_WhiteCannon:
\r
6294 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6295 fromX = fromY = -1;
\r
6298 case EP_WhiteCardinal:
\r
6299 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6300 fromX = fromY = -1;
\r
6303 case EP_WhiteMarshall:
\r
6304 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6305 fromX = fromY = -1;
\r
6308 case EP_WhiteKing:
\r
6309 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6310 fromX = fromY = -1;
\r
6313 case EP_BlackPawn:
\r
6314 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6315 fromX = fromY = -1;
\r
6318 case EP_BlackKnight:
\r
6319 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6320 fromX = fromY = -1;
\r
6323 case EP_BlackBishop:
\r
6324 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6325 fromX = fromY = -1;
\r
6328 case EP_BlackRook:
\r
6329 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6330 fromX = fromY = -1;
\r
6333 case EP_BlackQueen:
\r
6334 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6335 fromX = fromY = -1;
\r
6338 case EP_BlackFerz:
\r
6339 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6340 fromX = fromY = -1;
\r
6343 case EP_BlackWazir:
\r
6344 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6345 fromX = fromY = -1;
\r
6348 case EP_BlackAlfil:
\r
6349 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6350 fromX = fromY = -1;
\r
6353 case EP_BlackCannon:
\r
6354 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6355 fromX = fromY = -1;
\r
6358 case EP_BlackCardinal:
\r
6359 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6360 fromX = fromY = -1;
\r
6363 case EP_BlackMarshall:
\r
6364 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6365 fromX = fromY = -1;
\r
6368 case EP_BlackKing:
\r
6369 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6370 fromX = fromY = -1;
\r
6373 case EP_EmptySquare:
\r
6374 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6375 fromX = fromY = -1;
\r
6378 case EP_ClearBoard:
\r
6379 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6380 fromX = fromY = -1;
\r
6384 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6385 fromX = fromY = -1;
\r
6389 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6390 fromX = fromY = -1;
\r
6394 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6395 fromX = fromY = -1;
\r
6399 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6400 fromX = fromY = -1;
\r
6404 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6405 fromX = fromY = -1;
\r
6409 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6410 fromX = fromY = -1;
\r
6414 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6415 fromX = fromY = -1;
\r
6419 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6420 fromX = fromY = -1;
\r
6424 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6425 fromX = fromY = -1;
\r
6429 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6435 case CLOCK_TIMER_ID:
\r
6436 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6437 clockTimerEvent = 0;
\r
6438 DecrementClocks(); /* call into back end */
\r
6440 case LOAD_GAME_TIMER_ID:
\r
6441 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6442 loadGameTimerEvent = 0;
\r
6443 AutoPlayGameLoop(); /* call into back end */
\r
6445 case ANALYSIS_TIMER_ID:
\r
6446 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6447 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6448 AnalysisPeriodicEvent(0);
\r
6450 KillTimer(hwnd, analysisTimerEvent);
\r
6451 analysisTimerEvent = 0;
\r
6454 case DELAYED_TIMER_ID:
\r
6455 KillTimer(hwnd, delayedTimerEvent);
\r
6456 delayedTimerEvent = 0;
\r
6457 delayedTimerCallback();
\r
6462 case WM_USER_Input:
\r
6463 InputEvent(hwnd, message, wParam, lParam);
\r
6466 /* [AS] Also move "attached" child windows */
\r
6467 case WM_WINDOWPOSCHANGING:
\r
6469 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6470 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6472 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6473 /* Window is moving */
\r
6476 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6477 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6478 rcMain.right = boardX + winWidth;
\r
6479 rcMain.top = boardY;
\r
6480 rcMain.bottom = boardY + winHeight;
\r
6482 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6483 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6484 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6485 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6486 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6493 /* [AS] Snapping */
\r
6494 case WM_ENTERSIZEMOVE:
\r
6495 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6496 if (hwnd == hwndMain) {
\r
6497 doingSizing = TRUE;
\r
6500 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6504 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6505 if (hwnd == hwndMain) {
\r
6506 lastSizing = wParam;
\r
6511 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6512 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6514 case WM_EXITSIZEMOVE:
\r
6515 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6516 if (hwnd == hwndMain) {
\r
6518 doingSizing = FALSE;
\r
6519 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6520 GetClientRect(hwnd, &client);
\r
6521 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6523 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6525 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6528 case WM_DESTROY: /* message: window being destroyed */
\r
6529 PostQuitMessage(0);
\r
6533 if (hwnd == hwndMain) {
\r
6538 default: /* Passes it on if unprocessed */
\r
6539 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6544 /*---------------------------------------------------------------------------*\
\r
6546 * Misc utility routines
\r
6548 \*---------------------------------------------------------------------------*/
\r
6551 * Decent random number generator, at least not as bad as Windows
\r
6552 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6554 unsigned int randstate;
\r
6559 randstate = randstate * 1664525 + 1013904223;
\r
6560 return (int) randstate & 0x7fffffff;
\r
6564 mysrandom(unsigned int seed)
\r
6571 * returns TRUE if user selects a different color, FALSE otherwise
\r
6575 ChangeColor(HWND hwnd, COLORREF *which)
\r
6577 static BOOL firstTime = TRUE;
\r
6578 static DWORD customColors[16];
\r
6580 COLORREF newcolor;
\r
6585 /* Make initial colors in use available as custom colors */
\r
6586 /* Should we put the compiled-in defaults here instead? */
\r
6588 customColors[i++] = lightSquareColor & 0xffffff;
\r
6589 customColors[i++] = darkSquareColor & 0xffffff;
\r
6590 customColors[i++] = whitePieceColor & 0xffffff;
\r
6591 customColors[i++] = blackPieceColor & 0xffffff;
\r
6592 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6593 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6595 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6596 customColors[i++] = textAttribs[ccl].color;
\r
6598 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6599 firstTime = FALSE;
\r
6602 cc.lStructSize = sizeof(cc);
\r
6603 cc.hwndOwner = hwnd;
\r
6604 cc.hInstance = NULL;
\r
6605 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6606 cc.lpCustColors = (LPDWORD) customColors;
\r
6607 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6609 if (!ChooseColor(&cc)) return FALSE;
\r
6611 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6612 if (newcolor == *which) return FALSE;
\r
6613 *which = newcolor;
\r
6617 InitDrawingColors();
\r
6618 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6623 MyLoadSound(MySound *ms)
\r
6629 if (ms->data) free(ms->data);
\r
6632 switch (ms->name[0]) {
\r
6638 /* System sound from Control Panel. Don't preload here. */
\r
6642 if (ms->name[1] == NULLCHAR) {
\r
6643 /* "!" alone = silence */
\r
6646 /* Builtin wave resource. Error if not found. */
\r
6647 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6648 if (h == NULL) break;
\r
6649 ms->data = (void *)LoadResource(hInst, h);
\r
6650 if (h == NULL) break;
\r
6655 /* .wav file. Error if not found. */
\r
6656 f = fopen(ms->name, "rb");
\r
6657 if (f == NULL) break;
\r
6658 if (fstat(fileno(f), &st) < 0) break;
\r
6659 ms->data = malloc(st.st_size);
\r
6660 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6666 char buf[MSG_SIZ];
\r
6667 sprintf(buf, "Error loading sound %s", ms->name);
\r
6668 DisplayError(buf, GetLastError());
\r
6674 MyPlaySound(MySound *ms)
\r
6676 BOOLEAN ok = FALSE;
\r
6678 switch (ms->name[0]) {
\r
6680 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6685 /* System sound from Control Panel (deprecated feature).
\r
6686 "$" alone or an unset sound name gets default beep (still in use). */
\r
6687 if (ms->name[1]) {
\r
6688 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6690 if (!ok) ok = MessageBeep(MB_OK);
\r
6693 /* Builtin wave resource, or "!" alone for silence */
\r
6694 if (ms->name[1]) {
\r
6695 if (ms->data == NULL) return FALSE;
\r
6696 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6702 /* .wav file. Error if not found. */
\r
6703 if (ms->data == NULL) return FALSE;
\r
6704 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6707 /* Don't print an error: this can happen innocently if the sound driver
\r
6708 is busy; for instance, if another instance of WinBoard is playing
\r
6709 a sound at about the same time. */
\r
6712 char buf[MSG_SIZ];
\r
6713 sprintf(buf, "Error playing sound %s", ms->name);
\r
6714 DisplayError(buf, GetLastError());
\r
6722 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6725 OPENFILENAME *ofn;
\r
6726 static UINT *number; /* gross that this is static */
\r
6728 switch (message) {
\r
6729 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6730 /* Center the dialog over the application window */
\r
6731 ofn = (OPENFILENAME *) lParam;
\r
6732 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6733 number = (UINT *) ofn->lCustData;
\r
6734 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6738 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6739 return FALSE; /* Allow for further processing */
\r
6742 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6743 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6745 return FALSE; /* Allow for further processing */
\r
6751 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6753 static UINT *number;
\r
6754 OPENFILENAME *ofname;
\r
6757 case WM_INITDIALOG:
\r
6758 ofname = (OPENFILENAME *)lParam;
\r
6759 number = (UINT *)(ofname->lCustData);
\r
6762 ofnot = (OFNOTIFY *)lParam;
\r
6763 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6764 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6773 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6774 char *nameFilt, char *dlgTitle, UINT *number,
\r
6775 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6777 OPENFILENAME openFileName;
\r
6778 char buf1[MSG_SIZ];
\r
6781 if (fileName == NULL) fileName = buf1;
\r
6782 if (defName == NULL) {
\r
6783 strcpy(fileName, "*.");
\r
6784 strcat(fileName, defExt);
\r
6786 strcpy(fileName, defName);
\r
6788 if (fileTitle) strcpy(fileTitle, "");
\r
6789 if (number) *number = 0;
\r
6791 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6792 openFileName.hwndOwner = hwnd;
\r
6793 openFileName.hInstance = (HANDLE) hInst;
\r
6794 openFileName.lpstrFilter = nameFilt;
\r
6795 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6796 openFileName.nMaxCustFilter = 0L;
\r
6797 openFileName.nFilterIndex = 1L;
\r
6798 openFileName.lpstrFile = fileName;
\r
6799 openFileName.nMaxFile = MSG_SIZ;
\r
6800 openFileName.lpstrFileTitle = fileTitle;
\r
6801 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6802 openFileName.lpstrInitialDir = NULL;
\r
6803 openFileName.lpstrTitle = dlgTitle;
\r
6804 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6805 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6806 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6807 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6808 openFileName.nFileOffset = 0;
\r
6809 openFileName.nFileExtension = 0;
\r
6810 openFileName.lpstrDefExt = defExt;
\r
6811 openFileName.lCustData = (LONG) number;
\r
6812 openFileName.lpfnHook = oldDialog ?
\r
6813 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6814 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6816 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6817 GetOpenFileName(&openFileName)) {
\r
6818 /* open the file */
\r
6819 f = fopen(openFileName.lpstrFile, write);
\r
6821 MessageBox(hwnd, "File open failed", NULL,
\r
6822 MB_OK|MB_ICONEXCLAMATION);
\r
6826 int err = CommDlgExtendedError();
\r
6827 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6836 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6838 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6841 * Get the first pop-up menu in the menu template. This is the
\r
6842 * menu that TrackPopupMenu displays.
\r
6844 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6846 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6849 * TrackPopup uses screen coordinates, so convert the
\r
6850 * coordinates of the mouse click to screen coordinates.
\r
6852 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6854 /* Draw and track the floating pop-up menu. */
\r
6855 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6856 pt.x, pt.y, 0, hwnd, NULL);
\r
6858 /* Destroy the menu.*/
\r
6859 DestroyMenu(hmenu);
\r
6864 int sizeX, sizeY, newSizeX, newSizeY;
\r
6866 } ResizeEditPlusButtonsClosure;
\r
6869 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6871 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6875 if (hChild == cl->hText) return TRUE;
\r
6876 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6877 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6878 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6879 ScreenToClient(cl->hDlg, &pt);
\r
6880 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6881 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6885 /* Resize a dialog that has a (rich) edit field filling most of
\r
6886 the top, with a row of buttons below */
\r
6888 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6891 int newTextHeight, newTextWidth;
\r
6892 ResizeEditPlusButtonsClosure cl;
\r
6894 /*if (IsIconic(hDlg)) return;*/
\r
6895 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6897 cl.hdwp = BeginDeferWindowPos(8);
\r
6899 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6900 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6901 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6902 if (newTextHeight < 0) {
\r
6903 newSizeY += -newTextHeight;
\r
6904 newTextHeight = 0;
\r
6906 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6907 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6913 cl.newSizeX = newSizeX;
\r
6914 cl.newSizeY = newSizeY;
\r
6915 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6917 EndDeferWindowPos(cl.hdwp);
\r
6920 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6922 RECT rChild, rParent;
\r
6923 int wChild, hChild, wParent, hParent;
\r
6924 int wScreen, hScreen, xNew, yNew;
\r
6927 /* Get the Height and Width of the child window */
\r
6928 GetWindowRect (hwndChild, &rChild);
\r
6929 wChild = rChild.right - rChild.left;
\r
6930 hChild = rChild.bottom - rChild.top;
\r
6932 /* Get the Height and Width of the parent window */
\r
6933 GetWindowRect (hwndParent, &rParent);
\r
6934 wParent = rParent.right - rParent.left;
\r
6935 hParent = rParent.bottom - rParent.top;
\r
6937 /* Get the display limits */
\r
6938 hdc = GetDC (hwndChild);
\r
6939 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6940 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6941 ReleaseDC(hwndChild, hdc);
\r
6943 /* Calculate new X position, then adjust for screen */
\r
6944 xNew = rParent.left + ((wParent - wChild) /2);
\r
6947 } else if ((xNew+wChild) > wScreen) {
\r
6948 xNew = wScreen - wChild;
\r
6951 /* Calculate new Y position, then adjust for screen */
\r
6953 yNew = rParent.top + ((hParent - hChild) /2);
\r
6956 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6961 } else if ((yNew+hChild) > hScreen) {
\r
6962 yNew = hScreen - hChild;
\r
6965 /* Set it, and return */
\r
6966 return SetWindowPos (hwndChild, NULL,
\r
6967 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6970 /* Center one window over another */
\r
6971 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6973 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6976 /*---------------------------------------------------------------------------*\
\r
6978 * Startup Dialog functions
\r
6980 \*---------------------------------------------------------------------------*/
\r
6982 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6984 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6986 while (*cd != NULL) {
\r
6987 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6993 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6995 char buf1[ARG_MAX];
\r
6998 if (str[0] == '@') {
\r
6999 FILE* f = fopen(str + 1, "r");
\r
7001 DisplayFatalError(str + 1, errno, 2);
\r
7004 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
7006 buf1[len] = NULLCHAR;
\r
7010 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7013 char buf[MSG_SIZ];
\r
7014 char *end = strchr(str, '\n');
\r
7015 if (end == NULL) return;
\r
7016 memcpy(buf, str, end - str);
\r
7017 buf[end - str] = NULLCHAR;
\r
7018 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7024 SetStartupDialogEnables(HWND hDlg)
\r
7026 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7027 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7028 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7029 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7030 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7031 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7032 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7033 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7034 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7035 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7036 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7037 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7038 IsDlgButtonChecked(hDlg, OPT_View));
\r
7042 QuoteForFilename(char *filename)
\r
7044 int dquote, space;
\r
7045 dquote = strchr(filename, '"') != NULL;
\r
7046 space = strchr(filename, ' ') != NULL;
\r
7047 if (dquote || space) {
\r
7059 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7061 char buf[MSG_SIZ];
\r
7064 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7065 q = QuoteForFilename(nthcp);
\r
7066 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7067 if (*nthdir != NULLCHAR) {
\r
7068 q = QuoteForFilename(nthdir);
\r
7069 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7071 if (*nthcp == NULLCHAR) {
\r
7072 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7073 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7074 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7075 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7080 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7082 char buf[MSG_SIZ];
\r
7086 switch (message) {
\r
7087 case WM_INITDIALOG:
\r
7088 /* Center the dialog */
\r
7089 CenterWindow (hDlg, GetDesktopWindow());
\r
7090 /* Initialize the dialog items */
\r
7091 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7092 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7093 firstChessProgramNames);
\r
7094 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7095 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7096 secondChessProgramNames);
\r
7097 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7098 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7099 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7100 if (*appData.icsHelper != NULLCHAR) {
\r
7101 char *q = QuoteForFilename(appData.icsHelper);
\r
7102 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7104 if (*appData.icsHost == NULLCHAR) {
\r
7105 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7106 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7107 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7108 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7109 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7112 if (appData.icsActive) {
\r
7113 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7115 else if (appData.noChessProgram) {
\r
7116 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7119 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7122 SetStartupDialogEnables(hDlg);
\r
7126 switch (LOWORD(wParam)) {
\r
7128 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7129 strcpy(buf, "/fcp=");
\r
7130 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7132 ParseArgs(StringGet, &p);
\r
7133 strcpy(buf, "/scp=");
\r
7134 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7136 ParseArgs(StringGet, &p);
\r
7137 appData.noChessProgram = FALSE;
\r
7138 appData.icsActive = FALSE;
\r
7139 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7140 strcpy(buf, "/ics /icshost=");
\r
7141 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7143 ParseArgs(StringGet, &p);
\r
7144 if (appData.zippyPlay) {
\r
7145 strcpy(buf, "/fcp=");
\r
7146 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7148 ParseArgs(StringGet, &p);
\r
7150 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7151 appData.noChessProgram = TRUE;
\r
7152 appData.icsActive = FALSE;
\r
7154 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7155 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7158 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7159 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7161 ParseArgs(StringGet, &p);
\r
7163 EndDialog(hDlg, TRUE);
\r
7170 case IDM_HELPCONTENTS:
\r
7171 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7172 MessageBox (GetFocus(),
\r
7173 "Unable to activate help",
\r
7174 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7179 SetStartupDialogEnables(hDlg);
\r
7187 /*---------------------------------------------------------------------------*\
\r
7189 * About box dialog functions
\r
7191 \*---------------------------------------------------------------------------*/
\r
7193 /* Process messages for "About" dialog box */
\r
7195 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7197 switch (message) {
\r
7198 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7199 /* Center the dialog over the application window */
\r
7200 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7201 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7205 case WM_COMMAND: /* message: received a command */
\r
7206 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7207 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7208 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7216 /*---------------------------------------------------------------------------*\
\r
7218 * Comment Dialog functions
\r
7220 \*---------------------------------------------------------------------------*/
\r
7223 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7225 static HANDLE hwndText = NULL;
\r
7226 int len, newSizeX, newSizeY, flags;
\r
7227 static int sizeX, sizeY;
\r
7232 switch (message) {
\r
7233 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7234 /* Initialize the dialog items */
\r
7235 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7236 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7237 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7238 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7239 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7240 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7241 SetWindowText(hDlg, commentTitle);
\r
7242 if (editComment) {
\r
7243 SetFocus(hwndText);
\r
7245 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7247 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7248 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7249 MAKELPARAM(FALSE, 0));
\r
7250 /* Size and position the dialog */
\r
7251 if (!commentDialog) {
\r
7252 commentDialog = hDlg;
\r
7253 flags = SWP_NOZORDER;
\r
7254 GetClientRect(hDlg, &rect);
\r
7255 sizeX = rect.right;
\r
7256 sizeY = rect.bottom;
\r
7257 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7258 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7259 WINDOWPLACEMENT wp;
\r
7260 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7261 wp.length = sizeof(WINDOWPLACEMENT);
\r
7263 wp.showCmd = SW_SHOW;
\r
7264 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7265 wp.rcNormalPosition.left = commentX;
\r
7266 wp.rcNormalPosition.right = commentX + commentW;
\r
7267 wp.rcNormalPosition.top = commentY;
\r
7268 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7269 SetWindowPlacement(hDlg, &wp);
\r
7271 GetClientRect(hDlg, &rect);
\r
7272 newSizeX = rect.right;
\r
7273 newSizeY = rect.bottom;
\r
7274 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7275 newSizeX, newSizeY);
\r
7282 case WM_COMMAND: /* message: received a command */
\r
7283 switch (LOWORD(wParam)) {
\r
7285 if (editComment) {
\r
7287 /* Read changed options from the dialog box */
\r
7288 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7289 len = GetWindowTextLength(hwndText);
\r
7290 str = (char *) malloc(len + 1);
\r
7291 GetWindowText(hwndText, str, len + 1);
\r
7300 ReplaceComment(commentIndex, str);
\r
7307 case OPT_CancelComment:
\r
7311 case OPT_ClearComment:
\r
7312 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7315 case OPT_EditComment:
\r
7316 EditCommentEvent();
\r
7325 newSizeX = LOWORD(lParam);
\r
7326 newSizeY = HIWORD(lParam);
\r
7327 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7332 case WM_GETMINMAXINFO:
\r
7333 /* Prevent resizing window too small */
\r
7334 mmi = (MINMAXINFO *) lParam;
\r
7335 mmi->ptMinTrackSize.x = 100;
\r
7336 mmi->ptMinTrackSize.y = 100;
\r
7343 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7348 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7350 if (str == NULL) str = "";
\r
7351 p = (char *) malloc(2 * strlen(str) + 2);
\r
7354 if (*str == '\n') *q++ = '\r';
\r
7358 if (commentText != NULL) free(commentText);
\r
7360 commentIndex = index;
\r
7361 commentTitle = title;
\r
7363 editComment = edit;
\r
7365 if (commentDialog) {
\r
7366 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7367 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7369 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7370 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7371 hwndMain, (DLGPROC)lpProc);
\r
7372 FreeProcInstance(lpProc);
\r
7374 commentDialogUp = TRUE;
\r
7378 /*---------------------------------------------------------------------------*\
\r
7380 * Type-in move dialog functions
\r
7382 \*---------------------------------------------------------------------------*/
\r
7385 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7387 char move[MSG_SIZ];
\r
7389 ChessMove moveType;
\r
7390 int fromX, fromY, toX, toY;
\r
7393 switch (message) {
\r
7394 case WM_INITDIALOG:
\r
7395 move[0] = (char) lParam;
\r
7396 move[1] = NULLCHAR;
\r
7397 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7398 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7399 SetWindowText(hInput, move);
\r
7401 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7405 switch (LOWORD(wParam)) {
\r
7407 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7408 { int n; Board board;
\r
7410 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7411 EditPositionPasteFEN(move);
\r
7412 EndDialog(hDlg, TRUE);
\r
7415 // [HGM] movenum: allow move number to be typed in any mode
\r
7416 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7417 currentMove = 2*n-1;
\r
7418 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7419 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7420 EndDialog(hDlg, TRUE);
\r
7421 DrawPosition(TRUE, boards[currentMove]);
\r
7422 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7423 else DisplayMessage("", "");
\r
7427 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7428 gameMode != Training) {
\r
7429 DisplayMoveError("Displayed move is not current");
\r
7431 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7432 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7433 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7434 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7435 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7436 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7437 if (gameMode != Training)
\r
7438 forwardMostMove = currentMove;
\r
7439 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7441 DisplayMoveError("Could not parse move");
\r
7444 EndDialog(hDlg, TRUE);
\r
7447 EndDialog(hDlg, FALSE);
\r
7458 PopUpMoveDialog(char firstchar)
\r
7462 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7463 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7464 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7465 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7466 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7467 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7468 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7469 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7470 gameMode == Training) {
\r
7471 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7472 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7473 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7474 FreeProcInstance(lpProc);
\r
7478 /*---------------------------------------------------------------------------*\
\r
7480 * Type-in name dialog functions
\r
7482 \*---------------------------------------------------------------------------*/
\r
7485 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7487 char move[MSG_SIZ];
\r
7490 switch (message) {
\r
7491 case WM_INITDIALOG:
\r
7492 move[0] = (char) lParam;
\r
7493 move[1] = NULLCHAR;
\r
7494 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7495 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7496 SetWindowText(hInput, move);
\r
7498 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7502 switch (LOWORD(wParam)) {
\r
7504 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7505 appData.userName = strdup(move);
\r
7508 EndDialog(hDlg, TRUE);
\r
7511 EndDialog(hDlg, FALSE);
\r
7522 PopUpNameDialog(char firstchar)
\r
7526 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7527 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7528 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7529 FreeProcInstance(lpProc);
\r
7532 /*---------------------------------------------------------------------------*\
\r
7536 \*---------------------------------------------------------------------------*/
\r
7538 /* Nonmodal error box */
\r
7539 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7540 WPARAM wParam, LPARAM lParam);
\r
7543 ErrorPopUp(char *title, char *content)
\r
7547 BOOLEAN modal = hwndMain == NULL;
\r
7565 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7566 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7569 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7571 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7572 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7573 hwndMain, (DLGPROC)lpProc);
\r
7574 FreeProcInstance(lpProc);
\r
7581 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7582 if (errorDialog == NULL) return;
\r
7583 DestroyWindow(errorDialog);
\r
7584 errorDialog = NULL;
\r
7588 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7593 switch (message) {
\r
7594 case WM_INITDIALOG:
\r
7595 GetWindowRect(hDlg, &rChild);
\r
7598 SetWindowPos(hDlg, NULL, rChild.left,
\r
7599 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7600 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7604 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7605 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7606 and it doesn't work when you resize the dialog.
\r
7607 For now, just give it a default position.
\r
7609 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7611 errorDialog = hDlg;
\r
7612 SetWindowText(hDlg, errorTitle);
\r
7613 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7614 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7618 switch (LOWORD(wParam)) {
\r
7621 if (errorDialog == hDlg) errorDialog = NULL;
\r
7622 DestroyWindow(hDlg);
\r
7634 HWND gothicDialog = NULL;
\r
7637 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7641 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7643 switch (message) {
\r
7644 case WM_INITDIALOG:
\r
7645 GetWindowRect(hDlg, &rChild);
\r
7647 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7651 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7652 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7653 and it doesn't work when you resize the dialog.
\r
7654 For now, just give it a default position.
\r
7656 gothicDialog = hDlg;
\r
7657 SetWindowText(hDlg, errorTitle);
\r
7658 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7659 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7663 switch (LOWORD(wParam)) {
\r
7666 if (errorDialog == hDlg) errorDialog = NULL;
\r
7667 DestroyWindow(hDlg);
\r
7679 GothicPopUp(char *title, VariantClass variant)
\r
7682 static char *lastTitle;
\r
7684 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7685 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7687 if(lastTitle != title && gothicDialog != NULL) {
\r
7688 DestroyWindow(gothicDialog);
\r
7689 gothicDialog = NULL;
\r
7691 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7692 title = lastTitle;
\r
7693 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7694 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7695 hwndMain, (DLGPROC)lpProc);
\r
7696 FreeProcInstance(lpProc);
\r
7701 /*---------------------------------------------------------------------------*\
\r
7703 * Ics Interaction console functions
\r
7705 \*---------------------------------------------------------------------------*/
\r
7707 #define HISTORY_SIZE 64
\r
7708 static char *history[HISTORY_SIZE];
\r
7709 int histIn = 0, histP = 0;
\r
7712 SaveInHistory(char *cmd)
\r
7714 if (history[histIn] != NULL) {
\r
7715 free(history[histIn]);
\r
7716 history[histIn] = NULL;
\r
7718 if (*cmd == NULLCHAR) return;
\r
7719 history[histIn] = StrSave(cmd);
\r
7720 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7721 if (history[histIn] != NULL) {
\r
7722 free(history[histIn]);
\r
7723 history[histIn] = NULL;
\r
7729 PrevInHistory(char *cmd)
\r
7732 if (histP == histIn) {
\r
7733 if (history[histIn] != NULL) free(history[histIn]);
\r
7734 history[histIn] = StrSave(cmd);
\r
7736 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7737 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7739 return history[histP];
\r
7745 if (histP == histIn) return NULL;
\r
7746 histP = (histP + 1) % HISTORY_SIZE;
\r
7747 return history[histP];
\r
7754 BOOLEAN immediate;
\r
7755 } IcsTextMenuEntry;
\r
7756 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7757 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7760 ParseIcsTextMenu(char *icsTextMenuString)
\r
7763 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7764 char *p = icsTextMenuString;
\r
7765 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7768 if (e->command != NULL) {
\r
7770 e->command = NULL;
\r
7774 e = icsTextMenuEntry;
\r
7775 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7776 if (*p == ';' || *p == '\n') {
\r
7777 e->item = strdup("-");
\r
7778 e->command = NULL;
\r
7780 } else if (*p == '-') {
\r
7781 e->item = strdup("-");
\r
7782 e->command = NULL;
\r
7786 char *q, *r, *s, *t;
\r
7788 q = strchr(p, ',');
\r
7789 if (q == NULL) break;
\r
7791 r = strchr(q + 1, ',');
\r
7792 if (r == NULL) break;
\r
7794 s = strchr(r + 1, ',');
\r
7795 if (s == NULL) break;
\r
7798 t = strchr(s + 1, c);
\r
7801 t = strchr(s + 1, c);
\r
7803 if (t != NULL) *t = NULLCHAR;
\r
7804 e->item = strdup(p);
\r
7805 e->command = strdup(q + 1);
\r
7806 e->getname = *(r + 1) != '0';
\r
7807 e->immediate = *(s + 1) != '0';
\r
7811 if (t == NULL) break;
\r
7820 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7824 hmenu = LoadMenu(hInst, "TextMenu");
\r
7825 h = GetSubMenu(hmenu, 0);
\r
7827 if (strcmp(e->item, "-") == 0) {
\r
7828 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7830 if (e->item[0] == '|') {
\r
7831 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7832 IDM_CommandX + i, &e->item[1]);
\r
7834 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7843 WNDPROC consoleTextWindowProc;
\r
7846 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7848 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7849 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7853 SetWindowText(hInput, command);
\r
7855 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7857 sel.cpMin = 999999;
\r
7858 sel.cpMax = 999999;
\r
7859 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7864 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7865 if (sel.cpMin == sel.cpMax) {
\r
7866 /* Expand to surrounding word */
\r
7869 tr.chrg.cpMax = sel.cpMin;
\r
7870 tr.chrg.cpMin = --sel.cpMin;
\r
7871 if (sel.cpMin < 0) break;
\r
7872 tr.lpstrText = name;
\r
7873 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7874 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7878 tr.chrg.cpMin = sel.cpMax;
\r
7879 tr.chrg.cpMax = ++sel.cpMax;
\r
7880 tr.lpstrText = name;
\r
7881 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7882 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7885 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7886 MessageBeep(MB_ICONEXCLAMATION);
\r
7890 tr.lpstrText = name;
\r
7891 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7893 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7894 MessageBeep(MB_ICONEXCLAMATION);
\r
7897 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7900 sprintf(buf, "%s %s", command, name);
\r
7901 SetWindowText(hInput, buf);
\r
7902 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7904 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7905 SetWindowText(hInput, buf);
\r
7906 sel.cpMin = 999999;
\r
7907 sel.cpMax = 999999;
\r
7908 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7914 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7919 switch (message) {
\r
7921 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7924 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7927 sel.cpMin = 999999;
\r
7928 sel.cpMax = 999999;
\r
7929 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7930 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7935 if(wParam != '\022') {
\r
7936 if (wParam == '\t') {
\r
7937 if (GetKeyState(VK_SHIFT) < 0) {
\r
7939 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7940 if (buttonDesc[0].hwnd) {
\r
7941 SetFocus(buttonDesc[0].hwnd);
\r
7943 SetFocus(hwndMain);
\r
7947 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7950 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7951 JAWS_DELETE( SetFocus(hInput); )
\r
7952 SendMessage(hInput, message, wParam, lParam);
\r
7955 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7956 case WM_RBUTTONUP:
\r
7957 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7958 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7959 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7962 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7963 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7964 if (sel.cpMin == sel.cpMax) {
\r
7965 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7966 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7968 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7969 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7971 pt.x = LOWORD(lParam);
\r
7972 pt.y = HIWORD(lParam);
\r
7973 MenuPopup(hwnd, pt, hmenu, -1);
\r
7977 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7979 return SendMessage(hInput, message, wParam, lParam);
\r
7980 case WM_MBUTTONDOWN:
\r
7981 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7982 case WM_RBUTTONDOWN:
\r
7983 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7984 /* Move selection here if it was empty */
\r
7986 pt.x = LOWORD(lParam);
\r
7987 pt.y = HIWORD(lParam);
\r
7988 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7989 if (sel.cpMin == sel.cpMax) {
\r
7990 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7991 sel.cpMax = sel.cpMin;
\r
7992 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7994 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7998 switch (LOWORD(wParam)) {
\r
7999 case IDM_QuickPaste:
\r
8001 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8002 if (sel.cpMin == sel.cpMax) {
\r
8003 MessageBeep(MB_ICONEXCLAMATION);
\r
8006 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8007 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8008 SendMessage(hInput, WM_PASTE, 0, 0);
\r
8013 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8016 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8019 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8023 int i = LOWORD(wParam) - IDM_CommandX;
\r
8024 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8025 icsTextMenuEntry[i].command != NULL) {
\r
8026 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8027 icsTextMenuEntry[i].getname,
\r
8028 icsTextMenuEntry[i].immediate);
\r
8036 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8039 WNDPROC consoleInputWindowProc;
\r
8042 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8044 char buf[MSG_SIZ];
\r
8046 static BOOL sendNextChar = FALSE;
\r
8047 static BOOL quoteNextChar = FALSE;
\r
8048 InputSource *is = consoleInputSource;
\r
8052 switch (message) {
\r
8054 if (!appData.localLineEditing || sendNextChar) {
\r
8055 is->buf[0] = (CHAR) wParam;
\r
8057 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8058 sendNextChar = FALSE;
\r
8061 if (quoteNextChar) {
\r
8062 buf[0] = (char) wParam;
\r
8063 buf[1] = NULLCHAR;
\r
8064 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8065 quoteNextChar = FALSE;
\r
8069 case '\r': /* Enter key */
\r
8070 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8071 if (consoleEcho) SaveInHistory(is->buf);
\r
8072 is->buf[is->count++] = '\n';
\r
8073 is->buf[is->count] = NULLCHAR;
\r
8074 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8075 if (consoleEcho) {
\r
8076 ConsoleOutput(is->buf, is->count, TRUE);
\r
8077 } else if (appData.localLineEditing) {
\r
8078 ConsoleOutput("\n", 1, TRUE);
\r
8081 case '\033': /* Escape key */
\r
8082 SetWindowText(hwnd, "");
\r
8083 cf.cbSize = sizeof(CHARFORMAT);
\r
8084 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8085 if (consoleEcho) {
\r
8086 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8088 cf.crTextColor = COLOR_ECHOOFF;
\r
8090 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8091 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8093 case '\t': /* Tab key */
\r
8094 if (GetKeyState(VK_SHIFT) < 0) {
\r
8096 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8099 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8100 if (buttonDesc[0].hwnd) {
\r
8101 SetFocus(buttonDesc[0].hwnd);
\r
8103 SetFocus(hwndMain);
\r
8107 case '\023': /* Ctrl+S */
\r
8108 sendNextChar = TRUE;
\r
8110 case '\021': /* Ctrl+Q */
\r
8111 quoteNextChar = TRUE;
\r
8121 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8122 p = PrevInHistory(buf);
\r
8124 SetWindowText(hwnd, p);
\r
8125 sel.cpMin = 999999;
\r
8126 sel.cpMax = 999999;
\r
8127 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8132 p = NextInHistory();
\r
8134 SetWindowText(hwnd, p);
\r
8135 sel.cpMin = 999999;
\r
8136 sel.cpMax = 999999;
\r
8137 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8143 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8147 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8151 case WM_MBUTTONDOWN:
\r
8152 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8153 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8155 case WM_RBUTTONUP:
\r
8156 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8157 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8158 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8162 hmenu = LoadMenu(hInst, "InputMenu");
\r
8163 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8164 if (sel.cpMin == sel.cpMax) {
\r
8165 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8166 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8168 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8169 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8171 pt.x = LOWORD(lParam);
\r
8172 pt.y = HIWORD(lParam);
\r
8173 MenuPopup(hwnd, pt, hmenu, -1);
\r
8177 switch (LOWORD(wParam)) {
\r
8179 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8181 case IDM_SelectAll:
\r
8183 sel.cpMax = -1; /*999999?*/
\r
8184 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8187 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8190 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8193 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8198 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8201 #define CO_MAX 100000
\r
8202 #define CO_TRIM 1000
\r
8205 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8207 static SnapData sd;
\r
8208 static HWND hText, hInput /*, hFocus*/;
\r
8209 // InputSource *is = consoleInputSource;
\r
8211 static int sizeX, sizeY;
\r
8212 int newSizeX, newSizeY;
\r
8215 switch (message) {
\r
8216 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8217 hwndConsole = hDlg;
\r
8218 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8219 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8221 consoleTextWindowProc = (WNDPROC)
\r
8222 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8223 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8224 consoleInputWindowProc = (WNDPROC)
\r
8225 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8226 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8227 Colorize(ColorNormal, TRUE);
\r
8228 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8229 ChangedConsoleFont();
\r
8230 GetClientRect(hDlg, &rect);
\r
8231 sizeX = rect.right;
\r
8232 sizeY = rect.bottom;
\r
8233 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8234 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8235 WINDOWPLACEMENT wp;
\r
8236 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8237 wp.length = sizeof(WINDOWPLACEMENT);
\r
8239 wp.showCmd = SW_SHOW;
\r
8240 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8241 wp.rcNormalPosition.left = wpConsole.x;
\r
8242 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8243 wp.rcNormalPosition.top = wpConsole.y;
\r
8244 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8245 SetWindowPlacement(hDlg, &wp);
\r
8248 // [HGM] Chessknight's change 2004-07-13
\r
8249 else { /* Determine Defaults */
\r
8250 WINDOWPLACEMENT wp;
\r
8251 wpConsole.x = winWidth + 1;
\r
8252 wpConsole.y = boardY;
\r
8253 wpConsole.width = screenWidth - winWidth;
\r
8254 wpConsole.height = winHeight;
\r
8255 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8256 wp.length = sizeof(WINDOWPLACEMENT);
\r
8258 wp.showCmd = SW_SHOW;
\r
8259 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8260 wp.rcNormalPosition.left = wpConsole.x;
\r
8261 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8262 wp.rcNormalPosition.top = wpConsole.y;
\r
8263 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8264 SetWindowPlacement(hDlg, &wp);
\r
8279 if (IsIconic(hDlg)) break;
\r
8280 newSizeX = LOWORD(lParam);
\r
8281 newSizeY = HIWORD(lParam);
\r
8282 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8283 RECT rectText, rectInput;
\r
8285 int newTextHeight, newTextWidth;
\r
8286 GetWindowRect(hText, &rectText);
\r
8287 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8288 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8289 if (newTextHeight < 0) {
\r
8290 newSizeY += -newTextHeight;
\r
8291 newTextHeight = 0;
\r
8293 SetWindowPos(hText, NULL, 0, 0,
\r
8294 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8295 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8296 pt.x = rectInput.left;
\r
8297 pt.y = rectInput.top + newSizeY - sizeY;
\r
8298 ScreenToClient(hDlg, &pt);
\r
8299 SetWindowPos(hInput, NULL,
\r
8300 pt.x, pt.y, /* needs client coords */
\r
8301 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8302 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8308 case WM_GETMINMAXINFO:
\r
8309 /* Prevent resizing window too small */
\r
8310 mmi = (MINMAXINFO *) lParam;
\r
8311 mmi->ptMinTrackSize.x = 100;
\r
8312 mmi->ptMinTrackSize.y = 100;
\r
8315 /* [AS] Snapping */
\r
8316 case WM_ENTERSIZEMOVE:
\r
8317 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8320 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8323 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8325 case WM_EXITSIZEMOVE:
\r
8326 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8329 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8337 if (hwndConsole) return;
\r
8338 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8339 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8344 ConsoleOutput(char* data, int length, int forceVisible)
\r
8349 char buf[CO_MAX+1];
\r
8352 static int delayLF = 0;
\r
8353 CHARRANGE savesel, sel;
\r
8355 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8363 while (length--) {
\r
8371 } else if (*p == '\007') {
\r
8372 MyPlaySound(&sounds[(int)SoundBell]);
\r
8379 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8380 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8381 /* Save current selection */
\r
8382 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8383 exlen = GetWindowTextLength(hText);
\r
8384 /* Find out whether current end of text is visible */
\r
8385 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8386 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8387 /* Trim existing text if it's too long */
\r
8388 if (exlen + (q - buf) > CO_MAX) {
\r
8389 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8392 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8393 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8395 savesel.cpMin -= trim;
\r
8396 savesel.cpMax -= trim;
\r
8397 if (exlen < 0) exlen = 0;
\r
8398 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8399 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8401 /* Append the new text */
\r
8402 sel.cpMin = exlen;
\r
8403 sel.cpMax = exlen;
\r
8404 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8405 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8406 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8407 if (forceVisible || exlen == 0 ||
\r
8408 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8409 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8410 /* Scroll to make new end of text visible if old end of text
\r
8411 was visible or new text is an echo of user typein */
\r
8412 sel.cpMin = 9999999;
\r
8413 sel.cpMax = 9999999;
\r
8414 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8415 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8416 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8417 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8419 if (savesel.cpMax == exlen || forceVisible) {
\r
8420 /* Move insert point to new end of text if it was at the old
\r
8421 end of text or if the new text is an echo of user typein */
\r
8422 sel.cpMin = 9999999;
\r
8423 sel.cpMax = 9999999;
\r
8424 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8426 /* Restore previous selection */
\r
8427 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8429 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8436 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8440 COLORREF oldFg, oldBg;
\r
8444 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8446 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8447 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8448 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8451 rect.right = x + squareSize;
\r
8453 rect.bottom = y + squareSize;
\r
8456 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8457 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8458 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8459 &rect, str, strlen(str), NULL);
\r
8461 (void) SetTextColor(hdc, oldFg);
\r
8462 (void) SetBkColor(hdc, oldBg);
\r
8463 (void) SelectObject(hdc, oldFont);
\r
8467 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8468 RECT *rect, char *color, char *flagFell)
\r
8472 COLORREF oldFg, oldBg;
\r
8475 if (appData.clockMode) {
\r
8477 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8479 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8486 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8487 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8489 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8490 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8492 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8496 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8497 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8498 rect, str, strlen(str), NULL);
\r
8499 if(logoHeight > 0 && appData.clockMode) {
\r
8501 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8502 r.top = rect->top + logoHeight/2;
\r
8503 r.left = rect->left;
\r
8504 r.right = rect->right;
\r
8505 r.bottom = rect->bottom;
\r
8506 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8507 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8508 &r, str, strlen(str), NULL);
\r
8510 (void) SetTextColor(hdc, oldFg);
\r
8511 (void) SetBkColor(hdc, oldBg);
\r
8512 (void) SelectObject(hdc, oldFont);
\r
8517 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8523 if( count <= 0 ) {
\r
8524 if (appData.debugMode) {
\r
8525 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8528 return ERROR_INVALID_USER_BUFFER;
\r
8531 ResetEvent(ovl->hEvent);
\r
8532 ovl->Offset = ovl->OffsetHigh = 0;
\r
8533 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8537 err = GetLastError();
\r
8538 if (err == ERROR_IO_PENDING) {
\r
8539 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8543 err = GetLastError();
\r
8550 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8555 ResetEvent(ovl->hEvent);
\r
8556 ovl->Offset = ovl->OffsetHigh = 0;
\r
8557 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8561 err = GetLastError();
\r
8562 if (err == ERROR_IO_PENDING) {
\r
8563 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8567 err = GetLastError();
\r
8573 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8574 void CheckForInputBufferFull( InputSource * is )
\r
8576 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8577 /* Look for end of line */
\r
8578 char * p = is->buf;
\r
8580 while( p < is->next && *p != '\n' ) {
\r
8584 if( p >= is->next ) {
\r
8585 if (appData.debugMode) {
\r
8586 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8589 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8590 is->count = (DWORD) -1;
\r
8591 is->next = is->buf;
\r
8597 InputThread(LPVOID arg)
\r
8602 is = (InputSource *) arg;
\r
8603 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8604 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8605 while (is->hThread != NULL) {
\r
8606 is->error = DoReadFile(is->hFile, is->next,
\r
8607 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8608 &is->count, &ovl);
\r
8609 if (is->error == NO_ERROR) {
\r
8610 is->next += is->count;
\r
8612 if (is->error == ERROR_BROKEN_PIPE) {
\r
8613 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8616 is->count = (DWORD) -1;
\r
8617 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8622 CheckForInputBufferFull( is );
\r
8624 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8626 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8628 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8631 CloseHandle(ovl.hEvent);
\r
8632 CloseHandle(is->hFile);
\r
8634 if (appData.debugMode) {
\r
8635 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8642 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8644 NonOvlInputThread(LPVOID arg)
\r
8651 is = (InputSource *) arg;
\r
8652 while (is->hThread != NULL) {
\r
8653 is->error = ReadFile(is->hFile, is->next,
\r
8654 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8655 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8656 if (is->error == NO_ERROR) {
\r
8657 /* Change CRLF to LF */
\r
8658 if (is->next > is->buf) {
\r
8660 i = is->count + 1;
\r
8668 if (prev == '\r' && *p == '\n') {
\r
8680 if (is->error == ERROR_BROKEN_PIPE) {
\r
8681 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8684 is->count = (DWORD) -1;
\r
8688 CheckForInputBufferFull( is );
\r
8690 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8692 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8694 if (is->count < 0) break; /* Quit on error */
\r
8696 CloseHandle(is->hFile);
\r
8701 SocketInputThread(LPVOID arg)
\r
8705 is = (InputSource *) arg;
\r
8706 while (is->hThread != NULL) {
\r
8707 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8708 if ((int)is->count == SOCKET_ERROR) {
\r
8709 is->count = (DWORD) -1;
\r
8710 is->error = WSAGetLastError();
\r
8712 is->error = NO_ERROR;
\r
8713 is->next += is->count;
\r
8714 if (is->count == 0 && is->second == is) {
\r
8715 /* End of file on stderr; quit with no message */
\r
8719 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8721 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8723 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8729 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8733 is = (InputSource *) lParam;
\r
8734 if (is->lineByLine) {
\r
8735 /* Feed in lines one by one */
\r
8736 char *p = is->buf;
\r
8738 while (q < is->next) {
\r
8739 if (*q++ == '\n') {
\r
8740 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8745 /* Move any partial line to the start of the buffer */
\r
8747 while (p < is->next) {
\r
8752 if (is->error != NO_ERROR || is->count == 0) {
\r
8753 /* Notify backend of the error. Note: If there was a partial
\r
8754 line at the end, it is not flushed through. */
\r
8755 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8758 /* Feed in the whole chunk of input at once */
\r
8759 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8760 is->next = is->buf;
\r
8764 /*---------------------------------------------------------------------------*\
\r
8766 * Menu enables. Used when setting various modes.
\r
8768 \*---------------------------------------------------------------------------*/
\r
8776 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8778 while (enab->item > 0) {
\r
8779 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8784 Enables gnuEnables[] = {
\r
8785 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8786 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8787 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8788 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8789 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8790 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8791 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8792 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8793 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8794 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8798 Enables icsEnables[] = {
\r
8799 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8800 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8801 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8802 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8803 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8804 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8805 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8806 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8807 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8808 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8809 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8810 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8815 Enables zippyEnables[] = {
\r
8816 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8817 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8818 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8823 Enables ncpEnables[] = {
\r
8824 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8825 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8826 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8827 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8828 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8829 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8830 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8831 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8832 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8833 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8834 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8835 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8836 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8837 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8838 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8842 Enables trainingOnEnables[] = {
\r
8843 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8844 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8845 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8846 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8847 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8848 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8849 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8850 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8854 Enables trainingOffEnables[] = {
\r
8855 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8856 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8857 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8858 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8859 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8860 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8861 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8862 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8866 /* These modify either ncpEnables or gnuEnables */
\r
8867 Enables cmailEnables[] = {
\r
8868 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8869 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8870 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8871 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8872 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8873 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8874 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8878 Enables machineThinkingEnables[] = {
\r
8879 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8880 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8881 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8882 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8883 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8884 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8885 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8886 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8887 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8888 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8889 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8890 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8891 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8892 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8893 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8897 Enables userThinkingEnables[] = {
\r
8898 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8899 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8900 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8901 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8902 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8903 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8904 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8905 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8906 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8907 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8908 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8909 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8910 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8911 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8912 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8916 /*---------------------------------------------------------------------------*\
\r
8918 * Front-end interface functions exported by XBoard.
\r
8919 * Functions appear in same order as prototypes in frontend.h.
\r
8921 \*---------------------------------------------------------------------------*/
\r
8925 static UINT prevChecked = 0;
\r
8926 static int prevPausing = 0;
\r
8929 if (pausing != prevPausing) {
\r
8930 prevPausing = pausing;
\r
8931 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8932 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8933 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8936 switch (gameMode) {
\r
8937 case BeginningOfGame:
\r
8938 if (appData.icsActive)
\r
8939 nowChecked = IDM_IcsClient;
\r
8940 else if (appData.noChessProgram)
\r
8941 nowChecked = IDM_EditGame;
\r
8943 nowChecked = IDM_MachineBlack;
\r
8945 case MachinePlaysBlack:
\r
8946 nowChecked = IDM_MachineBlack;
\r
8948 case MachinePlaysWhite:
\r
8949 nowChecked = IDM_MachineWhite;
\r
8951 case TwoMachinesPlay:
\r
8952 nowChecked = IDM_TwoMachines;
\r
8955 nowChecked = IDM_AnalysisMode;
\r
8958 nowChecked = IDM_AnalyzeFile;
\r
8961 nowChecked = IDM_EditGame;
\r
8963 case PlayFromGameFile:
\r
8964 nowChecked = IDM_LoadGame;
\r
8966 case EditPosition:
\r
8967 nowChecked = IDM_EditPosition;
\r
8970 nowChecked = IDM_Training;
\r
8972 case IcsPlayingWhite:
\r
8973 case IcsPlayingBlack:
\r
8974 case IcsObserving:
\r
8976 nowChecked = IDM_IcsClient;
\r
8983 if (prevChecked != 0)
\r
8984 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8985 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8986 if (nowChecked != 0)
\r
8987 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8988 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8990 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8991 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8992 MF_BYCOMMAND|MF_ENABLED);
\r
8994 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8995 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8998 prevChecked = nowChecked;
\r
9000 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
9001 if (appData.icsActive) {
\r
9002 if (appData.icsEngineAnalyze) {
\r
9003 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9004 MF_BYCOMMAND|MF_CHECKED);
\r
9006 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9007 MF_BYCOMMAND|MF_UNCHECKED);
\r
9015 HMENU hmenu = GetMenu(hwndMain);
\r
9016 SetMenuEnables(hmenu, icsEnables);
\r
9017 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9018 MF_BYPOSITION|MF_ENABLED);
\r
9020 if (appData.zippyPlay) {
\r
9021 SetMenuEnables(hmenu, zippyEnables);
\r
9022 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9023 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9024 MF_BYCOMMAND|MF_ENABLED);
\r
9032 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9038 HMENU hmenu = GetMenu(hwndMain);
\r
9039 SetMenuEnables(hmenu, ncpEnables);
\r
9040 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9041 MF_BYPOSITION|MF_GRAYED);
\r
9042 DrawMenuBar(hwndMain);
\r
9048 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9052 SetTrainingModeOn()
\r
9055 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9056 for (i = 0; i < N_BUTTONS; i++) {
\r
9057 if (buttonDesc[i].hwnd != NULL)
\r
9058 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9063 VOID SetTrainingModeOff()
\r
9066 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9067 for (i = 0; i < N_BUTTONS; i++) {
\r
9068 if (buttonDesc[i].hwnd != NULL)
\r
9069 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9075 SetUserThinkingEnables()
\r
9077 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9081 SetMachineThinkingEnables()
\r
9083 HMENU hMenu = GetMenu(hwndMain);
\r
9084 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9086 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9088 if (gameMode == MachinePlaysBlack) {
\r
9089 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9090 } else if (gameMode == MachinePlaysWhite) {
\r
9091 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9092 } else if (gameMode == TwoMachinesPlay) {
\r
9093 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9099 DisplayTitle(char *str)
\r
9101 char title[MSG_SIZ], *host;
\r
9102 if (str[0] != NULLCHAR) {
\r
9103 strcpy(title, str);
\r
9104 } else if (appData.icsActive) {
\r
9105 if (appData.icsCommPort[0] != NULLCHAR)
\r
9108 host = appData.icsHost;
\r
9109 sprintf(title, "%s: %s", szTitle, host);
\r
9110 } else if (appData.noChessProgram) {
\r
9111 strcpy(title, szTitle);
\r
9113 strcpy(title, szTitle);
\r
9114 strcat(title, ": ");
\r
9115 strcat(title, first.tidy);
\r
9117 SetWindowText(hwndMain, title);
\r
9122 DisplayMessage(char *str1, char *str2)
\r
9126 int remain = MESSAGE_TEXT_MAX - 1;
\r
9129 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9130 messageText[0] = NULLCHAR;
\r
9132 len = strlen(str1);
\r
9133 if (len > remain) len = remain;
\r
9134 strncpy(messageText, str1, len);
\r
9135 messageText[len] = NULLCHAR;
\r
9138 if (*str2 && remain >= 2) {
\r
9140 strcat(messageText, " ");
\r
9143 len = strlen(str2);
\r
9144 if (len > remain) len = remain;
\r
9145 strncat(messageText, str2, len);
\r
9147 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9149 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9153 hdc = GetDC(hwndMain);
\r
9154 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9155 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9156 &messageRect, messageText, strlen(messageText), NULL);
\r
9157 (void) SelectObject(hdc, oldFont);
\r
9158 (void) ReleaseDC(hwndMain, hdc);
\r
9162 DisplayError(char *str, int error)
\r
9164 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9170 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9171 NULL, error, LANG_NEUTRAL,
\r
9172 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9174 sprintf(buf, "%s:\n%s", str, buf2);
\r
9176 ErrorMap *em = errmap;
\r
9177 while (em->err != 0 && em->err != error) em++;
\r
9178 if (em->err != 0) {
\r
9179 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9181 sprintf(buf, "%s:\nError code %d", str, error);
\r
9186 ErrorPopUp("Error", buf);
\r
9191 DisplayMoveError(char *str)
\r
9193 fromX = fromY = -1;
\r
9194 ClearHighlights();
\r
9195 DrawPosition(FALSE, NULL);
\r
9196 if (appData.popupMoveErrors) {
\r
9197 ErrorPopUp("Error", str);
\r
9199 DisplayMessage(str, "");
\r
9200 moveErrorMessageUp = TRUE;
\r
9205 DisplayFatalError(char *str, int error, int exitStatus)
\r
9207 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9209 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9212 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9213 NULL, error, LANG_NEUTRAL,
\r
9214 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9216 sprintf(buf, "%s:\n%s", str, buf2);
\r
9218 ErrorMap *em = errmap;
\r
9219 while (em->err != 0 && em->err != error) em++;
\r
9220 if (em->err != 0) {
\r
9221 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9223 sprintf(buf, "%s:\nError code %d", str, error);
\r
9228 if (appData.debugMode) {
\r
9229 fprintf(debugFP, "%s: %s\n", label, str);
\r
9231 if (appData.popupExitMessage) {
\r
9232 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9233 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9235 ExitEvent(exitStatus);
\r
9240 DisplayInformation(char *str)
\r
9242 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9247 DisplayNote(char *str)
\r
9249 ErrorPopUp("Note", str);
\r
9254 char *title, *question, *replyPrefix;
\r
9259 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9261 static QuestionParams *qp;
\r
9262 char reply[MSG_SIZ];
\r
9265 switch (message) {
\r
9266 case WM_INITDIALOG:
\r
9267 qp = (QuestionParams *) lParam;
\r
9268 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9269 SetWindowText(hDlg, qp->title);
\r
9270 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9271 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9275 switch (LOWORD(wParam)) {
\r
9277 strcpy(reply, qp->replyPrefix);
\r
9278 if (*reply) strcat(reply, " ");
\r
9279 len = strlen(reply);
\r
9280 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9281 strcat(reply, "\n");
\r
9282 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9283 EndDialog(hDlg, TRUE);
\r
9284 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9287 EndDialog(hDlg, FALSE);
\r
9298 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9300 QuestionParams qp;
\r
9304 qp.question = question;
\r
9305 qp.replyPrefix = replyPrefix;
\r
9307 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9308 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9309 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9310 FreeProcInstance(lpProc);
\r
9313 /* [AS] Pick FRC position */
\r
9314 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9316 static int * lpIndexFRC;
\r
9322 case WM_INITDIALOG:
\r
9323 lpIndexFRC = (int *) lParam;
\r
9325 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9327 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9328 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9329 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9330 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9335 switch( LOWORD(wParam) ) {
\r
9337 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9338 EndDialog( hDlg, 0 );
\r
9339 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9342 EndDialog( hDlg, 1 );
\r
9344 case IDC_NFG_Edit:
\r
9345 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9346 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9348 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9351 case IDC_NFG_Random:
\r
9352 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9353 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9366 int index = appData.defaultFrcPosition;
\r
9367 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9369 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9371 if( result == 0 ) {
\r
9372 appData.defaultFrcPosition = index;
\r
9378 /* [AS] Game list options */
\r
9384 static GLT_Item GLT_ItemInfo[] = {
\r
9385 { GLT_EVENT, "Event" },
\r
9386 { GLT_SITE, "Site" },
\r
9387 { GLT_DATE, "Date" },
\r
9388 { GLT_ROUND, "Round" },
\r
9389 { GLT_PLAYERS, "Players" },
\r
9390 { GLT_RESULT, "Result" },
\r
9391 { GLT_WHITE_ELO, "White Rating" },
\r
9392 { GLT_BLACK_ELO, "Black Rating" },
\r
9393 { GLT_TIME_CONTROL,"Time Control" },
\r
9394 { GLT_VARIANT, "Variant" },
\r
9395 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9399 const char * GLT_FindItem( char id )
\r
9401 const char * result = 0;
\r
9403 GLT_Item * list = GLT_ItemInfo;
\r
9405 while( list->id != 0 ) {
\r
9406 if( list->id == id ) {
\r
9407 result = list->name;
\r
9417 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9419 const char * name = GLT_FindItem( id );
\r
9422 if( index >= 0 ) {
\r
9423 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9426 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9431 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9435 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9438 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9442 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9444 pc = GLT_ALL_TAGS;
\r
9447 if( strchr( tags, *pc ) == 0 ) {
\r
9448 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9453 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9456 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9458 char result = '\0';
\r
9461 GLT_Item * list = GLT_ItemInfo;
\r
9463 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9464 while( list->id != 0 ) {
\r
9465 if( strcmp( list->name, name ) == 0 ) {
\r
9466 result = list->id;
\r
9477 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9479 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9480 int idx2 = idx1 + delta;
\r
9481 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9483 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9486 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9487 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9488 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9489 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9493 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9495 static char glt[64];
\r
9496 static char * lpUserGLT;
\r
9500 case WM_INITDIALOG:
\r
9501 lpUserGLT = (char *) lParam;
\r
9503 strcpy( glt, lpUserGLT );
\r
9505 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9507 /* Initialize list */
\r
9508 GLT_TagsToList( hDlg, glt );
\r
9510 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9515 switch( LOWORD(wParam) ) {
\r
9518 char * pc = lpUserGLT;
\r
9520 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9524 id = GLT_ListItemToTag( hDlg, idx );
\r
9528 } while( id != '\0' );
\r
9530 EndDialog( hDlg, 0 );
\r
9533 EndDialog( hDlg, 1 );
\r
9536 case IDC_GLT_Default:
\r
9537 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9538 GLT_TagsToList( hDlg, glt );
\r
9541 case IDC_GLT_Restore:
\r
9542 strcpy( glt, lpUserGLT );
\r
9543 GLT_TagsToList( hDlg, glt );
\r
9547 GLT_MoveSelection( hDlg, -1 );
\r
9550 case IDC_GLT_Down:
\r
9551 GLT_MoveSelection( hDlg, +1 );
\r
9561 int GameListOptions()
\r
9565 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9567 strcpy( glt, appData.gameListTags );
\r
9569 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9571 if( result == 0 ) {
\r
9572 /* [AS] Memory leak here! */
\r
9573 appData.gameListTags = strdup( glt );
\r
9581 DisplayIcsInteractionTitle(char *str)
\r
9583 char consoleTitle[MSG_SIZ];
\r
9585 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9586 SetWindowText(hwndConsole, consoleTitle);
\r
9590 DrawPosition(int fullRedraw, Board board)
\r
9592 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9599 fromX = fromY = -1;
\r
9600 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9601 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9602 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9603 dragInfo.lastpos = dragInfo.pos;
\r
9604 dragInfo.start.x = dragInfo.start.y = -1;
\r
9605 dragInfo.from = dragInfo.start;
\r
9607 DrawPosition(TRUE, NULL);
\r
9613 CommentPopUp(char *title, char *str)
\r
9615 HWND hwnd = GetActiveWindow();
\r
9616 EitherCommentPopUp(0, title, str, FALSE);
\r
9617 SetActiveWindow(hwnd);
\r
9621 CommentPopDown(void)
\r
9623 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9624 if (commentDialog) {
\r
9625 ShowWindow(commentDialog, SW_HIDE);
\r
9627 commentDialogUp = FALSE;
\r
9631 EditCommentPopUp(int index, char *title, char *str)
\r
9633 EitherCommentPopUp(index, title, str, TRUE);
\r
9640 MyPlaySound(&sounds[(int)SoundMove]);
\r
9643 VOID PlayIcsWinSound()
\r
9645 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9648 VOID PlayIcsLossSound()
\r
9650 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9653 VOID PlayIcsDrawSound()
\r
9655 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9658 VOID PlayIcsUnfinishedSound()
\r
9660 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9666 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9674 consoleEcho = TRUE;
\r
9675 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9676 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9677 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9686 consoleEcho = FALSE;
\r
9687 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9688 /* This works OK: set text and background both to the same color */
\r
9690 cf.crTextColor = COLOR_ECHOOFF;
\r
9691 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9692 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9695 /* No Raw()...? */
\r
9697 void Colorize(ColorClass cc, int continuation)
\r
9699 currentColorClass = cc;
\r
9700 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9701 consoleCF.crTextColor = textAttribs[cc].color;
\r
9702 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9703 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9709 static char buf[MSG_SIZ];
\r
9710 DWORD bufsiz = MSG_SIZ;
\r
9712 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9713 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9715 if (!GetUserName(buf, &bufsiz)) {
\r
9716 /*DisplayError("Error getting user name", GetLastError());*/
\r
9717 strcpy(buf, "User");
\r
9725 static char buf[MSG_SIZ];
\r
9726 DWORD bufsiz = MSG_SIZ;
\r
9728 if (!GetComputerName(buf, &bufsiz)) {
\r
9729 /*DisplayError("Error getting host name", GetLastError());*/
\r
9730 strcpy(buf, "Unknown");
\r
9737 ClockTimerRunning()
\r
9739 return clockTimerEvent != 0;
\r
9745 if (clockTimerEvent == 0) return FALSE;
\r
9746 KillTimer(hwndMain, clockTimerEvent);
\r
9747 clockTimerEvent = 0;
\r
9752 StartClockTimer(long millisec)
\r
9754 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9755 (UINT) millisec, NULL);
\r
9759 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9762 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9764 if(appData.noGUI) return;
\r
9765 hdc = GetDC(hwndMain);
\r
9766 if (!IsIconic(hwndMain)) {
\r
9767 DisplayAClock(hdc, timeRemaining, highlight,
\r
9768 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9770 if (highlight && iconCurrent == iconBlack) {
\r
9771 iconCurrent = iconWhite;
\r
9772 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9773 if (IsIconic(hwndMain)) {
\r
9774 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9777 (void) ReleaseDC(hwndMain, hdc);
\r
9779 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9783 DisplayBlackClock(long timeRemaining, int highlight)
\r
9786 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9788 if(appData.noGUI) return;
\r
9789 hdc = GetDC(hwndMain);
\r
9790 if (!IsIconic(hwndMain)) {
\r
9791 DisplayAClock(hdc, timeRemaining, highlight,
\r
9792 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9794 if (highlight && iconCurrent == iconWhite) {
\r
9795 iconCurrent = iconBlack;
\r
9796 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9797 if (IsIconic(hwndMain)) {
\r
9798 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9801 (void) ReleaseDC(hwndMain, hdc);
\r
9803 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9808 LoadGameTimerRunning()
\r
9810 return loadGameTimerEvent != 0;
\r
9814 StopLoadGameTimer()
\r
9816 if (loadGameTimerEvent == 0) return FALSE;
\r
9817 KillTimer(hwndMain, loadGameTimerEvent);
\r
9818 loadGameTimerEvent = 0;
\r
9823 StartLoadGameTimer(long millisec)
\r
9825 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9826 (UINT) millisec, NULL);
\r
9834 char fileTitle[MSG_SIZ];
\r
9836 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9837 f = OpenFileDialog(hwndMain, "a", defName,
\r
9838 appData.oldSaveStyle ? "gam" : "pgn",
\r
9840 "Save Game to File", NULL, fileTitle, NULL);
\r
9842 SaveGame(f, 0, "");
\r
9849 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9851 if (delayedTimerEvent != 0) {
\r
9852 if (appData.debugMode) {
\r
9853 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9855 KillTimer(hwndMain, delayedTimerEvent);
\r
9856 delayedTimerEvent = 0;
\r
9857 delayedTimerCallback();
\r
9859 delayedTimerCallback = cb;
\r
9860 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9861 (UINT) millisec, NULL);
\r
9864 DelayedEventCallback
\r
9867 if (delayedTimerEvent) {
\r
9868 return delayedTimerCallback;
\r
9875 CancelDelayedEvent()
\r
9877 if (delayedTimerEvent) {
\r
9878 KillTimer(hwndMain, delayedTimerEvent);
\r
9879 delayedTimerEvent = 0;
\r
9883 DWORD GetWin32Priority(int nice)
\r
9884 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9886 REALTIME_PRIORITY_CLASS 0x00000100
\r
9887 HIGH_PRIORITY_CLASS 0x00000080
\r
9888 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9889 NORMAL_PRIORITY_CLASS 0x00000020
\r
9890 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9891 IDLE_PRIORITY_CLASS 0x00000040
\r
9893 if (nice < -15) return 0x00000080;
\r
9894 if (nice < 0) return 0x00008000;
\r
9895 if (nice == 0) return 0x00000020;
\r
9896 if (nice < 15) return 0x00004000;
\r
9897 return 0x00000040;
\r
9900 /* Start a child process running the given program.
\r
9901 The process's standard output can be read from "from", and its
\r
9902 standard input can be written to "to".
\r
9903 Exit with fatal error if anything goes wrong.
\r
9904 Returns an opaque pointer that can be used to destroy the process
\r
9908 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9910 #define BUFSIZE 4096
\r
9912 HANDLE hChildStdinRd, hChildStdinWr,
\r
9913 hChildStdoutRd, hChildStdoutWr;
\r
9914 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9915 SECURITY_ATTRIBUTES saAttr;
\r
9917 PROCESS_INFORMATION piProcInfo;
\r
9918 STARTUPINFO siStartInfo;
\r
9920 char buf[MSG_SIZ];
\r
9923 if (appData.debugMode) {
\r
9924 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9929 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9930 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9931 saAttr.bInheritHandle = TRUE;
\r
9932 saAttr.lpSecurityDescriptor = NULL;
\r
9935 * The steps for redirecting child's STDOUT:
\r
9936 * 1. Create anonymous pipe to be STDOUT for child.
\r
9937 * 2. Create a noninheritable duplicate of read handle,
\r
9938 * and close the inheritable read handle.
\r
9941 /* Create a pipe for the child's STDOUT. */
\r
9942 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9943 return GetLastError();
\r
9946 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9947 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9948 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9949 FALSE, /* not inherited */
\r
9950 DUPLICATE_SAME_ACCESS);
\r
9952 return GetLastError();
\r
9954 CloseHandle(hChildStdoutRd);
\r
9957 * The steps for redirecting child's STDIN:
\r
9958 * 1. Create anonymous pipe to be STDIN for child.
\r
9959 * 2. Create a noninheritable duplicate of write handle,
\r
9960 * and close the inheritable write handle.
\r
9963 /* Create a pipe for the child's STDIN. */
\r
9964 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9965 return GetLastError();
\r
9968 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9969 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9970 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9971 FALSE, /* not inherited */
\r
9972 DUPLICATE_SAME_ACCESS);
\r
9974 return GetLastError();
\r
9976 CloseHandle(hChildStdinWr);
\r
9978 /* Arrange to (1) look in dir for the child .exe file, and
\r
9979 * (2) have dir be the child's working directory. Interpret
\r
9980 * dir relative to the directory WinBoard loaded from. */
\r
9981 GetCurrentDirectory(MSG_SIZ, buf);
\r
9982 SetCurrentDirectory(installDir);
\r
9983 SetCurrentDirectory(dir);
\r
9985 /* Now create the child process. */
\r
9987 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9988 siStartInfo.lpReserved = NULL;
\r
9989 siStartInfo.lpDesktop = NULL;
\r
9990 siStartInfo.lpTitle = NULL;
\r
9991 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9992 siStartInfo.cbReserved2 = 0;
\r
9993 siStartInfo.lpReserved2 = NULL;
\r
9994 siStartInfo.hStdInput = hChildStdinRd;
\r
9995 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9996 siStartInfo.hStdError = hChildStdoutWr;
\r
9998 fSuccess = CreateProcess(NULL,
\r
9999 cmdLine, /* command line */
\r
10000 NULL, /* process security attributes */
\r
10001 NULL, /* primary thread security attrs */
\r
10002 TRUE, /* handles are inherited */
\r
10003 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
10004 NULL, /* use parent's environment */
\r
10006 &siStartInfo, /* STARTUPINFO pointer */
\r
10007 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
10009 err = GetLastError();
\r
10010 SetCurrentDirectory(buf); /* return to prev directory */
\r
10011 if (! fSuccess) {
\r
10015 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10016 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10017 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10020 /* Close the handles we don't need in the parent */
\r
10021 CloseHandle(piProcInfo.hThread);
\r
10022 CloseHandle(hChildStdinRd);
\r
10023 CloseHandle(hChildStdoutWr);
\r
10025 /* Prepare return value */
\r
10026 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10027 cp->kind = CPReal;
\r
10028 cp->hProcess = piProcInfo.hProcess;
\r
10029 cp->pid = piProcInfo.dwProcessId;
\r
10030 cp->hFrom = hChildStdoutRdDup;
\r
10031 cp->hTo = hChildStdinWrDup;
\r
10033 *pr = (void *) cp;
\r
10035 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10036 2000 where engines sometimes don't see the initial command(s)
\r
10037 from WinBoard and hang. I don't understand how that can happen,
\r
10038 but the Sleep is harmless, so I've put it in. Others have also
\r
10039 reported what may be the same problem, so hopefully this will fix
\r
10040 it for them too. */
\r
10048 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10050 ChildProc *cp; int result;
\r
10052 cp = (ChildProc *) pr;
\r
10053 if (cp == NULL) return;
\r
10055 switch (cp->kind) {
\r
10057 /* TerminateProcess is considered harmful, so... */
\r
10058 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10059 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10060 /* The following doesn't work because the chess program
\r
10061 doesn't "have the same console" as WinBoard. Maybe
\r
10062 we could arrange for this even though neither WinBoard
\r
10063 nor the chess program uses a console for stdio? */
\r
10064 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10066 /* [AS] Special termination modes for misbehaving programs... */
\r
10067 if( signal == 9 ) {
\r
10068 result = TerminateProcess( cp->hProcess, 0 );
\r
10070 if ( appData.debugMode) {
\r
10071 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10074 else if( signal == 10 ) {
\r
10075 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10077 if( dw != WAIT_OBJECT_0 ) {
\r
10078 result = TerminateProcess( cp->hProcess, 0 );
\r
10080 if ( appData.debugMode) {
\r
10081 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10087 CloseHandle(cp->hProcess);
\r
10091 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10095 closesocket(cp->sock);
\r
10100 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10101 closesocket(cp->sock);
\r
10102 closesocket(cp->sock2);
\r
10110 InterruptChildProcess(ProcRef pr)
\r
10114 cp = (ChildProc *) pr;
\r
10115 if (cp == NULL) return;
\r
10116 switch (cp->kind) {
\r
10118 /* The following doesn't work because the chess program
\r
10119 doesn't "have the same console" as WinBoard. Maybe
\r
10120 we could arrange for this even though neither WinBoard
\r
10121 nor the chess program uses a console for stdio */
\r
10122 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10127 /* Can't interrupt */
\r
10131 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10138 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10140 char cmdLine[MSG_SIZ];
\r
10142 if (port[0] == NULLCHAR) {
\r
10143 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10145 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10147 return StartChildProcess(cmdLine, "", pr);
\r
10151 /* Code to open TCP sockets */
\r
10154 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10159 struct sockaddr_in sa, mysa;
\r
10160 struct hostent FAR *hp;
\r
10161 unsigned short uport;
\r
10162 WORD wVersionRequested;
\r
10165 /* Initialize socket DLL */
\r
10166 wVersionRequested = MAKEWORD(1, 1);
\r
10167 err = WSAStartup(wVersionRequested, &wsaData);
\r
10168 if (err != 0) return err;
\r
10170 /* Make socket */
\r
10171 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10172 err = WSAGetLastError();
\r
10177 /* Bind local address using (mostly) don't-care values.
\r
10179 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10180 mysa.sin_family = AF_INET;
\r
10181 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10182 uport = (unsigned short) 0;
\r
10183 mysa.sin_port = htons(uport);
\r
10184 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10185 == SOCKET_ERROR) {
\r
10186 err = WSAGetLastError();
\r
10191 /* Resolve remote host name */
\r
10192 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10193 if (!(hp = gethostbyname(host))) {
\r
10194 unsigned int b0, b1, b2, b3;
\r
10196 err = WSAGetLastError();
\r
10198 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10199 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10200 hp->h_addrtype = AF_INET;
\r
10201 hp->h_length = 4;
\r
10202 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10203 hp->h_addr_list[0] = (char *) malloc(4);
\r
10204 hp->h_addr_list[0][0] = (char) b0;
\r
10205 hp->h_addr_list[0][1] = (char) b1;
\r
10206 hp->h_addr_list[0][2] = (char) b2;
\r
10207 hp->h_addr_list[0][3] = (char) b3;
\r
10213 sa.sin_family = hp->h_addrtype;
\r
10214 uport = (unsigned short) atoi(port);
\r
10215 sa.sin_port = htons(uport);
\r
10216 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10218 /* Make connection */
\r
10219 if (connect(s, (struct sockaddr *) &sa,
\r
10220 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10221 err = WSAGetLastError();
\r
10226 /* Prepare return value */
\r
10227 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10228 cp->kind = CPSock;
\r
10230 *pr = (ProcRef *) cp;
\r
10236 OpenCommPort(char *name, ProcRef *pr)
\r
10241 char fullname[MSG_SIZ];
\r
10243 if (*name != '\\')
\r
10244 sprintf(fullname, "\\\\.\\%s", name);
\r
10246 strcpy(fullname, name);
\r
10248 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10249 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10250 if (h == (HANDLE) -1) {
\r
10251 return GetLastError();
\r
10255 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10257 /* Accumulate characters until a 100ms pause, then parse */
\r
10258 ct.ReadIntervalTimeout = 100;
\r
10259 ct.ReadTotalTimeoutMultiplier = 0;
\r
10260 ct.ReadTotalTimeoutConstant = 0;
\r
10261 ct.WriteTotalTimeoutMultiplier = 0;
\r
10262 ct.WriteTotalTimeoutConstant = 0;
\r
10263 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10265 /* Prepare return value */
\r
10266 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10267 cp->kind = CPComm;
\r
10270 *pr = (ProcRef *) cp;
\r
10276 OpenLoopback(ProcRef *pr)
\r
10278 DisplayFatalError("Not implemented", 0, 1);
\r
10284 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10288 SOCKET s, s2, s3;
\r
10289 struct sockaddr_in sa, mysa;
\r
10290 struct hostent FAR *hp;
\r
10291 unsigned short uport;
\r
10292 WORD wVersionRequested;
\r
10295 char stderrPortStr[MSG_SIZ];
\r
10297 /* Initialize socket DLL */
\r
10298 wVersionRequested = MAKEWORD(1, 1);
\r
10299 err = WSAStartup(wVersionRequested, &wsaData);
\r
10300 if (err != 0) return err;
\r
10302 /* Resolve remote host name */
\r
10303 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10304 if (!(hp = gethostbyname(host))) {
\r
10305 unsigned int b0, b1, b2, b3;
\r
10307 err = WSAGetLastError();
\r
10309 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10310 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10311 hp->h_addrtype = AF_INET;
\r
10312 hp->h_length = 4;
\r
10313 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10314 hp->h_addr_list[0] = (char *) malloc(4);
\r
10315 hp->h_addr_list[0][0] = (char) b0;
\r
10316 hp->h_addr_list[0][1] = (char) b1;
\r
10317 hp->h_addr_list[0][2] = (char) b2;
\r
10318 hp->h_addr_list[0][3] = (char) b3;
\r
10324 sa.sin_family = hp->h_addrtype;
\r
10325 uport = (unsigned short) 514;
\r
10326 sa.sin_port = htons(uport);
\r
10327 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10329 /* Bind local socket to unused "privileged" port address
\r
10331 s = INVALID_SOCKET;
\r
10332 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10333 mysa.sin_family = AF_INET;
\r
10334 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10335 for (fromPort = 1023;; fromPort--) {
\r
10336 if (fromPort < 0) {
\r
10338 return WSAEADDRINUSE;
\r
10340 if (s == INVALID_SOCKET) {
\r
10341 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10342 err = WSAGetLastError();
\r
10347 uport = (unsigned short) fromPort;
\r
10348 mysa.sin_port = htons(uport);
\r
10349 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10350 == SOCKET_ERROR) {
\r
10351 err = WSAGetLastError();
\r
10352 if (err == WSAEADDRINUSE) continue;
\r
10356 if (connect(s, (struct sockaddr *) &sa,
\r
10357 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10358 err = WSAGetLastError();
\r
10359 if (err == WSAEADDRINUSE) {
\r
10370 /* Bind stderr local socket to unused "privileged" port address
\r
10372 s2 = INVALID_SOCKET;
\r
10373 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10374 mysa.sin_family = AF_INET;
\r
10375 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10376 for (fromPort = 1023;; fromPort--) {
\r
10377 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10378 if (fromPort < 0) {
\r
10379 (void) closesocket(s);
\r
10381 return WSAEADDRINUSE;
\r
10383 if (s2 == INVALID_SOCKET) {
\r
10384 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10385 err = WSAGetLastError();
\r
10391 uport = (unsigned short) fromPort;
\r
10392 mysa.sin_port = htons(uport);
\r
10393 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10394 == SOCKET_ERROR) {
\r
10395 err = WSAGetLastError();
\r
10396 if (err == WSAEADDRINUSE) continue;
\r
10397 (void) closesocket(s);
\r
10401 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10402 err = WSAGetLastError();
\r
10403 if (err == WSAEADDRINUSE) {
\r
10405 s2 = INVALID_SOCKET;
\r
10408 (void) closesocket(s);
\r
10409 (void) closesocket(s2);
\r
10415 prevStderrPort = fromPort; // remember port used
\r
10416 sprintf(stderrPortStr, "%d", fromPort);
\r
10418 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10419 err = WSAGetLastError();
\r
10420 (void) closesocket(s);
\r
10421 (void) closesocket(s2);
\r
10426 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10427 err = WSAGetLastError();
\r
10428 (void) closesocket(s);
\r
10429 (void) closesocket(s2);
\r
10433 if (*user == NULLCHAR) user = UserName();
\r
10434 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10435 err = WSAGetLastError();
\r
10436 (void) closesocket(s);
\r
10437 (void) closesocket(s2);
\r
10441 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10442 err = WSAGetLastError();
\r
10443 (void) closesocket(s);
\r
10444 (void) closesocket(s2);
\r
10449 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10450 err = WSAGetLastError();
\r
10451 (void) closesocket(s);
\r
10452 (void) closesocket(s2);
\r
10456 (void) closesocket(s2); /* Stop listening */
\r
10458 /* Prepare return value */
\r
10459 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10460 cp->kind = CPRcmd;
\r
10463 *pr = (ProcRef *) cp;
\r
10470 AddInputSource(ProcRef pr, int lineByLine,
\r
10471 InputCallback func, VOIDSTAR closure)
\r
10473 InputSource *is, *is2 = NULL;
\r
10474 ChildProc *cp = (ChildProc *) pr;
\r
10476 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10477 is->lineByLine = lineByLine;
\r
10479 is->closure = closure;
\r
10480 is->second = NULL;
\r
10481 is->next = is->buf;
\r
10482 if (pr == NoProc) {
\r
10483 is->kind = CPReal;
\r
10484 consoleInputSource = is;
\r
10486 is->kind = cp->kind;
\r
10488 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10489 we create all threads suspended so that the is->hThread variable can be
\r
10490 safely assigned, then let the threads start with ResumeThread.
\r
10492 switch (cp->kind) {
\r
10494 is->hFile = cp->hFrom;
\r
10495 cp->hFrom = NULL; /* now owned by InputThread */
\r
10497 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10498 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10502 is->hFile = cp->hFrom;
\r
10503 cp->hFrom = NULL; /* now owned by InputThread */
\r
10505 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10506 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10510 is->sock = cp->sock;
\r
10512 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10513 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10517 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10519 is->sock = cp->sock;
\r
10520 is->second = is2;
\r
10521 is2->sock = cp->sock2;
\r
10522 is2->second = is2;
\r
10524 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10525 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10527 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10528 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10532 if( is->hThread != NULL ) {
\r
10533 ResumeThread( is->hThread );
\r
10536 if( is2 != NULL && is2->hThread != NULL ) {
\r
10537 ResumeThread( is2->hThread );
\r
10541 return (InputSourceRef) is;
\r
10545 RemoveInputSource(InputSourceRef isr)
\r
10549 is = (InputSource *) isr;
\r
10550 is->hThread = NULL; /* tell thread to stop */
\r
10551 CloseHandle(is->hThread);
\r
10552 if (is->second != NULL) {
\r
10553 is->second->hThread = NULL;
\r
10554 CloseHandle(is->second->hThread);
\r
10560 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10563 int outCount = SOCKET_ERROR;
\r
10564 ChildProc *cp = (ChildProc *) pr;
\r
10565 static OVERLAPPED ovl;
\r
10567 if (pr == NoProc) {
\r
10568 ConsoleOutput(message, count, FALSE);
\r
10572 if (ovl.hEvent == NULL) {
\r
10573 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10575 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10577 switch (cp->kind) {
\r
10580 outCount = send(cp->sock, message, count, 0);
\r
10581 if (outCount == SOCKET_ERROR) {
\r
10582 *outError = WSAGetLastError();
\r
10584 *outError = NO_ERROR;
\r
10589 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10590 &dOutCount, NULL)) {
\r
10591 *outError = NO_ERROR;
\r
10592 outCount = (int) dOutCount;
\r
10594 *outError = GetLastError();
\r
10599 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10600 &dOutCount, &ovl);
\r
10601 if (*outError == NO_ERROR) {
\r
10602 outCount = (int) dOutCount;
\r
10610 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10613 /* Ignore delay, not implemented for WinBoard */
\r
10614 return OutputToProcess(pr, message, count, outError);
\r
10619 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10620 char *buf, int count, int error)
\r
10622 DisplayFatalError("Not implemented", 0, 1);
\r
10625 /* see wgamelist.c for Game List functions */
\r
10626 /* see wedittags.c for Edit Tags functions */
\r
10633 char buf[MSG_SIZ];
\r
10636 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10637 f = fopen(buf, "r");
\r
10639 ProcessICSInitScript(f);
\r
10647 StartAnalysisClock()
\r
10649 if (analysisTimerEvent) return;
\r
10650 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10651 (UINT) 2000, NULL);
\r
10655 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10657 static HANDLE hwndText;
\r
10659 static int sizeX, sizeY;
\r
10660 int newSizeX, newSizeY, flags;
\r
10663 switch (message) {
\r
10664 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10665 /* Initialize the dialog items */
\r
10666 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10667 SetWindowText(hDlg, analysisTitle);
\r
10668 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10669 /* Size and position the dialog */
\r
10670 if (!analysisDialog) {
\r
10671 analysisDialog = hDlg;
\r
10672 flags = SWP_NOZORDER;
\r
10673 GetClientRect(hDlg, &rect);
\r
10674 sizeX = rect.right;
\r
10675 sizeY = rect.bottom;
\r
10676 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10677 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10678 WINDOWPLACEMENT wp;
\r
10679 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10680 wp.length = sizeof(WINDOWPLACEMENT);
\r
10682 wp.showCmd = SW_SHOW;
\r
10683 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10684 wp.rcNormalPosition.left = analysisX;
\r
10685 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10686 wp.rcNormalPosition.top = analysisY;
\r
10687 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10688 SetWindowPlacement(hDlg, &wp);
\r
10690 GetClientRect(hDlg, &rect);
\r
10691 newSizeX = rect.right;
\r
10692 newSizeY = rect.bottom;
\r
10693 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10694 newSizeX, newSizeY);
\r
10695 sizeX = newSizeX;
\r
10696 sizeY = newSizeY;
\r
10701 case WM_COMMAND: /* message: received a command */
\r
10702 switch (LOWORD(wParam)) {
\r
10704 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10705 ExitAnalyzeMode();
\r
10717 newSizeX = LOWORD(lParam);
\r
10718 newSizeY = HIWORD(lParam);
\r
10719 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10720 sizeX = newSizeX;
\r
10721 sizeY = newSizeY;
\r
10724 case WM_GETMINMAXINFO:
\r
10725 /* Prevent resizing window too small */
\r
10726 mmi = (MINMAXINFO *) lParam;
\r
10727 mmi->ptMinTrackSize.x = 100;
\r
10728 mmi->ptMinTrackSize.y = 100;
\r
10735 AnalysisPopUp(char* title, char* str)
\r
10741 EngineOutputPopUp();
\r
10744 if (str == NULL) str = "";
\r
10745 p = (char *) malloc(2 * strlen(str) + 2);
\r
10748 if (*str == '\n') *q++ = '\r';
\r
10752 if (analysisText != NULL) free(analysisText);
\r
10753 analysisText = p;
\r
10755 if (analysisDialog) {
\r
10756 SetWindowText(analysisDialog, title);
\r
10757 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10758 ShowWindow(analysisDialog, SW_SHOW);
\r
10760 analysisTitle = title;
\r
10761 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10762 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10763 hwndMain, (DLGPROC)lpProc);
\r
10764 FreeProcInstance(lpProc);
\r
10766 analysisDialogUp = TRUE;
\r
10770 AnalysisPopDown()
\r
10772 if (analysisDialog) {
\r
10773 ShowWindow(analysisDialog, SW_HIDE);
\r
10775 analysisDialogUp = FALSE;
\r
10780 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10782 highlightInfo.sq[0].x = fromX;
\r
10783 highlightInfo.sq[0].y = fromY;
\r
10784 highlightInfo.sq[1].x = toX;
\r
10785 highlightInfo.sq[1].y = toY;
\r
10789 ClearHighlights()
\r
10791 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10792 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10796 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10798 premoveHighlightInfo.sq[0].x = fromX;
\r
10799 premoveHighlightInfo.sq[0].y = fromY;
\r
10800 premoveHighlightInfo.sq[1].x = toX;
\r
10801 premoveHighlightInfo.sq[1].y = toY;
\r
10805 ClearPremoveHighlights()
\r
10807 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10808 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10812 ShutDownFrontEnd()
\r
10814 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10815 DeleteClipboardTempFiles();
\r
10821 if (IsIconic(hwndMain))
\r
10822 ShowWindow(hwndMain, SW_RESTORE);
\r
10824 SetActiveWindow(hwndMain);
\r
10828 * Prototypes for animation support routines
\r
10830 static void ScreenSquare(int column, int row, POINT * pt);
\r
10831 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10832 POINT frames[], int * nFrames);
\r
10836 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10837 { // [HGM] atomic: animate blast wave
\r
10839 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10840 explodeInfo.fromX = fromX;
\r
10841 explodeInfo.fromY = fromY;
\r
10842 explodeInfo.toX = toX;
\r
10843 explodeInfo.toY = toY;
\r
10844 for(i=1; i<nFrames; i++) {
\r
10845 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10846 DrawPosition(FALSE, NULL);
\r
10847 Sleep(appData.animSpeed);
\r
10849 explodeInfo.radius = 0;
\r
10850 DrawPosition(TRUE, NULL);
\r
10853 #define kFactor 4
\r
10856 AnimateMove(board, fromX, fromY, toX, toY)
\r
10863 ChessSquare piece;
\r
10864 POINT start, finish, mid;
\r
10865 POINT frames[kFactor * 2 + 1];
\r
10868 if (!appData.animate) return;
\r
10869 if (doingSizing) return;
\r
10870 if (fromY < 0 || fromX < 0) return;
\r
10871 piece = board[fromY][fromX];
\r
10872 if (piece >= EmptySquare) return;
\r
10874 ScreenSquare(fromX, fromY, &start);
\r
10875 ScreenSquare(toX, toY, &finish);
\r
10877 /* All pieces except knights move in straight line */
\r
10878 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10879 mid.x = start.x + (finish.x - start.x) / 2;
\r
10880 mid.y = start.y + (finish.y - start.y) / 2;
\r
10882 /* Knight: make diagonal movement then straight */
\r
10883 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10884 mid.x = start.x + (finish.x - start.x) / 2;
\r
10885 mid.y = finish.y;
\r
10887 mid.x = finish.x;
\r
10888 mid.y = start.y + (finish.y - start.y) / 2;
\r
10892 /* Don't use as many frames for very short moves */
\r
10893 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10894 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10896 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10898 animInfo.from.x = fromX;
\r
10899 animInfo.from.y = fromY;
\r
10900 animInfo.to.x = toX;
\r
10901 animInfo.to.y = toY;
\r
10902 animInfo.lastpos = start;
\r
10903 animInfo.piece = piece;
\r
10904 for (n = 0; n < nFrames; n++) {
\r
10905 animInfo.pos = frames[n];
\r
10906 DrawPosition(FALSE, NULL);
\r
10907 animInfo.lastpos = animInfo.pos;
\r
10908 Sleep(appData.animSpeed);
\r
10910 animInfo.pos = finish;
\r
10911 DrawPosition(FALSE, NULL);
\r
10912 animInfo.piece = EmptySquare;
\r
10913 if(gameInfo.variant == VariantAtomic &&
\r
10914 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10915 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10918 /* Convert board position to corner of screen rect and color */
\r
10921 ScreenSquare(column, row, pt)
\r
10922 int column; int row; POINT * pt;
\r
10925 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10926 pt->y = lineGap + row * (squareSize + lineGap);
\r
10928 pt->x = lineGap + column * (squareSize + lineGap);
\r
10929 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10933 /* Generate a series of frame coords from start->mid->finish.
\r
10934 The movement rate doubles until the half way point is
\r
10935 reached, then halves back down to the final destination,
\r
10936 which gives a nice slow in/out effect. The algorithmn
\r
10937 may seem to generate too many intermediates for short
\r
10938 moves, but remember that the purpose is to attract the
\r
10939 viewers attention to the piece about to be moved and
\r
10940 then to where it ends up. Too few frames would be less
\r
10944 Tween(start, mid, finish, factor, frames, nFrames)
\r
10945 POINT * start; POINT * mid;
\r
10946 POINT * finish; int factor;
\r
10947 POINT frames[]; int * nFrames;
\r
10949 int n, fraction = 1, count = 0;
\r
10951 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10952 for (n = 0; n < factor; n++)
\r
10954 for (n = 0; n < factor; n++) {
\r
10955 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10956 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10958 fraction = fraction / 2;
\r
10962 frames[count] = *mid;
\r
10965 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10967 for (n = 0; n < factor; n++) {
\r
10968 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10969 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10971 fraction = fraction * 2;
\r
10973 *nFrames = count;
\r
10977 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10982 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10983 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10985 OutputDebugString( buf );
\r
10988 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10990 EvalGraphSet( first, last, current, pvInfoList );
\r
10993 void SetProgramStats( FrontEndProgramStats * stats )
\r
10998 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10999 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
11001 OutputDebugString( buf );
\r
11004 EngineOutputUpdate( stats );
\r