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 6
\r
313 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
314 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
315 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
319 MySound sounds[(int)NSoundClasses];
\r
320 MyTextAttribs textAttribs[(int)NColorClasses];
\r
322 MyColorizeAttribs colorizeAttribs[] = {
\r
323 { (COLORREF)0, 0, "Shout Text" },
\r
324 { (COLORREF)0, 0, "SShout/CShout" },
\r
325 { (COLORREF)0, 0, "Channel 1 Text" },
\r
326 { (COLORREF)0, 0, "Channel Text" },
\r
327 { (COLORREF)0, 0, "Kibitz Text" },
\r
328 { (COLORREF)0, 0, "Tell Text" },
\r
329 { (COLORREF)0, 0, "Challenge Text" },
\r
330 { (COLORREF)0, 0, "Request Text" },
\r
331 { (COLORREF)0, 0, "Seek Text" },
\r
332 { (COLORREF)0, 0, "Normal Text" },
\r
333 { (COLORREF)0, 0, "None" }
\r
338 static char *commentTitle;
\r
339 static char *commentText;
\r
340 static int commentIndex;
\r
341 static Boolean editComment = FALSE;
\r
342 HWND commentDialog = NULL;
\r
343 BOOLEAN commentDialogUp = FALSE;
\r
344 static int commentX, commentY, commentH, commentW;
\r
346 static char *analysisTitle;
\r
347 static char *analysisText;
\r
348 HWND analysisDialog = NULL;
\r
349 BOOLEAN analysisDialogUp = FALSE;
\r
350 static int analysisX, analysisY, analysisH, analysisW;
\r
352 char errorTitle[MSG_SIZ];
\r
353 char errorMessage[2*MSG_SIZ];
\r
354 HWND errorDialog = NULL;
\r
355 BOOLEAN moveErrorMessageUp = FALSE;
\r
356 BOOLEAN consoleEcho = TRUE;
\r
357 CHARFORMAT consoleCF;
\r
358 COLORREF consoleBackgroundColor;
\r
360 char *programVersion;
\r
366 typedef int CPKind;
\r
375 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
378 #define INPUT_SOURCE_BUF_SIZE 4096
\r
380 typedef struct _InputSource {
\r
387 char buf[INPUT_SOURCE_BUF_SIZE];
\r
391 InputCallback func;
\r
392 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
396 InputSource *consoleInputSource;
\r
401 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
402 VOID ConsoleCreate();
\r
404 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
405 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
406 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
407 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
409 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
410 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
411 void ParseIcsTextMenu(char *icsTextMenuString);
\r
412 VOID PopUpMoveDialog(char firstchar);
\r
413 VOID PopUpNameDialog(char firstchar);
\r
414 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
418 int GameListOptions();
\r
420 HWND moveHistoryDialog = NULL;
\r
421 BOOLEAN moveHistoryDialogUp = FALSE;
\r
423 WindowPlacement wpMoveHistory;
\r
425 HWND evalGraphDialog = NULL;
\r
426 BOOLEAN evalGraphDialogUp = FALSE;
\r
428 WindowPlacement wpEvalGraph;
\r
430 HWND engineOutputDialog = NULL;
\r
431 BOOLEAN engineOutputDialogUp = FALSE;
\r
433 WindowPlacement wpEngineOutput;
\r
434 WindowPlacement wpGameList;
\r
435 WindowPlacement wpConsole;
\r
437 VOID MoveHistoryPopUp();
\r
438 VOID MoveHistoryPopDown();
\r
439 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
440 BOOL MoveHistoryIsUp();
\r
442 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
443 VOID EvalGraphPopUp();
\r
444 VOID EvalGraphPopDown();
\r
445 BOOL EvalGraphIsUp();
\r
447 VOID EngineOutputPopUp();
\r
448 VOID EngineOutputPopDown();
\r
449 BOOL EngineOutputIsUp();
\r
450 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
452 VOID GothicPopUp(char *title, VariantClass variant);
\r
454 * Setting "frozen" should disable all user input other than deleting
\r
455 * the window. We do this while engines are initializing themselves.
\r
457 static int frozen = 0;
\r
458 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
464 if (frozen) return;
\r
466 hmenu = GetMenu(hwndMain);
\r
467 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
468 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
470 DrawMenuBar(hwndMain);
\r
473 /* Undo a FreezeUI */
\r
479 if (!frozen) return;
\r
481 hmenu = GetMenu(hwndMain);
\r
482 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
483 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
485 DrawMenuBar(hwndMain);
\r
488 static int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
490 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
495 #define JAWS_ALT_INTERCEPT
\r
496 #define JAWS_KB_NAVIGATION
\r
497 #define JAWS_MENU_ITEMS
\r
498 #define JAWS_SILENCE
\r
499 #define JAWS_REPLAY
\r
500 #define JAWS_DELETE(X) X
\r
501 #define SAYMACHINEMOVE()
\r
505 /*---------------------------------------------------------------------------*\
\r
509 \*---------------------------------------------------------------------------*/
\r
512 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
513 LPSTR lpCmdLine, int nCmdShow)
\r
516 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
517 // INITCOMMONCONTROLSEX ex;
\r
521 LoadLibrary("RICHED32.DLL");
\r
522 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
524 if (!InitApplication(hInstance)) {
\r
527 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
533 // InitCommonControlsEx(&ex);
\r
534 InitCommonControls();
\r
536 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
537 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
538 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
540 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
542 while (GetMessage(&msg, /* message structure */
\r
543 NULL, /* handle of window receiving the message */
\r
544 0, /* lowest message to examine */
\r
545 0)) /* highest message to examine */
\r
548 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
549 // [HGM] navigate: switch between all windows with tab
\r
550 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
551 int i, currentElement = 0;
\r
553 // first determine what element of the chain we come from (if any)
\r
554 if(appData.icsActive) {
\r
555 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
556 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
558 if(engineOutputDialog && EngineOutputIsUp()) {
\r
559 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
560 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
562 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
563 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
565 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
566 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
567 if(msg.hwnd == e1) currentElement = 2; else
\r
568 if(msg.hwnd == e2) currentElement = 3; else
\r
569 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
570 if(msg.hwnd == mh) currentElement = 4; else
\r
571 if(msg.hwnd == evalGraphDialog) currentElement = 7; else
\r
572 if(msg.hwnd == hText) currentElement = 5; else
\r
573 if(msg.hwnd == hInput) currentElement = 6; else
\r
574 for (i = 0; i < N_BUTTONS; i++) {
\r
575 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
578 // determine where to go to
\r
579 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
581 currentElement = (currentElement + direction) % 7;
\r
582 switch(currentElement) {
\r
584 h = hwndMain; break; // passing this case always makes the loop exit
\r
586 h = buttonDesc[0].hwnd; break; // could be NULL
\r
588 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
591 if(!EngineOutputIsUp()) continue;
\r
594 if(!MoveHistoryIsUp()) continue;
\r
596 // case 5: // input to eval graph does not seem to get here!
\r
597 // if(!EvalGraphIsUp()) continue;
\r
598 // h = evalGraphDialog; break;
\r
600 if(!appData.icsActive) continue;
\r
604 if(!appData.icsActive) continue;
\r
610 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
611 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
614 continue; // this message now has been processed
\r
618 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
619 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
620 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
621 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
622 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
623 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
624 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
625 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
626 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
627 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
628 TranslateMessage(&msg); /* Translates virtual key codes */
\r
629 DispatchMessage(&msg); /* Dispatches message to window */
\r
634 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
637 /*---------------------------------------------------------------------------*\
\r
639 * Initialization functions
\r
641 \*---------------------------------------------------------------------------*/
\r
645 { // update user logo if necessary
\r
646 static char oldUserName[MSG_SIZ], *curName;
\r
648 if(appData.autoLogo) {
\r
649 curName = UserName();
\r
650 if(strcmp(curName, oldUserName)) {
\r
651 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
652 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
653 strcpy(oldUserName, curName);
\r
659 InitApplication(HINSTANCE hInstance)
\r
663 /* Fill in window class structure with parameters that describe the */
\r
666 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
667 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
668 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
669 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
670 wc.hInstance = hInstance; /* Owner of this class */
\r
671 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
672 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
673 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
674 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
675 wc.lpszClassName = szAppName; /* Name to register as */
\r
677 /* Register the window class and return success/failure code. */
\r
678 if (!RegisterClass(&wc)) return FALSE;
\r
680 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
681 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
683 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
684 wc.hInstance = hInstance;
\r
685 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
686 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
687 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
688 wc.lpszMenuName = NULL;
\r
689 wc.lpszClassName = szConsoleName;
\r
691 if (!RegisterClass(&wc)) return FALSE;
\r
696 /* Set by InitInstance, used by EnsureOnScreen */
\r
697 int screenHeight, screenWidth;
\r
700 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
702 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
703 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
704 if (*x > screenWidth - 32) *x = 0;
\r
705 if (*y > screenHeight - 32) *y = 0;
\r
706 if (*x < minX) *x = minX;
\r
707 if (*y < minY) *y = minY;
\r
711 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
713 HWND hwnd; /* Main window handle. */
\r
715 WINDOWPLACEMENT wp;
\r
718 hInst = hInstance; /* Store instance handle in our global variable */
\r
720 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
721 *filepart = NULLCHAR;
\r
723 GetCurrentDirectory(MSG_SIZ, installDir);
\r
725 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
726 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
727 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
728 if (appData.debugMode) {
\r
729 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
730 setbuf(debugFP, NULL);
\r
735 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
736 // InitEngineUCI( installDir, &second );
\r
738 /* Create a main window for this application instance. */
\r
739 hwnd = CreateWindow(szAppName, szTitle,
\r
740 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
741 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
742 NULL, NULL, hInstance, NULL);
\r
745 /* If window could not be created, return "failure" */
\r
750 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
751 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
752 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
754 if (first.programLogo == NULL && appData.debugMode) {
\r
755 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
757 } else if(appData.autoLogo) {
\r
758 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
760 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
761 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
765 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
766 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
768 if (second.programLogo == NULL && appData.debugMode) {
\r
769 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
771 } else if(appData.autoLogo) {
\r
773 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
774 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
775 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
777 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
778 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
779 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
785 iconWhite = LoadIcon(hInstance, "icon_white");
\r
786 iconBlack = LoadIcon(hInstance, "icon_black");
\r
787 iconCurrent = iconWhite;
\r
788 InitDrawingColors();
\r
789 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
790 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
791 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
792 /* Compute window size for each board size, and use the largest
\r
793 size that fits on this screen as the default. */
\r
794 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
795 if (boardSize == (BoardSize)-1 &&
\r
796 winH <= screenHeight
\r
797 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
798 && winW <= screenWidth) {
\r
799 boardSize = (BoardSize)ibs;
\r
803 InitDrawingSizes(boardSize, 0);
\r
805 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
807 /* [AS] Load textures if specified */
\r
808 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
810 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
811 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
812 liteBackTextureMode = appData.liteBackTextureMode;
\r
814 if (liteBackTexture == NULL && appData.debugMode) {
\r
815 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
819 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
820 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
821 darkBackTextureMode = appData.darkBackTextureMode;
\r
823 if (darkBackTexture == NULL && appData.debugMode) {
\r
824 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
828 mysrandom( (unsigned) time(NULL) );
\r
830 /* [AS] Restore layout */
\r
831 if( wpMoveHistory.visible ) {
\r
832 MoveHistoryPopUp();
\r
835 if( wpEvalGraph.visible ) {
\r
839 if( wpEngineOutput.visible ) {
\r
840 EngineOutputPopUp();
\r
845 /* Make the window visible; update its client area; and return "success" */
\r
846 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
847 wp.length = sizeof(WINDOWPLACEMENT);
\r
849 wp.showCmd = nCmdShow;
\r
850 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
851 wp.rcNormalPosition.left = boardX;
\r
852 wp.rcNormalPosition.right = boardX + winWidth;
\r
853 wp.rcNormalPosition.top = boardY;
\r
854 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
855 SetWindowPlacement(hwndMain, &wp);
\r
857 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
858 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
862 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
863 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
865 ShowWindow(hwndConsole, nCmdShow);
\r
867 UpdateWindow(hwnd);
\r
875 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
876 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
877 ArgSettingsFilename,
\r
878 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
886 String *pString; // ArgString
\r
887 int *pInt; // ArgInt
\r
888 float *pFloat; // ArgFloat
\r
889 Boolean *pBoolean; // ArgBoolean
\r
890 COLORREF *pColor; // ArgColor
\r
891 ColorClass cc; // ArgAttribs
\r
892 String *pFilename; // ArgFilename
\r
893 BoardSize *pBoardSize; // ArgBoardSize
\r
894 int whichFont; // ArgFont
\r
895 DCB *pDCB; // ArgCommSettings
\r
896 String *pFilename; // ArgSettingsFilename
\r
904 ArgDescriptor argDescriptors[] = {
\r
905 /* positional arguments */
\r
906 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
907 { "", ArgNone, NULL },
\r
908 /* keyword arguments */
\r
909 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
910 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
911 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
912 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
913 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
914 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
915 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
916 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
917 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
918 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
919 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
920 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
921 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
922 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
923 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
924 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
925 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
926 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
928 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
930 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
932 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
933 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
935 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
936 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
937 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
938 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
939 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
940 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
941 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
942 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
943 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
944 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
945 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
946 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
947 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
948 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
949 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
950 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
951 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
952 /*!!bitmapDirectory?*/
\r
953 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
954 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
955 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
956 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
957 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
958 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
959 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
960 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
961 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
962 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
963 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
964 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
965 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
966 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
967 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
968 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
969 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
970 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
971 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
972 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
973 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
974 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
975 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
976 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
977 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
978 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
979 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
980 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
981 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
982 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
983 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
984 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
985 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
986 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
987 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
988 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
989 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
990 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
991 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
992 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
993 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
994 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
995 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
996 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
997 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
998 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
999 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1000 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1001 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1002 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1003 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1004 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1005 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1006 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1007 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1008 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1009 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1010 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1011 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1012 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1013 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1014 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1015 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1016 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1017 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1018 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1019 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1020 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1021 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1022 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1023 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1024 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1025 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1026 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1027 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1028 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1029 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1030 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1031 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1032 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1033 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1034 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1035 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1036 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1037 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1038 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1039 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1040 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1041 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1042 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1043 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1044 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1045 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1046 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1047 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1048 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1049 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1050 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1051 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1052 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1053 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1054 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1055 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1056 TRUE }, /* must come after all fonts */
\r
1057 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1058 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1059 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1060 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1061 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1062 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1063 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1064 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1065 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1066 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1067 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1068 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1069 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1070 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1071 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1072 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1073 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1074 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1075 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1076 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1077 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1078 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1079 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1080 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1081 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1082 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1083 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1084 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1085 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1086 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1087 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1089 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1090 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1092 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1093 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1094 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1095 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1096 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1097 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1098 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1099 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1100 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1101 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1102 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1103 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1104 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1105 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1106 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1107 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1108 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1109 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1110 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1111 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1112 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1113 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1114 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1115 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1116 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1117 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1118 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1119 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1120 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1121 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1122 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1123 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1124 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1125 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1126 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1127 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1128 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1129 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1130 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1131 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1132 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1133 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1134 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1135 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1136 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1137 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1138 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1139 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1140 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1141 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1142 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1143 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1144 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1145 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1146 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1147 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1148 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1149 { "highlightLastMove", ArgBoolean,
\r
1150 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1151 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1152 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1153 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1154 { "highlightDragging", ArgBoolean,
\r
1155 (LPVOID) &appData.highlightDragging, TRUE },
\r
1156 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1157 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1158 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1159 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1160 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1161 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1162 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1163 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1164 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1165 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1166 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1167 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1168 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1169 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1170 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1171 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1172 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1173 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1174 { "soundShout", ArgFilename,
\r
1175 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1176 { "soundSShout", ArgFilename,
\r
1177 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1178 { "soundChannel1", ArgFilename,
\r
1179 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1180 { "soundChannel", ArgFilename,
\r
1181 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1182 { "soundKibitz", ArgFilename,
\r
1183 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1184 { "soundTell", ArgFilename,
\r
1185 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1186 { "soundChallenge", ArgFilename,
\r
1187 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1188 { "soundRequest", ArgFilename,
\r
1189 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1190 { "soundSeek", ArgFilename,
\r
1191 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1192 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1193 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1194 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1195 { "soundIcsLoss", ArgFilename,
\r
1196 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1197 { "soundIcsDraw", ArgFilename,
\r
1198 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1199 { "soundIcsUnfinished", ArgFilename,
\r
1200 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1201 { "soundIcsAlarm", ArgFilename,
\r
1202 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1203 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1204 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1205 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1206 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1207 { "reuseChessPrograms", ArgBoolean,
\r
1208 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1209 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1210 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1211 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1212 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1213 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1214 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1215 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1216 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1217 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1218 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1219 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1220 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1221 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1222 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1223 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1225 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1227 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1228 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1229 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1230 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1231 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1232 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1233 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1234 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1235 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1236 /* [AS] New features */
\r
1237 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1238 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1239 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1240 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1241 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1242 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1243 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1244 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1245 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1246 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1247 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1248 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1249 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1250 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1251 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1252 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1253 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1254 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1255 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1256 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1257 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1258 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1259 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1260 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1261 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1262 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1263 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1264 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1265 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1266 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1267 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1268 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1269 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1270 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1271 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1272 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1273 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1274 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1275 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1276 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1277 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1278 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1279 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1280 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1281 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1282 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1283 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1284 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1285 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1286 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1288 /* [HGM] board-size, adjudication and misc. options */
\r
1289 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1290 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1291 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1292 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1293 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1294 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1295 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1296 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1297 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1298 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1299 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1300 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1301 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1302 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1303 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1304 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1305 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1306 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1307 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1308 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1309 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1310 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1311 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1312 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1313 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1314 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1315 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1316 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1317 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1318 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1319 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1322 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1323 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1324 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1325 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1326 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1327 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1328 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1329 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1330 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1331 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1332 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1333 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1334 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1336 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1337 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1338 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1339 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1340 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1341 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1342 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1344 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1345 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1346 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1347 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1348 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1349 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1350 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1351 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1352 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1353 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1354 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1355 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1356 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1357 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1358 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1359 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1360 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1361 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1362 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1364 /* [HGM] options for broadcasting and time odds */
\r
1365 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1366 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1367 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1368 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1369 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1370 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1371 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1372 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1373 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1374 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1375 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1377 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1378 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1379 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1380 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1381 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1382 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1383 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1384 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1385 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1386 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1387 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1388 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1389 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1390 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1391 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1392 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1393 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1394 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1395 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1396 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1397 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1398 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1399 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1400 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1401 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1402 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1403 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1404 /* [AS] Layout stuff */
\r
1405 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1406 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1407 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1408 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1409 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1411 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1412 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1413 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1414 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1415 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1417 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1418 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1419 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1420 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1421 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1423 { NULL, ArgNone, NULL, FALSE }
\r
1427 /* Kludge for indirection files on command line */
\r
1428 char* lastIndirectionFilename;
\r
1429 ArgDescriptor argDescriptorIndirection =
\r
1430 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1434 ExitArgError(char *msg, char *badArg)
\r
1436 char buf[MSG_SIZ];
\r
1438 sprintf(buf, "%s %s", msg, badArg);
\r
1439 DisplayFatalError(buf, 0, 2);
\r
1443 /* Command line font name parser. NULL name means do nothing.
\r
1444 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1445 For backward compatibility, syntax without the colon is also
\r
1446 accepted, but font names with digits in them won't work in that case.
\r
1449 ParseFontName(char *name, MyFontParams *mfp)
\r
1452 if (name == NULL) return;
\r
1454 q = strchr(p, ':');
\r
1456 if (q - p >= sizeof(mfp->faceName))
\r
1457 ExitArgError("Font name too long:", name);
\r
1458 memcpy(mfp->faceName, p, q - p);
\r
1459 mfp->faceName[q - p] = NULLCHAR;
\r
1462 q = mfp->faceName;
\r
1463 while (*p && !isdigit(*p)) {
\r
1465 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1466 ExitArgError("Font name too long:", name);
\r
1468 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1471 if (!*p) ExitArgError("Font point size missing:", name);
\r
1472 mfp->pointSize = (float) atof(p);
\r
1473 mfp->bold = (strchr(p, 'b') != NULL);
\r
1474 mfp->italic = (strchr(p, 'i') != NULL);
\r
1475 mfp->underline = (strchr(p, 'u') != NULL);
\r
1476 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1479 /* Color name parser.
\r
1480 X version accepts X color names, but this one
\r
1481 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1483 ParseColorName(char *name)
\r
1485 int red, green, blue, count;
\r
1486 char buf[MSG_SIZ];
\r
1488 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1490 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1491 &red, &green, &blue);
\r
1494 sprintf(buf, "Can't parse color name %s", name);
\r
1495 DisplayError(buf, 0);
\r
1496 return RGB(0, 0, 0);
\r
1498 return PALETTERGB(red, green, blue);
\r
1502 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1504 char *e = argValue;
\r
1508 if (*e == 'b') eff |= CFE_BOLD;
\r
1509 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1510 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1511 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1512 else if (*e == '#' || isdigit(*e)) break;
\r
1516 *color = ParseColorName(e);
\r
1521 ParseBoardSize(char *name)
\r
1523 BoardSize bs = SizeTiny;
\r
1524 while (sizeInfo[bs].name != NULL) {
\r
1525 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1528 ExitArgError("Unrecognized board size value", name);
\r
1529 return bs; /* not reached */
\r
1534 StringGet(void *getClosure)
\r
1536 char **p = (char **) getClosure;
\r
1541 FileGet(void *getClosure)
\r
1544 FILE* f = (FILE*) getClosure;
\r
1547 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1554 /* Parse settings file named "name". If file found, return the
\r
1555 full name in fullname and return TRUE; else return FALSE */
\r
1557 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1561 int ok; char buf[MSG_SIZ];
\r
1563 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1564 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1565 sprintf(buf, "%s.ini", name);
\r
1566 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1569 f = fopen(fullname, "r");
\r
1571 ParseArgs(FileGet, f);
\r
1580 ParseArgs(GetFunc get, void *cl)
\r
1582 char argName[ARG_MAX];
\r
1583 char argValue[ARG_MAX];
\r
1584 ArgDescriptor *ad;
\r
1593 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1594 if (ch == NULLCHAR) break;
\r
1596 /* Comment to end of line */
\r
1598 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1600 } else if (ch == '/' || ch == '-') {
\r
1603 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1604 ch != '\n' && ch != '\t') {
\r
1610 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1611 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1613 if (ad->argName == NULL)
\r
1614 ExitArgError("Unrecognized argument", argName);
\r
1616 } else if (ch == '@') {
\r
1617 /* Indirection file */
\r
1618 ad = &argDescriptorIndirection;
\r
1621 /* Positional argument */
\r
1622 ad = &argDescriptors[posarg++];
\r
1623 strcpy(argName, ad->argName);
\r
1626 if (ad->argType == ArgTrue) {
\r
1627 *(Boolean *) ad->argLoc = TRUE;
\r
1630 if (ad->argType == ArgFalse) {
\r
1631 *(Boolean *) ad->argLoc = FALSE;
\r
1635 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1636 if (ch == NULLCHAR || ch == '\n') {
\r
1637 ExitArgError("No value provided for argument", argName);
\r
1641 // Quoting with { }. No characters have to (or can) be escaped.
\r
1642 // Thus the string cannot contain a '}' character.
\r
1662 } else if (ch == '\'' || ch == '"') {
\r
1663 // Quoting with ' ' or " ", with \ as escape character.
\r
1664 // Inconvenient for long strings that may contain Windows filenames.
\r
1681 if (ch == start) {
\r
1690 if (ad->argType == ArgFilename
\r
1691 || ad->argType == ArgSettingsFilename) {
\r
1697 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1721 for (i = 0; i < 3; i++) {
\r
1722 if (ch >= '0' && ch <= '7') {
\r
1723 octval = octval*8 + (ch - '0');
\r
1730 *q++ = (char) octval;
\r
1741 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1748 switch (ad->argType) {
\r
1750 *(int *) ad->argLoc = atoi(argValue);
\r
1754 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1758 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1762 *(int *) ad->argLoc = atoi(argValue);
\r
1763 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1767 *(float *) ad->argLoc = (float) atof(argValue);
\r
1772 *(char **) ad->argLoc = strdup(argValue);
\r
1775 case ArgSettingsFilename:
\r
1777 char fullname[MSG_SIZ];
\r
1778 if (ParseSettingsFile(argValue, fullname)) {
\r
1779 if (ad->argLoc != NULL) {
\r
1780 *(char **) ad->argLoc = strdup(fullname);
\r
1783 if (ad->argLoc != NULL) {
\r
1785 ExitArgError("Failed to open indirection file", argValue);
\r
1792 switch (argValue[0]) {
\r
1795 *(Boolean *) ad->argLoc = TRUE;
\r
1799 *(Boolean *) ad->argLoc = FALSE;
\r
1802 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1808 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1811 case ArgAttribs: {
\r
1812 ColorClass cc = (ColorClass)ad->argLoc;
\r
1813 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1817 case ArgBoardSize:
\r
1818 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1822 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1825 case ArgCommSettings:
\r
1826 ParseCommSettings(argValue, &dcb);
\r
1830 ExitArgError("Unrecognized argument", argValue);
\r
1839 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1841 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1842 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1845 lf->lfEscapement = 0;
\r
1846 lf->lfOrientation = 0;
\r
1847 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1848 lf->lfItalic = mfp->italic;
\r
1849 lf->lfUnderline = mfp->underline;
\r
1850 lf->lfStrikeOut = mfp->strikeout;
\r
1851 lf->lfCharSet = DEFAULT_CHARSET;
\r
1852 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1853 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1854 lf->lfQuality = DEFAULT_QUALITY;
\r
1855 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1856 strcpy(lf->lfFaceName, mfp->faceName);
\r
1860 CreateFontInMF(MyFont *mf)
\r
1862 LFfromMFP(&mf->lf, &mf->mfp);
\r
1863 if (mf->hf) DeleteObject(mf->hf);
\r
1864 mf->hf = CreateFontIndirect(&mf->lf);
\r
1868 SetDefaultTextAttribs()
\r
1871 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1872 ParseAttribs(&textAttribs[cc].color,
\r
1873 &textAttribs[cc].effects,
\r
1874 defaultTextAttribs[cc]);
\r
1879 SetDefaultSounds()
\r
1883 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1884 textAttribs[cc].sound.name = strdup("");
\r
1885 textAttribs[cc].sound.data = NULL;
\r
1887 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1888 sounds[sc].name = strdup("");
\r
1889 sounds[sc].data = NULL;
\r
1891 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1899 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1900 MyLoadSound(&textAttribs[cc].sound);
\r
1902 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1903 MyLoadSound(&sounds[sc]);
\r
1908 InitAppData(LPSTR lpCmdLine)
\r
1911 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1914 programName = szAppName;
\r
1916 /* Initialize to defaults */
\r
1917 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1918 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1919 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1920 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1921 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1922 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1923 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1924 SetDefaultTextAttribs();
\r
1925 SetDefaultSounds();
\r
1926 appData.movesPerSession = MOVES_PER_SESSION;
\r
1927 appData.initString = INIT_STRING;
\r
1928 appData.secondInitString = INIT_STRING;
\r
1929 appData.firstComputerString = COMPUTER_STRING;
\r
1930 appData.secondComputerString = COMPUTER_STRING;
\r
1931 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1932 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1933 appData.firstPlaysBlack = FALSE;
\r
1934 appData.noChessProgram = FALSE;
\r
1935 chessProgram = FALSE;
\r
1936 appData.firstHost = FIRST_HOST;
\r
1937 appData.secondHost = SECOND_HOST;
\r
1938 appData.firstDirectory = FIRST_DIRECTORY;
\r
1939 appData.secondDirectory = SECOND_DIRECTORY;
\r
1940 appData.bitmapDirectory = "";
\r
1941 appData.remoteShell = REMOTE_SHELL;
\r
1942 appData.remoteUser = "";
\r
1943 appData.timeDelay = TIME_DELAY;
\r
1944 appData.timeControl = TIME_CONTROL;
\r
1945 appData.timeIncrement = TIME_INCREMENT;
\r
1946 appData.icsActive = FALSE;
\r
1947 appData.icsHost = "";
\r
1948 appData.icsPort = ICS_PORT;
\r
1949 appData.icsCommPort = ICS_COMM_PORT;
\r
1950 appData.icsLogon = ICS_LOGON;
\r
1951 appData.icsHelper = "";
\r
1952 appData.useTelnet = FALSE;
\r
1953 appData.telnetProgram = TELNET_PROGRAM;
\r
1954 appData.gateway = "";
\r
1955 appData.loadGameFile = "";
\r
1956 appData.loadGameIndex = 0;
\r
1957 appData.saveGameFile = "";
\r
1958 appData.autoSaveGames = FALSE;
\r
1959 appData.loadPositionFile = "";
\r
1960 appData.loadPositionIndex = 1;
\r
1961 appData.savePositionFile = "";
\r
1962 appData.matchMode = FALSE;
\r
1963 appData.matchGames = 0;
\r
1964 appData.monoMode = FALSE;
\r
1965 appData.debugMode = FALSE;
\r
1966 appData.clockMode = TRUE;
\r
1967 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1968 appData.Iconic = FALSE; /*unused*/
\r
1969 appData.searchTime = "";
\r
1970 appData.searchDepth = 0;
\r
1971 appData.showCoords = FALSE;
\r
1972 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1973 appData.autoCallFlag = FALSE;
\r
1974 appData.flipView = FALSE;
\r
1975 appData.autoFlipView = TRUE;
\r
1976 appData.cmailGameName = "";
\r
1977 appData.alwaysPromoteToQueen = FALSE;
\r
1978 appData.oldSaveStyle = FALSE;
\r
1979 appData.quietPlay = FALSE;
\r
1980 appData.showThinking = FALSE;
\r
1981 appData.ponderNextMove = TRUE;
\r
1982 appData.periodicUpdates = TRUE;
\r
1983 appData.popupExitMessage = TRUE;
\r
1984 appData.popupMoveErrors = FALSE;
\r
1985 appData.autoObserve = FALSE;
\r
1986 appData.autoComment = FALSE;
\r
1987 appData.animate = TRUE;
\r
1988 appData.animSpeed = 10;
\r
1989 appData.animateDragging = TRUE;
\r
1990 appData.highlightLastMove = TRUE;
\r
1991 appData.getMoveList = TRUE;
\r
1992 appData.testLegality = TRUE;
\r
1993 appData.premove = TRUE;
\r
1994 appData.premoveWhite = FALSE;
\r
1995 appData.premoveWhiteText = "";
\r
1996 appData.premoveBlack = FALSE;
\r
1997 appData.premoveBlackText = "";
\r
1998 appData.icsAlarm = TRUE;
\r
1999 appData.icsAlarmTime = 5000;
\r
2000 appData.autoRaiseBoard = TRUE;
\r
2001 appData.localLineEditing = TRUE;
\r
2002 appData.colorize = TRUE;
\r
2003 appData.reuseFirst = TRUE;
\r
2004 appData.reuseSecond = TRUE;
\r
2005 appData.blindfold = FALSE;
\r
2006 appData.icsEngineAnalyze = FALSE;
\r
2007 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2008 dcb.DCBlength = sizeof(DCB);
\r
2009 dcb.BaudRate = 9600;
\r
2010 dcb.fBinary = TRUE;
\r
2011 dcb.fParity = FALSE;
\r
2012 dcb.fOutxCtsFlow = FALSE;
\r
2013 dcb.fOutxDsrFlow = FALSE;
\r
2014 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2015 dcb.fDsrSensitivity = FALSE;
\r
2016 dcb.fTXContinueOnXoff = TRUE;
\r
2017 dcb.fOutX = FALSE;
\r
2019 dcb.fNull = FALSE;
\r
2020 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2021 dcb.fAbortOnError = FALSE;
\r
2023 dcb.Parity = SPACEPARITY;
\r
2024 dcb.StopBits = ONESTOPBIT;
\r
2025 settingsFileName = SETTINGS_FILE;
\r
2026 saveSettingsOnExit = TRUE;
\r
2027 boardX = CW_USEDEFAULT;
\r
2028 boardY = CW_USEDEFAULT;
\r
2029 analysisX = CW_USEDEFAULT;
\r
2030 analysisY = CW_USEDEFAULT;
\r
2031 analysisW = CW_USEDEFAULT;
\r
2032 analysisH = CW_USEDEFAULT;
\r
2033 commentX = CW_USEDEFAULT;
\r
2034 commentY = CW_USEDEFAULT;
\r
2035 commentW = CW_USEDEFAULT;
\r
2036 commentH = CW_USEDEFAULT;
\r
2037 editTagsX = CW_USEDEFAULT;
\r
2038 editTagsY = CW_USEDEFAULT;
\r
2039 editTagsW = CW_USEDEFAULT;
\r
2040 editTagsH = CW_USEDEFAULT;
\r
2041 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2042 icsNames = ICS_NAMES;
\r
2043 firstChessProgramNames = FCP_NAMES;
\r
2044 secondChessProgramNames = SCP_NAMES;
\r
2045 appData.initialMode = "";
\r
2046 appData.variant = "normal";
\r
2047 appData.firstProtocolVersion = PROTOVER;
\r
2048 appData.secondProtocolVersion = PROTOVER;
\r
2049 appData.showButtonBar = TRUE;
\r
2051 /* [AS] New properties (see comments in header file) */
\r
2052 appData.firstScoreIsAbsolute = FALSE;
\r
2053 appData.secondScoreIsAbsolute = FALSE;
\r
2054 appData.saveExtendedInfoInPGN = FALSE;
\r
2055 appData.hideThinkingFromHuman = FALSE;
\r
2056 appData.liteBackTextureFile = "";
\r
2057 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2058 appData.darkBackTextureFile = "";
\r
2059 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2060 appData.renderPiecesWithFont = "";
\r
2061 appData.fontToPieceTable = "";
\r
2062 appData.fontBackColorWhite = 0;
\r
2063 appData.fontForeColorWhite = 0;
\r
2064 appData.fontBackColorBlack = 0;
\r
2065 appData.fontForeColorBlack = 0;
\r
2066 appData.fontPieceSize = 80;
\r
2067 appData.overrideLineGap = 1;
\r
2068 appData.adjudicateLossThreshold = 0;
\r
2069 appData.delayBeforeQuit = 0;
\r
2070 appData.delayAfterQuit = 0;
\r
2071 appData.nameOfDebugFile = "winboard.debug";
\r
2072 appData.pgnEventHeader = "Computer Chess Game";
\r
2073 appData.defaultFrcPosition = -1;
\r
2074 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2075 appData.saveOutOfBookInfo = TRUE;
\r
2076 appData.showEvalInMoveHistory = TRUE;
\r
2077 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2078 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2079 appData.highlightMoveWithArrow = FALSE;
\r
2080 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2081 appData.useStickyWindows = TRUE;
\r
2082 appData.adjudicateDrawMoves = 0;
\r
2083 appData.autoDisplayComment = TRUE;
\r
2084 appData.autoDisplayTags = TRUE;
\r
2085 appData.firstIsUCI = FALSE;
\r
2086 appData.secondIsUCI = FALSE;
\r
2087 appData.firstHasOwnBookUCI = TRUE;
\r
2088 appData.secondHasOwnBookUCI = TRUE;
\r
2089 appData.polyglotDir = "";
\r
2090 appData.usePolyglotBook = FALSE;
\r
2091 appData.polyglotBook = "";
\r
2092 appData.defaultHashSize = 64;
\r
2093 appData.defaultCacheSizeEGTB = 4;
\r
2094 appData.defaultPathEGTB = "c:\\egtb";
\r
2095 appData.firstOptions = "";
\r
2096 appData.secondOptions = "";
\r
2098 InitWindowPlacement( &wpGameList );
\r
2099 InitWindowPlacement( &wpMoveHistory );
\r
2100 InitWindowPlacement( &wpEvalGraph );
\r
2101 InitWindowPlacement( &wpEngineOutput );
\r
2102 InitWindowPlacement( &wpConsole );
\r
2104 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2105 appData.NrFiles = -1;
\r
2106 appData.NrRanks = -1;
\r
2107 appData.holdingsSize = -1;
\r
2108 appData.testClaims = FALSE;
\r
2109 appData.checkMates = FALSE;
\r
2110 appData.materialDraws= FALSE;
\r
2111 appData.trivialDraws = FALSE;
\r
2112 appData.ruleMoves = 51;
\r
2113 appData.drawRepeats = 6;
\r
2114 appData.matchPause = 10000;
\r
2115 appData.alphaRank = FALSE;
\r
2116 appData.allWhite = FALSE;
\r
2117 appData.upsideDown = FALSE;
\r
2118 appData.serverPause = 15;
\r
2119 appData.serverMovesName = NULL;
\r
2120 appData.suppressLoadMoves = FALSE;
\r
2121 appData.firstTimeOdds = 1;
\r
2122 appData.secondTimeOdds = 1;
\r
2123 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2124 appData.secondAccumulateTC = 1;
\r
2125 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2126 appData.secondNPS = -1;
\r
2127 appData.engineComments = 1;
\r
2128 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2129 appData.egtFormats = "";
\r
2132 appData.zippyTalk = ZIPPY_TALK;
\r
2133 appData.zippyPlay = ZIPPY_PLAY;
\r
2134 appData.zippyLines = ZIPPY_LINES;
\r
2135 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2136 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2137 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2138 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2139 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2140 appData.zippyUseI = ZIPPY_USE_I;
\r
2141 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2142 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2143 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2144 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2145 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2146 appData.zippyAbort = ZIPPY_ABORT;
\r
2147 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2148 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2149 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2152 /* Point font array elements to structures and
\r
2153 parse default font names */
\r
2154 for (i=0; i<NUM_FONTS; i++) {
\r
2155 for (j=0; j<NUM_SIZES; j++) {
\r
2156 font[j][i] = &fontRec[j][i];
\r
2157 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2161 /* Parse default settings file if any */
\r
2162 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2163 settingsFileName = strdup(buf);
\r
2166 /* Parse command line */
\r
2167 ParseArgs(StringGet, &lpCmdLine);
\r
2169 /* [HGM] make sure board size is acceptable */
\r
2170 if(appData.NrFiles > BOARD_SIZE ||
\r
2171 appData.NrRanks > BOARD_SIZE )
\r
2172 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2174 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2175 * with options from the command line, we now make an even higher priority
\r
2176 * overrule by WB options attached to the engine command line. This so that
\r
2177 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2180 if(appData.firstChessProgram != NULL) {
\r
2181 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2182 static char *f = "first";
\r
2183 char buf[MSG_SIZ], *q = buf;
\r
2184 if(p != NULL) { // engine command line contains WinBoard options
\r
2185 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2186 ParseArgs(StringGet, &q);
\r
2187 p[-1] = 0; // cut them offengine command line
\r
2190 // now do same for second chess program
\r
2191 if(appData.secondChessProgram != NULL) {
\r
2192 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2193 static char *s = "second";
\r
2194 char buf[MSG_SIZ], *q = buf;
\r
2195 if(p != NULL) { // engine command line contains WinBoard options
\r
2196 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2197 ParseArgs(StringGet, &q);
\r
2198 p[-1] = 0; // cut them offengine command line
\r
2203 /* Propagate options that affect others */
\r
2204 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2205 if (appData.icsActive || appData.noChessProgram) {
\r
2206 chessProgram = FALSE; /* not local chess program mode */
\r
2209 /* Open startup dialog if needed */
\r
2210 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2211 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2212 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2213 *appData.secondChessProgram == NULLCHAR))) {
\r
2216 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2217 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2218 FreeProcInstance(lpProc);
\r
2221 /* Make sure save files land in the right (?) directory */
\r
2222 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2223 appData.saveGameFile = strdup(buf);
\r
2225 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2226 appData.savePositionFile = strdup(buf);
\r
2229 /* Finish initialization for fonts and sounds */
\r
2230 for (i=0; i<NUM_FONTS; i++) {
\r
2231 for (j=0; j<NUM_SIZES; j++) {
\r
2232 CreateFontInMF(font[j][i]);
\r
2235 /* xboard, and older WinBoards, controlled the move sound with the
\r
2236 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2237 always turn the option on (so that the backend will call us),
\r
2238 then let the user turn the sound off by setting it to silence if
\r
2239 desired. To accommodate old winboard.ini files saved by old
\r
2240 versions of WinBoard, we also turn off the sound if the option
\r
2241 was initially set to false. */
\r
2242 if (!appData.ringBellAfterMoves) {
\r
2243 sounds[(int)SoundMove].name = strdup("");
\r
2244 appData.ringBellAfterMoves = TRUE;
\r
2246 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2247 SetCurrentDirectory(installDir);
\r
2249 SetCurrentDirectory(currDir);
\r
2251 p = icsTextMenuString;
\r
2252 if (p[0] == '@') {
\r
2253 FILE* f = fopen(p + 1, "r");
\r
2255 DisplayFatalError(p + 1, errno, 2);
\r
2258 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2260 buf[i] = NULLCHAR;
\r
2263 ParseIcsTextMenu(strdup(p));
\r
2270 HMENU hmenu = GetMenu(hwndMain);
\r
2272 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2273 MF_BYCOMMAND|((appData.icsActive &&
\r
2274 *appData.icsCommPort != NULLCHAR) ?
\r
2275 MF_ENABLED : MF_GRAYED));
\r
2276 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2277 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2278 MF_CHECKED : MF_UNCHECKED));
\r
2283 SaveSettings(char* name)
\r
2286 ArgDescriptor *ad;
\r
2287 WINDOWPLACEMENT wp;
\r
2288 char dir[MSG_SIZ];
\r
2290 if (!hwndMain) return;
\r
2292 GetCurrentDirectory(MSG_SIZ, dir);
\r
2293 SetCurrentDirectory(installDir);
\r
2294 f = fopen(name, "w");
\r
2295 SetCurrentDirectory(dir);
\r
2297 DisplayError(name, errno);
\r
2300 fprintf(f, ";\n");
\r
2301 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2302 fprintf(f, ";\n");
\r
2303 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2304 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2305 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2306 fprintf(f, ";\n");
\r
2308 wp.length = sizeof(WINDOWPLACEMENT);
\r
2309 GetWindowPlacement(hwndMain, &wp);
\r
2310 boardX = wp.rcNormalPosition.left;
\r
2311 boardY = wp.rcNormalPosition.top;
\r
2313 if (hwndConsole) {
\r
2314 GetWindowPlacement(hwndConsole, &wp);
\r
2315 wpConsole.x = wp.rcNormalPosition.left;
\r
2316 wpConsole.y = wp.rcNormalPosition.top;
\r
2317 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2318 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2321 if (analysisDialog) {
\r
2322 GetWindowPlacement(analysisDialog, &wp);
\r
2323 analysisX = wp.rcNormalPosition.left;
\r
2324 analysisY = wp.rcNormalPosition.top;
\r
2325 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2326 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2329 if (commentDialog) {
\r
2330 GetWindowPlacement(commentDialog, &wp);
\r
2331 commentX = wp.rcNormalPosition.left;
\r
2332 commentY = wp.rcNormalPosition.top;
\r
2333 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2334 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2337 if (editTagsDialog) {
\r
2338 GetWindowPlacement(editTagsDialog, &wp);
\r
2339 editTagsX = wp.rcNormalPosition.left;
\r
2340 editTagsY = wp.rcNormalPosition.top;
\r
2341 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2342 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2345 if (gameListDialog) {
\r
2346 GetWindowPlacement(gameListDialog, &wp);
\r
2347 wpGameList.x = wp.rcNormalPosition.left;
\r
2348 wpGameList.y = wp.rcNormalPosition.top;
\r
2349 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2350 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2353 /* [AS] Move history */
\r
2354 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2356 if( moveHistoryDialog ) {
\r
2357 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2358 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2359 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2360 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2361 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2364 /* [AS] Eval graph */
\r
2365 wpEvalGraph.visible = EvalGraphIsUp();
\r
2367 if( evalGraphDialog ) {
\r
2368 GetWindowPlacement(evalGraphDialog, &wp);
\r
2369 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2370 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2371 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2372 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2375 /* [AS] Engine output */
\r
2376 wpEngineOutput.visible = EngineOutputIsUp();
\r
2378 if( engineOutputDialog ) {
\r
2379 GetWindowPlacement(engineOutputDialog, &wp);
\r
2380 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2381 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2382 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2383 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2386 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2387 if (!ad->save) continue;
\r
2388 switch (ad->argType) {
\r
2391 char *p = *(char **)ad->argLoc;
\r
2392 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2393 /* Quote multiline values or \-containing values
\r
2394 with { } if possible */
\r
2395 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2397 /* Else quote with " " */
\r
2398 fprintf(f, "/%s=\"", ad->argName);
\r
2400 if (*p == '\n') fprintf(f, "\n");
\r
2401 else if (*p == '\r') fprintf(f, "\\r");
\r
2402 else if (*p == '\t') fprintf(f, "\\t");
\r
2403 else if (*p == '\b') fprintf(f, "\\b");
\r
2404 else if (*p == '\f') fprintf(f, "\\f");
\r
2405 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2406 else if (*p == '\"') fprintf(f, "\\\"");
\r
2407 else if (*p == '\\') fprintf(f, "\\\\");
\r
2411 fprintf(f, "\"\n");
\r
2417 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2420 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2423 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2426 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2429 fprintf(f, "/%s=%s\n", ad->argName,
\r
2430 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2433 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2436 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2440 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2441 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2442 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2447 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2448 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2449 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2450 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2451 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2452 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2453 (ta->effects) ? " " : "",
\r
2454 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2458 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2459 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2461 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2464 case ArgBoardSize:
\r
2465 fprintf(f, "/%s=%s\n", ad->argName,
\r
2466 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2471 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2472 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2473 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2474 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2475 ad->argName, mfp->faceName, mfp->pointSize,
\r
2476 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2477 mfp->bold ? "b" : "",
\r
2478 mfp->italic ? "i" : "",
\r
2479 mfp->underline ? "u" : "",
\r
2480 mfp->strikeout ? "s" : "");
\r
2484 case ArgCommSettings:
\r
2485 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2487 case ArgSettingsFilename: ;
\r
2495 /*---------------------------------------------------------------------------*\
\r
2497 * GDI board drawing routines
\r
2499 \*---------------------------------------------------------------------------*/
\r
2501 /* [AS] Draw square using background texture */
\r
2502 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2507 return; /* Should never happen! */
\r
2510 SetGraphicsMode( dst, GM_ADVANCED );
\r
2517 /* X reflection */
\r
2522 x.eDx = (FLOAT) dw + dx - 1;
\r
2525 SetWorldTransform( dst, &x );
\r
2528 /* Y reflection */
\r
2534 x.eDy = (FLOAT) dh + dy - 1;
\r
2536 SetWorldTransform( dst, &x );
\r
2544 x.eDx = (FLOAT) dx;
\r
2545 x.eDy = (FLOAT) dy;
\r
2548 SetWorldTransform( dst, &x );
\r
2552 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2560 SetWorldTransform( dst, &x );
\r
2562 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2565 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2567 PM_WP = (int) WhitePawn,
\r
2568 PM_WN = (int) WhiteKnight,
\r
2569 PM_WB = (int) WhiteBishop,
\r
2570 PM_WR = (int) WhiteRook,
\r
2571 PM_WQ = (int) WhiteQueen,
\r
2572 PM_WF = (int) WhiteFerz,
\r
2573 PM_WW = (int) WhiteWazir,
\r
2574 PM_WE = (int) WhiteAlfil,
\r
2575 PM_WM = (int) WhiteMan,
\r
2576 PM_WO = (int) WhiteCannon,
\r
2577 PM_WU = (int) WhiteUnicorn,
\r
2578 PM_WH = (int) WhiteNightrider,
\r
2579 PM_WA = (int) WhiteAngel,
\r
2580 PM_WC = (int) WhiteMarshall,
\r
2581 PM_WAB = (int) WhiteCardinal,
\r
2582 PM_WD = (int) WhiteDragon,
\r
2583 PM_WL = (int) WhiteLance,
\r
2584 PM_WS = (int) WhiteCobra,
\r
2585 PM_WV = (int) WhiteFalcon,
\r
2586 PM_WSG = (int) WhiteSilver,
\r
2587 PM_WG = (int) WhiteGrasshopper,
\r
2588 PM_WK = (int) WhiteKing,
\r
2589 PM_BP = (int) BlackPawn,
\r
2590 PM_BN = (int) BlackKnight,
\r
2591 PM_BB = (int) BlackBishop,
\r
2592 PM_BR = (int) BlackRook,
\r
2593 PM_BQ = (int) BlackQueen,
\r
2594 PM_BF = (int) BlackFerz,
\r
2595 PM_BW = (int) BlackWazir,
\r
2596 PM_BE = (int) BlackAlfil,
\r
2597 PM_BM = (int) BlackMan,
\r
2598 PM_BO = (int) BlackCannon,
\r
2599 PM_BU = (int) BlackUnicorn,
\r
2600 PM_BH = (int) BlackNightrider,
\r
2601 PM_BA = (int) BlackAngel,
\r
2602 PM_BC = (int) BlackMarshall,
\r
2603 PM_BG = (int) BlackGrasshopper,
\r
2604 PM_BAB = (int) BlackCardinal,
\r
2605 PM_BD = (int) BlackDragon,
\r
2606 PM_BL = (int) BlackLance,
\r
2607 PM_BS = (int) BlackCobra,
\r
2608 PM_BV = (int) BlackFalcon,
\r
2609 PM_BSG = (int) BlackSilver,
\r
2610 PM_BK = (int) BlackKing
\r
2613 static HFONT hPieceFont = NULL;
\r
2614 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2615 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2616 static int fontBitmapSquareSize = 0;
\r
2617 static char pieceToFontChar[(int) EmptySquare] =
\r
2618 { 'p', 'n', 'b', 'r', 'q',
\r
2619 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2620 'k', 'o', 'm', 'v', 't', 'w',
\r
2621 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2624 extern BOOL SetCharTable( char *table, const char * map );
\r
2625 /* [HGM] moved to backend.c */
\r
2627 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2630 BYTE r1 = GetRValue( color );
\r
2631 BYTE g1 = GetGValue( color );
\r
2632 BYTE b1 = GetBValue( color );
\r
2638 /* Create a uniform background first */
\r
2639 hbrush = CreateSolidBrush( color );
\r
2640 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2641 FillRect( hdc, &rc, hbrush );
\r
2642 DeleteObject( hbrush );
\r
2645 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2646 int steps = squareSize / 2;
\r
2649 for( i=0; i<steps; i++ ) {
\r
2650 BYTE r = r1 - (r1-r2) * i / steps;
\r
2651 BYTE g = g1 - (g1-g2) * i / steps;
\r
2652 BYTE b = b1 - (b1-b2) * i / steps;
\r
2654 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2655 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2656 FillRect( hdc, &rc, hbrush );
\r
2657 DeleteObject(hbrush);
\r
2660 else if( mode == 2 ) {
\r
2661 /* Diagonal gradient, good more or less for every piece */
\r
2662 POINT triangle[3];
\r
2663 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2664 HBRUSH hbrush_old;
\r
2665 int steps = squareSize;
\r
2668 triangle[0].x = squareSize - steps;
\r
2669 triangle[0].y = squareSize;
\r
2670 triangle[1].x = squareSize;
\r
2671 triangle[1].y = squareSize;
\r
2672 triangle[2].x = squareSize;
\r
2673 triangle[2].y = squareSize - steps;
\r
2675 for( i=0; i<steps; i++ ) {
\r
2676 BYTE r = r1 - (r1-r2) * i / steps;
\r
2677 BYTE g = g1 - (g1-g2) * i / steps;
\r
2678 BYTE b = b1 - (b1-b2) * i / steps;
\r
2680 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2681 hbrush_old = SelectObject( hdc, hbrush );
\r
2682 Polygon( hdc, triangle, 3 );
\r
2683 SelectObject( hdc, hbrush_old );
\r
2684 DeleteObject(hbrush);
\r
2689 SelectObject( hdc, hpen );
\r
2694 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2695 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2696 piece: follow the steps as explained below.
\r
2698 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2702 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2706 int backColor = whitePieceColor;
\r
2707 int foreColor = blackPieceColor;
\r
2709 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2710 backColor = appData.fontBackColorWhite;
\r
2711 foreColor = appData.fontForeColorWhite;
\r
2713 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2714 backColor = appData.fontBackColorBlack;
\r
2715 foreColor = appData.fontForeColorBlack;
\r
2719 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2721 hbm_old = SelectObject( hdc, hbm );
\r
2725 rc.right = squareSize;
\r
2726 rc.bottom = squareSize;
\r
2728 /* Step 1: background is now black */
\r
2729 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2731 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2733 pt.x = (squareSize - sz.cx) / 2;
\r
2734 pt.y = (squareSize - sz.cy) / 2;
\r
2736 SetBkMode( hdc, TRANSPARENT );
\r
2737 SetTextColor( hdc, chroma );
\r
2738 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2739 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2741 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2742 /* Step 3: the area outside the piece is filled with white */
\r
2743 // FloodFill( hdc, 0, 0, chroma );
\r
2744 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2745 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2746 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2747 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2748 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2750 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2751 but if the start point is not inside the piece we're lost!
\r
2752 There should be a better way to do this... if we could create a region or path
\r
2753 from the fill operation we would be fine for example.
\r
2755 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2756 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2758 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2759 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2760 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2762 SelectObject( dc2, bm2 );
\r
2763 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2764 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2765 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2766 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2767 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2770 DeleteObject( bm2 );
\r
2773 SetTextColor( hdc, 0 );
\r
2775 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2776 draw the piece again in black for safety.
\r
2778 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2780 SelectObject( hdc, hbm_old );
\r
2782 if( hPieceMask[index] != NULL ) {
\r
2783 DeleteObject( hPieceMask[index] );
\r
2786 hPieceMask[index] = hbm;
\r
2789 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2791 SelectObject( hdc, hbm );
\r
2794 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2795 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2796 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2798 SelectObject( dc1, hPieceMask[index] );
\r
2799 SelectObject( dc2, bm2 );
\r
2800 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2801 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2804 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2805 the piece background and deletes (makes transparent) the rest.
\r
2806 Thanks to that mask, we are free to paint the background with the greates
\r
2807 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2808 We use this, to make gradients and give the pieces a "roundish" look.
\r
2810 SetPieceBackground( hdc, backColor, 2 );
\r
2811 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2815 DeleteObject( bm2 );
\r
2818 SetTextColor( hdc, foreColor );
\r
2819 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2821 SelectObject( hdc, hbm_old );
\r
2823 if( hPieceFace[index] != NULL ) {
\r
2824 DeleteObject( hPieceFace[index] );
\r
2827 hPieceFace[index] = hbm;
\r
2830 static int TranslatePieceToFontPiece( int piece )
\r
2860 case BlackMarshall:
\r
2864 case BlackNightrider:
\r
2870 case BlackUnicorn:
\r
2874 case BlackGrasshopper:
\r
2886 case BlackCardinal:
\r
2893 case WhiteMarshall:
\r
2897 case WhiteNightrider:
\r
2903 case WhiteUnicorn:
\r
2907 case WhiteGrasshopper:
\r
2919 case WhiteCardinal:
\r
2928 void CreatePiecesFromFont()
\r
2931 HDC hdc_window = NULL;
\r
2937 if( fontBitmapSquareSize < 0 ) {
\r
2938 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2942 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2943 fontBitmapSquareSize = -1;
\r
2947 if( fontBitmapSquareSize != squareSize ) {
\r
2948 hdc_window = GetDC( hwndMain );
\r
2949 hdc = CreateCompatibleDC( hdc_window );
\r
2951 if( hPieceFont != NULL ) {
\r
2952 DeleteObject( hPieceFont );
\r
2955 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2956 hPieceMask[i] = NULL;
\r
2957 hPieceFace[i] = NULL;
\r
2963 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2964 fontHeight = appData.fontPieceSize;
\r
2967 fontHeight = (fontHeight * squareSize) / 100;
\r
2969 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2971 lf.lfEscapement = 0;
\r
2972 lf.lfOrientation = 0;
\r
2973 lf.lfWeight = FW_NORMAL;
\r
2975 lf.lfUnderline = 0;
\r
2976 lf.lfStrikeOut = 0;
\r
2977 lf.lfCharSet = DEFAULT_CHARSET;
\r
2978 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2979 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2980 lf.lfQuality = PROOF_QUALITY;
\r
2981 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2982 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2983 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2985 hPieceFont = CreateFontIndirect( &lf );
\r
2987 if( hPieceFont == NULL ) {
\r
2988 fontBitmapSquareSize = -2;
\r
2991 /* Setup font-to-piece character table */
\r
2992 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2993 /* No (or wrong) global settings, try to detect the font */
\r
2994 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2996 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2998 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2999 /* DiagramTT* family */
\r
3000 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3002 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3003 /* Fairy symbols */
\r
3004 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3006 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3007 /* Good Companion (Some characters get warped as literal :-( */
\r
3008 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3009 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3010 SetCharTable(pieceToFontChar, s);
\r
3013 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3014 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3018 /* Create bitmaps */
\r
3019 hfont_old = SelectObject( hdc, hPieceFont );
\r
3021 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3022 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3023 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3024 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3025 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3026 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3027 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3028 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3029 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3030 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3031 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3032 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3034 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3035 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3036 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3037 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3038 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3039 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3040 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3042 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3043 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3048 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3050 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3051 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3055 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3056 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3063 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3064 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3065 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3067 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3068 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3069 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3071 SelectObject( hdc, hfont_old );
\r
3073 fontBitmapSquareSize = squareSize;
\r
3077 if( hdc != NULL ) {
\r
3081 if( hdc_window != NULL ) {
\r
3082 ReleaseDC( hwndMain, hdc_window );
\r
3087 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3091 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3092 if (gameInfo.event &&
\r
3093 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3094 strcmp(name, "k80s") == 0) {
\r
3095 strcpy(name, "tim");
\r
3097 return LoadBitmap(hinst, name);
\r
3101 /* Insert a color into the program's logical palette
\r
3102 structure. This code assumes the given color is
\r
3103 the result of the RGB or PALETTERGB macro, and it
\r
3104 knows how those macros work (which is documented).
\r
3107 InsertInPalette(COLORREF color)
\r
3109 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3111 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3112 DisplayFatalError("Too many colors", 0, 1);
\r
3113 pLogPal->palNumEntries--;
\r
3117 pe->peFlags = (char) 0;
\r
3118 pe->peRed = (char) (0xFF & color);
\r
3119 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3120 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3126 InitDrawingColors()
\r
3128 if (pLogPal == NULL) {
\r
3129 /* Allocate enough memory for a logical palette with
\r
3130 * PALETTESIZE entries and set the size and version fields
\r
3131 * of the logical palette structure.
\r
3133 pLogPal = (NPLOGPALETTE)
\r
3134 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3135 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3136 pLogPal->palVersion = 0x300;
\r
3138 pLogPal->palNumEntries = 0;
\r
3140 InsertInPalette(lightSquareColor);
\r
3141 InsertInPalette(darkSquareColor);
\r
3142 InsertInPalette(whitePieceColor);
\r
3143 InsertInPalette(blackPieceColor);
\r
3144 InsertInPalette(highlightSquareColor);
\r
3145 InsertInPalette(premoveHighlightColor);
\r
3147 /* create a logical color palette according the information
\r
3148 * in the LOGPALETTE structure.
\r
3150 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3152 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3153 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3154 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3155 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3156 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3157 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3158 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3159 /* [AS] Force rendering of the font-based pieces */
\r
3160 if( fontBitmapSquareSize > 0 ) {
\r
3161 fontBitmapSquareSize = 0;
\r
3167 BoardWidth(int boardSize, int n)
\r
3168 { /* [HGM] argument n added to allow different width and height */
\r
3169 int lineGap = sizeInfo[boardSize].lineGap;
\r
3171 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3172 lineGap = appData.overrideLineGap;
\r
3175 return (n + 1) * lineGap +
\r
3176 n * sizeInfo[boardSize].squareSize;
\r
3179 /* Respond to board resize by dragging edge */
\r
3181 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3183 BoardSize newSize = NUM_SIZES - 1;
\r
3184 static int recurse = 0;
\r
3185 if (IsIconic(hwndMain)) return;
\r
3186 if (recurse > 0) return;
\r
3188 while (newSize > 0) {
\r
3189 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3190 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3191 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3194 boardSize = newSize;
\r
3195 InitDrawingSizes(boardSize, flags);
\r
3202 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3204 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3205 ChessSquare piece;
\r
3206 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3208 SIZE clockSize, messageSize;
\r
3210 char buf[MSG_SIZ];
\r
3212 HMENU hmenu = GetMenu(hwndMain);
\r
3213 RECT crect, wrect, oldRect;
\r
3215 LOGBRUSH logbrush;
\r
3217 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3218 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3220 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3221 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3223 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3224 oldRect.top = boardY;
\r
3225 oldRect.right = boardX + winWidth;
\r
3226 oldRect.bottom = boardY + winHeight;
\r
3228 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3229 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3230 squareSize = sizeInfo[boardSize].squareSize;
\r
3231 lineGap = sizeInfo[boardSize].lineGap;
\r
3232 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3234 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3235 lineGap = appData.overrideLineGap;
\r
3238 if (tinyLayout != oldTinyLayout) {
\r
3239 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3241 style &= ~WS_SYSMENU;
\r
3242 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3243 "&Minimize\tCtrl+F4");
\r
3245 style |= WS_SYSMENU;
\r
3246 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3248 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3250 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3251 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3252 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3254 DrawMenuBar(hwndMain);
\r
3257 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3258 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3260 /* Get text area sizes */
\r
3261 hdc = GetDC(hwndMain);
\r
3262 if (appData.clockMode) {
\r
3263 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3265 sprintf(buf, "White");
\r
3267 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3268 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3269 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3270 str = "We only care about the height here";
\r
3271 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3272 SelectObject(hdc, oldFont);
\r
3273 ReleaseDC(hwndMain, hdc);
\r
3275 /* Compute where everything goes */
\r
3276 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3277 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3278 logoHeight = 2*clockSize.cy;
\r
3279 leftLogoRect.left = OUTER_MARGIN;
\r
3280 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3281 leftLogoRect.top = OUTER_MARGIN;
\r
3282 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3284 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3285 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3286 rightLogoRect.top = OUTER_MARGIN;
\r
3287 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3290 whiteRect.left = leftLogoRect.right;
\r
3291 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3292 whiteRect.top = OUTER_MARGIN;
\r
3293 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3295 blackRect.right = rightLogoRect.left;
\r
3296 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3297 blackRect.top = whiteRect.top;
\r
3298 blackRect.bottom = whiteRect.bottom;
\r
3300 whiteRect.left = OUTER_MARGIN;
\r
3301 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3302 whiteRect.top = OUTER_MARGIN;
\r
3303 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3305 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3306 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3307 blackRect.top = whiteRect.top;
\r
3308 blackRect.bottom = whiteRect.bottom;
\r
3311 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3312 if (appData.showButtonBar) {
\r
3313 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3314 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3316 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3318 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3319 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3321 boardRect.left = OUTER_MARGIN;
\r
3322 boardRect.right = boardRect.left + boardWidth;
\r
3323 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3324 boardRect.bottom = boardRect.top + boardHeight;
\r
3326 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3327 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3328 oldBoardSize = boardSize;
\r
3329 oldTinyLayout = tinyLayout;
\r
3330 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3331 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3332 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3333 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3334 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3335 winHeight = winH; // without disturbing window attachments
\r
3336 GetWindowRect(hwndMain, &wrect);
\r
3337 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3338 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3340 // [HGM] placement: let attached windows follow size change.
\r
3341 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3342 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3343 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3344 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3345 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3347 /* compensate if menu bar wrapped */
\r
3348 GetClientRect(hwndMain, &crect);
\r
3349 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3350 winHeight += offby;
\r
3352 case WMSZ_TOPLEFT:
\r
3353 SetWindowPos(hwndMain, NULL,
\r
3354 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3355 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3358 case WMSZ_TOPRIGHT:
\r
3360 SetWindowPos(hwndMain, NULL,
\r
3361 wrect.left, wrect.bottom - winHeight,
\r
3362 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3365 case WMSZ_BOTTOMLEFT:
\r
3367 SetWindowPos(hwndMain, NULL,
\r
3368 wrect.right - winWidth, wrect.top,
\r
3369 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3372 case WMSZ_BOTTOMRIGHT:
\r
3376 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3377 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3382 for (i = 0; i < N_BUTTONS; i++) {
\r
3383 if (buttonDesc[i].hwnd != NULL) {
\r
3384 DestroyWindow(buttonDesc[i].hwnd);
\r
3385 buttonDesc[i].hwnd = NULL;
\r
3387 if (appData.showButtonBar) {
\r
3388 buttonDesc[i].hwnd =
\r
3389 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3390 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3391 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3392 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3393 (HMENU) buttonDesc[i].id,
\r
3394 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3396 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3397 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3398 MAKELPARAM(FALSE, 0));
\r
3400 if (buttonDesc[i].id == IDM_Pause)
\r
3401 hwndPause = buttonDesc[i].hwnd;
\r
3402 buttonDesc[i].wndproc = (WNDPROC)
\r
3403 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3406 if (gridPen != NULL) DeleteObject(gridPen);
\r
3407 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3408 if (premovePen != NULL) DeleteObject(premovePen);
\r
3409 if (lineGap != 0) {
\r
3410 logbrush.lbStyle = BS_SOLID;
\r
3411 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3413 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3414 lineGap, &logbrush, 0, NULL);
\r
3415 logbrush.lbColor = highlightSquareColor;
\r
3417 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3418 lineGap, &logbrush, 0, NULL);
\r
3420 logbrush.lbColor = premoveHighlightColor;
\r
3422 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3423 lineGap, &logbrush, 0, NULL);
\r
3425 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3426 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3427 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3428 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3429 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3430 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3431 BOARD_WIDTH * (squareSize + lineGap);
\r
3432 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3434 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3435 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3436 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3437 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3438 lineGap / 2 + (i * (squareSize + lineGap));
\r
3439 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3440 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3441 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3445 /* [HGM] Licensing requirement */
\r
3447 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3450 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3452 GothicPopUp( "", VariantNormal);
\r
3455 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3457 /* Load piece bitmaps for this board size */
\r
3458 for (i=0; i<=2; i++) {
\r
3459 for (piece = WhitePawn;
\r
3460 (int) piece < (int) BlackPawn;
\r
3461 piece = (ChessSquare) ((int) piece + 1)) {
\r
3462 if (pieceBitmap[i][piece] != NULL)
\r
3463 DeleteObject(pieceBitmap[i][piece]);
\r
3467 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3468 // Orthodox Chess pieces
\r
3469 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3470 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3471 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3472 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3473 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3474 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3475 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3476 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3477 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3478 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3479 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3480 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3481 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3482 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3483 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3484 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3485 // in Shogi, Hijack the unused Queen for Lance
\r
3486 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3487 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3488 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3490 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3491 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3492 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3495 if(squareSize <= 72 && squareSize >= 33) {
\r
3496 /* A & C are available in most sizes now */
\r
3497 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3498 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3499 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3500 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3501 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3502 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3503 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3504 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3505 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3506 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3507 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3508 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3509 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3510 } else { // Smirf-like
\r
3511 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3512 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3513 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3515 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3516 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3517 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3518 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3519 } else { // WinBoard standard
\r
3520 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3521 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3522 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3527 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3528 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3529 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3530 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3531 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3532 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3533 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3534 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3535 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3536 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3537 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3538 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3539 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3540 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3541 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3542 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3543 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3544 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3545 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3546 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3547 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3548 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3549 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3550 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3551 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3552 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3553 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3554 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3555 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3556 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3557 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3559 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3560 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3561 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3562 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3563 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3564 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3565 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3566 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3567 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3568 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3569 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3570 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3571 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3573 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3574 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3575 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3576 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3577 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3578 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3579 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3580 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3581 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3582 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3583 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3584 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3587 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3588 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3589 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3590 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3591 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3592 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3593 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3594 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3595 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3596 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3597 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3598 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3599 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3600 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3601 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3605 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3606 /* special Shogi support in this size */
\r
3607 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3608 for (piece = WhitePawn;
\r
3609 (int) piece < (int) BlackPawn;
\r
3610 piece = (ChessSquare) ((int) piece + 1)) {
\r
3611 if (pieceBitmap[i][piece] != NULL)
\r
3612 DeleteObject(pieceBitmap[i][piece]);
\r
3615 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3616 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3617 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3618 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3619 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3620 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3621 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3622 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3623 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3624 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3625 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3626 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3627 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3628 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3629 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3630 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3631 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3632 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3633 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3634 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3635 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3636 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3637 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3638 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3639 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3640 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3641 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3642 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3643 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3644 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3645 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3646 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3647 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3648 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3649 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3650 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3651 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3652 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3653 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3654 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3655 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3656 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3662 PieceBitmap(ChessSquare p, int kind)
\r
3664 if ((int) p >= (int) BlackPawn)
\r
3665 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3667 return pieceBitmap[kind][(int) p];
\r
3670 /***************************************************************/
\r
3672 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3673 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3675 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3676 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3680 SquareToPos(int row, int column, int * x, int * y)
\r
3683 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3684 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3686 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3687 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3692 DrawCoordsOnDC(HDC hdc)
\r
3694 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
3695 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
3696 char str[2] = { NULLCHAR, NULLCHAR };
\r
3697 int oldMode, oldAlign, x, y, start, i;
\r
3701 if (!appData.showCoords)
\r
3704 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3706 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3707 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3708 oldAlign = GetTextAlign(hdc);
\r
3709 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3711 y = boardRect.top + lineGap;
\r
3712 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3714 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3715 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3716 str[0] = files[start + i];
\r
3717 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3718 y += squareSize + lineGap;
\r
3721 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3723 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3724 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3725 str[0] = ranks[start + i];
\r
3726 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3727 x += squareSize + lineGap;
\r
3730 SelectObject(hdc, oldBrush);
\r
3731 SetBkMode(hdc, oldMode);
\r
3732 SetTextAlign(hdc, oldAlign);
\r
3733 SelectObject(hdc, oldFont);
\r
3737 DrawGridOnDC(HDC hdc)
\r
3741 if (lineGap != 0) {
\r
3742 oldPen = SelectObject(hdc, gridPen);
\r
3743 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3744 SelectObject(hdc, oldPen);
\r
3748 #define HIGHLIGHT_PEN 0
\r
3749 #define PREMOVE_PEN 1
\r
3752 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3755 HPEN oldPen, hPen;
\r
3756 if (lineGap == 0) return;
\r
3758 x1 = boardRect.left +
\r
3759 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3760 y1 = boardRect.top +
\r
3761 lineGap/2 + y * (squareSize + lineGap);
\r
3763 x1 = boardRect.left +
\r
3764 lineGap/2 + x * (squareSize + lineGap);
\r
3765 y1 = boardRect.top +
\r
3766 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3768 hPen = pen ? premovePen : highlightPen;
\r
3769 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3770 MoveToEx(hdc, x1, y1, NULL);
\r
3771 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3772 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3773 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3774 LineTo(hdc, x1, y1);
\r
3775 SelectObject(hdc, oldPen);
\r
3779 DrawHighlightsOnDC(HDC hdc)
\r
3782 for (i=0; i<2; i++) {
\r
3783 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3784 DrawHighlightOnDC(hdc, TRUE,
\r
3785 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3788 for (i=0; i<2; i++) {
\r
3789 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3790 premoveHighlightInfo.sq[i].y >= 0) {
\r
3791 DrawHighlightOnDC(hdc, TRUE,
\r
3792 premoveHighlightInfo.sq[i].x,
\r
3793 premoveHighlightInfo.sq[i].y,
\r
3799 /* Note: sqcolor is used only in monoMode */
\r
3800 /* Note that this code is largely duplicated in woptions.c,
\r
3801 function DrawSampleSquare, so that needs to be updated too */
\r
3803 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3805 HBITMAP oldBitmap;
\r
3809 if (appData.blindfold) return;
\r
3811 /* [AS] Use font-based pieces if needed */
\r
3812 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3813 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3814 CreatePiecesFromFont();
\r
3816 if( fontBitmapSquareSize == squareSize ) {
\r
3817 int index = TranslatePieceToFontPiece(piece);
\r
3819 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3823 squareSize, squareSize,
\r
3828 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3832 squareSize, squareSize,
\r
3841 if (appData.monoMode) {
\r
3842 SelectObject(tmphdc, PieceBitmap(piece,
\r
3843 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3844 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3845 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3847 tmpSize = squareSize;
\r
3849 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3850 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3851 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3852 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3853 x += (squareSize - minorSize)>>1;
\r
3854 y += squareSize - minorSize - 2;
\r
3855 tmpSize = minorSize;
\r
3857 if (color || appData.allWhite ) {
\r
3858 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3860 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3861 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3862 if(appData.upsideDown && color==flipView)
\r
3863 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3865 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3867 /* Use black piece color for outline of white pieces */
\r
3868 /* Not sure this looks really good (though xboard does it).
\r
3869 Maybe better to have another selectable color, default black */
\r
3870 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3871 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3872 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3874 /* Use black for outline of white pieces */
\r
3875 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3876 if(appData.upsideDown && color==flipView)
\r
3877 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3879 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3883 /* Use white piece color for details of black pieces */
\r
3884 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3885 WHITE_PIECE ones aren't always the right shape. */
\r
3886 /* Not sure this looks really good (though xboard does it).
\r
3887 Maybe better to have another selectable color, default medium gray? */
\r
3888 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3889 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3890 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3891 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3892 SelectObject(hdc, blackPieceBrush);
\r
3893 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3895 /* Use square color for details of black pieces */
\r
3896 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3897 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3898 if(appData.upsideDown && !flipView)
\r
3899 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3901 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3904 SelectObject(hdc, oldBrush);
\r
3905 SelectObject(tmphdc, oldBitmap);
\r
3909 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3910 int GetBackTextureMode( int algo )
\r
3912 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3916 case BACK_TEXTURE_MODE_PLAIN:
\r
3917 result = 1; /* Always use identity map */
\r
3919 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3920 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3928 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3929 to handle redraws cleanly (as random numbers would always be different).
\r
3931 VOID RebuildTextureSquareInfo()
\r
3941 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3943 if( liteBackTexture != NULL ) {
\r
3944 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3945 lite_w = bi.bmWidth;
\r
3946 lite_h = bi.bmHeight;
\r
3950 if( darkBackTexture != NULL ) {
\r
3951 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3952 dark_w = bi.bmWidth;
\r
3953 dark_h = bi.bmHeight;
\r
3957 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3958 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3959 if( (col + row) & 1 ) {
\r
3961 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3962 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3963 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3964 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3969 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3970 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3971 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3972 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3979 /* [AS] Arrow highlighting support */
\r
3981 static int A_WIDTH = 5; /* Width of arrow body */
\r
3983 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3984 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3986 static double Sqr( double x )
\r
3991 static int Round( double x )
\r
3993 return (int) (x + 0.5);
\r
3996 /* Draw an arrow between two points using current settings */
\r
3997 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
4000 double dx, dy, j, k, x, y;
\r
4002 if( d_x == s_x ) {
\r
4003 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4005 arrow[0].x = s_x + A_WIDTH;
\r
4008 arrow[1].x = s_x + A_WIDTH;
\r
4009 arrow[1].y = d_y - h;
\r
4011 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4012 arrow[2].y = d_y - h;
\r
4017 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4018 arrow[4].y = d_y - h;
\r
4020 arrow[5].x = s_x - A_WIDTH;
\r
4021 arrow[5].y = d_y - h;
\r
4023 arrow[6].x = s_x - A_WIDTH;
\r
4026 else if( d_y == s_y ) {
\r
4027 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4030 arrow[0].y = s_y + A_WIDTH;
\r
4032 arrow[1].x = d_x - w;
\r
4033 arrow[1].y = s_y + A_WIDTH;
\r
4035 arrow[2].x = d_x - w;
\r
4036 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4041 arrow[4].x = d_x - w;
\r
4042 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4044 arrow[5].x = d_x - w;
\r
4045 arrow[5].y = s_y - A_WIDTH;
\r
4048 arrow[6].y = s_y - A_WIDTH;
\r
4051 /* [AS] Needed a lot of paper for this! :-) */
\r
4052 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4053 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4055 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4057 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4062 arrow[0].x = Round(x - j);
\r
4063 arrow[0].y = Round(y + j*dx);
\r
4065 arrow[1].x = Round(x + j);
\r
4066 arrow[1].y = Round(y - j*dx);
\r
4069 x = (double) d_x - k;
\r
4070 y = (double) d_y - k*dy;
\r
4073 x = (double) d_x + k;
\r
4074 y = (double) d_y + k*dy;
\r
4077 arrow[2].x = Round(x + j);
\r
4078 arrow[2].y = Round(y - j*dx);
\r
4080 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4081 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4086 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4087 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4089 arrow[6].x = Round(x - j);
\r
4090 arrow[6].y = Round(y + j*dx);
\r
4093 Polygon( hdc, arrow, 7 );
\r
4096 /* [AS] Draw an arrow between two squares */
\r
4097 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4099 int s_x, s_y, d_x, d_y;
\r
4106 if( s_col == d_col && s_row == d_row ) {
\r
4110 /* Get source and destination points */
\r
4111 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4112 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4115 d_y += squareSize / 4;
\r
4117 else if( d_y < s_y ) {
\r
4118 d_y += 3 * squareSize / 4;
\r
4121 d_y += squareSize / 2;
\r
4125 d_x += squareSize / 4;
\r
4127 else if( d_x < s_x ) {
\r
4128 d_x += 3 * squareSize / 4;
\r
4131 d_x += squareSize / 2;
\r
4134 s_x += squareSize / 2;
\r
4135 s_y += squareSize / 2;
\r
4137 /* Adjust width */
\r
4138 A_WIDTH = squareSize / 14;
\r
4141 stLB.lbStyle = BS_SOLID;
\r
4142 stLB.lbColor = appData.highlightArrowColor;
\r
4145 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4146 holdpen = SelectObject( hdc, hpen );
\r
4147 hbrush = CreateBrushIndirect( &stLB );
\r
4148 holdbrush = SelectObject( hdc, hbrush );
\r
4150 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4152 SelectObject( hdc, holdpen );
\r
4153 SelectObject( hdc, holdbrush );
\r
4154 DeleteObject( hpen );
\r
4155 DeleteObject( hbrush );
\r
4158 BOOL HasHighlightInfo()
\r
4160 BOOL result = FALSE;
\r
4162 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4163 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4171 BOOL IsDrawArrowEnabled()
\r
4173 BOOL result = FALSE;
\r
4175 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4182 VOID DrawArrowHighlight( HDC hdc )
\r
4184 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4185 DrawArrowBetweenSquares( hdc,
\r
4186 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4187 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4191 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4193 HRGN result = NULL;
\r
4195 if( HasHighlightInfo() ) {
\r
4196 int x1, y1, x2, y2;
\r
4197 int sx, sy, dx, dy;
\r
4199 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4200 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4202 sx = MIN( x1, x2 );
\r
4203 sy = MIN( y1, y2 );
\r
4204 dx = MAX( x1, x2 ) + squareSize;
\r
4205 dy = MAX( y1, y2 ) + squareSize;
\r
4207 result = CreateRectRgn( sx, sy, dx, dy );
\r
4214 Warning: this function modifies the behavior of several other functions.
\r
4216 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4217 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4218 repaint is scattered all over the place, which is not good for features such as
\r
4219 "arrow highlighting" that require a full repaint of the board.
\r
4221 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4222 user interaction, when speed is not so important) but especially to avoid errors
\r
4223 in the displayed graphics.
\r
4225 In such patched places, I always try refer to this function so there is a single
\r
4226 place to maintain knowledge.
\r
4228 To restore the original behavior, just return FALSE unconditionally.
\r
4230 BOOL IsFullRepaintPreferrable()
\r
4232 BOOL result = FALSE;
\r
4234 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4235 /* Arrow may appear on the board */
\r
4243 This function is called by DrawPosition to know whether a full repaint must
\r
4246 Only DrawPosition may directly call this function, which makes use of
\r
4247 some state information. Other function should call DrawPosition specifying
\r
4248 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4250 BOOL DrawPositionNeedsFullRepaint()
\r
4252 BOOL result = FALSE;
\r
4255 Probably a slightly better policy would be to trigger a full repaint
\r
4256 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4257 but animation is fast enough that it's difficult to notice.
\r
4259 if( animInfo.piece == EmptySquare ) {
\r
4260 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4269 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4271 int row, column, x, y, square_color, piece_color;
\r
4272 ChessSquare piece;
\r
4274 HDC texture_hdc = NULL;
\r
4276 /* [AS] Initialize background textures if needed */
\r
4277 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4278 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4279 if( backTextureSquareSize != squareSize
\r
4280 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4281 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4282 backTextureSquareSize = squareSize;
\r
4283 RebuildTextureSquareInfo();
\r
4286 texture_hdc = CreateCompatibleDC( hdc );
\r
4289 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4290 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4292 SquareToPos(row, column, &x, &y);
\r
4294 piece = board[row][column];
\r
4296 square_color = ((column + row) % 2) == 1;
\r
4297 if( gameInfo.variant == VariantXiangqi ) {
\r
4298 square_color = !InPalace(row, column);
\r
4299 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4300 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4302 piece_color = (int) piece < (int) BlackPawn;
\r
4305 /* [HGM] holdings file: light square or black */
\r
4306 if(column == BOARD_LEFT-2) {
\r
4307 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4310 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4314 if(column == BOARD_RGHT + 1 ) {
\r
4315 if( row < gameInfo.holdingsSize )
\r
4318 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4322 if(column == BOARD_LEFT-1 ) /* left align */
\r
4323 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4324 else if( column == BOARD_RGHT) /* right align */
\r
4325 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4327 if (appData.monoMode) {
\r
4328 if (piece == EmptySquare) {
\r
4329 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4330 square_color ? WHITENESS : BLACKNESS);
\r
4332 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4335 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4336 /* [AS] Draw the square using a texture bitmap */
\r
4337 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4338 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4339 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4342 squareSize, squareSize,
\r
4345 backTextureSquareInfo[r][c].mode,
\r
4346 backTextureSquareInfo[r][c].x,
\r
4347 backTextureSquareInfo[r][c].y );
\r
4349 SelectObject( texture_hdc, hbm );
\r
4351 if (piece != EmptySquare) {
\r
4352 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4356 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4358 oldBrush = SelectObject(hdc, brush );
\r
4359 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4360 SelectObject(hdc, oldBrush);
\r
4361 if (piece != EmptySquare)
\r
4362 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4367 if( texture_hdc != NULL ) {
\r
4368 DeleteDC( texture_hdc );
\r
4372 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4373 void fputDW(FILE *f, int x)
\r
4375 fputc(x & 255, f);
\r
4376 fputc(x>>8 & 255, f);
\r
4377 fputc(x>>16 & 255, f);
\r
4378 fputc(x>>24 & 255, f);
\r
4381 #define MAX_CLIPS 200 /* more than enough */
\r
4384 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4386 // HBITMAP bufferBitmap;
\r
4391 int w = 100, h = 50;
\r
4393 if(logo == NULL) return;
\r
4394 // GetClientRect(hwndMain, &Rect);
\r
4395 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4396 // Rect.bottom-Rect.top+1);
\r
4397 tmphdc = CreateCompatibleDC(hdc);
\r
4398 hbm = SelectObject(tmphdc, logo);
\r
4399 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4403 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4404 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4405 SelectObject(tmphdc, hbm);
\r
4410 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4412 static Board lastReq, lastDrawn;
\r
4413 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4414 static int lastDrawnFlipView = 0;
\r
4415 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4416 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4419 HBITMAP bufferBitmap;
\r
4420 HBITMAP oldBitmap;
\r
4422 HRGN clips[MAX_CLIPS];
\r
4423 ChessSquare dragged_piece = EmptySquare;
\r
4425 /* I'm undecided on this - this function figures out whether a full
\r
4426 * repaint is necessary on its own, so there's no real reason to have the
\r
4427 * caller tell it that. I think this can safely be set to FALSE - but
\r
4428 * if we trust the callers not to request full repaints unnessesarily, then
\r
4429 * we could skip some clipping work. In other words, only request a full
\r
4430 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4431 * gamestart and similar) --Hawk
\r
4433 Boolean fullrepaint = repaint;
\r
4435 if( DrawPositionNeedsFullRepaint() ) {
\r
4436 fullrepaint = TRUE;
\r
4440 if( fullrepaint ) {
\r
4441 static int repaint_count = 0;
\r
4445 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4446 OutputDebugString( buf );
\r
4450 if (board == NULL) {
\r
4451 if (!lastReqValid) {
\r
4456 CopyBoard(lastReq, board);
\r
4460 if (doingSizing) {
\r
4464 if (IsIconic(hwndMain)) {
\r
4468 if (hdc == NULL) {
\r
4469 hdc = GetDC(hwndMain);
\r
4470 if (!appData.monoMode) {
\r
4471 SelectPalette(hdc, hPal, FALSE);
\r
4472 RealizePalette(hdc);
\r
4476 releaseDC = FALSE;
\r
4480 fprintf(debugFP, "*******************************\n"
\r
4482 "dragInfo.from (%d,%d)\n"
\r
4483 "dragInfo.start (%d,%d)\n"
\r
4484 "dragInfo.pos (%d,%d)\n"
\r
4485 "dragInfo.lastpos (%d,%d)\n",
\r
4486 repaint ? "TRUE" : "FALSE",
\r
4487 dragInfo.from.x, dragInfo.from.y,
\r
4488 dragInfo.start.x, dragInfo.start.y,
\r
4489 dragInfo.pos.x, dragInfo.pos.y,
\r
4490 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4491 fprintf(debugFP, "prev: ");
\r
4492 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4493 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4494 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4497 fprintf(debugFP, "\n");
\r
4498 fprintf(debugFP, "board: ");
\r
4499 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4500 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4501 fprintf(debugFP, "%d ", board[row][column]);
\r
4504 fprintf(debugFP, "\n");
\r
4508 /* Create some work-DCs */
\r
4509 hdcmem = CreateCompatibleDC(hdc);
\r
4510 tmphdc = CreateCompatibleDC(hdc);
\r
4512 /* If dragging is in progress, we temporarely remove the piece */
\r
4513 /* [HGM] or temporarily decrease count if stacked */
\r
4514 /* !! Moved to before board compare !! */
\r
4515 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4516 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4517 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4518 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4519 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4521 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4522 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4523 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4525 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4528 /* Figure out which squares need updating by comparing the
\r
4529 * newest board with the last drawn board and checking if
\r
4530 * flipping has changed.
\r
4532 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4533 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4534 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4535 if (lastDrawn[row][column] != board[row][column]) {
\r
4536 SquareToPos(row, column, &x, &y);
\r
4537 clips[num_clips++] =
\r
4538 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4542 for (i=0; i<2; i++) {
\r
4543 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4544 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4545 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4546 lastDrawnHighlight.sq[i].y >= 0) {
\r
4547 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4548 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4549 clips[num_clips++] =
\r
4550 CreateRectRgn(x - lineGap, y - lineGap,
\r
4551 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4553 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4554 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4555 clips[num_clips++] =
\r
4556 CreateRectRgn(x - lineGap, y - lineGap,
\r
4557 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4561 for (i=0; i<2; i++) {
\r
4562 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4563 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4564 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4565 lastDrawnPremove.sq[i].y >= 0) {
\r
4566 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4567 lastDrawnPremove.sq[i].x, &x, &y);
\r
4568 clips[num_clips++] =
\r
4569 CreateRectRgn(x - lineGap, y - lineGap,
\r
4570 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4572 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4573 premoveHighlightInfo.sq[i].y >= 0) {
\r
4574 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4575 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4576 clips[num_clips++] =
\r
4577 CreateRectRgn(x - lineGap, y - lineGap,
\r
4578 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4583 fullrepaint = TRUE;
\r
4586 /* Create a buffer bitmap - this is the actual bitmap
\r
4587 * being written to. When all the work is done, we can
\r
4588 * copy it to the real DC (the screen). This avoids
\r
4589 * the problems with flickering.
\r
4591 GetClientRect(hwndMain, &Rect);
\r
4592 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4593 Rect.bottom-Rect.top+1);
\r
4594 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4595 if (!appData.monoMode) {
\r
4596 SelectPalette(hdcmem, hPal, FALSE);
\r
4599 /* Create clips for dragging */
\r
4600 if (!fullrepaint) {
\r
4601 if (dragInfo.from.x >= 0) {
\r
4602 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4603 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4605 if (dragInfo.start.x >= 0) {
\r
4606 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4607 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4609 if (dragInfo.pos.x >= 0) {
\r
4610 x = dragInfo.pos.x - squareSize / 2;
\r
4611 y = dragInfo.pos.y - squareSize / 2;
\r
4612 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4614 if (dragInfo.lastpos.x >= 0) {
\r
4615 x = dragInfo.lastpos.x - squareSize / 2;
\r
4616 y = dragInfo.lastpos.y - squareSize / 2;
\r
4617 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4621 /* Are we animating a move?
\r
4623 * - remove the piece from the board (temporarely)
\r
4624 * - calculate the clipping region
\r
4626 if (!fullrepaint) {
\r
4627 if (animInfo.piece != EmptySquare) {
\r
4628 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4629 x = boardRect.left + animInfo.lastpos.x;
\r
4630 y = boardRect.top + animInfo.lastpos.y;
\r
4631 x2 = boardRect.left + animInfo.pos.x;
\r
4632 y2 = boardRect.top + animInfo.pos.y;
\r
4633 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4634 /* Slight kludge. The real problem is that after AnimateMove is
\r
4635 done, the position on the screen does not match lastDrawn.
\r
4636 This currently causes trouble only on e.p. captures in
\r
4637 atomic, where the piece moves to an empty square and then
\r
4638 explodes. The old and new positions both had an empty square
\r
4639 at the destination, but animation has drawn a piece there and
\r
4640 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4641 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4645 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4646 if (num_clips == 0)
\r
4647 fullrepaint = TRUE;
\r
4649 /* Set clipping on the memory DC */
\r
4650 if (!fullrepaint) {
\r
4651 SelectClipRgn(hdcmem, clips[0]);
\r
4652 for (x = 1; x < num_clips; x++) {
\r
4653 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4654 abort(); // this should never ever happen!
\r
4658 /* Do all the drawing to the memory DC */
\r
4659 if(explodeInfo.radius) { // [HGM] atomic
\r
4661 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4662 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4663 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4664 x += squareSize/2;
\r
4665 y += squareSize/2;
\r
4666 if(!fullrepaint) {
\r
4667 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4668 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4670 DrawGridOnDC(hdcmem);
\r
4671 DrawHighlightsOnDC(hdcmem);
\r
4672 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4673 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4674 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4675 SelectObject(hdcmem, oldBrush);
\r
4677 DrawGridOnDC(hdcmem);
\r
4678 DrawHighlightsOnDC(hdcmem);
\r
4679 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4682 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4683 if(appData.autoLogo) {
\r
4685 switch(gameMode) { // pick logos based on game mode
\r
4686 case IcsObserving:
\r
4687 whiteLogo = second.programLogo; // ICS logo
\r
4688 blackLogo = second.programLogo;
\r
4691 case IcsPlayingWhite:
\r
4692 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4693 blackLogo = second.programLogo; // ICS logo
\r
4695 case IcsPlayingBlack:
\r
4696 whiteLogo = second.programLogo; // ICS logo
\r
4697 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4699 case TwoMachinesPlay:
\r
4700 if(first.twoMachinesColor[0] == 'b') {
\r
4701 whiteLogo = second.programLogo;
\r
4702 blackLogo = first.programLogo;
\r
4705 case MachinePlaysWhite:
\r
4706 blackLogo = userLogo;
\r
4708 case MachinePlaysBlack:
\r
4709 whiteLogo = userLogo;
\r
4710 blackLogo = first.programLogo;
\r
4713 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4714 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4717 if( appData.highlightMoveWithArrow ) {
\r
4718 DrawArrowHighlight(hdcmem);
\r
4721 DrawCoordsOnDC(hdcmem);
\r
4723 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4724 /* to make sure lastDrawn contains what is actually drawn */
\r
4726 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4727 if (dragged_piece != EmptySquare) {
\r
4728 /* [HGM] or restack */
\r
4729 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4730 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4732 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4733 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4734 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4735 x = dragInfo.pos.x - squareSize / 2;
\r
4736 y = dragInfo.pos.y - squareSize / 2;
\r
4737 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4738 ((int) dragged_piece < (int) BlackPawn),
\r
4739 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4742 /* Put the animated piece back into place and draw it */
\r
4743 if (animInfo.piece != EmptySquare) {
\r
4744 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4745 x = boardRect.left + animInfo.pos.x;
\r
4746 y = boardRect.top + animInfo.pos.y;
\r
4747 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4748 ((int) animInfo.piece < (int) BlackPawn),
\r
4749 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4752 /* Release the bufferBitmap by selecting in the old bitmap
\r
4753 * and delete the memory DC
\r
4755 SelectObject(hdcmem, oldBitmap);
\r
4758 /* Set clipping on the target DC */
\r
4759 if (!fullrepaint) {
\r
4760 SelectClipRgn(hdc, clips[0]);
\r
4761 for (x = 1; x < num_clips; x++) {
\r
4762 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4763 abort(); // this should never ever happen!
\r
4767 /* Copy the new bitmap onto the screen in one go.
\r
4768 * This way we avoid any flickering
\r
4770 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4771 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4772 boardRect.right - boardRect.left,
\r
4773 boardRect.bottom - boardRect.top,
\r
4774 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4775 if(saveDiagFlag) {
\r
4776 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4777 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4779 GetObject(bufferBitmap, sizeof(b), &b);
\r
4780 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4781 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4782 bih.biWidth = b.bmWidth;
\r
4783 bih.biHeight = b.bmHeight;
\r
4785 bih.biBitCount = b.bmBitsPixel;
\r
4786 bih.biCompression = 0;
\r
4787 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4788 bih.biXPelsPerMeter = 0;
\r
4789 bih.biYPelsPerMeter = 0;
\r
4790 bih.biClrUsed = 0;
\r
4791 bih.biClrImportant = 0;
\r
4792 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4793 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4794 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4795 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4798 wb = b.bmWidthBytes;
\r
4800 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4801 int k = ((int*) pData)[i];
\r
4802 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4803 if(j >= 16) break;
\r
4805 if(j >= nrColors) nrColors = j+1;
\r
4807 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4809 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4810 for(w=0; w<(wb>>2); w+=2) {
\r
4811 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4812 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4813 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4814 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4815 pData[p++] = m | j<<4;
\r
4817 while(p&3) pData[p++] = 0;
\r
4820 wb = ((wb+31)>>5)<<2;
\r
4822 // write BITMAPFILEHEADER
\r
4823 fprintf(diagFile, "BM");
\r
4824 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4825 fputDW(diagFile, 0);
\r
4826 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4827 // write BITMAPINFOHEADER
\r
4828 fputDW(diagFile, 40);
\r
4829 fputDW(diagFile, b.bmWidth);
\r
4830 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4831 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4832 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4833 fputDW(diagFile, 0);
\r
4834 fputDW(diagFile, 0);
\r
4835 fputDW(diagFile, 0);
\r
4836 fputDW(diagFile, 0);
\r
4837 fputDW(diagFile, 0);
\r
4838 fputDW(diagFile, 0);
\r
4839 // write color table
\r
4841 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4842 // write bitmap data
\r
4843 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4844 fputc(pData[i], diagFile);
\r
4849 SelectObject(tmphdc, oldBitmap);
\r
4851 /* Massive cleanup */
\r
4852 for (x = 0; x < num_clips; x++)
\r
4853 DeleteObject(clips[x]);
\r
4856 DeleteObject(bufferBitmap);
\r
4859 ReleaseDC(hwndMain, hdc);
\r
4861 if (lastDrawnFlipView != flipView) {
\r
4863 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4865 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4868 /* CopyBoard(lastDrawn, board);*/
\r
4869 lastDrawnHighlight = highlightInfo;
\r
4870 lastDrawnPremove = premoveHighlightInfo;
\r
4871 lastDrawnFlipView = flipView;
\r
4872 lastDrawnValid = 1;
\r
4875 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4880 saveDiagFlag = 1; diagFile = f;
\r
4881 HDCDrawPosition(NULL, TRUE, NULL);
\r
4885 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4892 /*---------------------------------------------------------------------------*\
\r
4893 | CLIENT PAINT PROCEDURE
\r
4894 | This is the main event-handler for the WM_PAINT message.
\r
4896 \*---------------------------------------------------------------------------*/
\r
4898 PaintProc(HWND hwnd)
\r
4904 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4905 if (IsIconic(hwnd)) {
\r
4906 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4908 if (!appData.monoMode) {
\r
4909 SelectPalette(hdc, hPal, FALSE);
\r
4910 RealizePalette(hdc);
\r
4912 HDCDrawPosition(hdc, 1, NULL);
\r
4914 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4915 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4916 ETO_CLIPPED|ETO_OPAQUE,
\r
4917 &messageRect, messageText, strlen(messageText), NULL);
\r
4918 SelectObject(hdc, oldFont);
\r
4919 DisplayBothClocks();
\r
4921 EndPaint(hwnd,&ps);
\r
4929 * If the user selects on a border boundary, return -1; if off the board,
\r
4930 * return -2. Otherwise map the event coordinate to the square.
\r
4931 * The offset boardRect.left or boardRect.top must already have been
\r
4932 * subtracted from x.
\r
4935 EventToSquare(int x)
\r
4942 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4944 x /= (squareSize + lineGap);
\r
4945 if (x >= BOARD_SIZE)
\r
4956 DropEnable dropEnables[] = {
\r
4957 { 'P', DP_Pawn, "Pawn" },
\r
4958 { 'N', DP_Knight, "Knight" },
\r
4959 { 'B', DP_Bishop, "Bishop" },
\r
4960 { 'R', DP_Rook, "Rook" },
\r
4961 { 'Q', DP_Queen, "Queen" },
\r
4965 SetupDropMenu(HMENU hmenu)
\r
4967 int i, count, enable;
\r
4969 extern char white_holding[], black_holding[];
\r
4970 char item[MSG_SIZ];
\r
4972 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4973 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4974 dropEnables[i].piece);
\r
4976 while (p && *p++ == dropEnables[i].piece) count++;
\r
4977 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4978 enable = count > 0 || !appData.testLegality
\r
4979 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4980 && !appData.icsActive);
\r
4981 ModifyMenu(hmenu, dropEnables[i].command,
\r
4982 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4983 dropEnables[i].command, item);
\r
4987 /* Event handler for mouse messages */
\r
4989 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4993 static int recursive = 0;
\r
4995 // BOOLEAN needsRedraw = FALSE;
\r
4996 BOOLEAN saveAnimate;
\r
4997 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4998 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4999 ChessMove moveType;
\r
5002 if (message == WM_MBUTTONUP) {
\r
5003 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5004 to the middle button: we simulate pressing the left button too!
\r
5006 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5007 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5013 pt.x = LOWORD(lParam);
\r
5014 pt.y = HIWORD(lParam);
\r
5015 x = EventToSquare(pt.x - boardRect.left);
\r
5016 y = EventToSquare(pt.y - boardRect.top);
\r
5017 if (!flipView && y >= 0) {
\r
5018 y = BOARD_HEIGHT - 1 - y;
\r
5020 if (flipView && x >= 0) {
\r
5021 x = BOARD_WIDTH - 1 - x;
\r
5024 switch (message) {
\r
5025 case WM_LBUTTONDOWN:
\r
5026 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5027 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5028 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5029 if(gameInfo.holdingsWidth &&
\r
5030 (WhiteOnMove(currentMove)
\r
5031 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5032 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5033 // click in right holdings, for determining promotion piece
\r
5034 ChessSquare p = boards[currentMove][y][x];
\r
5035 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5036 if(p != EmptySquare) {
\r
5037 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5038 fromX = fromY = -1;
\r
5042 DrawPosition(FALSE, boards[currentMove]);
\r
5046 sameAgain = FALSE;
\r
5048 /* Downclick vertically off board; check if on clock */
\r
5049 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5050 if (gameMode == EditPosition) {
\r
5051 SetWhiteToPlayEvent();
\r
5052 } else if (gameMode == IcsPlayingBlack ||
\r
5053 gameMode == MachinePlaysWhite) {
\r
5055 } else if (gameMode == EditGame) {
\r
5056 AdjustClock(flipClock, -1);
\r
5058 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5059 if (gameMode == EditPosition) {
\r
5060 SetBlackToPlayEvent();
\r
5061 } else if (gameMode == IcsPlayingWhite ||
\r
5062 gameMode == MachinePlaysBlack) {
\r
5064 } else if (gameMode == EditGame) {
\r
5065 AdjustClock(!flipClock, -1);
\r
5068 if (!appData.highlightLastMove) {
\r
5069 ClearHighlights();
\r
5070 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5072 fromX = fromY = -1;
\r
5073 dragInfo.start.x = dragInfo.start.y = -1;
\r
5074 dragInfo.from = dragInfo.start;
\r
5076 } else if (x < 0 || y < 0
\r
5077 /* [HGM] block clicks between board and holdings */
\r
5078 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5079 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5080 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5081 /* EditPosition, empty square, or different color piece;
\r
5082 click-click move is possible */
\r
5085 } else if (fromX == x && fromY == y) {
\r
5086 /* Downclick on same square again */
\r
5087 ClearHighlights();
\r
5088 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5089 sameAgain = TRUE;
\r
5090 } else if (fromX != -1 &&
\r
5091 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5093 /* Downclick on different square. */
\r
5094 /* [HGM] if on holdings file, should count as new first click ! */
\r
5095 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5098 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5099 to make sure move is legal before showing promotion popup */
\r
5100 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5101 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5102 fromX = fromY = -1;
\r
5103 ClearHighlights();
\r
5104 DrawPosition(FALSE, boards[currentMove]);
\r
5107 if(moveType != ImpossibleMove) {
\r
5108 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5109 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5110 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5111 appData.alwaysPromoteToQueen)) {
\r
5112 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5113 if (!appData.highlightLastMove) {
\r
5114 ClearHighlights();
\r
5115 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5118 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5119 SetHighlights(fromX, fromY, toX, toY);
\r
5120 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5121 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5122 If promotion to Q is legal, all are legal! */
\r
5123 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5124 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5125 // kludge to temporarily execute move on display, wthout promotng yet
\r
5126 promotionChoice = TRUE;
\r
5127 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5128 boards[currentMove][toY][toX] = p;
\r
5129 DrawPosition(FALSE, boards[currentMove]);
\r
5130 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5131 boards[currentMove][toY][toX] = q;
\r
5133 PromotionPopup(hwnd);
\r
5134 } else { /* not a promotion */
\r
5135 if (appData.animate || appData.highlightLastMove) {
\r
5136 SetHighlights(fromX, fromY, toX, toY);
\r
5138 ClearHighlights();
\r
5140 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5141 fromX = fromY = -1;
\r
5142 if (appData.animate && !appData.highlightLastMove) {
\r
5143 ClearHighlights();
\r
5144 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5150 /* [HGM] it seemed that braces were missing here */
\r
5151 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5152 fromX = fromY = -1;
\r
5156 ClearHighlights();
\r
5157 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5159 /* First downclick, or restart on a square with same color piece */
\r
5160 if (!frozen && OKToStartUserMove(x, y)) {
\r
5163 dragInfo.lastpos = pt;
\r
5164 dragInfo.from.x = fromX;
\r
5165 dragInfo.from.y = fromY;
\r
5166 dragInfo.start = dragInfo.from;
\r
5167 SetCapture(hwndMain);
\r
5169 fromX = fromY = -1;
\r
5170 dragInfo.start.x = dragInfo.start.y = -1;
\r
5171 dragInfo.from = dragInfo.start;
\r
5172 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5176 case WM_LBUTTONUP:
\r
5178 if (fromX == -1) break;
\r
5179 if (x == fromX && y == fromY) {
\r
5180 dragInfo.from.x = dragInfo.from.y = -1;
\r
5181 /* Upclick on same square */
\r
5183 /* Clicked same square twice: abort click-click move */
\r
5184 fromX = fromY = -1;
\r
5186 ClearPremoveHighlights();
\r
5188 /* First square clicked: start click-click move */
\r
5189 SetHighlights(fromX, fromY, -1, -1);
\r
5191 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5192 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5193 /* Errant click; ignore */
\r
5196 /* Finish drag move. */
\r
5197 if (appData.debugMode) {
\r
5198 fprintf(debugFP, "release\n");
\r
5200 dragInfo.from.x = dragInfo.from.y = -1;
\r
5203 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5204 appData.animate = appData.animate && !appData.animateDragging;
\r
5205 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5206 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5207 fromX = fromY = -1;
\r
5208 ClearHighlights();
\r
5209 DrawPosition(FALSE, boards[currentMove]);
\r
5210 appData.animate = saveAnimate;
\r
5213 if(moveType != ImpossibleMove) {
\r
5214 /* [HGM] use move type to determine if move is promotion.
\r
5215 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5216 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5217 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5218 appData.alwaysPromoteToQueen))
\r
5219 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5221 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5222 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5223 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5224 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5225 // kludge to temporarily execute move on display, wthout promotng yet
\r
5226 promotionChoice = TRUE;
\r
5227 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5228 boards[currentMove][toY][toX] = p;
\r
5229 DrawPosition(FALSE, boards[currentMove]);
\r
5230 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5231 boards[currentMove][toY][toX] = q;
\r
5232 appData.animate = saveAnimate;
\r
5235 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5237 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5238 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5239 moveType == WhiteCapturesEnPassant ||
\r
5240 moveType == BlackCapturesEnPassant ) )
\r
5241 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5242 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5245 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5246 appData.animate = saveAnimate;
\r
5247 fromX = fromY = -1;
\r
5248 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5249 ClearHighlights();
\r
5251 if (appData.animate || appData.animateDragging ||
\r
5252 appData.highlightDragging || gotPremove) {
\r
5253 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5256 dragInfo.start.x = dragInfo.start.y = -1;
\r
5257 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5260 case WM_MOUSEMOVE:
\r
5261 if ((appData.animateDragging || appData.highlightDragging)
\r
5262 && (wParam & MK_LBUTTON)
\r
5263 && dragInfo.from.x >= 0)
\r
5265 BOOL full_repaint = FALSE;
\r
5267 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5268 if (appData.animateDragging) {
\r
5269 dragInfo.pos = pt;
\r
5271 if (appData.highlightDragging) {
\r
5272 SetHighlights(fromX, fromY, x, y);
\r
5273 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5274 full_repaint = TRUE;
\r
5278 DrawPosition( full_repaint, NULL);
\r
5280 dragInfo.lastpos = dragInfo.pos;
\r
5284 case WM_MOUSEWHEEL: // [DM]
\r
5285 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5286 /* Mouse Wheel is being rolled forward
\r
5287 * Play moves forward
\r
5289 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5290 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5291 /* Mouse Wheel is being rolled backward
\r
5292 * Play moves backward
\r
5294 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5295 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5299 case WM_MBUTTONDOWN:
\r
5300 case WM_RBUTTONDOWN:
\r
5303 fromX = fromY = -1;
\r
5304 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5305 dragInfo.start.x = dragInfo.start.y = -1;
\r
5306 dragInfo.from = dragInfo.start;
\r
5307 dragInfo.lastpos = dragInfo.pos;
\r
5308 if (appData.highlightDragging) {
\r
5309 ClearHighlights();
\r
5312 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5313 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5314 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5315 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5316 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5319 DrawPosition(TRUE, NULL);
\r
5321 switch (gameMode) {
\r
5322 case EditPosition:
\r
5323 case IcsExamining:
\r
5324 if (x < 0 || y < 0) break;
\r
5327 if (message == WM_MBUTTONDOWN) {
\r
5328 buttonCount = 3; /* even if system didn't think so */
\r
5329 if (wParam & MK_SHIFT)
\r
5330 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5332 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5333 } else { /* message == WM_RBUTTONDOWN */
\r
5335 if (buttonCount == 3) {
\r
5336 if (wParam & MK_SHIFT)
\r
5337 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5339 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5341 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5344 /* Just have one menu, on the right button. Windows users don't
\r
5345 think to try the middle one, and sometimes other software steals
\r
5346 it, or it doesn't really exist. */
\r
5347 if(gameInfo.variant != VariantShogi)
\r
5348 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5350 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5354 case IcsPlayingWhite:
\r
5355 case IcsPlayingBlack:
\r
5357 case MachinePlaysWhite:
\r
5358 case MachinePlaysBlack:
\r
5359 if (appData.testLegality &&
\r
5360 gameInfo.variant != VariantBughouse &&
\r
5361 gameInfo.variant != VariantCrazyhouse) break;
\r
5362 if (x < 0 || y < 0) break;
\r
5365 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5366 SetupDropMenu(hmenu);
\r
5367 MenuPopup(hwnd, pt, hmenu, -1);
\r
5378 /* Preprocess messages for buttons in main window */
\r
5380 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5382 int id = GetWindowLong(hwnd, GWL_ID);
\r
5385 for (i=0; i<N_BUTTONS; i++) {
\r
5386 if (buttonDesc[i].id == id) break;
\r
5388 if (i == N_BUTTONS) return 0;
\r
5389 switch (message) {
\r
5394 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5395 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5402 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5405 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5406 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5407 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5408 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5410 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5412 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5413 PopUpMoveDialog((char)wParam);
\r
5419 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5422 /* Process messages for Promotion dialog box */
\r
5424 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5428 switch (message) {
\r
5429 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5430 /* Center the dialog over the application window */
\r
5431 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5432 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5433 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5434 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5435 SW_SHOW : SW_HIDE);
\r
5436 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5437 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5438 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5439 PieceToChar(WhiteAngel) != '~') ||
\r
5440 (PieceToChar(BlackAngel) >= 'A' &&
\r
5441 PieceToChar(BlackAngel) != '~') ) ?
\r
5442 SW_SHOW : SW_HIDE);
\r
5443 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5444 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5445 PieceToChar(WhiteMarshall) != '~') ||
\r
5446 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5447 PieceToChar(BlackMarshall) != '~') ) ?
\r
5448 SW_SHOW : SW_HIDE);
\r
5449 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5450 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5451 gameInfo.variant != VariantShogi ?
\r
5452 SW_SHOW : SW_HIDE);
\r
5453 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5454 gameInfo.variant != VariantShogi ?
\r
5455 SW_SHOW : SW_HIDE);
\r
5456 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5457 gameInfo.variant == VariantShogi ?
\r
5458 SW_SHOW : SW_HIDE);
\r
5459 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5460 gameInfo.variant == VariantShogi ?
\r
5461 SW_SHOW : SW_HIDE);
\r
5462 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5463 gameInfo.variant == VariantSuper ?
\r
5464 SW_SHOW : SW_HIDE);
\r
5467 case WM_COMMAND: /* message: received a command */
\r
5468 switch (LOWORD(wParam)) {
\r
5470 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5471 ClearHighlights();
\r
5472 DrawPosition(FALSE, NULL);
\r
5475 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5478 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5481 promoChar = PieceToChar(BlackRook);
\r
5484 promoChar = PieceToChar(BlackBishop);
\r
5486 case PB_Chancellor:
\r
5487 promoChar = PieceToChar(BlackMarshall);
\r
5489 case PB_Archbishop:
\r
5490 promoChar = PieceToChar(BlackAngel);
\r
5493 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5498 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5499 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5500 only show the popup when we are already sure the move is valid or
\r
5501 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5502 will figure out it is a promotion from the promoChar. */
\r
5503 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5504 if (!appData.highlightLastMove) {
\r
5505 ClearHighlights();
\r
5506 DrawPosition(FALSE, NULL);
\r
5513 /* Pop up promotion dialog */
\r
5515 PromotionPopup(HWND hwnd)
\r
5519 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5520 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5521 hwnd, (DLGPROC)lpProc);
\r
5522 FreeProcInstance(lpProc);
\r
5525 /* Toggle ShowThinking */
\r
5527 ToggleShowThinking()
\r
5529 appData.showThinking = !appData.showThinking;
\r
5530 ShowThinkingEvent();
\r
5534 LoadGameDialog(HWND hwnd, char* title)
\r
5538 char fileTitle[MSG_SIZ];
\r
5539 f = OpenFileDialog(hwnd, "rb", "",
\r
5540 appData.oldSaveStyle ? "gam" : "pgn",
\r
5542 title, &number, fileTitle, NULL);
\r
5544 cmailMsgLoaded = FALSE;
\r
5545 if (number == 0) {
\r
5546 int error = GameListBuild(f);
\r
5548 DisplayError("Cannot build game list", error);
\r
5549 } else if (!ListEmpty(&gameList) &&
\r
5550 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5551 GameListPopUp(f, fileTitle);
\r
5554 GameListDestroy();
\r
5557 LoadGame(f, number, fileTitle, FALSE);
\r
5562 ChangedConsoleFont()
\r
5565 CHARRANGE tmpsel, sel;
\r
5566 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5567 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5568 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5571 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5572 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5573 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5574 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5575 * size. This was undocumented in the version of MSVC++ that I had
\r
5576 * when I wrote the code, but is apparently documented now.
\r
5578 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5579 cfmt.bCharSet = f->lf.lfCharSet;
\r
5580 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5581 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5582 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5583 /* Why are the following seemingly needed too? */
\r
5584 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5585 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5586 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5588 tmpsel.cpMax = -1; /*999999?*/
\r
5589 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5590 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5591 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5592 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5594 paraf.cbSize = sizeof(paraf);
\r
5595 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5596 paraf.dxStartIndent = 0;
\r
5597 paraf.dxOffset = WRAP_INDENT;
\r
5598 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5599 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5602 /*---------------------------------------------------------------------------*\
\r
5604 * Window Proc for main window
\r
5606 \*---------------------------------------------------------------------------*/
\r
5608 /* Process messages for main window, etc. */
\r
5610 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5613 int wmId, wmEvent;
\r
5617 char fileTitle[MSG_SIZ];
\r
5618 char buf[MSG_SIZ];
\r
5619 static SnapData sd;
\r
5621 switch (message) {
\r
5623 case WM_PAINT: /* message: repaint portion of window */
\r
5627 case WM_ERASEBKGND:
\r
5628 if (IsIconic(hwnd)) {
\r
5629 /* Cheat; change the message */
\r
5630 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5632 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5636 case WM_LBUTTONDOWN:
\r
5637 case WM_MBUTTONDOWN:
\r
5638 case WM_RBUTTONDOWN:
\r
5639 case WM_LBUTTONUP:
\r
5640 case WM_MBUTTONUP:
\r
5641 case WM_RBUTTONUP:
\r
5642 case WM_MOUSEMOVE:
\r
5643 case WM_MOUSEWHEEL:
\r
5644 MouseEvent(hwnd, message, wParam, lParam);
\r
5647 JAWS_KB_NAVIGATION
\r
5651 JAWS_ALT_INTERCEPT
\r
5653 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5654 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5655 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5656 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5658 SendMessage(h, message, wParam, lParam);
\r
5659 } else if(lParam != KF_REPEAT) {
\r
5660 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5661 PopUpMoveDialog((char)wParam);
\r
5662 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5663 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5668 case WM_PALETTECHANGED:
\r
5669 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5671 HDC hdc = GetDC(hwndMain);
\r
5672 SelectPalette(hdc, hPal, TRUE);
\r
5673 nnew = RealizePalette(hdc);
\r
5675 paletteChanged = TRUE;
\r
5677 UpdateColors(hdc);
\r
5679 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5682 ReleaseDC(hwnd, hdc);
\r
5686 case WM_QUERYNEWPALETTE:
\r
5687 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5689 HDC hdc = GetDC(hwndMain);
\r
5690 paletteChanged = FALSE;
\r
5691 SelectPalette(hdc, hPal, FALSE);
\r
5692 nnew = RealizePalette(hdc);
\r
5694 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5696 ReleaseDC(hwnd, hdc);
\r
5701 case WM_COMMAND: /* message: command from application menu */
\r
5702 wmId = LOWORD(wParam);
\r
5703 wmEvent = HIWORD(wParam);
\r
5708 AnalysisPopDown();
\r
5709 SAY("new game enter a move to play against the computer with white");
\r
5712 case IDM_NewGameFRC:
\r
5713 if( NewGameFRC() == 0 ) {
\r
5715 AnalysisPopDown();
\r
5719 case IDM_NewVariant:
\r
5720 NewVariantPopup(hwnd);
\r
5723 case IDM_LoadGame:
\r
5724 LoadGameDialog(hwnd, "Load Game from File");
\r
5727 case IDM_LoadNextGame:
\r
5731 case IDM_LoadPrevGame:
\r
5735 case IDM_ReloadGame:
\r
5739 case IDM_LoadPosition:
\r
5740 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5741 Reset(FALSE, TRUE);
\r
5744 f = OpenFileDialog(hwnd, "rb", "",
\r
5745 appData.oldSaveStyle ? "pos" : "fen",
\r
5747 "Load Position from File", &number, fileTitle, NULL);
\r
5749 LoadPosition(f, number, fileTitle);
\r
5753 case IDM_LoadNextPosition:
\r
5754 ReloadPosition(1);
\r
5757 case IDM_LoadPrevPosition:
\r
5758 ReloadPosition(-1);
\r
5761 case IDM_ReloadPosition:
\r
5762 ReloadPosition(0);
\r
5765 case IDM_SaveGame:
\r
5766 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5767 f = OpenFileDialog(hwnd, "a", defName,
\r
5768 appData.oldSaveStyle ? "gam" : "pgn",
\r
5770 "Save Game to File", NULL, fileTitle, NULL);
\r
5772 SaveGame(f, 0, "");
\r
5776 case IDM_SavePosition:
\r
5777 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5778 f = OpenFileDialog(hwnd, "a", defName,
\r
5779 appData.oldSaveStyle ? "pos" : "fen",
\r
5781 "Save Position to File", NULL, fileTitle, NULL);
\r
5783 SavePosition(f, 0, "");
\r
5787 case IDM_SaveDiagram:
\r
5788 defName = "diagram";
\r
5789 f = OpenFileDialog(hwnd, "wb", defName,
\r
5792 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5798 case IDM_CopyGame:
\r
5799 CopyGameToClipboard();
\r
5802 case IDM_PasteGame:
\r
5803 PasteGameFromClipboard();
\r
5806 case IDM_CopyGameListToClipboard:
\r
5807 CopyGameListToClipboard();
\r
5810 /* [AS] Autodetect FEN or PGN data */
\r
5811 case IDM_PasteAny:
\r
5812 PasteGameOrFENFromClipboard();
\r
5815 /* [AS] Move history */
\r
5816 case IDM_ShowMoveHistory:
\r
5817 if( MoveHistoryIsUp() ) {
\r
5818 MoveHistoryPopDown();
\r
5821 MoveHistoryPopUp();
\r
5825 /* [AS] Eval graph */
\r
5826 case IDM_ShowEvalGraph:
\r
5827 if( EvalGraphIsUp() ) {
\r
5828 EvalGraphPopDown();
\r
5832 SetFocus(hwndMain);
\r
5836 /* [AS] Engine output */
\r
5837 case IDM_ShowEngineOutput:
\r
5838 if( EngineOutputIsUp() ) {
\r
5839 EngineOutputPopDown();
\r
5842 EngineOutputPopUp();
\r
5846 /* [AS] User adjudication */
\r
5847 case IDM_UserAdjudication_White:
\r
5848 UserAdjudicationEvent( +1 );
\r
5851 case IDM_UserAdjudication_Black:
\r
5852 UserAdjudicationEvent( -1 );
\r
5855 case IDM_UserAdjudication_Draw:
\r
5856 UserAdjudicationEvent( 0 );
\r
5859 /* [AS] Game list options dialog */
\r
5860 case IDM_GameListOptions:
\r
5861 GameListOptions();
\r
5864 case IDM_CopyPosition:
\r
5865 CopyFENToClipboard();
\r
5868 case IDM_PastePosition:
\r
5869 PasteFENFromClipboard();
\r
5872 case IDM_MailMove:
\r
5876 case IDM_ReloadCMailMsg:
\r
5877 Reset(TRUE, TRUE);
\r
5878 ReloadCmailMsgEvent(FALSE);
\r
5881 case IDM_Minimize:
\r
5882 ShowWindow(hwnd, SW_MINIMIZE);
\r
5889 case IDM_MachineWhite:
\r
5890 MachineWhiteEvent();
\r
5892 * refresh the tags dialog only if it's visible
\r
5894 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5896 tags = PGNTags(&gameInfo);
\r
5897 TagsPopUp(tags, CmailMsg());
\r
5900 SAY("computer starts playing white");
\r
5903 case IDM_MachineBlack:
\r
5904 MachineBlackEvent();
\r
5906 * refresh the tags dialog only if it's visible
\r
5908 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5910 tags = PGNTags(&gameInfo);
\r
5911 TagsPopUp(tags, CmailMsg());
\r
5914 SAY("computer starts playing black");
\r
5917 case IDM_TwoMachines:
\r
5918 TwoMachinesEvent();
\r
5920 * refresh the tags dialog only if it's visible
\r
5922 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5924 tags = PGNTags(&gameInfo);
\r
5925 TagsPopUp(tags, CmailMsg());
\r
5928 SAY("programs start playing each other");
\r
5931 case IDM_AnalysisMode:
\r
5932 if (!first.analysisSupport) {
\r
5933 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5934 DisplayError(buf, 0);
\r
5936 SAY("analyzing current position");
\r
5937 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5938 if (appData.icsActive) {
\r
5939 if (gameMode != IcsObserving) {
\r
5940 sprintf(buf, "You are not observing a game");
\r
5941 DisplayError(buf, 0);
\r
5942 /* secure check */
\r
5943 if (appData.icsEngineAnalyze) {
\r
5944 if (appData.debugMode)
\r
5945 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5946 ExitAnalyzeMode();
\r
5952 /* if enable, user want disable icsEngineAnalyze */
\r
5953 if (appData.icsEngineAnalyze) {
\r
5954 ExitAnalyzeMode();
\r
5958 appData.icsEngineAnalyze = TRUE;
\r
5959 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5962 if (!appData.showThinking) ToggleShowThinking();
\r
5963 AnalyzeModeEvent();
\r
5967 case IDM_AnalyzeFile:
\r
5968 if (!first.analysisSupport) {
\r
5969 char buf[MSG_SIZ];
\r
5970 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5971 DisplayError(buf, 0);
\r
5973 if (!appData.showThinking) ToggleShowThinking();
\r
5974 AnalyzeFileEvent();
\r
5975 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5976 AnalysisPeriodicEvent(1);
\r
5980 case IDM_IcsClient:
\r
5984 case IDM_EditGame:
\r
5989 case IDM_EditPosition:
\r
5990 EditPositionEvent();
\r
5991 SAY("to set up a position type a FEN");
\r
5994 case IDM_Training:
\r
5998 case IDM_ShowGameList:
\r
5999 ShowGameListProc();
\r
6002 case IDM_EditTags:
\r
6006 case IDM_EditComment:
\r
6007 if (commentDialogUp && editComment) {
\r
6010 EditCommentEvent();
\r
6030 case IDM_CallFlag:
\r
6050 case IDM_StopObserving:
\r
6051 StopObservingEvent();
\r
6054 case IDM_StopExamining:
\r
6055 StopExaminingEvent();
\r
6058 case IDM_TypeInMove:
\r
6059 PopUpMoveDialog('\000');
\r
6062 case IDM_TypeInName:
\r
6063 PopUpNameDialog('\000');
\r
6066 case IDM_Backward:
\r
6068 SetFocus(hwndMain);
\r
6075 SetFocus(hwndMain);
\r
6080 SetFocus(hwndMain);
\r
6085 SetFocus(hwndMain);
\r
6092 case IDM_TruncateGame:
\r
6093 TruncateGameEvent();
\r
6100 case IDM_RetractMove:
\r
6101 RetractMoveEvent();
\r
6104 case IDM_FlipView:
\r
6105 flipView = !flipView;
\r
6106 DrawPosition(FALSE, NULL);
\r
6109 case IDM_FlipClock:
\r
6110 flipClock = !flipClock;
\r
6111 DisplayBothClocks();
\r
6112 DrawPosition(FALSE, NULL);
\r
6115 case IDM_GeneralOptions:
\r
6116 GeneralOptionsPopup(hwnd);
\r
6117 DrawPosition(TRUE, NULL);
\r
6120 case IDM_BoardOptions:
\r
6121 BoardOptionsPopup(hwnd);
\r
6124 case IDM_EnginePlayOptions:
\r
6125 EnginePlayOptionsPopup(hwnd);
\r
6128 case IDM_OptionsUCI:
\r
6129 UciOptionsPopup(hwnd);
\r
6132 case IDM_IcsOptions:
\r
6133 IcsOptionsPopup(hwnd);
\r
6137 FontsOptionsPopup(hwnd);
\r
6141 SoundOptionsPopup(hwnd);
\r
6144 case IDM_CommPort:
\r
6145 CommPortOptionsPopup(hwnd);
\r
6148 case IDM_LoadOptions:
\r
6149 LoadOptionsPopup(hwnd);
\r
6152 case IDM_SaveOptions:
\r
6153 SaveOptionsPopup(hwnd);
\r
6156 case IDM_TimeControl:
\r
6157 TimeControlOptionsPopup(hwnd);
\r
6160 case IDM_SaveSettings:
\r
6161 SaveSettings(settingsFileName);
\r
6164 case IDM_SaveSettingsOnExit:
\r
6165 saveSettingsOnExit = !saveSettingsOnExit;
\r
6166 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6167 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6168 MF_CHECKED : MF_UNCHECKED));
\r
6179 case IDM_AboutGame:
\r
6184 appData.debugMode = !appData.debugMode;
\r
6185 if (appData.debugMode) {
\r
6186 char dir[MSG_SIZ];
\r
6187 GetCurrentDirectory(MSG_SIZ, dir);
\r
6188 SetCurrentDirectory(installDir);
\r
6189 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6190 SetCurrentDirectory(dir);
\r
6191 setbuf(debugFP, NULL);
\r
6198 case IDM_HELPCONTENTS:
\r
6199 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6200 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6201 MessageBox (GetFocus(),
\r
6202 "Unable to activate help",
\r
6203 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6207 case IDM_HELPSEARCH:
\r
6208 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6209 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6210 MessageBox (GetFocus(),
\r
6211 "Unable to activate help",
\r
6212 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6216 case IDM_HELPHELP:
\r
6217 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6218 MessageBox (GetFocus(),
\r
6219 "Unable to activate help",
\r
6220 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6225 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6227 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6228 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6229 FreeProcInstance(lpProc);
\r
6232 case IDM_DirectCommand1:
\r
6233 AskQuestionEvent("Direct Command",
\r
6234 "Send to chess program:", "", "1");
\r
6236 case IDM_DirectCommand2:
\r
6237 AskQuestionEvent("Direct Command",
\r
6238 "Send to second chess program:", "", "2");
\r
6241 case EP_WhitePawn:
\r
6242 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6243 fromX = fromY = -1;
\r
6246 case EP_WhiteKnight:
\r
6247 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6248 fromX = fromY = -1;
\r
6251 case EP_WhiteBishop:
\r
6252 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6253 fromX = fromY = -1;
\r
6256 case EP_WhiteRook:
\r
6257 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6258 fromX = fromY = -1;
\r
6261 case EP_WhiteQueen:
\r
6262 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6263 fromX = fromY = -1;
\r
6266 case EP_WhiteFerz:
\r
6267 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6268 fromX = fromY = -1;
\r
6271 case EP_WhiteWazir:
\r
6272 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6273 fromX = fromY = -1;
\r
6276 case EP_WhiteAlfil:
\r
6277 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6278 fromX = fromY = -1;
\r
6281 case EP_WhiteCannon:
\r
6282 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6283 fromX = fromY = -1;
\r
6286 case EP_WhiteCardinal:
\r
6287 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6288 fromX = fromY = -1;
\r
6291 case EP_WhiteMarshall:
\r
6292 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6293 fromX = fromY = -1;
\r
6296 case EP_WhiteKing:
\r
6297 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6298 fromX = fromY = -1;
\r
6301 case EP_BlackPawn:
\r
6302 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6303 fromX = fromY = -1;
\r
6306 case EP_BlackKnight:
\r
6307 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6308 fromX = fromY = -1;
\r
6311 case EP_BlackBishop:
\r
6312 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6313 fromX = fromY = -1;
\r
6316 case EP_BlackRook:
\r
6317 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6318 fromX = fromY = -1;
\r
6321 case EP_BlackQueen:
\r
6322 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6323 fromX = fromY = -1;
\r
6326 case EP_BlackFerz:
\r
6327 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6328 fromX = fromY = -1;
\r
6331 case EP_BlackWazir:
\r
6332 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6333 fromX = fromY = -1;
\r
6336 case EP_BlackAlfil:
\r
6337 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6338 fromX = fromY = -1;
\r
6341 case EP_BlackCannon:
\r
6342 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6343 fromX = fromY = -1;
\r
6346 case EP_BlackCardinal:
\r
6347 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6348 fromX = fromY = -1;
\r
6351 case EP_BlackMarshall:
\r
6352 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6353 fromX = fromY = -1;
\r
6356 case EP_BlackKing:
\r
6357 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6358 fromX = fromY = -1;
\r
6361 case EP_EmptySquare:
\r
6362 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6363 fromX = fromY = -1;
\r
6366 case EP_ClearBoard:
\r
6367 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6368 fromX = fromY = -1;
\r
6372 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6373 fromX = fromY = -1;
\r
6377 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6378 fromX = fromY = -1;
\r
6382 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6383 fromX = fromY = -1;
\r
6387 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6388 fromX = fromY = -1;
\r
6392 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6393 fromX = fromY = -1;
\r
6397 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6398 fromX = fromY = -1;
\r
6402 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6403 fromX = fromY = -1;
\r
6407 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6408 fromX = fromY = -1;
\r
6412 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6413 fromX = fromY = -1;
\r
6417 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6423 case CLOCK_TIMER_ID:
\r
6424 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6425 clockTimerEvent = 0;
\r
6426 DecrementClocks(); /* call into back end */
\r
6428 case LOAD_GAME_TIMER_ID:
\r
6429 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6430 loadGameTimerEvent = 0;
\r
6431 AutoPlayGameLoop(); /* call into back end */
\r
6433 case ANALYSIS_TIMER_ID:
\r
6434 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6435 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6436 AnalysisPeriodicEvent(0);
\r
6438 KillTimer(hwnd, analysisTimerEvent);
\r
6439 analysisTimerEvent = 0;
\r
6442 case DELAYED_TIMER_ID:
\r
6443 KillTimer(hwnd, delayedTimerEvent);
\r
6444 delayedTimerEvent = 0;
\r
6445 delayedTimerCallback();
\r
6450 case WM_USER_Input:
\r
6451 InputEvent(hwnd, message, wParam, lParam);
\r
6454 /* [AS] Also move "attached" child windows */
\r
6455 case WM_WINDOWPOSCHANGING:
\r
6457 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6458 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6460 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6461 /* Window is moving */
\r
6464 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6465 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6466 rcMain.right = boardX + winWidth;
\r
6467 rcMain.top = boardY;
\r
6468 rcMain.bottom = boardY + winHeight;
\r
6470 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6471 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6472 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6473 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6474 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6481 /* [AS] Snapping */
\r
6482 case WM_ENTERSIZEMOVE:
\r
6483 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6484 if (hwnd == hwndMain) {
\r
6485 doingSizing = TRUE;
\r
6488 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6492 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6493 if (hwnd == hwndMain) {
\r
6494 lastSizing = wParam;
\r
6499 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6500 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6502 case WM_EXITSIZEMOVE:
\r
6503 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6504 if (hwnd == hwndMain) {
\r
6506 doingSizing = FALSE;
\r
6507 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6508 GetClientRect(hwnd, &client);
\r
6509 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6511 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6513 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6516 case WM_DESTROY: /* message: window being destroyed */
\r
6517 PostQuitMessage(0);
\r
6521 if (hwnd == hwndMain) {
\r
6526 default: /* Passes it on if unprocessed */
\r
6527 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6532 /*---------------------------------------------------------------------------*\
\r
6534 * Misc utility routines
\r
6536 \*---------------------------------------------------------------------------*/
\r
6539 * Decent random number generator, at least not as bad as Windows
\r
6540 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6542 unsigned int randstate;
\r
6547 randstate = randstate * 1664525 + 1013904223;
\r
6548 return (int) randstate & 0x7fffffff;
\r
6552 mysrandom(unsigned int seed)
\r
6559 * returns TRUE if user selects a different color, FALSE otherwise
\r
6563 ChangeColor(HWND hwnd, COLORREF *which)
\r
6565 static BOOL firstTime = TRUE;
\r
6566 static DWORD customColors[16];
\r
6568 COLORREF newcolor;
\r
6573 /* Make initial colors in use available as custom colors */
\r
6574 /* Should we put the compiled-in defaults here instead? */
\r
6576 customColors[i++] = lightSquareColor & 0xffffff;
\r
6577 customColors[i++] = darkSquareColor & 0xffffff;
\r
6578 customColors[i++] = whitePieceColor & 0xffffff;
\r
6579 customColors[i++] = blackPieceColor & 0xffffff;
\r
6580 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6581 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6583 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6584 customColors[i++] = textAttribs[ccl].color;
\r
6586 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6587 firstTime = FALSE;
\r
6590 cc.lStructSize = sizeof(cc);
\r
6591 cc.hwndOwner = hwnd;
\r
6592 cc.hInstance = NULL;
\r
6593 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6594 cc.lpCustColors = (LPDWORD) customColors;
\r
6595 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6597 if (!ChooseColor(&cc)) return FALSE;
\r
6599 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6600 if (newcolor == *which) return FALSE;
\r
6601 *which = newcolor;
\r
6605 InitDrawingColors();
\r
6606 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6611 MyLoadSound(MySound *ms)
\r
6617 if (ms->data) free(ms->data);
\r
6620 switch (ms->name[0]) {
\r
6626 /* System sound from Control Panel. Don't preload here. */
\r
6630 if (ms->name[1] == NULLCHAR) {
\r
6631 /* "!" alone = silence */
\r
6634 /* Builtin wave resource. Error if not found. */
\r
6635 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6636 if (h == NULL) break;
\r
6637 ms->data = (void *)LoadResource(hInst, h);
\r
6638 if (h == NULL) break;
\r
6643 /* .wav file. Error if not found. */
\r
6644 f = fopen(ms->name, "rb");
\r
6645 if (f == NULL) break;
\r
6646 if (fstat(fileno(f), &st) < 0) break;
\r
6647 ms->data = malloc(st.st_size);
\r
6648 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6654 char buf[MSG_SIZ];
\r
6655 sprintf(buf, "Error loading sound %s", ms->name);
\r
6656 DisplayError(buf, GetLastError());
\r
6662 MyPlaySound(MySound *ms)
\r
6664 BOOLEAN ok = FALSE;
\r
6665 if(appData.debugMode) fprintf(debugFP, "make sound %s %x %d\n", ms->name, ms, ms->name[0]);
\r
6666 switch (ms->name[0]) {
\r
6668 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6673 /* System sound from Control Panel (deprecated feature).
\r
6674 "$" alone or an unset sound name gets default beep (still in use). */
\r
6675 if (ms->name[1]) {
\r
6676 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6678 if (!ok) ok = MessageBeep(MB_OK);
\r
6681 /* Builtin wave resource, or "!" alone for silence */
\r
6682 if (ms->name[1]) {
\r
6683 if (ms->data == NULL) return FALSE;
\r
6684 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6690 /* .wav file. Error if not found. */
\r
6691 if (ms->data == NULL) return FALSE;
\r
6692 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6695 /* Don't print an error: this can happen innocently if the sound driver
\r
6696 is busy; for instance, if another instance of WinBoard is playing
\r
6697 a sound at about the same time. */
\r
6700 char buf[MSG_SIZ];
\r
6701 sprintf(buf, "Error playing sound %s", ms->name);
\r
6702 DisplayError(buf, GetLastError());
\r
6710 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6713 OPENFILENAME *ofn;
\r
6714 static UINT *number; /* gross that this is static */
\r
6716 switch (message) {
\r
6717 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6718 /* Center the dialog over the application window */
\r
6719 ofn = (OPENFILENAME *) lParam;
\r
6720 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6721 number = (UINT *) ofn->lCustData;
\r
6722 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6726 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6727 return FALSE; /* Allow for further processing */
\r
6730 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6731 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6733 return FALSE; /* Allow for further processing */
\r
6739 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6741 static UINT *number;
\r
6742 OPENFILENAME *ofname;
\r
6745 case WM_INITDIALOG:
\r
6746 ofname = (OPENFILENAME *)lParam;
\r
6747 number = (UINT *)(ofname->lCustData);
\r
6750 ofnot = (OFNOTIFY *)lParam;
\r
6751 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6752 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6761 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6762 char *nameFilt, char *dlgTitle, UINT *number,
\r
6763 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6765 OPENFILENAME openFileName;
\r
6766 char buf1[MSG_SIZ];
\r
6769 if (fileName == NULL) fileName = buf1;
\r
6770 if (defName == NULL) {
\r
6771 strcpy(fileName, "*.");
\r
6772 strcat(fileName, defExt);
\r
6774 strcpy(fileName, defName);
\r
6776 if (fileTitle) strcpy(fileTitle, "");
\r
6777 if (number) *number = 0;
\r
6779 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6780 openFileName.hwndOwner = hwnd;
\r
6781 openFileName.hInstance = (HANDLE) hInst;
\r
6782 openFileName.lpstrFilter = nameFilt;
\r
6783 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6784 openFileName.nMaxCustFilter = 0L;
\r
6785 openFileName.nFilterIndex = 1L;
\r
6786 openFileName.lpstrFile = fileName;
\r
6787 openFileName.nMaxFile = MSG_SIZ;
\r
6788 openFileName.lpstrFileTitle = fileTitle;
\r
6789 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6790 openFileName.lpstrInitialDir = NULL;
\r
6791 openFileName.lpstrTitle = dlgTitle;
\r
6792 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6793 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6794 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6795 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6796 openFileName.nFileOffset = 0;
\r
6797 openFileName.nFileExtension = 0;
\r
6798 openFileName.lpstrDefExt = defExt;
\r
6799 openFileName.lCustData = (LONG) number;
\r
6800 openFileName.lpfnHook = oldDialog ?
\r
6801 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6802 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6804 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6805 GetOpenFileName(&openFileName)) {
\r
6806 /* open the file */
\r
6807 f = fopen(openFileName.lpstrFile, write);
\r
6809 MessageBox(hwnd, "File open failed", NULL,
\r
6810 MB_OK|MB_ICONEXCLAMATION);
\r
6814 int err = CommDlgExtendedError();
\r
6815 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6824 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6826 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6829 * Get the first pop-up menu in the menu template. This is the
\r
6830 * menu that TrackPopupMenu displays.
\r
6832 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6834 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6837 * TrackPopup uses screen coordinates, so convert the
\r
6838 * coordinates of the mouse click to screen coordinates.
\r
6840 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6842 /* Draw and track the floating pop-up menu. */
\r
6843 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6844 pt.x, pt.y, 0, hwnd, NULL);
\r
6846 /* Destroy the menu.*/
\r
6847 DestroyMenu(hmenu);
\r
6852 int sizeX, sizeY, newSizeX, newSizeY;
\r
6854 } ResizeEditPlusButtonsClosure;
\r
6857 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6859 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6863 if (hChild == cl->hText) return TRUE;
\r
6864 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6865 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6866 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6867 ScreenToClient(cl->hDlg, &pt);
\r
6868 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6869 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6873 /* Resize a dialog that has a (rich) edit field filling most of
\r
6874 the top, with a row of buttons below */
\r
6876 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6879 int newTextHeight, newTextWidth;
\r
6880 ResizeEditPlusButtonsClosure cl;
\r
6882 /*if (IsIconic(hDlg)) return;*/
\r
6883 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6885 cl.hdwp = BeginDeferWindowPos(8);
\r
6887 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6888 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6889 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6890 if (newTextHeight < 0) {
\r
6891 newSizeY += -newTextHeight;
\r
6892 newTextHeight = 0;
\r
6894 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6895 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6901 cl.newSizeX = newSizeX;
\r
6902 cl.newSizeY = newSizeY;
\r
6903 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6905 EndDeferWindowPos(cl.hdwp);
\r
6908 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6910 RECT rChild, rParent;
\r
6911 int wChild, hChild, wParent, hParent;
\r
6912 int wScreen, hScreen, xNew, yNew;
\r
6915 /* Get the Height and Width of the child window */
\r
6916 GetWindowRect (hwndChild, &rChild);
\r
6917 wChild = rChild.right - rChild.left;
\r
6918 hChild = rChild.bottom - rChild.top;
\r
6920 /* Get the Height and Width of the parent window */
\r
6921 GetWindowRect (hwndParent, &rParent);
\r
6922 wParent = rParent.right - rParent.left;
\r
6923 hParent = rParent.bottom - rParent.top;
\r
6925 /* Get the display limits */
\r
6926 hdc = GetDC (hwndChild);
\r
6927 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6928 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6929 ReleaseDC(hwndChild, hdc);
\r
6931 /* Calculate new X position, then adjust for screen */
\r
6932 xNew = rParent.left + ((wParent - wChild) /2);
\r
6935 } else if ((xNew+wChild) > wScreen) {
\r
6936 xNew = wScreen - wChild;
\r
6939 /* Calculate new Y position, then adjust for screen */
\r
6941 yNew = rParent.top + ((hParent - hChild) /2);
\r
6944 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6949 } else if ((yNew+hChild) > hScreen) {
\r
6950 yNew = hScreen - hChild;
\r
6953 /* Set it, and return */
\r
6954 return SetWindowPos (hwndChild, NULL,
\r
6955 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6958 /* Center one window over another */
\r
6959 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6961 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6964 /*---------------------------------------------------------------------------*\
\r
6966 * Startup Dialog functions
\r
6968 \*---------------------------------------------------------------------------*/
\r
6970 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6972 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6974 while (*cd != NULL) {
\r
6975 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6981 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6983 char buf1[ARG_MAX];
\r
6986 if (str[0] == '@') {
\r
6987 FILE* f = fopen(str + 1, "r");
\r
6989 DisplayFatalError(str + 1, errno, 2);
\r
6992 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6994 buf1[len] = NULLCHAR;
\r
6998 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7001 char buf[MSG_SIZ];
\r
7002 char *end = strchr(str, '\n');
\r
7003 if (end == NULL) return;
\r
7004 memcpy(buf, str, end - str);
\r
7005 buf[end - str] = NULLCHAR;
\r
7006 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7012 SetStartupDialogEnables(HWND hDlg)
\r
7014 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7015 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7016 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7017 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7018 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7019 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7020 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7021 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7022 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7023 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7024 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7025 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7026 IsDlgButtonChecked(hDlg, OPT_View));
\r
7030 QuoteForFilename(char *filename)
\r
7032 int dquote, space;
\r
7033 dquote = strchr(filename, '"') != NULL;
\r
7034 space = strchr(filename, ' ') != NULL;
\r
7035 if (dquote || space) {
\r
7047 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7049 char buf[MSG_SIZ];
\r
7052 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7053 q = QuoteForFilename(nthcp);
\r
7054 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7055 if (*nthdir != NULLCHAR) {
\r
7056 q = QuoteForFilename(nthdir);
\r
7057 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7059 if (*nthcp == NULLCHAR) {
\r
7060 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7061 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7062 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7063 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7068 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7070 char buf[MSG_SIZ];
\r
7074 switch (message) {
\r
7075 case WM_INITDIALOG:
\r
7076 /* Center the dialog */
\r
7077 CenterWindow (hDlg, GetDesktopWindow());
\r
7078 /* Initialize the dialog items */
\r
7079 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7080 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7081 firstChessProgramNames);
\r
7082 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7083 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7084 secondChessProgramNames);
\r
7085 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7086 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7087 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7088 if (*appData.icsHelper != NULLCHAR) {
\r
7089 char *q = QuoteForFilename(appData.icsHelper);
\r
7090 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7092 if (*appData.icsHost == NULLCHAR) {
\r
7093 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7094 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7095 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7096 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7097 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7100 if (appData.icsActive) {
\r
7101 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7103 else if (appData.noChessProgram) {
\r
7104 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7107 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7110 SetStartupDialogEnables(hDlg);
\r
7114 switch (LOWORD(wParam)) {
\r
7116 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7117 strcpy(buf, "/fcp=");
\r
7118 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7120 ParseArgs(StringGet, &p);
\r
7121 strcpy(buf, "/scp=");
\r
7122 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7124 ParseArgs(StringGet, &p);
\r
7125 appData.noChessProgram = FALSE;
\r
7126 appData.icsActive = FALSE;
\r
7127 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7128 strcpy(buf, "/ics /icshost=");
\r
7129 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7131 ParseArgs(StringGet, &p);
\r
7132 if (appData.zippyPlay) {
\r
7133 strcpy(buf, "/fcp=");
\r
7134 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7136 ParseArgs(StringGet, &p);
\r
7138 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7139 appData.noChessProgram = TRUE;
\r
7140 appData.icsActive = FALSE;
\r
7142 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7143 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7146 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7147 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7149 ParseArgs(StringGet, &p);
\r
7151 EndDialog(hDlg, TRUE);
\r
7158 case IDM_HELPCONTENTS:
\r
7159 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7160 MessageBox (GetFocus(),
\r
7161 "Unable to activate help",
\r
7162 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7167 SetStartupDialogEnables(hDlg);
\r
7175 /*---------------------------------------------------------------------------*\
\r
7177 * About box dialog functions
\r
7179 \*---------------------------------------------------------------------------*/
\r
7181 /* Process messages for "About" dialog box */
\r
7183 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7185 switch (message) {
\r
7186 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7187 /* Center the dialog over the application window */
\r
7188 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7189 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7192 case WM_COMMAND: /* message: received a command */
\r
7193 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7194 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7195 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7203 /*---------------------------------------------------------------------------*\
\r
7205 * Comment Dialog functions
\r
7207 \*---------------------------------------------------------------------------*/
\r
7210 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7212 static HANDLE hwndText = NULL;
\r
7213 int len, newSizeX, newSizeY, flags;
\r
7214 static int sizeX, sizeY;
\r
7219 switch (message) {
\r
7220 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7221 /* Initialize the dialog items */
\r
7222 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7223 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7224 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7225 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7226 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7227 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7228 SetWindowText(hDlg, commentTitle);
\r
7229 if (editComment) {
\r
7230 SetFocus(hwndText);
\r
7232 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7234 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7235 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7236 MAKELPARAM(FALSE, 0));
\r
7237 /* Size and position the dialog */
\r
7238 if (!commentDialog) {
\r
7239 commentDialog = hDlg;
\r
7240 flags = SWP_NOZORDER;
\r
7241 GetClientRect(hDlg, &rect);
\r
7242 sizeX = rect.right;
\r
7243 sizeY = rect.bottom;
\r
7244 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7245 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7246 WINDOWPLACEMENT wp;
\r
7247 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7248 wp.length = sizeof(WINDOWPLACEMENT);
\r
7250 wp.showCmd = SW_SHOW;
\r
7251 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7252 wp.rcNormalPosition.left = commentX;
\r
7253 wp.rcNormalPosition.right = commentX + commentW;
\r
7254 wp.rcNormalPosition.top = commentY;
\r
7255 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7256 SetWindowPlacement(hDlg, &wp);
\r
7258 GetClientRect(hDlg, &rect);
\r
7259 newSizeX = rect.right;
\r
7260 newSizeY = rect.bottom;
\r
7261 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7262 newSizeX, newSizeY);
\r
7269 case WM_COMMAND: /* message: received a command */
\r
7270 switch (LOWORD(wParam)) {
\r
7272 if (editComment) {
\r
7274 /* Read changed options from the dialog box */
\r
7275 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7276 len = GetWindowTextLength(hwndText);
\r
7277 str = (char *) malloc(len + 1);
\r
7278 GetWindowText(hwndText, str, len + 1);
\r
7287 ReplaceComment(commentIndex, str);
\r
7294 case OPT_CancelComment:
\r
7298 case OPT_ClearComment:
\r
7299 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7302 case OPT_EditComment:
\r
7303 EditCommentEvent();
\r
7312 newSizeX = LOWORD(lParam);
\r
7313 newSizeY = HIWORD(lParam);
\r
7314 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7319 case WM_GETMINMAXINFO:
\r
7320 /* Prevent resizing window too small */
\r
7321 mmi = (MINMAXINFO *) lParam;
\r
7322 mmi->ptMinTrackSize.x = 100;
\r
7323 mmi->ptMinTrackSize.y = 100;
\r
7330 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7335 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7337 if (str == NULL) str = "";
\r
7338 p = (char *) malloc(2 * strlen(str) + 2);
\r
7341 if (*str == '\n') *q++ = '\r';
\r
7345 if (commentText != NULL) free(commentText);
\r
7347 commentIndex = index;
\r
7348 commentTitle = title;
\r
7350 editComment = edit;
\r
7352 if (commentDialog) {
\r
7353 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7354 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7356 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7357 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7358 hwndMain, (DLGPROC)lpProc);
\r
7359 FreeProcInstance(lpProc);
\r
7361 commentDialogUp = TRUE;
\r
7365 /*---------------------------------------------------------------------------*\
\r
7367 * Type-in move dialog functions
\r
7369 \*---------------------------------------------------------------------------*/
\r
7372 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7374 char move[MSG_SIZ];
\r
7376 ChessMove moveType;
\r
7377 int fromX, fromY, toX, toY;
\r
7380 switch (message) {
\r
7381 case WM_INITDIALOG:
\r
7382 move[0] = (char) lParam;
\r
7383 move[1] = NULLCHAR;
\r
7384 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7385 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7386 SetWindowText(hInput, move);
\r
7388 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7392 switch (LOWORD(wParam)) {
\r
7394 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7395 { int n; Board board;
\r
7397 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7398 EditPositionPasteFEN(move);
\r
7399 EndDialog(hDlg, TRUE);
\r
7402 // [HGM] movenum: allow move number to be typed in any mode
\r
7403 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7404 currentMove = 2*n-1;
\r
7405 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7406 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7407 EndDialog(hDlg, TRUE);
\r
7408 DrawPosition(TRUE, boards[currentMove]);
\r
7409 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7410 else DisplayMessage("", "");
\r
7414 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7415 gameMode != Training) {
\r
7416 DisplayMoveError("Displayed move is not current");
\r
7418 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7419 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7420 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7421 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7422 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7423 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7424 if (gameMode != Training)
\r
7425 forwardMostMove = currentMove;
\r
7426 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7428 DisplayMoveError("Could not parse move");
\r
7431 EndDialog(hDlg, TRUE);
\r
7434 EndDialog(hDlg, FALSE);
\r
7445 PopUpMoveDialog(char firstchar)
\r
7449 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7450 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7451 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7452 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7453 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7454 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7455 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7456 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7457 gameMode == Training) {
\r
7458 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7459 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7460 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7461 FreeProcInstance(lpProc);
\r
7465 /*---------------------------------------------------------------------------*\
\r
7467 * Type-in name dialog functions
\r
7469 \*---------------------------------------------------------------------------*/
\r
7472 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7474 char move[MSG_SIZ];
\r
7477 switch (message) {
\r
7478 case WM_INITDIALOG:
\r
7479 move[0] = (char) lParam;
\r
7480 move[1] = NULLCHAR;
\r
7481 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7482 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7483 SetWindowText(hInput, move);
\r
7485 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7489 switch (LOWORD(wParam)) {
\r
7491 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7492 appData.userName = strdup(move);
\r
7495 EndDialog(hDlg, TRUE);
\r
7498 EndDialog(hDlg, FALSE);
\r
7509 PopUpNameDialog(char firstchar)
\r
7513 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7514 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7515 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7516 FreeProcInstance(lpProc);
\r
7519 /*---------------------------------------------------------------------------*\
\r
7523 \*---------------------------------------------------------------------------*/
\r
7525 /* Nonmodal error box */
\r
7526 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7527 WPARAM wParam, LPARAM lParam);
\r
7530 ErrorPopUp(char *title, char *content)
\r
7534 BOOLEAN modal = hwndMain == NULL;
\r
7552 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7553 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7556 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7558 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7559 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7560 hwndMain, (DLGPROC)lpProc);
\r
7561 FreeProcInstance(lpProc);
\r
7568 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7569 if (errorDialog == NULL) return;
\r
7570 DestroyWindow(errorDialog);
\r
7571 errorDialog = NULL;
\r
7575 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7580 switch (message) {
\r
7581 case WM_INITDIALOG:
\r
7582 GetWindowRect(hDlg, &rChild);
\r
7585 SetWindowPos(hDlg, NULL, rChild.left,
\r
7586 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7587 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7591 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7592 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7593 and it doesn't work when you resize the dialog.
\r
7594 For now, just give it a default position.
\r
7596 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7598 errorDialog = hDlg;
\r
7599 SetWindowText(hDlg, errorTitle);
\r
7600 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7601 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7605 switch (LOWORD(wParam)) {
\r
7608 if (errorDialog == hDlg) errorDialog = NULL;
\r
7609 DestroyWindow(hDlg);
\r
7621 HWND gothicDialog = NULL;
\r
7624 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7628 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7630 switch (message) {
\r
7631 case WM_INITDIALOG:
\r
7632 GetWindowRect(hDlg, &rChild);
\r
7634 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7638 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7639 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7640 and it doesn't work when you resize the dialog.
\r
7641 For now, just give it a default position.
\r
7643 gothicDialog = hDlg;
\r
7644 SetWindowText(hDlg, errorTitle);
\r
7645 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7646 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7650 switch (LOWORD(wParam)) {
\r
7653 if (errorDialog == hDlg) errorDialog = NULL;
\r
7654 DestroyWindow(hDlg);
\r
7666 GothicPopUp(char *title, VariantClass variant)
\r
7669 static char *lastTitle;
\r
7671 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7672 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7674 if(lastTitle != title && gothicDialog != NULL) {
\r
7675 DestroyWindow(gothicDialog);
\r
7676 gothicDialog = NULL;
\r
7678 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7679 title = lastTitle;
\r
7680 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7681 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7682 hwndMain, (DLGPROC)lpProc);
\r
7683 FreeProcInstance(lpProc);
\r
7688 /*---------------------------------------------------------------------------*\
\r
7690 * Ics Interaction console functions
\r
7692 \*---------------------------------------------------------------------------*/
\r
7694 #define HISTORY_SIZE 64
\r
7695 static char *history[HISTORY_SIZE];
\r
7696 int histIn = 0, histP = 0;
\r
7699 SaveInHistory(char *cmd)
\r
7701 if (history[histIn] != NULL) {
\r
7702 free(history[histIn]);
\r
7703 history[histIn] = NULL;
\r
7705 if (*cmd == NULLCHAR) return;
\r
7706 history[histIn] = StrSave(cmd);
\r
7707 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7708 if (history[histIn] != NULL) {
\r
7709 free(history[histIn]);
\r
7710 history[histIn] = NULL;
\r
7716 PrevInHistory(char *cmd)
\r
7719 if (histP == histIn) {
\r
7720 if (history[histIn] != NULL) free(history[histIn]);
\r
7721 history[histIn] = StrSave(cmd);
\r
7723 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7724 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7726 return history[histP];
\r
7732 if (histP == histIn) return NULL;
\r
7733 histP = (histP + 1) % HISTORY_SIZE;
\r
7734 return history[histP];
\r
7741 BOOLEAN immediate;
\r
7742 } IcsTextMenuEntry;
\r
7743 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7744 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7747 ParseIcsTextMenu(char *icsTextMenuString)
\r
7750 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7751 char *p = icsTextMenuString;
\r
7752 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7755 if (e->command != NULL) {
\r
7757 e->command = NULL;
\r
7761 e = icsTextMenuEntry;
\r
7762 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7763 if (*p == ';' || *p == '\n') {
\r
7764 e->item = strdup("-");
\r
7765 e->command = NULL;
\r
7767 } else if (*p == '-') {
\r
7768 e->item = strdup("-");
\r
7769 e->command = NULL;
\r
7773 char *q, *r, *s, *t;
\r
7775 q = strchr(p, ',');
\r
7776 if (q == NULL) break;
\r
7778 r = strchr(q + 1, ',');
\r
7779 if (r == NULL) break;
\r
7781 s = strchr(r + 1, ',');
\r
7782 if (s == NULL) break;
\r
7785 t = strchr(s + 1, c);
\r
7788 t = strchr(s + 1, c);
\r
7790 if (t != NULL) *t = NULLCHAR;
\r
7791 e->item = strdup(p);
\r
7792 e->command = strdup(q + 1);
\r
7793 e->getname = *(r + 1) != '0';
\r
7794 e->immediate = *(s + 1) != '0';
\r
7798 if (t == NULL) break;
\r
7807 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7811 hmenu = LoadMenu(hInst, "TextMenu");
\r
7812 h = GetSubMenu(hmenu, 0);
\r
7814 if (strcmp(e->item, "-") == 0) {
\r
7815 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7817 if (e->item[0] == '|') {
\r
7818 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7819 IDM_CommandX + i, &e->item[1]);
\r
7821 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7830 WNDPROC consoleTextWindowProc;
\r
7833 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7835 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7836 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7840 SetWindowText(hInput, command);
\r
7842 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7844 sel.cpMin = 999999;
\r
7845 sel.cpMax = 999999;
\r
7846 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7851 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7852 if (sel.cpMin == sel.cpMax) {
\r
7853 /* Expand to surrounding word */
\r
7856 tr.chrg.cpMax = sel.cpMin;
\r
7857 tr.chrg.cpMin = --sel.cpMin;
\r
7858 if (sel.cpMin < 0) break;
\r
7859 tr.lpstrText = name;
\r
7860 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7861 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7865 tr.chrg.cpMin = sel.cpMax;
\r
7866 tr.chrg.cpMax = ++sel.cpMax;
\r
7867 tr.lpstrText = name;
\r
7868 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7869 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7872 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7873 MessageBeep(MB_ICONEXCLAMATION);
\r
7877 tr.lpstrText = name;
\r
7878 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7880 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7881 MessageBeep(MB_ICONEXCLAMATION);
\r
7884 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7887 sprintf(buf, "%s %s", command, name);
\r
7888 SetWindowText(hInput, buf);
\r
7889 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7891 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7892 SetWindowText(hInput, buf);
\r
7893 sel.cpMin = 999999;
\r
7894 sel.cpMax = 999999;
\r
7895 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7901 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7906 switch (message) {
\r
7908 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7911 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7914 sel.cpMin = 999999;
\r
7915 sel.cpMax = 999999;
\r
7916 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7917 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7922 if(wParam != '\022') {
\r
7923 if (wParam == '\t') {
\r
7924 if (GetKeyState(VK_SHIFT) < 0) {
\r
7926 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7927 if (buttonDesc[0].hwnd) {
\r
7928 SetFocus(buttonDesc[0].hwnd);
\r
7930 SetFocus(hwndMain);
\r
7934 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7937 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7938 JAWS_DELETE( SetFocus(hInput); )
\r
7939 SendMessage(hInput, message, wParam, lParam);
\r
7942 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7943 case WM_RBUTTONUP:
\r
7944 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7945 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7946 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7949 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7950 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7951 if (sel.cpMin == sel.cpMax) {
\r
7952 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7953 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7955 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7956 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7958 pt.x = LOWORD(lParam);
\r
7959 pt.y = HIWORD(lParam);
\r
7960 MenuPopup(hwnd, pt, hmenu, -1);
\r
7964 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7966 return SendMessage(hInput, message, wParam, lParam);
\r
7967 case WM_MBUTTONDOWN:
\r
7968 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7969 case WM_RBUTTONDOWN:
\r
7970 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7971 /* Move selection here if it was empty */
\r
7973 pt.x = LOWORD(lParam);
\r
7974 pt.y = HIWORD(lParam);
\r
7975 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7976 if (sel.cpMin == sel.cpMax) {
\r
7977 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7978 sel.cpMax = sel.cpMin;
\r
7979 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7981 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7985 switch (LOWORD(wParam)) {
\r
7986 case IDM_QuickPaste:
\r
7988 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7989 if (sel.cpMin == sel.cpMax) {
\r
7990 MessageBeep(MB_ICONEXCLAMATION);
\r
7993 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7994 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7995 SendMessage(hInput, WM_PASTE, 0, 0);
\r
8000 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8003 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8006 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8010 int i = LOWORD(wParam) - IDM_CommandX;
\r
8011 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8012 icsTextMenuEntry[i].command != NULL) {
\r
8013 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8014 icsTextMenuEntry[i].getname,
\r
8015 icsTextMenuEntry[i].immediate);
\r
8023 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8026 WNDPROC consoleInputWindowProc;
\r
8029 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8031 char buf[MSG_SIZ];
\r
8033 static BOOL sendNextChar = FALSE;
\r
8034 static BOOL quoteNextChar = FALSE;
\r
8035 InputSource *is = consoleInputSource;
\r
8039 switch (message) {
\r
8041 if (!appData.localLineEditing || sendNextChar) {
\r
8042 is->buf[0] = (CHAR) wParam;
\r
8044 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8045 sendNextChar = FALSE;
\r
8048 if (quoteNextChar) {
\r
8049 buf[0] = (char) wParam;
\r
8050 buf[1] = NULLCHAR;
\r
8051 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8052 quoteNextChar = FALSE;
\r
8056 case '\r': /* Enter key */
\r
8057 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8058 if (consoleEcho) SaveInHistory(is->buf);
\r
8059 is->buf[is->count++] = '\n';
\r
8060 is->buf[is->count] = NULLCHAR;
\r
8061 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8062 if (consoleEcho) {
\r
8063 ConsoleOutput(is->buf, is->count, TRUE);
\r
8064 } else if (appData.localLineEditing) {
\r
8065 ConsoleOutput("\n", 1, TRUE);
\r
8068 case '\033': /* Escape key */
\r
8069 SetWindowText(hwnd, "");
\r
8070 cf.cbSize = sizeof(CHARFORMAT);
\r
8071 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8072 if (consoleEcho) {
\r
8073 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8075 cf.crTextColor = COLOR_ECHOOFF;
\r
8077 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8078 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8080 case '\t': /* Tab key */
\r
8081 if (GetKeyState(VK_SHIFT) < 0) {
\r
8083 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8086 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8087 if (buttonDesc[0].hwnd) {
\r
8088 SetFocus(buttonDesc[0].hwnd);
\r
8090 SetFocus(hwndMain);
\r
8094 case '\023': /* Ctrl+S */
\r
8095 sendNextChar = TRUE;
\r
8097 case '\021': /* Ctrl+Q */
\r
8098 quoteNextChar = TRUE;
\r
8108 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8109 p = PrevInHistory(buf);
\r
8111 SetWindowText(hwnd, p);
\r
8112 sel.cpMin = 999999;
\r
8113 sel.cpMax = 999999;
\r
8114 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8119 p = NextInHistory();
\r
8121 SetWindowText(hwnd, p);
\r
8122 sel.cpMin = 999999;
\r
8123 sel.cpMax = 999999;
\r
8124 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8130 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8134 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8138 case WM_MBUTTONDOWN:
\r
8139 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8140 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8142 case WM_RBUTTONUP:
\r
8143 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8144 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8145 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8149 hmenu = LoadMenu(hInst, "InputMenu");
\r
8150 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8151 if (sel.cpMin == sel.cpMax) {
\r
8152 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8153 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8155 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8156 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8158 pt.x = LOWORD(lParam);
\r
8159 pt.y = HIWORD(lParam);
\r
8160 MenuPopup(hwnd, pt, hmenu, -1);
\r
8164 switch (LOWORD(wParam)) {
\r
8166 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8168 case IDM_SelectAll:
\r
8170 sel.cpMax = -1; /*999999?*/
\r
8171 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8174 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8177 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8180 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8185 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8188 #define CO_MAX 100000
\r
8189 #define CO_TRIM 1000
\r
8192 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8194 static SnapData sd;
\r
8195 static HWND hText, hInput /*, hFocus*/;
\r
8196 // InputSource *is = consoleInputSource;
\r
8198 static int sizeX, sizeY;
\r
8199 int newSizeX, newSizeY;
\r
8202 switch (message) {
\r
8203 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8204 hwndConsole = hDlg;
\r
8205 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8206 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8208 consoleTextWindowProc = (WNDPROC)
\r
8209 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8210 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8211 consoleInputWindowProc = (WNDPROC)
\r
8212 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8213 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8214 Colorize(ColorNormal, TRUE);
\r
8215 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8216 ChangedConsoleFont();
\r
8217 GetClientRect(hDlg, &rect);
\r
8218 sizeX = rect.right;
\r
8219 sizeY = rect.bottom;
\r
8220 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8221 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8222 WINDOWPLACEMENT wp;
\r
8223 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8224 wp.length = sizeof(WINDOWPLACEMENT);
\r
8226 wp.showCmd = SW_SHOW;
\r
8227 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8228 wp.rcNormalPosition.left = wpConsole.x;
\r
8229 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8230 wp.rcNormalPosition.top = wpConsole.y;
\r
8231 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8232 SetWindowPlacement(hDlg, &wp);
\r
8235 // [HGM] Chessknight's change 2004-07-13
\r
8236 else { /* Determine Defaults */
\r
8237 WINDOWPLACEMENT wp;
\r
8238 wpConsole.x = winWidth + 1;
\r
8239 wpConsole.y = boardY;
\r
8240 wpConsole.width = screenWidth - winWidth;
\r
8241 wpConsole.height = winHeight;
\r
8242 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8243 wp.length = sizeof(WINDOWPLACEMENT);
\r
8245 wp.showCmd = SW_SHOW;
\r
8246 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8247 wp.rcNormalPosition.left = wpConsole.x;
\r
8248 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8249 wp.rcNormalPosition.top = wpConsole.y;
\r
8250 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8251 SetWindowPlacement(hDlg, &wp);
\r
8266 if (IsIconic(hDlg)) break;
\r
8267 newSizeX = LOWORD(lParam);
\r
8268 newSizeY = HIWORD(lParam);
\r
8269 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8270 RECT rectText, rectInput;
\r
8272 int newTextHeight, newTextWidth;
\r
8273 GetWindowRect(hText, &rectText);
\r
8274 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8275 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8276 if (newTextHeight < 0) {
\r
8277 newSizeY += -newTextHeight;
\r
8278 newTextHeight = 0;
\r
8280 SetWindowPos(hText, NULL, 0, 0,
\r
8281 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8282 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8283 pt.x = rectInput.left;
\r
8284 pt.y = rectInput.top + newSizeY - sizeY;
\r
8285 ScreenToClient(hDlg, &pt);
\r
8286 SetWindowPos(hInput, NULL,
\r
8287 pt.x, pt.y, /* needs client coords */
\r
8288 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8289 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8295 case WM_GETMINMAXINFO:
\r
8296 /* Prevent resizing window too small */
\r
8297 mmi = (MINMAXINFO *) lParam;
\r
8298 mmi->ptMinTrackSize.x = 100;
\r
8299 mmi->ptMinTrackSize.y = 100;
\r
8302 /* [AS] Snapping */
\r
8303 case WM_ENTERSIZEMOVE:
\r
8304 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8307 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8310 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8312 case WM_EXITSIZEMOVE:
\r
8313 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8316 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8324 if (hwndConsole) return;
\r
8325 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8326 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8331 ConsoleOutput(char* data, int length, int forceVisible)
\r
8336 char buf[CO_MAX+1];
\r
8339 static int delayLF = 0;
\r
8340 CHARRANGE savesel, sel;
\r
8342 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8350 while (length--) {
\r
8358 } else if (*p == '\007') {
\r
8359 MyPlaySound(&sounds[(int)SoundBell]);
\r
8366 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8367 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8368 /* Save current selection */
\r
8369 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8370 exlen = GetWindowTextLength(hText);
\r
8371 /* Find out whether current end of text is visible */
\r
8372 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8373 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8374 /* Trim existing text if it's too long */
\r
8375 if (exlen + (q - buf) > CO_MAX) {
\r
8376 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8379 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8380 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8382 savesel.cpMin -= trim;
\r
8383 savesel.cpMax -= trim;
\r
8384 if (exlen < 0) exlen = 0;
\r
8385 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8386 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8388 /* Append the new text */
\r
8389 sel.cpMin = exlen;
\r
8390 sel.cpMax = exlen;
\r
8391 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8392 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8393 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8394 if (forceVisible || exlen == 0 ||
\r
8395 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8396 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8397 /* Scroll to make new end of text visible if old end of text
\r
8398 was visible or new text is an echo of user typein */
\r
8399 sel.cpMin = 9999999;
\r
8400 sel.cpMax = 9999999;
\r
8401 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8402 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8403 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8404 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8406 if (savesel.cpMax == exlen || forceVisible) {
\r
8407 /* Move insert point to new end of text if it was at the old
\r
8408 end of text or if the new text is an echo of user typein */
\r
8409 sel.cpMin = 9999999;
\r
8410 sel.cpMax = 9999999;
\r
8411 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8413 /* Restore previous selection */
\r
8414 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8416 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8423 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8427 COLORREF oldFg, oldBg;
\r
8431 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8433 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8434 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8435 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8438 rect.right = x + squareSize;
\r
8440 rect.bottom = y + squareSize;
\r
8443 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8444 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8445 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8446 &rect, str, strlen(str), NULL);
\r
8448 (void) SetTextColor(hdc, oldFg);
\r
8449 (void) SetBkColor(hdc, oldBg);
\r
8450 (void) SelectObject(hdc, oldFont);
\r
8454 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8455 RECT *rect, char *color, char *flagFell)
\r
8459 COLORREF oldFg, oldBg;
\r
8462 if (appData.clockMode) {
\r
8464 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8466 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8473 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8474 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8476 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8477 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8479 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8483 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8484 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8485 rect, str, strlen(str), NULL);
\r
8486 if(logoHeight > 0 && appData.clockMode) {
\r
8488 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8489 r.top = rect->top + logoHeight/2;
\r
8490 r.left = rect->left;
\r
8491 r.right = rect->right;
\r
8492 r.bottom = rect->bottom;
\r
8493 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8494 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8495 &r, str, strlen(str), NULL);
\r
8497 (void) SetTextColor(hdc, oldFg);
\r
8498 (void) SetBkColor(hdc, oldBg);
\r
8499 (void) SelectObject(hdc, oldFont);
\r
8504 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8510 if( count <= 0 ) {
\r
8511 if (appData.debugMode) {
\r
8512 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8515 return ERROR_INVALID_USER_BUFFER;
\r
8518 ResetEvent(ovl->hEvent);
\r
8519 ovl->Offset = ovl->OffsetHigh = 0;
\r
8520 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8524 err = GetLastError();
\r
8525 if (err == ERROR_IO_PENDING) {
\r
8526 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8530 err = GetLastError();
\r
8537 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8542 ResetEvent(ovl->hEvent);
\r
8543 ovl->Offset = ovl->OffsetHigh = 0;
\r
8544 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8548 err = GetLastError();
\r
8549 if (err == ERROR_IO_PENDING) {
\r
8550 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8554 err = GetLastError();
\r
8560 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8561 void CheckForInputBufferFull( InputSource * is )
\r
8563 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8564 /* Look for end of line */
\r
8565 char * p = is->buf;
\r
8567 while( p < is->next && *p != '\n' ) {
\r
8571 if( p >= is->next ) {
\r
8572 if (appData.debugMode) {
\r
8573 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8576 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8577 is->count = (DWORD) -1;
\r
8578 is->next = is->buf;
\r
8584 InputThread(LPVOID arg)
\r
8589 is = (InputSource *) arg;
\r
8590 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8591 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8592 while (is->hThread != NULL) {
\r
8593 is->error = DoReadFile(is->hFile, is->next,
\r
8594 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8595 &is->count, &ovl);
\r
8596 if (is->error == NO_ERROR) {
\r
8597 is->next += is->count;
\r
8599 if (is->error == ERROR_BROKEN_PIPE) {
\r
8600 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8603 is->count = (DWORD) -1;
\r
8604 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8609 CheckForInputBufferFull( is );
\r
8611 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8613 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8615 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8618 CloseHandle(ovl.hEvent);
\r
8619 CloseHandle(is->hFile);
\r
8621 if (appData.debugMode) {
\r
8622 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8629 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8631 NonOvlInputThread(LPVOID arg)
\r
8638 is = (InputSource *) arg;
\r
8639 while (is->hThread != NULL) {
\r
8640 is->error = ReadFile(is->hFile, is->next,
\r
8641 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8642 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8643 if (is->error == NO_ERROR) {
\r
8644 /* Change CRLF to LF */
\r
8645 if (is->next > is->buf) {
\r
8647 i = is->count + 1;
\r
8655 if (prev == '\r' && *p == '\n') {
\r
8667 if (is->error == ERROR_BROKEN_PIPE) {
\r
8668 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8671 is->count = (DWORD) -1;
\r
8675 CheckForInputBufferFull( is );
\r
8677 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8679 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8681 if (is->count < 0) break; /* Quit on error */
\r
8683 CloseHandle(is->hFile);
\r
8688 SocketInputThread(LPVOID arg)
\r
8692 is = (InputSource *) arg;
\r
8693 while (is->hThread != NULL) {
\r
8694 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8695 if ((int)is->count == SOCKET_ERROR) {
\r
8696 is->count = (DWORD) -1;
\r
8697 is->error = WSAGetLastError();
\r
8699 is->error = NO_ERROR;
\r
8700 is->next += is->count;
\r
8701 if (is->count == 0 && is->second == is) {
\r
8702 /* End of file on stderr; quit with no message */
\r
8706 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8708 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8710 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8716 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8720 is = (InputSource *) lParam;
\r
8721 if (is->lineByLine) {
\r
8722 /* Feed in lines one by one */
\r
8723 char *p = is->buf;
\r
8725 while (q < is->next) {
\r
8726 if (*q++ == '\n') {
\r
8727 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8732 /* Move any partial line to the start of the buffer */
\r
8734 while (p < is->next) {
\r
8739 if (is->error != NO_ERROR || is->count == 0) {
\r
8740 /* Notify backend of the error. Note: If there was a partial
\r
8741 line at the end, it is not flushed through. */
\r
8742 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8745 /* Feed in the whole chunk of input at once */
\r
8746 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8747 is->next = is->buf;
\r
8751 /*---------------------------------------------------------------------------*\
\r
8753 * Menu enables. Used when setting various modes.
\r
8755 \*---------------------------------------------------------------------------*/
\r
8763 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8765 while (enab->item > 0) {
\r
8766 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8771 Enables gnuEnables[] = {
\r
8772 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8773 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8774 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8775 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8776 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8777 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8778 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8779 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8780 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8781 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8785 Enables icsEnables[] = {
\r
8786 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8787 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8788 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8789 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8790 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8791 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8792 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8793 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8794 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8795 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8796 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8797 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8802 Enables zippyEnables[] = {
\r
8803 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8804 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8805 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8810 Enables ncpEnables[] = {
\r
8811 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8812 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8813 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8814 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8815 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8816 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8817 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8818 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8819 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8820 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8822 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8823 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8824 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8825 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8829 Enables trainingOnEnables[] = {
\r
8830 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8831 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8832 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8833 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8834 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8835 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8836 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8837 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8841 Enables trainingOffEnables[] = {
\r
8842 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8843 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8844 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8845 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8846 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8847 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8848 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8849 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8853 /* These modify either ncpEnables or gnuEnables */
\r
8854 Enables cmailEnables[] = {
\r
8855 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8856 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8857 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8858 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8859 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8860 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8861 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8865 Enables machineThinkingEnables[] = {
\r
8866 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8867 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8868 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8869 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8870 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8871 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8872 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8873 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8874 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8875 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8876 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8877 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8878 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8879 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8880 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8884 Enables userThinkingEnables[] = {
\r
8885 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8886 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8887 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8888 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8889 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8890 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8891 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8892 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8893 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8894 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8895 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8896 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8897 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8898 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8899 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8903 /*---------------------------------------------------------------------------*\
\r
8905 * Front-end interface functions exported by XBoard.
\r
8906 * Functions appear in same order as prototypes in frontend.h.
\r
8908 \*---------------------------------------------------------------------------*/
\r
8912 static UINT prevChecked = 0;
\r
8913 static int prevPausing = 0;
\r
8916 if (pausing != prevPausing) {
\r
8917 prevPausing = pausing;
\r
8918 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8919 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8920 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8923 switch (gameMode) {
\r
8924 case BeginningOfGame:
\r
8925 if (appData.icsActive)
\r
8926 nowChecked = IDM_IcsClient;
\r
8927 else if (appData.noChessProgram)
\r
8928 nowChecked = IDM_EditGame;
\r
8930 nowChecked = IDM_MachineBlack;
\r
8932 case MachinePlaysBlack:
\r
8933 nowChecked = IDM_MachineBlack;
\r
8935 case MachinePlaysWhite:
\r
8936 nowChecked = IDM_MachineWhite;
\r
8938 case TwoMachinesPlay:
\r
8939 nowChecked = IDM_TwoMachines;
\r
8942 nowChecked = IDM_AnalysisMode;
\r
8945 nowChecked = IDM_AnalyzeFile;
\r
8948 nowChecked = IDM_EditGame;
\r
8950 case PlayFromGameFile:
\r
8951 nowChecked = IDM_LoadGame;
\r
8953 case EditPosition:
\r
8954 nowChecked = IDM_EditPosition;
\r
8957 nowChecked = IDM_Training;
\r
8959 case IcsPlayingWhite:
\r
8960 case IcsPlayingBlack:
\r
8961 case IcsObserving:
\r
8963 nowChecked = IDM_IcsClient;
\r
8970 if (prevChecked != 0)
\r
8971 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8972 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8973 if (nowChecked != 0)
\r
8974 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8975 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8977 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8978 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8979 MF_BYCOMMAND|MF_ENABLED);
\r
8981 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8982 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8985 prevChecked = nowChecked;
\r
8987 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8988 if (appData.icsActive) {
\r
8989 if (appData.icsEngineAnalyze) {
\r
8990 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8991 MF_BYCOMMAND|MF_CHECKED);
\r
8993 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8994 MF_BYCOMMAND|MF_UNCHECKED);
\r
9002 HMENU hmenu = GetMenu(hwndMain);
\r
9003 SetMenuEnables(hmenu, icsEnables);
\r
9004 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9005 MF_BYPOSITION|MF_ENABLED);
\r
9007 if (appData.zippyPlay) {
\r
9008 SetMenuEnables(hmenu, zippyEnables);
\r
9009 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9010 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9011 MF_BYCOMMAND|MF_ENABLED);
\r
9019 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9025 HMENU hmenu = GetMenu(hwndMain);
\r
9026 SetMenuEnables(hmenu, ncpEnables);
\r
9027 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9028 MF_BYPOSITION|MF_GRAYED);
\r
9029 DrawMenuBar(hwndMain);
\r
9035 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9039 SetTrainingModeOn()
\r
9042 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9043 for (i = 0; i < N_BUTTONS; i++) {
\r
9044 if (buttonDesc[i].hwnd != NULL)
\r
9045 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9050 VOID SetTrainingModeOff()
\r
9053 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9054 for (i = 0; i < N_BUTTONS; i++) {
\r
9055 if (buttonDesc[i].hwnd != NULL)
\r
9056 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9062 SetUserThinkingEnables()
\r
9064 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9068 SetMachineThinkingEnables()
\r
9070 HMENU hMenu = GetMenu(hwndMain);
\r
9071 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9073 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9075 if (gameMode == MachinePlaysBlack) {
\r
9076 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9077 } else if (gameMode == MachinePlaysWhite) {
\r
9078 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9079 } else if (gameMode == TwoMachinesPlay) {
\r
9080 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9086 DisplayTitle(char *str)
\r
9088 char title[MSG_SIZ], *host;
\r
9089 if (str[0] != NULLCHAR) {
\r
9090 strcpy(title, str);
\r
9091 } else if (appData.icsActive) {
\r
9092 if (appData.icsCommPort[0] != NULLCHAR)
\r
9095 host = appData.icsHost;
\r
9096 sprintf(title, "%s: %s", szTitle, host);
\r
9097 } else if (appData.noChessProgram) {
\r
9098 strcpy(title, szTitle);
\r
9100 strcpy(title, szTitle);
\r
9101 strcat(title, ": ");
\r
9102 strcat(title, first.tidy);
\r
9104 SetWindowText(hwndMain, title);
\r
9109 DisplayMessage(char *str1, char *str2)
\r
9113 int remain = MESSAGE_TEXT_MAX - 1;
\r
9116 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9117 messageText[0] = NULLCHAR;
\r
9119 len = strlen(str1);
\r
9120 if (len > remain) len = remain;
\r
9121 strncpy(messageText, str1, len);
\r
9122 messageText[len] = NULLCHAR;
\r
9125 if (*str2 && remain >= 2) {
\r
9127 strcat(messageText, " ");
\r
9130 len = strlen(str2);
\r
9131 if (len > remain) len = remain;
\r
9132 strncat(messageText, str2, len);
\r
9134 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9136 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9140 hdc = GetDC(hwndMain);
\r
9141 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9142 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9143 &messageRect, messageText, strlen(messageText), NULL);
\r
9144 (void) SelectObject(hdc, oldFont);
\r
9145 (void) ReleaseDC(hwndMain, hdc);
\r
9149 DisplayError(char *str, int error)
\r
9151 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9157 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9158 NULL, error, LANG_NEUTRAL,
\r
9159 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9161 sprintf(buf, "%s:\n%s", str, buf2);
\r
9163 ErrorMap *em = errmap;
\r
9164 while (em->err != 0 && em->err != error) em++;
\r
9165 if (em->err != 0) {
\r
9166 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9168 sprintf(buf, "%s:\nError code %d", str, error);
\r
9173 ErrorPopUp("Error", buf);
\r
9178 DisplayMoveError(char *str)
\r
9180 fromX = fromY = -1;
\r
9181 ClearHighlights();
\r
9182 DrawPosition(FALSE, NULL);
\r
9183 if (appData.popupMoveErrors) {
\r
9184 ErrorPopUp("Error", str);
\r
9186 DisplayMessage(str, "");
\r
9187 moveErrorMessageUp = TRUE;
\r
9192 DisplayFatalError(char *str, int error, int exitStatus)
\r
9194 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9196 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9199 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9200 NULL, error, LANG_NEUTRAL,
\r
9201 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9203 sprintf(buf, "%s:\n%s", str, buf2);
\r
9205 ErrorMap *em = errmap;
\r
9206 while (em->err != 0 && em->err != error) em++;
\r
9207 if (em->err != 0) {
\r
9208 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9210 sprintf(buf, "%s:\nError code %d", str, error);
\r
9215 if (appData.debugMode) {
\r
9216 fprintf(debugFP, "%s: %s\n", label, str);
\r
9218 if (appData.popupExitMessage) {
\r
9219 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9220 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9222 ExitEvent(exitStatus);
\r
9227 DisplayInformation(char *str)
\r
9229 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9234 DisplayNote(char *str)
\r
9236 ErrorPopUp("Note", str);
\r
9241 char *title, *question, *replyPrefix;
\r
9246 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9248 static QuestionParams *qp;
\r
9249 char reply[MSG_SIZ];
\r
9252 switch (message) {
\r
9253 case WM_INITDIALOG:
\r
9254 qp = (QuestionParams *) lParam;
\r
9255 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9256 SetWindowText(hDlg, qp->title);
\r
9257 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9258 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9262 switch (LOWORD(wParam)) {
\r
9264 strcpy(reply, qp->replyPrefix);
\r
9265 if (*reply) strcat(reply, " ");
\r
9266 len = strlen(reply);
\r
9267 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9268 strcat(reply, "\n");
\r
9269 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9270 EndDialog(hDlg, TRUE);
\r
9271 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9274 EndDialog(hDlg, FALSE);
\r
9285 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9287 QuestionParams qp;
\r
9291 qp.question = question;
\r
9292 qp.replyPrefix = replyPrefix;
\r
9294 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9295 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9296 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9297 FreeProcInstance(lpProc);
\r
9300 /* [AS] Pick FRC position */
\r
9301 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9303 static int * lpIndexFRC;
\r
9309 case WM_INITDIALOG:
\r
9310 lpIndexFRC = (int *) lParam;
\r
9312 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9314 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9315 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9316 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9317 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9322 switch( LOWORD(wParam) ) {
\r
9324 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9325 EndDialog( hDlg, 0 );
\r
9326 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9329 EndDialog( hDlg, 1 );
\r
9331 case IDC_NFG_Edit:
\r
9332 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9333 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9335 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9338 case IDC_NFG_Random:
\r
9339 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9340 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9353 int index = appData.defaultFrcPosition;
\r
9354 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9356 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9358 if( result == 0 ) {
\r
9359 appData.defaultFrcPosition = index;
\r
9365 /* [AS] Game list options */
\r
9371 static GLT_Item GLT_ItemInfo[] = {
\r
9372 { GLT_EVENT, "Event" },
\r
9373 { GLT_SITE, "Site" },
\r
9374 { GLT_DATE, "Date" },
\r
9375 { GLT_ROUND, "Round" },
\r
9376 { GLT_PLAYERS, "Players" },
\r
9377 { GLT_RESULT, "Result" },
\r
9378 { GLT_WHITE_ELO, "White Rating" },
\r
9379 { GLT_BLACK_ELO, "Black Rating" },
\r
9380 { GLT_TIME_CONTROL,"Time Control" },
\r
9381 { GLT_VARIANT, "Variant" },
\r
9382 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9386 const char * GLT_FindItem( char id )
\r
9388 const char * result = 0;
\r
9390 GLT_Item * list = GLT_ItemInfo;
\r
9392 while( list->id != 0 ) {
\r
9393 if( list->id == id ) {
\r
9394 result = list->name;
\r
9404 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9406 const char * name = GLT_FindItem( id );
\r
9409 if( index >= 0 ) {
\r
9410 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9413 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9418 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9422 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9425 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9429 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9431 pc = GLT_ALL_TAGS;
\r
9434 if( strchr( tags, *pc ) == 0 ) {
\r
9435 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9440 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9443 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9445 char result = '\0';
\r
9448 GLT_Item * list = GLT_ItemInfo;
\r
9450 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9451 while( list->id != 0 ) {
\r
9452 if( strcmp( list->name, name ) == 0 ) {
\r
9453 result = list->id;
\r
9464 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9466 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9467 int idx2 = idx1 + delta;
\r
9468 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9470 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9473 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9474 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9475 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9476 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9480 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9482 static char glt[64];
\r
9483 static char * lpUserGLT;
\r
9487 case WM_INITDIALOG:
\r
9488 lpUserGLT = (char *) lParam;
\r
9490 strcpy( glt, lpUserGLT );
\r
9492 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9494 /* Initialize list */
\r
9495 GLT_TagsToList( hDlg, glt );
\r
9497 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9502 switch( LOWORD(wParam) ) {
\r
9505 char * pc = lpUserGLT;
\r
9507 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9511 id = GLT_ListItemToTag( hDlg, idx );
\r
9515 } while( id != '\0' );
\r
9517 EndDialog( hDlg, 0 );
\r
9520 EndDialog( hDlg, 1 );
\r
9523 case IDC_GLT_Default:
\r
9524 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9525 GLT_TagsToList( hDlg, glt );
\r
9528 case IDC_GLT_Restore:
\r
9529 strcpy( glt, lpUserGLT );
\r
9530 GLT_TagsToList( hDlg, glt );
\r
9534 GLT_MoveSelection( hDlg, -1 );
\r
9537 case IDC_GLT_Down:
\r
9538 GLT_MoveSelection( hDlg, +1 );
\r
9548 int GameListOptions()
\r
9552 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9554 strcpy( glt, appData.gameListTags );
\r
9556 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9558 if( result == 0 ) {
\r
9559 /* [AS] Memory leak here! */
\r
9560 appData.gameListTags = strdup( glt );
\r
9568 DisplayIcsInteractionTitle(char *str)
\r
9570 char consoleTitle[MSG_SIZ];
\r
9572 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9573 SetWindowText(hwndConsole, consoleTitle);
\r
9577 DrawPosition(int fullRedraw, Board board)
\r
9579 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9586 fromX = fromY = -1;
\r
9587 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9588 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9589 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9590 dragInfo.lastpos = dragInfo.pos;
\r
9591 dragInfo.start.x = dragInfo.start.y = -1;
\r
9592 dragInfo.from = dragInfo.start;
\r
9594 DrawPosition(TRUE, NULL);
\r
9600 CommentPopUp(char *title, char *str)
\r
9602 HWND hwnd = GetActiveWindow();
\r
9603 EitherCommentPopUp(0, title, str, FALSE);
\r
9604 SetActiveWindow(hwnd);
\r
9608 CommentPopDown(void)
\r
9610 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9611 if (commentDialog) {
\r
9612 ShowWindow(commentDialog, SW_HIDE);
\r
9614 commentDialogUp = FALSE;
\r
9618 EditCommentPopUp(int index, char *title, char *str)
\r
9620 EitherCommentPopUp(index, title, str, TRUE);
\r
9627 MyPlaySound(&sounds[(int)SoundMove]);
\r
9630 VOID PlayIcsWinSound()
\r
9632 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9635 VOID PlayIcsLossSound()
\r
9637 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9640 VOID PlayIcsDrawSound()
\r
9642 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9645 VOID PlayIcsUnfinishedSound()
\r
9647 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9653 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9661 consoleEcho = TRUE;
\r
9662 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9663 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9664 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9673 consoleEcho = FALSE;
\r
9674 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9675 /* This works OK: set text and background both to the same color */
\r
9677 cf.crTextColor = COLOR_ECHOOFF;
\r
9678 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9679 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9682 /* No Raw()...? */
\r
9684 void Colorize(ColorClass cc, int continuation)
\r
9686 currentColorClass = cc;
\r
9687 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9688 consoleCF.crTextColor = textAttribs[cc].color;
\r
9689 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9690 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9696 static char buf[MSG_SIZ];
\r
9697 DWORD bufsiz = MSG_SIZ;
\r
9699 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9700 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9702 if (!GetUserName(buf, &bufsiz)) {
\r
9703 /*DisplayError("Error getting user name", GetLastError());*/
\r
9704 strcpy(buf, "User");
\r
9712 static char buf[MSG_SIZ];
\r
9713 DWORD bufsiz = MSG_SIZ;
\r
9715 if (!GetComputerName(buf, &bufsiz)) {
\r
9716 /*DisplayError("Error getting host name", GetLastError());*/
\r
9717 strcpy(buf, "Unknown");
\r
9724 ClockTimerRunning()
\r
9726 return clockTimerEvent != 0;
\r
9732 if (clockTimerEvent == 0) return FALSE;
\r
9733 KillTimer(hwndMain, clockTimerEvent);
\r
9734 clockTimerEvent = 0;
\r
9739 StartClockTimer(long millisec)
\r
9741 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9742 (UINT) millisec, NULL);
\r
9746 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9749 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9751 if(appData.noGUI) return;
\r
9752 hdc = GetDC(hwndMain);
\r
9753 if (!IsIconic(hwndMain)) {
\r
9754 DisplayAClock(hdc, timeRemaining, highlight,
\r
9755 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9757 if (highlight && iconCurrent == iconBlack) {
\r
9758 iconCurrent = iconWhite;
\r
9759 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9760 if (IsIconic(hwndMain)) {
\r
9761 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9764 (void) ReleaseDC(hwndMain, hdc);
\r
9766 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9770 DisplayBlackClock(long timeRemaining, int highlight)
\r
9773 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9775 if(appData.noGUI) return;
\r
9776 hdc = GetDC(hwndMain);
\r
9777 if (!IsIconic(hwndMain)) {
\r
9778 DisplayAClock(hdc, timeRemaining, highlight,
\r
9779 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9781 if (highlight && iconCurrent == iconWhite) {
\r
9782 iconCurrent = iconBlack;
\r
9783 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9784 if (IsIconic(hwndMain)) {
\r
9785 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9788 (void) ReleaseDC(hwndMain, hdc);
\r
9790 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9795 LoadGameTimerRunning()
\r
9797 return loadGameTimerEvent != 0;
\r
9801 StopLoadGameTimer()
\r
9803 if (loadGameTimerEvent == 0) return FALSE;
\r
9804 KillTimer(hwndMain, loadGameTimerEvent);
\r
9805 loadGameTimerEvent = 0;
\r
9810 StartLoadGameTimer(long millisec)
\r
9812 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9813 (UINT) millisec, NULL);
\r
9821 char fileTitle[MSG_SIZ];
\r
9823 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9824 f = OpenFileDialog(hwndMain, "a", defName,
\r
9825 appData.oldSaveStyle ? "gam" : "pgn",
\r
9827 "Save Game to File", NULL, fileTitle, NULL);
\r
9829 SaveGame(f, 0, "");
\r
9836 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9838 if (delayedTimerEvent != 0) {
\r
9839 if (appData.debugMode) {
\r
9840 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9842 KillTimer(hwndMain, delayedTimerEvent);
\r
9843 delayedTimerEvent = 0;
\r
9844 delayedTimerCallback();
\r
9846 delayedTimerCallback = cb;
\r
9847 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9848 (UINT) millisec, NULL);
\r
9851 DelayedEventCallback
\r
9854 if (delayedTimerEvent) {
\r
9855 return delayedTimerCallback;
\r
9862 CancelDelayedEvent()
\r
9864 if (delayedTimerEvent) {
\r
9865 KillTimer(hwndMain, delayedTimerEvent);
\r
9866 delayedTimerEvent = 0;
\r
9870 DWORD GetWin32Priority(int nice)
\r
9871 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9873 REALTIME_PRIORITY_CLASS 0x00000100
\r
9874 HIGH_PRIORITY_CLASS 0x00000080
\r
9875 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9876 NORMAL_PRIORITY_CLASS 0x00000020
\r
9877 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9878 IDLE_PRIORITY_CLASS 0x00000040
\r
9880 if (nice < -15) return 0x00000080;
\r
9881 if (nice < 0) return 0x00008000;
\r
9882 if (nice == 0) return 0x00000020;
\r
9883 if (nice < 15) return 0x00004000;
\r
9884 return 0x00000040;
\r
9887 /* Start a child process running the given program.
\r
9888 The process's standard output can be read from "from", and its
\r
9889 standard input can be written to "to".
\r
9890 Exit with fatal error if anything goes wrong.
\r
9891 Returns an opaque pointer that can be used to destroy the process
\r
9895 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9897 #define BUFSIZE 4096
\r
9899 HANDLE hChildStdinRd, hChildStdinWr,
\r
9900 hChildStdoutRd, hChildStdoutWr;
\r
9901 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9902 SECURITY_ATTRIBUTES saAttr;
\r
9904 PROCESS_INFORMATION piProcInfo;
\r
9905 STARTUPINFO siStartInfo;
\r
9907 char buf[MSG_SIZ];
\r
9910 if (appData.debugMode) {
\r
9911 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9916 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9917 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9918 saAttr.bInheritHandle = TRUE;
\r
9919 saAttr.lpSecurityDescriptor = NULL;
\r
9922 * The steps for redirecting child's STDOUT:
\r
9923 * 1. Create anonymous pipe to be STDOUT for child.
\r
9924 * 2. Create a noninheritable duplicate of read handle,
\r
9925 * and close the inheritable read handle.
\r
9928 /* Create a pipe for the child's STDOUT. */
\r
9929 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9930 return GetLastError();
\r
9933 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9934 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9935 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9936 FALSE, /* not inherited */
\r
9937 DUPLICATE_SAME_ACCESS);
\r
9939 return GetLastError();
\r
9941 CloseHandle(hChildStdoutRd);
\r
9944 * The steps for redirecting child's STDIN:
\r
9945 * 1. Create anonymous pipe to be STDIN for child.
\r
9946 * 2. Create a noninheritable duplicate of write handle,
\r
9947 * and close the inheritable write handle.
\r
9950 /* Create a pipe for the child's STDIN. */
\r
9951 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9952 return GetLastError();
\r
9955 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9956 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9957 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9958 FALSE, /* not inherited */
\r
9959 DUPLICATE_SAME_ACCESS);
\r
9961 return GetLastError();
\r
9963 CloseHandle(hChildStdinWr);
\r
9965 /* Arrange to (1) look in dir for the child .exe file, and
\r
9966 * (2) have dir be the child's working directory. Interpret
\r
9967 * dir relative to the directory WinBoard loaded from. */
\r
9968 GetCurrentDirectory(MSG_SIZ, buf);
\r
9969 SetCurrentDirectory(installDir);
\r
9970 SetCurrentDirectory(dir);
\r
9972 /* Now create the child process. */
\r
9974 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9975 siStartInfo.lpReserved = NULL;
\r
9976 siStartInfo.lpDesktop = NULL;
\r
9977 siStartInfo.lpTitle = NULL;
\r
9978 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9979 siStartInfo.cbReserved2 = 0;
\r
9980 siStartInfo.lpReserved2 = NULL;
\r
9981 siStartInfo.hStdInput = hChildStdinRd;
\r
9982 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9983 siStartInfo.hStdError = hChildStdoutWr;
\r
9985 fSuccess = CreateProcess(NULL,
\r
9986 cmdLine, /* command line */
\r
9987 NULL, /* process security attributes */
\r
9988 NULL, /* primary thread security attrs */
\r
9989 TRUE, /* handles are inherited */
\r
9990 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9991 NULL, /* use parent's environment */
\r
9993 &siStartInfo, /* STARTUPINFO pointer */
\r
9994 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9996 err = GetLastError();
\r
9997 SetCurrentDirectory(buf); /* return to prev directory */
\r
10002 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10003 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10004 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10007 /* Close the handles we don't need in the parent */
\r
10008 CloseHandle(piProcInfo.hThread);
\r
10009 CloseHandle(hChildStdinRd);
\r
10010 CloseHandle(hChildStdoutWr);
\r
10012 /* Prepare return value */
\r
10013 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10014 cp->kind = CPReal;
\r
10015 cp->hProcess = piProcInfo.hProcess;
\r
10016 cp->pid = piProcInfo.dwProcessId;
\r
10017 cp->hFrom = hChildStdoutRdDup;
\r
10018 cp->hTo = hChildStdinWrDup;
\r
10020 *pr = (void *) cp;
\r
10022 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10023 2000 where engines sometimes don't see the initial command(s)
\r
10024 from WinBoard and hang. I don't understand how that can happen,
\r
10025 but the Sleep is harmless, so I've put it in. Others have also
\r
10026 reported what may be the same problem, so hopefully this will fix
\r
10027 it for them too. */
\r
10035 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10037 ChildProc *cp; int result;
\r
10039 cp = (ChildProc *) pr;
\r
10040 if (cp == NULL) return;
\r
10042 switch (cp->kind) {
\r
10044 /* TerminateProcess is considered harmful, so... */
\r
10045 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10046 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10047 /* The following doesn't work because the chess program
\r
10048 doesn't "have the same console" as WinBoard. Maybe
\r
10049 we could arrange for this even though neither WinBoard
\r
10050 nor the chess program uses a console for stdio? */
\r
10051 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10053 /* [AS] Special termination modes for misbehaving programs... */
\r
10054 if( signal == 9 ) {
\r
10055 result = TerminateProcess( cp->hProcess, 0 );
\r
10057 if ( appData.debugMode) {
\r
10058 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10061 else if( signal == 10 ) {
\r
10062 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10064 if( dw != WAIT_OBJECT_0 ) {
\r
10065 result = TerminateProcess( cp->hProcess, 0 );
\r
10067 if ( appData.debugMode) {
\r
10068 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10074 CloseHandle(cp->hProcess);
\r
10078 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10082 closesocket(cp->sock);
\r
10087 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10088 closesocket(cp->sock);
\r
10089 closesocket(cp->sock2);
\r
10097 InterruptChildProcess(ProcRef pr)
\r
10101 cp = (ChildProc *) pr;
\r
10102 if (cp == NULL) return;
\r
10103 switch (cp->kind) {
\r
10105 /* The following doesn't work because the chess program
\r
10106 doesn't "have the same console" as WinBoard. Maybe
\r
10107 we could arrange for this even though neither WinBoard
\r
10108 nor the chess program uses a console for stdio */
\r
10109 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10114 /* Can't interrupt */
\r
10118 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10125 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10127 char cmdLine[MSG_SIZ];
\r
10129 if (port[0] == NULLCHAR) {
\r
10130 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10132 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10134 return StartChildProcess(cmdLine, "", pr);
\r
10138 /* Code to open TCP sockets */
\r
10141 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10146 struct sockaddr_in sa, mysa;
\r
10147 struct hostent FAR *hp;
\r
10148 unsigned short uport;
\r
10149 WORD wVersionRequested;
\r
10152 /* Initialize socket DLL */
\r
10153 wVersionRequested = MAKEWORD(1, 1);
\r
10154 err = WSAStartup(wVersionRequested, &wsaData);
\r
10155 if (err != 0) return err;
\r
10157 /* Make socket */
\r
10158 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10159 err = WSAGetLastError();
\r
10164 /* Bind local address using (mostly) don't-care values.
\r
10166 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10167 mysa.sin_family = AF_INET;
\r
10168 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10169 uport = (unsigned short) 0;
\r
10170 mysa.sin_port = htons(uport);
\r
10171 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10172 == SOCKET_ERROR) {
\r
10173 err = WSAGetLastError();
\r
10178 /* Resolve remote host name */
\r
10179 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10180 if (!(hp = gethostbyname(host))) {
\r
10181 unsigned int b0, b1, b2, b3;
\r
10183 err = WSAGetLastError();
\r
10185 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10186 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10187 hp->h_addrtype = AF_INET;
\r
10188 hp->h_length = 4;
\r
10189 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10190 hp->h_addr_list[0] = (char *) malloc(4);
\r
10191 hp->h_addr_list[0][0] = (char) b0;
\r
10192 hp->h_addr_list[0][1] = (char) b1;
\r
10193 hp->h_addr_list[0][2] = (char) b2;
\r
10194 hp->h_addr_list[0][3] = (char) b3;
\r
10200 sa.sin_family = hp->h_addrtype;
\r
10201 uport = (unsigned short) atoi(port);
\r
10202 sa.sin_port = htons(uport);
\r
10203 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10205 /* Make connection */
\r
10206 if (connect(s, (struct sockaddr *) &sa,
\r
10207 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10208 err = WSAGetLastError();
\r
10213 /* Prepare return value */
\r
10214 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10215 cp->kind = CPSock;
\r
10217 *pr = (ProcRef *) cp;
\r
10223 OpenCommPort(char *name, ProcRef *pr)
\r
10228 char fullname[MSG_SIZ];
\r
10230 if (*name != '\\')
\r
10231 sprintf(fullname, "\\\\.\\%s", name);
\r
10233 strcpy(fullname, name);
\r
10235 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10236 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10237 if (h == (HANDLE) -1) {
\r
10238 return GetLastError();
\r
10242 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10244 /* Accumulate characters until a 100ms pause, then parse */
\r
10245 ct.ReadIntervalTimeout = 100;
\r
10246 ct.ReadTotalTimeoutMultiplier = 0;
\r
10247 ct.ReadTotalTimeoutConstant = 0;
\r
10248 ct.WriteTotalTimeoutMultiplier = 0;
\r
10249 ct.WriteTotalTimeoutConstant = 0;
\r
10250 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10252 /* Prepare return value */
\r
10253 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10254 cp->kind = CPComm;
\r
10257 *pr = (ProcRef *) cp;
\r
10263 OpenLoopback(ProcRef *pr)
\r
10265 DisplayFatalError("Not implemented", 0, 1);
\r
10271 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10275 SOCKET s, s2, s3;
\r
10276 struct sockaddr_in sa, mysa;
\r
10277 struct hostent FAR *hp;
\r
10278 unsigned short uport;
\r
10279 WORD wVersionRequested;
\r
10282 char stderrPortStr[MSG_SIZ];
\r
10284 /* Initialize socket DLL */
\r
10285 wVersionRequested = MAKEWORD(1, 1);
\r
10286 err = WSAStartup(wVersionRequested, &wsaData);
\r
10287 if (err != 0) return err;
\r
10289 /* Resolve remote host name */
\r
10290 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10291 if (!(hp = gethostbyname(host))) {
\r
10292 unsigned int b0, b1, b2, b3;
\r
10294 err = WSAGetLastError();
\r
10296 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10297 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10298 hp->h_addrtype = AF_INET;
\r
10299 hp->h_length = 4;
\r
10300 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10301 hp->h_addr_list[0] = (char *) malloc(4);
\r
10302 hp->h_addr_list[0][0] = (char) b0;
\r
10303 hp->h_addr_list[0][1] = (char) b1;
\r
10304 hp->h_addr_list[0][2] = (char) b2;
\r
10305 hp->h_addr_list[0][3] = (char) b3;
\r
10311 sa.sin_family = hp->h_addrtype;
\r
10312 uport = (unsigned short) 514;
\r
10313 sa.sin_port = htons(uport);
\r
10314 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10316 /* Bind local socket to unused "privileged" port address
\r
10318 s = INVALID_SOCKET;
\r
10319 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10320 mysa.sin_family = AF_INET;
\r
10321 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10322 for (fromPort = 1023;; fromPort--) {
\r
10323 if (fromPort < 0) {
\r
10325 return WSAEADDRINUSE;
\r
10327 if (s == INVALID_SOCKET) {
\r
10328 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10329 err = WSAGetLastError();
\r
10334 uport = (unsigned short) fromPort;
\r
10335 mysa.sin_port = htons(uport);
\r
10336 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10337 == SOCKET_ERROR) {
\r
10338 err = WSAGetLastError();
\r
10339 if (err == WSAEADDRINUSE) continue;
\r
10343 if (connect(s, (struct sockaddr *) &sa,
\r
10344 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10345 err = WSAGetLastError();
\r
10346 if (err == WSAEADDRINUSE) {
\r
10357 /* Bind stderr local socket to unused "privileged" port address
\r
10359 s2 = INVALID_SOCKET;
\r
10360 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10361 mysa.sin_family = AF_INET;
\r
10362 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10363 for (fromPort = 1023;; fromPort--) {
\r
10364 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10365 if (fromPort < 0) {
\r
10366 (void) closesocket(s);
\r
10368 return WSAEADDRINUSE;
\r
10370 if (s2 == INVALID_SOCKET) {
\r
10371 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10372 err = WSAGetLastError();
\r
10378 uport = (unsigned short) fromPort;
\r
10379 mysa.sin_port = htons(uport);
\r
10380 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10381 == SOCKET_ERROR) {
\r
10382 err = WSAGetLastError();
\r
10383 if (err == WSAEADDRINUSE) continue;
\r
10384 (void) closesocket(s);
\r
10388 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10389 err = WSAGetLastError();
\r
10390 if (err == WSAEADDRINUSE) {
\r
10392 s2 = INVALID_SOCKET;
\r
10395 (void) closesocket(s);
\r
10396 (void) closesocket(s2);
\r
10402 prevStderrPort = fromPort; // remember port used
\r
10403 sprintf(stderrPortStr, "%d", fromPort);
\r
10405 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10406 err = WSAGetLastError();
\r
10407 (void) closesocket(s);
\r
10408 (void) closesocket(s2);
\r
10413 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10414 err = WSAGetLastError();
\r
10415 (void) closesocket(s);
\r
10416 (void) closesocket(s2);
\r
10420 if (*user == NULLCHAR) user = UserName();
\r
10421 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10422 err = WSAGetLastError();
\r
10423 (void) closesocket(s);
\r
10424 (void) closesocket(s2);
\r
10428 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10429 err = WSAGetLastError();
\r
10430 (void) closesocket(s);
\r
10431 (void) closesocket(s2);
\r
10436 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10437 err = WSAGetLastError();
\r
10438 (void) closesocket(s);
\r
10439 (void) closesocket(s2);
\r
10443 (void) closesocket(s2); /* Stop listening */
\r
10445 /* Prepare return value */
\r
10446 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10447 cp->kind = CPRcmd;
\r
10450 *pr = (ProcRef *) cp;
\r
10457 AddInputSource(ProcRef pr, int lineByLine,
\r
10458 InputCallback func, VOIDSTAR closure)
\r
10460 InputSource *is, *is2 = NULL;
\r
10461 ChildProc *cp = (ChildProc *) pr;
\r
10463 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10464 is->lineByLine = lineByLine;
\r
10466 is->closure = closure;
\r
10467 is->second = NULL;
\r
10468 is->next = is->buf;
\r
10469 if (pr == NoProc) {
\r
10470 is->kind = CPReal;
\r
10471 consoleInputSource = is;
\r
10473 is->kind = cp->kind;
\r
10475 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10476 we create all threads suspended so that the is->hThread variable can be
\r
10477 safely assigned, then let the threads start with ResumeThread.
\r
10479 switch (cp->kind) {
\r
10481 is->hFile = cp->hFrom;
\r
10482 cp->hFrom = NULL; /* now owned by InputThread */
\r
10484 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10485 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10489 is->hFile = cp->hFrom;
\r
10490 cp->hFrom = NULL; /* now owned by InputThread */
\r
10492 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10493 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10497 is->sock = cp->sock;
\r
10499 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10500 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10504 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10506 is->sock = cp->sock;
\r
10507 is->second = is2;
\r
10508 is2->sock = cp->sock2;
\r
10509 is2->second = is2;
\r
10511 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10512 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10514 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10515 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10519 if( is->hThread != NULL ) {
\r
10520 ResumeThread( is->hThread );
\r
10523 if( is2 != NULL && is2->hThread != NULL ) {
\r
10524 ResumeThread( is2->hThread );
\r
10528 return (InputSourceRef) is;
\r
10532 RemoveInputSource(InputSourceRef isr)
\r
10536 is = (InputSource *) isr;
\r
10537 is->hThread = NULL; /* tell thread to stop */
\r
10538 CloseHandle(is->hThread);
\r
10539 if (is->second != NULL) {
\r
10540 is->second->hThread = NULL;
\r
10541 CloseHandle(is->second->hThread);
\r
10547 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10550 int outCount = SOCKET_ERROR;
\r
10551 ChildProc *cp = (ChildProc *) pr;
\r
10552 static OVERLAPPED ovl;
\r
10554 if (pr == NoProc) {
\r
10555 ConsoleOutput(message, count, FALSE);
\r
10559 if (ovl.hEvent == NULL) {
\r
10560 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10562 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10564 switch (cp->kind) {
\r
10567 outCount = send(cp->sock, message, count, 0);
\r
10568 if (outCount == SOCKET_ERROR) {
\r
10569 *outError = WSAGetLastError();
\r
10571 *outError = NO_ERROR;
\r
10576 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10577 &dOutCount, NULL)) {
\r
10578 *outError = NO_ERROR;
\r
10579 outCount = (int) dOutCount;
\r
10581 *outError = GetLastError();
\r
10586 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10587 &dOutCount, &ovl);
\r
10588 if (*outError == NO_ERROR) {
\r
10589 outCount = (int) dOutCount;
\r
10597 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10600 /* Ignore delay, not implemented for WinBoard */
\r
10601 return OutputToProcess(pr, message, count, outError);
\r
10606 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10607 char *buf, int count, int error)
\r
10609 DisplayFatalError("Not implemented", 0, 1);
\r
10612 /* see wgamelist.c for Game List functions */
\r
10613 /* see wedittags.c for Edit Tags functions */
\r
10620 char buf[MSG_SIZ];
\r
10623 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10624 f = fopen(buf, "r");
\r
10626 ProcessICSInitScript(f);
\r
10634 StartAnalysisClock()
\r
10636 if (analysisTimerEvent) return;
\r
10637 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10638 (UINT) 2000, NULL);
\r
10642 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10644 static HANDLE hwndText;
\r
10646 static int sizeX, sizeY;
\r
10647 int newSizeX, newSizeY, flags;
\r
10650 switch (message) {
\r
10651 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10652 /* Initialize the dialog items */
\r
10653 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10654 SetWindowText(hDlg, analysisTitle);
\r
10655 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10656 /* Size and position the dialog */
\r
10657 if (!analysisDialog) {
\r
10658 analysisDialog = hDlg;
\r
10659 flags = SWP_NOZORDER;
\r
10660 GetClientRect(hDlg, &rect);
\r
10661 sizeX = rect.right;
\r
10662 sizeY = rect.bottom;
\r
10663 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10664 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10665 WINDOWPLACEMENT wp;
\r
10666 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10667 wp.length = sizeof(WINDOWPLACEMENT);
\r
10669 wp.showCmd = SW_SHOW;
\r
10670 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10671 wp.rcNormalPosition.left = analysisX;
\r
10672 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10673 wp.rcNormalPosition.top = analysisY;
\r
10674 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10675 SetWindowPlacement(hDlg, &wp);
\r
10677 GetClientRect(hDlg, &rect);
\r
10678 newSizeX = rect.right;
\r
10679 newSizeY = rect.bottom;
\r
10680 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10681 newSizeX, newSizeY);
\r
10682 sizeX = newSizeX;
\r
10683 sizeY = newSizeY;
\r
10688 case WM_COMMAND: /* message: received a command */
\r
10689 switch (LOWORD(wParam)) {
\r
10691 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10692 ExitAnalyzeMode();
\r
10704 newSizeX = LOWORD(lParam);
\r
10705 newSizeY = HIWORD(lParam);
\r
10706 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10707 sizeX = newSizeX;
\r
10708 sizeY = newSizeY;
\r
10711 case WM_GETMINMAXINFO:
\r
10712 /* Prevent resizing window too small */
\r
10713 mmi = (MINMAXINFO *) lParam;
\r
10714 mmi->ptMinTrackSize.x = 100;
\r
10715 mmi->ptMinTrackSize.y = 100;
\r
10722 AnalysisPopUp(char* title, char* str)
\r
10728 EngineOutputPopUp();
\r
10731 if (str == NULL) str = "";
\r
10732 p = (char *) malloc(2 * strlen(str) + 2);
\r
10735 if (*str == '\n') *q++ = '\r';
\r
10739 if (analysisText != NULL) free(analysisText);
\r
10740 analysisText = p;
\r
10742 if (analysisDialog) {
\r
10743 SetWindowText(analysisDialog, title);
\r
10744 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10745 ShowWindow(analysisDialog, SW_SHOW);
\r
10747 analysisTitle = title;
\r
10748 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10749 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10750 hwndMain, (DLGPROC)lpProc);
\r
10751 FreeProcInstance(lpProc);
\r
10753 analysisDialogUp = TRUE;
\r
10757 AnalysisPopDown()
\r
10759 if (analysisDialog) {
\r
10760 ShowWindow(analysisDialog, SW_HIDE);
\r
10762 analysisDialogUp = FALSE;
\r
10767 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10769 highlightInfo.sq[0].x = fromX;
\r
10770 highlightInfo.sq[0].y = fromY;
\r
10771 highlightInfo.sq[1].x = toX;
\r
10772 highlightInfo.sq[1].y = toY;
\r
10776 ClearHighlights()
\r
10778 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10779 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10783 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10785 premoveHighlightInfo.sq[0].x = fromX;
\r
10786 premoveHighlightInfo.sq[0].y = fromY;
\r
10787 premoveHighlightInfo.sq[1].x = toX;
\r
10788 premoveHighlightInfo.sq[1].y = toY;
\r
10792 ClearPremoveHighlights()
\r
10794 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10795 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10799 ShutDownFrontEnd()
\r
10801 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10802 DeleteClipboardTempFiles();
\r
10808 if (IsIconic(hwndMain))
\r
10809 ShowWindow(hwndMain, SW_RESTORE);
\r
10811 SetActiveWindow(hwndMain);
\r
10815 * Prototypes for animation support routines
\r
10817 static void ScreenSquare(int column, int row, POINT * pt);
\r
10818 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10819 POINT frames[], int * nFrames);
\r
10823 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10824 { // [HGM] atomic: animate blast wave
\r
10826 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10827 explodeInfo.fromX = fromX;
\r
10828 explodeInfo.fromY = fromY;
\r
10829 explodeInfo.toX = toX;
\r
10830 explodeInfo.toY = toY;
\r
10831 for(i=1; i<nFrames; i++) {
\r
10832 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10833 DrawPosition(FALSE, NULL);
\r
10834 Sleep(appData.animSpeed);
\r
10836 explodeInfo.radius = 0;
\r
10837 DrawPosition(TRUE, NULL);
\r
10840 #define kFactor 4
\r
10843 AnimateMove(board, fromX, fromY, toX, toY)
\r
10850 ChessSquare piece;
\r
10851 POINT start, finish, mid;
\r
10852 POINT frames[kFactor * 2 + 1];
\r
10855 if (!appData.animate) return;
\r
10856 if (doingSizing) return;
\r
10857 if (fromY < 0 || fromX < 0) return;
\r
10858 piece = board[fromY][fromX];
\r
10859 if (piece >= EmptySquare) return;
\r
10861 ScreenSquare(fromX, fromY, &start);
\r
10862 ScreenSquare(toX, toY, &finish);
\r
10864 /* All pieces except knights move in straight line */
\r
10865 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10866 mid.x = start.x + (finish.x - start.x) / 2;
\r
10867 mid.y = start.y + (finish.y - start.y) / 2;
\r
10869 /* Knight: make diagonal movement then straight */
\r
10870 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10871 mid.x = start.x + (finish.x - start.x) / 2;
\r
10872 mid.y = finish.y;
\r
10874 mid.x = finish.x;
\r
10875 mid.y = start.y + (finish.y - start.y) / 2;
\r
10879 /* Don't use as many frames for very short moves */
\r
10880 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10881 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10883 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10885 animInfo.from.x = fromX;
\r
10886 animInfo.from.y = fromY;
\r
10887 animInfo.to.x = toX;
\r
10888 animInfo.to.y = toY;
\r
10889 animInfo.lastpos = start;
\r
10890 animInfo.piece = piece;
\r
10891 for (n = 0; n < nFrames; n++) {
\r
10892 animInfo.pos = frames[n];
\r
10893 DrawPosition(FALSE, NULL);
\r
10894 animInfo.lastpos = animInfo.pos;
\r
10895 Sleep(appData.animSpeed);
\r
10897 animInfo.pos = finish;
\r
10898 DrawPosition(FALSE, NULL);
\r
10899 animInfo.piece = EmptySquare;
\r
10900 if(gameInfo.variant == VariantAtomic &&
\r
10901 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10902 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10905 /* Convert board position to corner of screen rect and color */
\r
10908 ScreenSquare(column, row, pt)
\r
10909 int column; int row; POINT * pt;
\r
10912 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10913 pt->y = lineGap + row * (squareSize + lineGap);
\r
10915 pt->x = lineGap + column * (squareSize + lineGap);
\r
10916 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10920 /* Generate a series of frame coords from start->mid->finish.
\r
10921 The movement rate doubles until the half way point is
\r
10922 reached, then halves back down to the final destination,
\r
10923 which gives a nice slow in/out effect. The algorithmn
\r
10924 may seem to generate too many intermediates for short
\r
10925 moves, but remember that the purpose is to attract the
\r
10926 viewers attention to the piece about to be moved and
\r
10927 then to where it ends up. Too few frames would be less
\r
10931 Tween(start, mid, finish, factor, frames, nFrames)
\r
10932 POINT * start; POINT * mid;
\r
10933 POINT * finish; int factor;
\r
10934 POINT frames[]; int * nFrames;
\r
10936 int n, fraction = 1, count = 0;
\r
10938 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10939 for (n = 0; n < factor; n++)
\r
10941 for (n = 0; n < factor; n++) {
\r
10942 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10943 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10945 fraction = fraction / 2;
\r
10949 frames[count] = *mid;
\r
10952 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10954 for (n = 0; n < factor; n++) {
\r
10955 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10956 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10958 fraction = fraction * 2;
\r
10960 *nFrames = count;
\r
10964 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10969 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10970 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10972 OutputDebugString( buf );
\r
10975 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10977 EvalGraphSet( first, last, current, pvInfoList );
\r
10980 void SetProgramStats( FrontEndProgramStats * stats )
\r
10985 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10986 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10988 OutputDebugString( buf );
\r
10991 EngineOutputUpdate( stats );
\r