2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
83 #include "winboard.h"
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
87 #include "wclipbrd.h"
\r
88 #include "wgamelist.h"
\r
89 #include "wedittags.h"
\r
90 #include "woptions.h"
\r
91 #include "wsockerr.h"
\r
92 #include "defaults.h"
\r
96 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
99 void mysrandom(unsigned int seed);
\r
101 extern int whiteFlag, blackFlag;
\r
102 Boolean flipClock = FALSE;
\r
104 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
105 VOID NewVariantPopup(HWND hwnd);
\r
106 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
107 /*char*/int promoChar));
\r
108 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
109 void DisplayMove P((int moveNumber));
\r
110 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
112 ChessSquare piece;
\r
113 POINT pos; /* window coordinates of current pos */
\r
114 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
115 POINT from; /* board coordinates of the piece's orig pos */
\r
116 POINT to; /* board coordinates of the piece's new pos */
\r
119 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
122 POINT start; /* window coordinates of start pos */
\r
123 POINT pos; /* window coordinates of current pos */
\r
124 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
125 POINT from; /* board coordinates of the piece's orig pos */
\r
128 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
131 POINT sq[2]; /* board coordinates of from, to squares */
\r
134 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
135 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
137 typedef struct { // [HGM] atomic
\r
138 int fromX, fromY, toX, toY, radius;
\r
141 static ExplodeInfo explodeInfo;
\r
143 /* Window class names */
\r
144 char szAppName[] = "WinBoard";
\r
145 char szConsoleName[] = "WBConsole";
\r
147 /* Title bar text */
\r
148 char szTitle[] = "WinBoard";
\r
149 char szConsoleTitle[] = "I C S Interaction";
\r
152 char *settingsFileName;
\r
153 BOOLEAN saveSettingsOnExit;
\r
154 char installDir[MSG_SIZ];
\r
156 BoardSize boardSize;
\r
157 BOOLEAN chessProgram;
\r
158 static int boardX, boardY;
\r
159 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
160 static int squareSize, lineGap, minorSize;
\r
161 static int winWidth, winHeight, winW, winH;
\r
162 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
163 static int logoHeight = 0;
\r
164 static char messageText[MESSAGE_TEXT_MAX];
\r
165 static int clockTimerEvent = 0;
\r
166 static int loadGameTimerEvent = 0;
\r
167 static int analysisTimerEvent = 0;
\r
168 static DelayedEventCallback delayedTimerCallback;
\r
169 static int delayedTimerEvent = 0;
\r
170 static int buttonCount = 2;
\r
171 char *icsTextMenuString;
\r
173 char *firstChessProgramNames;
\r
174 char *secondChessProgramNames;
\r
176 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
178 #define PALETTESIZE 256
\r
180 HINSTANCE hInst; /* current instance */
\r
181 HWND hwndMain = NULL; /* root window*/
\r
182 HWND hwndConsole = NULL;
\r
183 BOOLEAN alwaysOnTop = FALSE;
\r
185 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
186 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
188 ColorClass currentColorClass;
\r
190 HWND hCommPort = NULL; /* currently open comm port */
\r
191 static HWND hwndPause; /* pause button */
\r
192 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
193 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
194 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
195 explodeBrush, /* [HGM] atomic */
\r
196 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
197 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
198 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
199 static HPEN gridPen = NULL;
\r
200 static HPEN highlightPen = NULL;
\r
201 static HPEN premovePen = NULL;
\r
202 static NPLOGPALETTE pLogPal;
\r
203 static BOOL paletteChanged = FALSE;
\r
204 static HICON iconWhite, iconBlack, iconCurrent;
\r
205 static int doingSizing = FALSE;
\r
206 static int lastSizing = 0;
\r
207 static int prevStderrPort;
\r
208 static HBITMAP userLogo;
\r
210 /* [AS] Support for background textures */
\r
211 #define BACK_TEXTURE_MODE_DISABLED 0
\r
212 #define BACK_TEXTURE_MODE_PLAIN 1
\r
213 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
215 static HBITMAP liteBackTexture = NULL;
\r
216 static HBITMAP darkBackTexture = NULL;
\r
217 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
218 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
219 static int backTextureSquareSize = 0;
\r
220 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
222 #if __GNUC__ && !defined(_winmajor)
\r
223 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
225 #define oldDialog (_winmajor < 4)
\r
228 char *defaultTextAttribs[] =
\r
230 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
231 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
241 int cliWidth, cliHeight;
\r
244 SizeInfo sizeInfo[] =
\r
246 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
247 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
248 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
249 { "petite", 33, 1, 1, 1, 0, 0 },
\r
250 { "slim", 37, 2, 1, 0, 0, 0 },
\r
251 { "small", 40, 2, 1, 0, 0, 0 },
\r
252 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
253 { "middling", 49, 2, 0, 0, 0, 0 },
\r
254 { "average", 54, 2, 0, 0, 0, 0 },
\r
255 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
256 { "medium", 64, 3, 0, 0, 0, 0 },
\r
257 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
258 { "large", 80, 3, 0, 0, 0, 0 },
\r
259 { "big", 87, 3, 0, 0, 0, 0 },
\r
260 { "huge", 95, 3, 0, 0, 0, 0 },
\r
261 { "giant", 108, 3, 0, 0, 0, 0 },
\r
262 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
263 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
264 { NULL, 0, 0, 0, 0, 0, 0 }
\r
267 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
268 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
270 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
271 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
272 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
273 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
274 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
275 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
276 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
277 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
278 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
279 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
280 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
281 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
282 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
283 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
284 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
285 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
286 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
287 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
290 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
299 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
300 #define N_BUTTONS 5
\r
302 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
304 {"<<", IDM_ToStart, NULL, NULL},
\r
305 {"<", IDM_Backward, NULL, NULL},
\r
306 {"P", IDM_Pause, NULL, NULL},
\r
307 {">", IDM_Forward, NULL, NULL},
\r
308 {">>", IDM_ToEnd, NULL, NULL},
\r
311 int tinyLayout = 0, smallLayout = 0;
\r
312 #define MENU_BAR_ITEMS 7
\r
313 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
314 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
315 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
319 MySound sounds[(int)NSoundClasses];
\r
320 MyTextAttribs textAttribs[(int)NColorClasses];
\r
322 MyColorizeAttribs colorizeAttribs[] = {
\r
323 { (COLORREF)0, 0, "Shout Text" },
\r
324 { (COLORREF)0, 0, "SShout/CShout" },
\r
325 { (COLORREF)0, 0, "Channel 1 Text" },
\r
326 { (COLORREF)0, 0, "Channel Text" },
\r
327 { (COLORREF)0, 0, "Kibitz Text" },
\r
328 { (COLORREF)0, 0, "Tell Text" },
\r
329 { (COLORREF)0, 0, "Challenge Text" },
\r
330 { (COLORREF)0, 0, "Request Text" },
\r
331 { (COLORREF)0, 0, "Seek Text" },
\r
332 { (COLORREF)0, 0, "Normal Text" },
\r
333 { (COLORREF)0, 0, "None" }
\r
338 static char *commentTitle;
\r
339 static char *commentText;
\r
340 static int commentIndex;
\r
341 static Boolean editComment = FALSE;
\r
342 HWND commentDialog = NULL;
\r
343 BOOLEAN commentDialogUp = FALSE;
\r
344 static int commentX, commentY, commentH, commentW;
\r
346 static char *analysisTitle;
\r
347 static char *analysisText;
\r
348 HWND analysisDialog = NULL;
\r
349 BOOLEAN analysisDialogUp = FALSE;
\r
350 static int analysisX, analysisY, analysisH, analysisW;
\r
352 char errorTitle[MSG_SIZ];
\r
353 char errorMessage[2*MSG_SIZ];
\r
354 HWND errorDialog = NULL;
\r
355 BOOLEAN moveErrorMessageUp = FALSE;
\r
356 BOOLEAN consoleEcho = TRUE;
\r
357 CHARFORMAT consoleCF;
\r
358 COLORREF consoleBackgroundColor;
\r
360 char *programVersion;
\r
366 typedef int CPKind;
\r
375 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
378 #define INPUT_SOURCE_BUF_SIZE 4096
\r
380 typedef struct _InputSource {
\r
387 char buf[INPUT_SOURCE_BUF_SIZE];
\r
391 InputCallback func;
\r
392 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
396 InputSource *consoleInputSource;
\r
401 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
402 VOID ConsoleCreate();
\r
404 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
405 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
406 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
407 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
409 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
410 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
411 void ParseIcsTextMenu(char *icsTextMenuString);
\r
412 VOID PopUpMoveDialog(char firstchar);
\r
413 VOID PopUpNameDialog(char firstchar);
\r
414 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
418 int GameListOptions();
\r
420 HWND moveHistoryDialog = NULL;
\r
421 BOOLEAN moveHistoryDialogUp = FALSE;
\r
423 WindowPlacement wpMoveHistory;
\r
425 HWND evalGraphDialog = NULL;
\r
426 BOOLEAN evalGraphDialogUp = FALSE;
\r
428 WindowPlacement wpEvalGraph;
\r
430 HWND engineOutputDialog = NULL;
\r
431 BOOLEAN engineOutputDialogUp = FALSE;
\r
433 WindowPlacement wpEngineOutput;
\r
434 WindowPlacement wpGameList;
\r
435 WindowPlacement wpConsole;
\r
437 VOID MoveHistoryPopUp();
\r
438 VOID MoveHistoryPopDown();
\r
439 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
440 BOOL MoveHistoryIsUp();
\r
442 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
443 VOID EvalGraphPopUp();
\r
444 VOID EvalGraphPopDown();
\r
445 BOOL EvalGraphIsUp();
\r
447 VOID EngineOutputPopUp();
\r
448 VOID EngineOutputPopDown();
\r
449 BOOL EngineOutputIsUp();
\r
450 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
452 VOID GothicPopUp(char *title, VariantClass variant);
\r
454 * Setting "frozen" should disable all user input other than deleting
\r
455 * the window. We do this while engines are initializing themselves.
\r
457 static int frozen = 0;
\r
458 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
464 if (frozen) return;
\r
466 hmenu = GetMenu(hwndMain);
\r
467 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
468 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
470 DrawMenuBar(hwndMain);
\r
473 /* Undo a FreezeUI */
\r
479 if (!frozen) return;
\r
481 hmenu = GetMenu(hwndMain);
\r
482 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
483 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
485 DrawMenuBar(hwndMain);
\r
488 static int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
490 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
495 #define JAWS_ALT_INTERCEPT
\r
496 #define JAWS_KB_NAVIGATION
\r
497 #define JAWS_MENU_ITEMS
\r
498 #define JAWS_SILENCE
\r
499 #define JAWS_REPLAY
\r
501 #define JAWS_COPYRIGHT
\r
502 #define JAWS_DELETE(X) X
\r
503 #define SAYMACHINEMOVE()
\r
507 /*---------------------------------------------------------------------------*\
\r
511 \*---------------------------------------------------------------------------*/
\r
514 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
515 LPSTR lpCmdLine, int nCmdShow)
\r
518 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
519 // INITCOMMONCONTROLSEX ex;
\r
523 LoadLibrary("RICHED32.DLL");
\r
524 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
526 if (!InitApplication(hInstance)) {
\r
529 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
535 // InitCommonControlsEx(&ex);
\r
536 InitCommonControls();
\r
538 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
539 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
540 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
542 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
544 while (GetMessage(&msg, /* message structure */
\r
545 NULL, /* handle of window receiving the message */
\r
546 0, /* lowest message to examine */
\r
547 0)) /* highest message to examine */
\r
550 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
551 // [HGM] navigate: switch between all windows with tab
\r
552 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
553 int i, currentElement = 0;
\r
555 // first determine what element of the chain we come from (if any)
\r
556 if(appData.icsActive) {
\r
557 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
558 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
560 if(engineOutputDialog && EngineOutputIsUp()) {
\r
561 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
562 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
564 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
565 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
567 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
568 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
569 if(msg.hwnd == e1) currentElement = 2; else
\r
570 if(msg.hwnd == e2) currentElement = 3; else
\r
571 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
572 if(msg.hwnd == mh) currentElement = 4; else
\r
573 if(msg.hwnd == evalGraphDialog) currentElement = 7; else
\r
574 if(msg.hwnd == hText) currentElement = 5; else
\r
575 if(msg.hwnd == hInput) currentElement = 6; else
\r
576 for (i = 0; i < N_BUTTONS; i++) {
\r
577 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
580 // determine where to go to
\r
581 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
583 currentElement = (currentElement + direction) % 7;
\r
584 switch(currentElement) {
\r
586 h = hwndMain; break; // passing this case always makes the loop exit
\r
588 h = buttonDesc[0].hwnd; break; // could be NULL
\r
590 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
593 if(!EngineOutputIsUp()) continue;
\r
596 if(!MoveHistoryIsUp()) continue;
\r
598 // case 5: // input to eval graph does not seem to get here!
\r
599 // if(!EvalGraphIsUp()) continue;
\r
600 // h = evalGraphDialog; break;
\r
602 if(!appData.icsActive) continue;
\r
606 if(!appData.icsActive) continue;
\r
612 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
613 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
616 continue; // this message now has been processed
\r
620 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
621 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
622 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
623 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
624 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
625 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
626 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
627 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
628 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
629 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
630 TranslateMessage(&msg); /* Translates virtual key codes */
\r
631 DispatchMessage(&msg); /* Dispatches message to window */
\r
636 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
639 /*---------------------------------------------------------------------------*\
\r
641 * Initialization functions
\r
643 \*---------------------------------------------------------------------------*/
\r
647 { // update user logo if necessary
\r
648 static char oldUserName[MSG_SIZ], *curName;
\r
650 if(appData.autoLogo) {
\r
651 curName = UserName();
\r
652 if(strcmp(curName, oldUserName)) {
\r
653 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
654 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
655 strcpy(oldUserName, curName);
\r
661 InitApplication(HINSTANCE hInstance)
\r
665 /* Fill in window class structure with parameters that describe the */
\r
668 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
669 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
670 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
671 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
672 wc.hInstance = hInstance; /* Owner of this class */
\r
673 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
674 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
675 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
676 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
677 wc.lpszClassName = szAppName; /* Name to register as */
\r
679 /* Register the window class and return success/failure code. */
\r
680 if (!RegisterClass(&wc)) return FALSE;
\r
682 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
683 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
685 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
686 wc.hInstance = hInstance;
\r
687 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
688 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
689 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
690 wc.lpszMenuName = NULL;
\r
691 wc.lpszClassName = szConsoleName;
\r
693 if (!RegisterClass(&wc)) return FALSE;
\r
698 /* Set by InitInstance, used by EnsureOnScreen */
\r
699 int screenHeight, screenWidth;
\r
702 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
704 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
705 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
706 if (*x > screenWidth - 32) *x = 0;
\r
707 if (*y > screenHeight - 32) *y = 0;
\r
708 if (*x < minX) *x = minX;
\r
709 if (*y < minY) *y = minY;
\r
713 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
715 HWND hwnd; /* Main window handle. */
\r
717 WINDOWPLACEMENT wp;
\r
720 hInst = hInstance; /* Store instance handle in our global variable */
\r
722 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
723 *filepart = NULLCHAR;
\r
725 GetCurrentDirectory(MSG_SIZ, installDir);
\r
727 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
728 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
729 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
730 if (appData.debugMode) {
\r
731 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
732 setbuf(debugFP, NULL);
\r
737 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
738 // InitEngineUCI( installDir, &second );
\r
740 /* Create a main window for this application instance. */
\r
741 hwnd = CreateWindow(szAppName, szTitle,
\r
742 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
743 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
744 NULL, NULL, hInstance, NULL);
\r
747 /* If window could not be created, return "failure" */
\r
752 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
753 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
754 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
756 if (first.programLogo == NULL && appData.debugMode) {
\r
757 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
759 } else if(appData.autoLogo) {
\r
760 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
762 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
763 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
767 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
768 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
770 if (second.programLogo == NULL && appData.debugMode) {
\r
771 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
773 } else if(appData.autoLogo) {
\r
775 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
776 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
777 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
779 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
780 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
781 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
787 iconWhite = LoadIcon(hInstance, "icon_white");
\r
788 iconBlack = LoadIcon(hInstance, "icon_black");
\r
789 iconCurrent = iconWhite;
\r
790 InitDrawingColors();
\r
791 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
792 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
793 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
794 /* Compute window size for each board size, and use the largest
\r
795 size that fits on this screen as the default. */
\r
796 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
797 if (boardSize == (BoardSize)-1 &&
\r
798 winH <= screenHeight
\r
799 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
800 && winW <= screenWidth) {
\r
801 boardSize = (BoardSize)ibs;
\r
805 InitDrawingSizes(boardSize, 0);
\r
807 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
809 /* [AS] Load textures if specified */
\r
810 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
812 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
813 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
814 liteBackTextureMode = appData.liteBackTextureMode;
\r
816 if (liteBackTexture == NULL && appData.debugMode) {
\r
817 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
821 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
822 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
823 darkBackTextureMode = appData.darkBackTextureMode;
\r
825 if (darkBackTexture == NULL && appData.debugMode) {
\r
826 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
830 mysrandom( (unsigned) time(NULL) );
\r
832 /* [AS] Restore layout */
\r
833 if( wpMoveHistory.visible ) {
\r
834 MoveHistoryPopUp();
\r
837 if( wpEvalGraph.visible ) {
\r
841 if( wpEngineOutput.visible ) {
\r
842 EngineOutputPopUp();
\r
847 /* Make the window visible; update its client area; and return "success" */
\r
848 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
849 wp.length = sizeof(WINDOWPLACEMENT);
\r
851 wp.showCmd = nCmdShow;
\r
852 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
853 wp.rcNormalPosition.left = boardX;
\r
854 wp.rcNormalPosition.right = boardX + winWidth;
\r
855 wp.rcNormalPosition.top = boardY;
\r
856 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
857 SetWindowPlacement(hwndMain, &wp);
\r
859 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
860 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
864 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
865 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
867 ShowWindow(hwndConsole, nCmdShow);
\r
869 UpdateWindow(hwnd);
\r
877 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
878 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
879 ArgSettingsFilename,
\r
880 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
888 String *pString; // ArgString
\r
889 int *pInt; // ArgInt
\r
890 float *pFloat; // ArgFloat
\r
891 Boolean *pBoolean; // ArgBoolean
\r
892 COLORREF *pColor; // ArgColor
\r
893 ColorClass cc; // ArgAttribs
\r
894 String *pFilename; // ArgFilename
\r
895 BoardSize *pBoardSize; // ArgBoardSize
\r
896 int whichFont; // ArgFont
\r
897 DCB *pDCB; // ArgCommSettings
\r
898 String *pFilename; // ArgSettingsFilename
\r
906 ArgDescriptor argDescriptors[] = {
\r
907 /* positional arguments */
\r
908 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
909 { "", ArgNone, NULL },
\r
910 /* keyword arguments */
\r
911 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
912 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
913 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
914 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
915 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
916 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
917 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
918 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
919 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
920 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
921 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
922 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
923 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
924 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
925 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
926 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
927 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
928 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
930 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
932 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
934 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
935 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
937 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
938 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
939 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
940 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
941 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
942 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
943 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
944 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
945 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
946 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
947 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
948 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
949 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
950 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
951 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
952 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
953 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
954 /*!!bitmapDirectory?*/
\r
955 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
956 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
957 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
958 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
959 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
960 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
961 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
962 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
963 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
964 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
965 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
966 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
967 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
968 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
969 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
970 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
971 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
972 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
973 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
974 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
975 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
976 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
977 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
978 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
979 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
980 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
981 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
982 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
983 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
984 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
985 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
986 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
987 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
988 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
989 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
990 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
991 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
992 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
993 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
994 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
995 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
996 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
997 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
998 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
999 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1000 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1001 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1002 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1003 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1004 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1005 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1006 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1007 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1008 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1009 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1010 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1011 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1012 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1013 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1014 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1015 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1016 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1017 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1018 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1019 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1020 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1021 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1022 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1023 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1024 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1025 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1026 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1027 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1028 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1029 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1030 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1031 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1032 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1033 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1034 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1035 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1036 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1037 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1038 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1039 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1040 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1041 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1042 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1043 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1044 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1045 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1046 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1047 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1048 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1049 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1050 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1051 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1052 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1053 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1054 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1055 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1056 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1057 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1058 TRUE }, /* must come after all fonts */
\r
1059 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1060 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1061 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1062 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1063 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1064 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1065 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1066 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1067 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1068 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1069 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1070 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1071 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1072 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1073 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1074 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1075 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1076 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1077 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1078 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1079 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1080 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1081 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1082 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1083 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1084 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1085 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1086 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1087 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1088 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1089 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1091 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1092 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1094 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1095 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1096 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1097 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1098 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1099 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1100 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1101 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1102 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1103 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1104 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1105 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1106 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1107 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1108 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1109 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1110 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1111 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1112 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1113 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1114 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1115 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1116 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1117 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1118 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1119 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1120 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1121 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1122 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1123 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1124 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1125 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1126 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1127 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1128 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1129 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1130 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1131 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1132 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1133 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1134 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1135 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1136 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1137 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1138 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1139 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1140 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1141 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1142 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1143 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1144 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1145 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1146 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1147 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1148 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1149 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1150 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1151 { "highlightLastMove", ArgBoolean,
\r
1152 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1153 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1154 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1155 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1156 { "highlightDragging", ArgBoolean,
\r
1157 (LPVOID) &appData.highlightDragging, TRUE },
\r
1158 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1159 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1160 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1161 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1162 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1163 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1164 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1165 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1166 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1167 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1168 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1169 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1170 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1171 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1172 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1173 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1174 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1175 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1176 { "soundShout", ArgFilename,
\r
1177 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1178 { "soundSShout", ArgFilename,
\r
1179 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1180 { "soundChannel1", ArgFilename,
\r
1181 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1182 { "soundChannel", ArgFilename,
\r
1183 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1184 { "soundKibitz", ArgFilename,
\r
1185 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1186 { "soundTell", ArgFilename,
\r
1187 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1188 { "soundChallenge", ArgFilename,
\r
1189 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1190 { "soundRequest", ArgFilename,
\r
1191 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1192 { "soundSeek", ArgFilename,
\r
1193 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1194 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1195 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1196 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1197 { "soundIcsLoss", ArgFilename,
\r
1198 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1199 { "soundIcsDraw", ArgFilename,
\r
1200 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1201 { "soundIcsUnfinished", ArgFilename,
\r
1202 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1203 { "soundIcsAlarm", ArgFilename,
\r
1204 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1205 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1206 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1207 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1208 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1209 { "reuseChessPrograms", ArgBoolean,
\r
1210 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1211 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1212 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1213 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1214 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1215 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1216 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1217 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1218 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1219 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1220 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1221 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1222 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1223 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1224 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1225 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1227 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1229 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1230 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1231 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1232 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1233 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1234 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1235 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1236 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1237 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1238 /* [AS] New features */
\r
1239 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1240 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1241 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1242 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1243 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1244 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1245 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1246 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1247 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1248 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1249 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1250 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1251 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1252 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1253 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1254 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1255 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1256 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1257 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1258 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1259 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1260 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1261 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1262 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1263 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1264 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1265 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1266 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1267 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1268 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1269 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1270 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1271 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1272 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1273 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1274 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1275 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1276 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1277 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1278 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1279 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1280 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1281 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1282 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1283 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1284 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1285 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1286 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1287 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1288 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1290 /* [HGM] board-size, adjudication and misc. options */
\r
1291 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1292 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1293 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1294 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1295 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1296 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1297 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1298 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1299 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1300 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1301 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1302 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1303 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1304 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1305 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1306 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1307 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1308 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1309 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1310 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1311 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1312 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1313 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1314 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1315 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1316 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1317 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1318 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1319 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1320 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1321 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1324 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1325 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1326 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1327 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1328 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1329 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1330 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1331 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1332 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1333 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1334 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1335 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1336 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1338 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1339 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1340 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1341 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1342 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1343 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1344 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1346 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1347 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1348 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1349 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1350 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1351 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1352 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1353 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1354 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1355 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1356 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1357 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1358 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1359 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1360 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1361 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1362 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1363 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1364 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1366 /* [HGM] options for broadcasting and time odds */
\r
1367 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1368 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1369 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1370 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1371 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1372 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1373 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1374 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1375 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1376 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1377 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1379 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1380 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1381 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1382 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1383 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1384 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1385 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1386 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1387 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1388 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1389 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1390 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1391 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1392 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1393 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1394 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1395 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1396 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1397 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1398 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1399 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1400 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1401 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1402 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1403 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1404 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1405 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1406 /* [AS] Layout stuff */
\r
1407 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1408 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1409 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1410 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1411 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1413 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1414 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1415 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1416 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1417 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1419 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1420 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1421 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1422 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1423 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1425 { NULL, ArgNone, NULL, FALSE }
\r
1429 /* Kludge for indirection files on command line */
\r
1430 char* lastIndirectionFilename;
\r
1431 ArgDescriptor argDescriptorIndirection =
\r
1432 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1436 ExitArgError(char *msg, char *badArg)
\r
1438 char buf[MSG_SIZ];
\r
1440 sprintf(buf, "%s %s", msg, badArg);
\r
1441 DisplayFatalError(buf, 0, 2);
\r
1445 /* Command line font name parser. NULL name means do nothing.
\r
1446 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1447 For backward compatibility, syntax without the colon is also
\r
1448 accepted, but font names with digits in them won't work in that case.
\r
1451 ParseFontName(char *name, MyFontParams *mfp)
\r
1454 if (name == NULL) return;
\r
1456 q = strchr(p, ':');
\r
1458 if (q - p >= sizeof(mfp->faceName))
\r
1459 ExitArgError("Font name too long:", name);
\r
1460 memcpy(mfp->faceName, p, q - p);
\r
1461 mfp->faceName[q - p] = NULLCHAR;
\r
1464 q = mfp->faceName;
\r
1465 while (*p && !isdigit(*p)) {
\r
1467 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1468 ExitArgError("Font name too long:", name);
\r
1470 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1473 if (!*p) ExitArgError("Font point size missing:", name);
\r
1474 mfp->pointSize = (float) atof(p);
\r
1475 mfp->bold = (strchr(p, 'b') != NULL);
\r
1476 mfp->italic = (strchr(p, 'i') != NULL);
\r
1477 mfp->underline = (strchr(p, 'u') != NULL);
\r
1478 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1481 /* Color name parser.
\r
1482 X version accepts X color names, but this one
\r
1483 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1485 ParseColorName(char *name)
\r
1487 int red, green, blue, count;
\r
1488 char buf[MSG_SIZ];
\r
1490 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1492 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1493 &red, &green, &blue);
\r
1496 sprintf(buf, "Can't parse color name %s", name);
\r
1497 DisplayError(buf, 0);
\r
1498 return RGB(0, 0, 0);
\r
1500 return PALETTERGB(red, green, blue);
\r
1504 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1506 char *e = argValue;
\r
1510 if (*e == 'b') eff |= CFE_BOLD;
\r
1511 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1512 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1513 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1514 else if (*e == '#' || isdigit(*e)) break;
\r
1518 *color = ParseColorName(e);
\r
1523 ParseBoardSize(char *name)
\r
1525 BoardSize bs = SizeTiny;
\r
1526 while (sizeInfo[bs].name != NULL) {
\r
1527 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1530 ExitArgError("Unrecognized board size value", name);
\r
1531 return bs; /* not reached */
\r
1536 StringGet(void *getClosure)
\r
1538 char **p = (char **) getClosure;
\r
1543 FileGet(void *getClosure)
\r
1546 FILE* f = (FILE*) getClosure;
\r
1549 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1556 /* Parse settings file named "name". If file found, return the
\r
1557 full name in fullname and return TRUE; else return FALSE */
\r
1559 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1563 int ok; char buf[MSG_SIZ];
\r
1565 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1566 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1567 sprintf(buf, "%s.ini", name);
\r
1568 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1571 f = fopen(fullname, "r");
\r
1573 ParseArgs(FileGet, f);
\r
1582 ParseArgs(GetFunc get, void *cl)
\r
1584 char argName[ARG_MAX];
\r
1585 char argValue[ARG_MAX];
\r
1586 ArgDescriptor *ad;
\r
1595 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1596 if (ch == NULLCHAR) break;
\r
1598 /* Comment to end of line */
\r
1600 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1602 } else if (ch == '/' || ch == '-') {
\r
1605 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1606 ch != '\n' && ch != '\t') {
\r
1612 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1613 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1615 if (ad->argName == NULL)
\r
1616 ExitArgError("Unrecognized argument", argName);
\r
1618 } else if (ch == '@') {
\r
1619 /* Indirection file */
\r
1620 ad = &argDescriptorIndirection;
\r
1623 /* Positional argument */
\r
1624 ad = &argDescriptors[posarg++];
\r
1625 strcpy(argName, ad->argName);
\r
1628 if (ad->argType == ArgTrue) {
\r
1629 *(Boolean *) ad->argLoc = TRUE;
\r
1632 if (ad->argType == ArgFalse) {
\r
1633 *(Boolean *) ad->argLoc = FALSE;
\r
1637 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1638 if (ch == NULLCHAR || ch == '\n') {
\r
1639 ExitArgError("No value provided for argument", argName);
\r
1643 // Quoting with { }. No characters have to (or can) be escaped.
\r
1644 // Thus the string cannot contain a '}' character.
\r
1664 } else if (ch == '\'' || ch == '"') {
\r
1665 // Quoting with ' ' or " ", with \ as escape character.
\r
1666 // Inconvenient for long strings that may contain Windows filenames.
\r
1683 if (ch == start) {
\r
1692 if (ad->argType == ArgFilename
\r
1693 || ad->argType == ArgSettingsFilename) {
\r
1699 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1723 for (i = 0; i < 3; i++) {
\r
1724 if (ch >= '0' && ch <= '7') {
\r
1725 octval = octval*8 + (ch - '0');
\r
1732 *q++ = (char) octval;
\r
1743 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1750 switch (ad->argType) {
\r
1752 *(int *) ad->argLoc = atoi(argValue);
\r
1756 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1760 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1764 *(int *) ad->argLoc = atoi(argValue);
\r
1765 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1769 *(float *) ad->argLoc = (float) atof(argValue);
\r
1774 *(char **) ad->argLoc = strdup(argValue);
\r
1777 case ArgSettingsFilename:
\r
1779 char fullname[MSG_SIZ];
\r
1780 if (ParseSettingsFile(argValue, fullname)) {
\r
1781 if (ad->argLoc != NULL) {
\r
1782 *(char **) ad->argLoc = strdup(fullname);
\r
1785 if (ad->argLoc != NULL) {
\r
1787 ExitArgError("Failed to open indirection file", argValue);
\r
1794 switch (argValue[0]) {
\r
1797 *(Boolean *) ad->argLoc = TRUE;
\r
1801 *(Boolean *) ad->argLoc = FALSE;
\r
1804 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1810 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1813 case ArgAttribs: {
\r
1814 ColorClass cc = (ColorClass)ad->argLoc;
\r
1815 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1819 case ArgBoardSize:
\r
1820 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1824 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1827 case ArgCommSettings:
\r
1828 ParseCommSettings(argValue, &dcb);
\r
1832 ExitArgError("Unrecognized argument", argValue);
\r
1841 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1843 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1844 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1847 lf->lfEscapement = 0;
\r
1848 lf->lfOrientation = 0;
\r
1849 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1850 lf->lfItalic = mfp->italic;
\r
1851 lf->lfUnderline = mfp->underline;
\r
1852 lf->lfStrikeOut = mfp->strikeout;
\r
1853 lf->lfCharSet = DEFAULT_CHARSET;
\r
1854 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1855 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1856 lf->lfQuality = DEFAULT_QUALITY;
\r
1857 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1858 strcpy(lf->lfFaceName, mfp->faceName);
\r
1862 CreateFontInMF(MyFont *mf)
\r
1864 LFfromMFP(&mf->lf, &mf->mfp);
\r
1865 if (mf->hf) DeleteObject(mf->hf);
\r
1866 mf->hf = CreateFontIndirect(&mf->lf);
\r
1870 SetDefaultTextAttribs()
\r
1873 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1874 ParseAttribs(&textAttribs[cc].color,
\r
1875 &textAttribs[cc].effects,
\r
1876 defaultTextAttribs[cc]);
\r
1881 SetDefaultSounds()
\r
1885 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1886 textAttribs[cc].sound.name = strdup("");
\r
1887 textAttribs[cc].sound.data = NULL;
\r
1889 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1890 sounds[sc].name = strdup("");
\r
1891 sounds[sc].data = NULL;
\r
1893 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1901 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1902 MyLoadSound(&textAttribs[cc].sound);
\r
1904 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1905 MyLoadSound(&sounds[sc]);
\r
1910 InitAppData(LPSTR lpCmdLine)
\r
1913 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1916 programName = szAppName;
\r
1918 /* Initialize to defaults */
\r
1919 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1920 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1921 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1922 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1923 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1924 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1925 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1926 SetDefaultTextAttribs();
\r
1927 SetDefaultSounds();
\r
1928 appData.movesPerSession = MOVES_PER_SESSION;
\r
1929 appData.initString = INIT_STRING;
\r
1930 appData.secondInitString = INIT_STRING;
\r
1931 appData.firstComputerString = COMPUTER_STRING;
\r
1932 appData.secondComputerString = COMPUTER_STRING;
\r
1933 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1934 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1935 appData.firstPlaysBlack = FALSE;
\r
1936 appData.noChessProgram = FALSE;
\r
1937 chessProgram = FALSE;
\r
1938 appData.firstHost = FIRST_HOST;
\r
1939 appData.secondHost = SECOND_HOST;
\r
1940 appData.firstDirectory = FIRST_DIRECTORY;
\r
1941 appData.secondDirectory = SECOND_DIRECTORY;
\r
1942 appData.bitmapDirectory = "";
\r
1943 appData.remoteShell = REMOTE_SHELL;
\r
1944 appData.remoteUser = "";
\r
1945 appData.timeDelay = TIME_DELAY;
\r
1946 appData.timeControl = TIME_CONTROL;
\r
1947 appData.timeIncrement = TIME_INCREMENT;
\r
1948 appData.icsActive = FALSE;
\r
1949 appData.icsHost = "";
\r
1950 appData.icsPort = ICS_PORT;
\r
1951 appData.icsCommPort = ICS_COMM_PORT;
\r
1952 appData.icsLogon = ICS_LOGON;
\r
1953 appData.icsHelper = "";
\r
1954 appData.useTelnet = FALSE;
\r
1955 appData.telnetProgram = TELNET_PROGRAM;
\r
1956 appData.gateway = "";
\r
1957 appData.loadGameFile = "";
\r
1958 appData.loadGameIndex = 0;
\r
1959 appData.saveGameFile = "";
\r
1960 appData.autoSaveGames = FALSE;
\r
1961 appData.loadPositionFile = "";
\r
1962 appData.loadPositionIndex = 1;
\r
1963 appData.savePositionFile = "";
\r
1964 appData.matchMode = FALSE;
\r
1965 appData.matchGames = 0;
\r
1966 appData.monoMode = FALSE;
\r
1967 appData.debugMode = FALSE;
\r
1968 appData.clockMode = TRUE;
\r
1969 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1970 appData.Iconic = FALSE; /*unused*/
\r
1971 appData.searchTime = "";
\r
1972 appData.searchDepth = 0;
\r
1973 appData.showCoords = FALSE;
\r
1974 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1975 appData.autoCallFlag = FALSE;
\r
1976 appData.flipView = FALSE;
\r
1977 appData.autoFlipView = TRUE;
\r
1978 appData.cmailGameName = "";
\r
1979 appData.alwaysPromoteToQueen = FALSE;
\r
1980 appData.oldSaveStyle = FALSE;
\r
1981 appData.quietPlay = FALSE;
\r
1982 appData.showThinking = FALSE;
\r
1983 appData.ponderNextMove = TRUE;
\r
1984 appData.periodicUpdates = TRUE;
\r
1985 appData.popupExitMessage = TRUE;
\r
1986 appData.popupMoveErrors = FALSE;
\r
1987 appData.autoObserve = FALSE;
\r
1988 appData.autoComment = FALSE;
\r
1989 appData.animate = TRUE;
\r
1990 appData.animSpeed = 10;
\r
1991 appData.animateDragging = TRUE;
\r
1992 appData.highlightLastMove = TRUE;
\r
1993 appData.getMoveList = TRUE;
\r
1994 appData.testLegality = TRUE;
\r
1995 appData.premove = TRUE;
\r
1996 appData.premoveWhite = FALSE;
\r
1997 appData.premoveWhiteText = "";
\r
1998 appData.premoveBlack = FALSE;
\r
1999 appData.premoveBlackText = "";
\r
2000 appData.icsAlarm = TRUE;
\r
2001 appData.icsAlarmTime = 5000;
\r
2002 appData.autoRaiseBoard = TRUE;
\r
2003 appData.localLineEditing = TRUE;
\r
2004 appData.colorize = TRUE;
\r
2005 appData.reuseFirst = TRUE;
\r
2006 appData.reuseSecond = TRUE;
\r
2007 appData.blindfold = FALSE;
\r
2008 appData.icsEngineAnalyze = FALSE;
\r
2009 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2010 dcb.DCBlength = sizeof(DCB);
\r
2011 dcb.BaudRate = 9600;
\r
2012 dcb.fBinary = TRUE;
\r
2013 dcb.fParity = FALSE;
\r
2014 dcb.fOutxCtsFlow = FALSE;
\r
2015 dcb.fOutxDsrFlow = FALSE;
\r
2016 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2017 dcb.fDsrSensitivity = FALSE;
\r
2018 dcb.fTXContinueOnXoff = TRUE;
\r
2019 dcb.fOutX = FALSE;
\r
2021 dcb.fNull = FALSE;
\r
2022 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2023 dcb.fAbortOnError = FALSE;
\r
2025 dcb.Parity = SPACEPARITY;
\r
2026 dcb.StopBits = ONESTOPBIT;
\r
2027 settingsFileName = SETTINGS_FILE;
\r
2028 saveSettingsOnExit = TRUE;
\r
2029 boardX = CW_USEDEFAULT;
\r
2030 boardY = CW_USEDEFAULT;
\r
2031 analysisX = CW_USEDEFAULT;
\r
2032 analysisY = CW_USEDEFAULT;
\r
2033 analysisW = CW_USEDEFAULT;
\r
2034 analysisH = CW_USEDEFAULT;
\r
2035 commentX = CW_USEDEFAULT;
\r
2036 commentY = CW_USEDEFAULT;
\r
2037 commentW = CW_USEDEFAULT;
\r
2038 commentH = CW_USEDEFAULT;
\r
2039 editTagsX = CW_USEDEFAULT;
\r
2040 editTagsY = CW_USEDEFAULT;
\r
2041 editTagsW = CW_USEDEFAULT;
\r
2042 editTagsH = CW_USEDEFAULT;
\r
2043 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2044 icsNames = ICS_NAMES;
\r
2045 firstChessProgramNames = FCP_NAMES;
\r
2046 secondChessProgramNames = SCP_NAMES;
\r
2047 appData.initialMode = "";
\r
2048 appData.variant = "normal";
\r
2049 appData.firstProtocolVersion = PROTOVER;
\r
2050 appData.secondProtocolVersion = PROTOVER;
\r
2051 appData.showButtonBar = TRUE;
\r
2053 /* [AS] New properties (see comments in header file) */
\r
2054 appData.firstScoreIsAbsolute = FALSE;
\r
2055 appData.secondScoreIsAbsolute = FALSE;
\r
2056 appData.saveExtendedInfoInPGN = FALSE;
\r
2057 appData.hideThinkingFromHuman = FALSE;
\r
2058 appData.liteBackTextureFile = "";
\r
2059 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2060 appData.darkBackTextureFile = "";
\r
2061 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2062 appData.renderPiecesWithFont = "";
\r
2063 appData.fontToPieceTable = "";
\r
2064 appData.fontBackColorWhite = 0;
\r
2065 appData.fontForeColorWhite = 0;
\r
2066 appData.fontBackColorBlack = 0;
\r
2067 appData.fontForeColorBlack = 0;
\r
2068 appData.fontPieceSize = 80;
\r
2069 appData.overrideLineGap = 1;
\r
2070 appData.adjudicateLossThreshold = 0;
\r
2071 appData.delayBeforeQuit = 0;
\r
2072 appData.delayAfterQuit = 0;
\r
2073 appData.nameOfDebugFile = "winboard.debug";
\r
2074 appData.pgnEventHeader = "Computer Chess Game";
\r
2075 appData.defaultFrcPosition = -1;
\r
2076 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2077 appData.saveOutOfBookInfo = TRUE;
\r
2078 appData.showEvalInMoveHistory = TRUE;
\r
2079 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2080 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2081 appData.highlightMoveWithArrow = FALSE;
\r
2082 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2083 appData.useStickyWindows = TRUE;
\r
2084 appData.adjudicateDrawMoves = 0;
\r
2085 appData.autoDisplayComment = TRUE;
\r
2086 appData.autoDisplayTags = TRUE;
\r
2087 appData.firstIsUCI = FALSE;
\r
2088 appData.secondIsUCI = FALSE;
\r
2089 appData.firstHasOwnBookUCI = TRUE;
\r
2090 appData.secondHasOwnBookUCI = TRUE;
\r
2091 appData.polyglotDir = "";
\r
2092 appData.usePolyglotBook = FALSE;
\r
2093 appData.polyglotBook = "";
\r
2094 appData.defaultHashSize = 64;
\r
2095 appData.defaultCacheSizeEGTB = 4;
\r
2096 appData.defaultPathEGTB = "c:\\egtb";
\r
2097 appData.firstOptions = "";
\r
2098 appData.secondOptions = "";
\r
2100 InitWindowPlacement( &wpGameList );
\r
2101 InitWindowPlacement( &wpMoveHistory );
\r
2102 InitWindowPlacement( &wpEvalGraph );
\r
2103 InitWindowPlacement( &wpEngineOutput );
\r
2104 InitWindowPlacement( &wpConsole );
\r
2106 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2107 appData.NrFiles = -1;
\r
2108 appData.NrRanks = -1;
\r
2109 appData.holdingsSize = -1;
\r
2110 appData.testClaims = FALSE;
\r
2111 appData.checkMates = FALSE;
\r
2112 appData.materialDraws= FALSE;
\r
2113 appData.trivialDraws = FALSE;
\r
2114 appData.ruleMoves = 51;
\r
2115 appData.drawRepeats = 6;
\r
2116 appData.matchPause = 10000;
\r
2117 appData.alphaRank = FALSE;
\r
2118 appData.allWhite = FALSE;
\r
2119 appData.upsideDown = FALSE;
\r
2120 appData.serverPause = 15;
\r
2121 appData.serverMovesName = NULL;
\r
2122 appData.suppressLoadMoves = FALSE;
\r
2123 appData.firstTimeOdds = 1;
\r
2124 appData.secondTimeOdds = 1;
\r
2125 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2126 appData.secondAccumulateTC = 1;
\r
2127 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2128 appData.secondNPS = -1;
\r
2129 appData.engineComments = 1;
\r
2130 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2131 appData.egtFormats = "";
\r
2134 appData.zippyTalk = ZIPPY_TALK;
\r
2135 appData.zippyPlay = ZIPPY_PLAY;
\r
2136 appData.zippyLines = ZIPPY_LINES;
\r
2137 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2138 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2139 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2140 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2141 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2142 appData.zippyUseI = ZIPPY_USE_I;
\r
2143 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2144 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2145 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2146 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2147 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2148 appData.zippyAbort = ZIPPY_ABORT;
\r
2149 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2150 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2151 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2154 /* Point font array elements to structures and
\r
2155 parse default font names */
\r
2156 for (i=0; i<NUM_FONTS; i++) {
\r
2157 for (j=0; j<NUM_SIZES; j++) {
\r
2158 font[j][i] = &fontRec[j][i];
\r
2159 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2163 /* Parse default settings file if any */
\r
2164 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2165 settingsFileName = strdup(buf);
\r
2168 /* Parse command line */
\r
2169 ParseArgs(StringGet, &lpCmdLine);
\r
2171 /* [HGM] make sure board size is acceptable */
\r
2172 if(appData.NrFiles > BOARD_SIZE ||
\r
2173 appData.NrRanks > BOARD_SIZE )
\r
2174 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2176 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2177 * with options from the command line, we now make an even higher priority
\r
2178 * overrule by WB options attached to the engine command line. This so that
\r
2179 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2182 if(appData.firstChessProgram != NULL) {
\r
2183 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2184 static char *f = "first";
\r
2185 char buf[MSG_SIZ], *q = buf;
\r
2186 if(p != NULL) { // engine command line contains WinBoard options
\r
2187 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2188 ParseArgs(StringGet, &q);
\r
2189 p[-1] = 0; // cut them offengine command line
\r
2192 // now do same for second chess program
\r
2193 if(appData.secondChessProgram != NULL) {
\r
2194 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2195 static char *s = "second";
\r
2196 char buf[MSG_SIZ], *q = buf;
\r
2197 if(p != NULL) { // engine command line contains WinBoard options
\r
2198 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2199 ParseArgs(StringGet, &q);
\r
2200 p[-1] = 0; // cut them offengine command line
\r
2205 /* Propagate options that affect others */
\r
2206 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2207 if (appData.icsActive || appData.noChessProgram) {
\r
2208 chessProgram = FALSE; /* not local chess program mode */
\r
2211 /* Open startup dialog if needed */
\r
2212 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2213 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2214 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2215 *appData.secondChessProgram == NULLCHAR))) {
\r
2218 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2219 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2220 FreeProcInstance(lpProc);
\r
2223 /* Make sure save files land in the right (?) directory */
\r
2224 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2225 appData.saveGameFile = strdup(buf);
\r
2227 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2228 appData.savePositionFile = strdup(buf);
\r
2231 /* Finish initialization for fonts and sounds */
\r
2232 for (i=0; i<NUM_FONTS; i++) {
\r
2233 for (j=0; j<NUM_SIZES; j++) {
\r
2234 CreateFontInMF(font[j][i]);
\r
2237 /* xboard, and older WinBoards, controlled the move sound with the
\r
2238 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2239 always turn the option on (so that the backend will call us),
\r
2240 then let the user turn the sound off by setting it to silence if
\r
2241 desired. To accommodate old winboard.ini files saved by old
\r
2242 versions of WinBoard, we also turn off the sound if the option
\r
2243 was initially set to false. */
\r
2244 if (!appData.ringBellAfterMoves) {
\r
2245 sounds[(int)SoundMove].name = strdup("");
\r
2246 appData.ringBellAfterMoves = TRUE;
\r
2248 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2249 SetCurrentDirectory(installDir);
\r
2251 SetCurrentDirectory(currDir);
\r
2253 p = icsTextMenuString;
\r
2254 if (p[0] == '@') {
\r
2255 FILE* f = fopen(p + 1, "r");
\r
2257 DisplayFatalError(p + 1, errno, 2);
\r
2260 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2262 buf[i] = NULLCHAR;
\r
2265 ParseIcsTextMenu(strdup(p));
\r
2272 HMENU hmenu = GetMenu(hwndMain);
\r
2274 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2275 MF_BYCOMMAND|((appData.icsActive &&
\r
2276 *appData.icsCommPort != NULLCHAR) ?
\r
2277 MF_ENABLED : MF_GRAYED));
\r
2278 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2279 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2280 MF_CHECKED : MF_UNCHECKED));
\r
2285 SaveSettings(char* name)
\r
2288 ArgDescriptor *ad;
\r
2289 WINDOWPLACEMENT wp;
\r
2290 char dir[MSG_SIZ];
\r
2292 if (!hwndMain) return;
\r
2294 GetCurrentDirectory(MSG_SIZ, dir);
\r
2295 SetCurrentDirectory(installDir);
\r
2296 f = fopen(name, "w");
\r
2297 SetCurrentDirectory(dir);
\r
2299 DisplayError(name, errno);
\r
2302 fprintf(f, ";\n");
\r
2303 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2304 fprintf(f, ";\n");
\r
2305 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2306 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2307 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2308 fprintf(f, ";\n");
\r
2310 wp.length = sizeof(WINDOWPLACEMENT);
\r
2311 GetWindowPlacement(hwndMain, &wp);
\r
2312 boardX = wp.rcNormalPosition.left;
\r
2313 boardY = wp.rcNormalPosition.top;
\r
2315 if (hwndConsole) {
\r
2316 GetWindowPlacement(hwndConsole, &wp);
\r
2317 wpConsole.x = wp.rcNormalPosition.left;
\r
2318 wpConsole.y = wp.rcNormalPosition.top;
\r
2319 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2320 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2323 if (analysisDialog) {
\r
2324 GetWindowPlacement(analysisDialog, &wp);
\r
2325 analysisX = wp.rcNormalPosition.left;
\r
2326 analysisY = wp.rcNormalPosition.top;
\r
2327 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2328 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2331 if (commentDialog) {
\r
2332 GetWindowPlacement(commentDialog, &wp);
\r
2333 commentX = wp.rcNormalPosition.left;
\r
2334 commentY = wp.rcNormalPosition.top;
\r
2335 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2336 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2339 if (editTagsDialog) {
\r
2340 GetWindowPlacement(editTagsDialog, &wp);
\r
2341 editTagsX = wp.rcNormalPosition.left;
\r
2342 editTagsY = wp.rcNormalPosition.top;
\r
2343 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2344 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2347 if (gameListDialog) {
\r
2348 GetWindowPlacement(gameListDialog, &wp);
\r
2349 wpGameList.x = wp.rcNormalPosition.left;
\r
2350 wpGameList.y = wp.rcNormalPosition.top;
\r
2351 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2352 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2355 /* [AS] Move history */
\r
2356 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2358 if( moveHistoryDialog ) {
\r
2359 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2360 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2361 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2362 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2363 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2366 /* [AS] Eval graph */
\r
2367 wpEvalGraph.visible = EvalGraphIsUp();
\r
2369 if( evalGraphDialog ) {
\r
2370 GetWindowPlacement(evalGraphDialog, &wp);
\r
2371 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2372 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2373 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2374 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2377 /* [AS] Engine output */
\r
2378 wpEngineOutput.visible = EngineOutputIsUp();
\r
2380 if( engineOutputDialog ) {
\r
2381 GetWindowPlacement(engineOutputDialog, &wp);
\r
2382 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2383 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2384 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2385 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2388 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2389 if (!ad->save) continue;
\r
2390 switch (ad->argType) {
\r
2393 char *p = *(char **)ad->argLoc;
\r
2394 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2395 /* Quote multiline values or \-containing values
\r
2396 with { } if possible */
\r
2397 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2399 /* Else quote with " " */
\r
2400 fprintf(f, "/%s=\"", ad->argName);
\r
2402 if (*p == '\n') fprintf(f, "\n");
\r
2403 else if (*p == '\r') fprintf(f, "\\r");
\r
2404 else if (*p == '\t') fprintf(f, "\\t");
\r
2405 else if (*p == '\b') fprintf(f, "\\b");
\r
2406 else if (*p == '\f') fprintf(f, "\\f");
\r
2407 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2408 else if (*p == '\"') fprintf(f, "\\\"");
\r
2409 else if (*p == '\\') fprintf(f, "\\\\");
\r
2413 fprintf(f, "\"\n");
\r
2419 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2422 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2425 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2428 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2431 fprintf(f, "/%s=%s\n", ad->argName,
\r
2432 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2435 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2438 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2442 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2443 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2444 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2449 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2450 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2451 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2452 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2453 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2454 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2455 (ta->effects) ? " " : "",
\r
2456 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2460 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2461 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2463 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2466 case ArgBoardSize:
\r
2467 fprintf(f, "/%s=%s\n", ad->argName,
\r
2468 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2473 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2474 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2475 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2476 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2477 ad->argName, mfp->faceName, mfp->pointSize,
\r
2478 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2479 mfp->bold ? "b" : "",
\r
2480 mfp->italic ? "i" : "",
\r
2481 mfp->underline ? "u" : "",
\r
2482 mfp->strikeout ? "s" : "");
\r
2486 case ArgCommSettings:
\r
2487 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2489 case ArgSettingsFilename: ;
\r
2497 /*---------------------------------------------------------------------------*\
\r
2499 * GDI board drawing routines
\r
2501 \*---------------------------------------------------------------------------*/
\r
2503 /* [AS] Draw square using background texture */
\r
2504 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2509 return; /* Should never happen! */
\r
2512 SetGraphicsMode( dst, GM_ADVANCED );
\r
2519 /* X reflection */
\r
2524 x.eDx = (FLOAT) dw + dx - 1;
\r
2527 SetWorldTransform( dst, &x );
\r
2530 /* Y reflection */
\r
2536 x.eDy = (FLOAT) dh + dy - 1;
\r
2538 SetWorldTransform( dst, &x );
\r
2546 x.eDx = (FLOAT) dx;
\r
2547 x.eDy = (FLOAT) dy;
\r
2550 SetWorldTransform( dst, &x );
\r
2554 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2562 SetWorldTransform( dst, &x );
\r
2564 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2567 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2569 PM_WP = (int) WhitePawn,
\r
2570 PM_WN = (int) WhiteKnight,
\r
2571 PM_WB = (int) WhiteBishop,
\r
2572 PM_WR = (int) WhiteRook,
\r
2573 PM_WQ = (int) WhiteQueen,
\r
2574 PM_WF = (int) WhiteFerz,
\r
2575 PM_WW = (int) WhiteWazir,
\r
2576 PM_WE = (int) WhiteAlfil,
\r
2577 PM_WM = (int) WhiteMan,
\r
2578 PM_WO = (int) WhiteCannon,
\r
2579 PM_WU = (int) WhiteUnicorn,
\r
2580 PM_WH = (int) WhiteNightrider,
\r
2581 PM_WA = (int) WhiteAngel,
\r
2582 PM_WC = (int) WhiteMarshall,
\r
2583 PM_WAB = (int) WhiteCardinal,
\r
2584 PM_WD = (int) WhiteDragon,
\r
2585 PM_WL = (int) WhiteLance,
\r
2586 PM_WS = (int) WhiteCobra,
\r
2587 PM_WV = (int) WhiteFalcon,
\r
2588 PM_WSG = (int) WhiteSilver,
\r
2589 PM_WG = (int) WhiteGrasshopper,
\r
2590 PM_WK = (int) WhiteKing,
\r
2591 PM_BP = (int) BlackPawn,
\r
2592 PM_BN = (int) BlackKnight,
\r
2593 PM_BB = (int) BlackBishop,
\r
2594 PM_BR = (int) BlackRook,
\r
2595 PM_BQ = (int) BlackQueen,
\r
2596 PM_BF = (int) BlackFerz,
\r
2597 PM_BW = (int) BlackWazir,
\r
2598 PM_BE = (int) BlackAlfil,
\r
2599 PM_BM = (int) BlackMan,
\r
2600 PM_BO = (int) BlackCannon,
\r
2601 PM_BU = (int) BlackUnicorn,
\r
2602 PM_BH = (int) BlackNightrider,
\r
2603 PM_BA = (int) BlackAngel,
\r
2604 PM_BC = (int) BlackMarshall,
\r
2605 PM_BG = (int) BlackGrasshopper,
\r
2606 PM_BAB = (int) BlackCardinal,
\r
2607 PM_BD = (int) BlackDragon,
\r
2608 PM_BL = (int) BlackLance,
\r
2609 PM_BS = (int) BlackCobra,
\r
2610 PM_BV = (int) BlackFalcon,
\r
2611 PM_BSG = (int) BlackSilver,
\r
2612 PM_BK = (int) BlackKing
\r
2615 static HFONT hPieceFont = NULL;
\r
2616 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2617 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2618 static int fontBitmapSquareSize = 0;
\r
2619 static char pieceToFontChar[(int) EmptySquare] =
\r
2620 { 'p', 'n', 'b', 'r', 'q',
\r
2621 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2622 'k', 'o', 'm', 'v', 't', 'w',
\r
2623 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2626 extern BOOL SetCharTable( char *table, const char * map );
\r
2627 /* [HGM] moved to backend.c */
\r
2629 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2632 BYTE r1 = GetRValue( color );
\r
2633 BYTE g1 = GetGValue( color );
\r
2634 BYTE b1 = GetBValue( color );
\r
2640 /* Create a uniform background first */
\r
2641 hbrush = CreateSolidBrush( color );
\r
2642 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2643 FillRect( hdc, &rc, hbrush );
\r
2644 DeleteObject( hbrush );
\r
2647 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2648 int steps = squareSize / 2;
\r
2651 for( i=0; i<steps; i++ ) {
\r
2652 BYTE r = r1 - (r1-r2) * i / steps;
\r
2653 BYTE g = g1 - (g1-g2) * i / steps;
\r
2654 BYTE b = b1 - (b1-b2) * i / steps;
\r
2656 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2657 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2658 FillRect( hdc, &rc, hbrush );
\r
2659 DeleteObject(hbrush);
\r
2662 else if( mode == 2 ) {
\r
2663 /* Diagonal gradient, good more or less for every piece */
\r
2664 POINT triangle[3];
\r
2665 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2666 HBRUSH hbrush_old;
\r
2667 int steps = squareSize;
\r
2670 triangle[0].x = squareSize - steps;
\r
2671 triangle[0].y = squareSize;
\r
2672 triangle[1].x = squareSize;
\r
2673 triangle[1].y = squareSize;
\r
2674 triangle[2].x = squareSize;
\r
2675 triangle[2].y = squareSize - steps;
\r
2677 for( i=0; i<steps; i++ ) {
\r
2678 BYTE r = r1 - (r1-r2) * i / steps;
\r
2679 BYTE g = g1 - (g1-g2) * i / steps;
\r
2680 BYTE b = b1 - (b1-b2) * i / steps;
\r
2682 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2683 hbrush_old = SelectObject( hdc, hbrush );
\r
2684 Polygon( hdc, triangle, 3 );
\r
2685 SelectObject( hdc, hbrush_old );
\r
2686 DeleteObject(hbrush);
\r
2691 SelectObject( hdc, hpen );
\r
2696 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2697 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2698 piece: follow the steps as explained below.
\r
2700 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2704 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2708 int backColor = whitePieceColor;
\r
2709 int foreColor = blackPieceColor;
\r
2711 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2712 backColor = appData.fontBackColorWhite;
\r
2713 foreColor = appData.fontForeColorWhite;
\r
2715 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2716 backColor = appData.fontBackColorBlack;
\r
2717 foreColor = appData.fontForeColorBlack;
\r
2721 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2723 hbm_old = SelectObject( hdc, hbm );
\r
2727 rc.right = squareSize;
\r
2728 rc.bottom = squareSize;
\r
2730 /* Step 1: background is now black */
\r
2731 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2733 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2735 pt.x = (squareSize - sz.cx) / 2;
\r
2736 pt.y = (squareSize - sz.cy) / 2;
\r
2738 SetBkMode( hdc, TRANSPARENT );
\r
2739 SetTextColor( hdc, chroma );
\r
2740 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2741 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2743 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2744 /* Step 3: the area outside the piece is filled with white */
\r
2745 // FloodFill( hdc, 0, 0, chroma );
\r
2746 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2747 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2748 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2749 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2750 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2752 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2753 but if the start point is not inside the piece we're lost!
\r
2754 There should be a better way to do this... if we could create a region or path
\r
2755 from the fill operation we would be fine for example.
\r
2757 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2758 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2760 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2761 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2762 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2764 SelectObject( dc2, bm2 );
\r
2765 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2766 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2767 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2768 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2769 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2772 DeleteObject( bm2 );
\r
2775 SetTextColor( hdc, 0 );
\r
2777 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2778 draw the piece again in black for safety.
\r
2780 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2782 SelectObject( hdc, hbm_old );
\r
2784 if( hPieceMask[index] != NULL ) {
\r
2785 DeleteObject( hPieceMask[index] );
\r
2788 hPieceMask[index] = hbm;
\r
2791 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2793 SelectObject( hdc, hbm );
\r
2796 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2797 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2798 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2800 SelectObject( dc1, hPieceMask[index] );
\r
2801 SelectObject( dc2, bm2 );
\r
2802 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2803 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2806 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2807 the piece background and deletes (makes transparent) the rest.
\r
2808 Thanks to that mask, we are free to paint the background with the greates
\r
2809 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2810 We use this, to make gradients and give the pieces a "roundish" look.
\r
2812 SetPieceBackground( hdc, backColor, 2 );
\r
2813 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2817 DeleteObject( bm2 );
\r
2820 SetTextColor( hdc, foreColor );
\r
2821 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2823 SelectObject( hdc, hbm_old );
\r
2825 if( hPieceFace[index] != NULL ) {
\r
2826 DeleteObject( hPieceFace[index] );
\r
2829 hPieceFace[index] = hbm;
\r
2832 static int TranslatePieceToFontPiece( int piece )
\r
2862 case BlackMarshall:
\r
2866 case BlackNightrider:
\r
2872 case BlackUnicorn:
\r
2876 case BlackGrasshopper:
\r
2888 case BlackCardinal:
\r
2895 case WhiteMarshall:
\r
2899 case WhiteNightrider:
\r
2905 case WhiteUnicorn:
\r
2909 case WhiteGrasshopper:
\r
2921 case WhiteCardinal:
\r
2930 void CreatePiecesFromFont()
\r
2933 HDC hdc_window = NULL;
\r
2939 if( fontBitmapSquareSize < 0 ) {
\r
2940 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2944 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2945 fontBitmapSquareSize = -1;
\r
2949 if( fontBitmapSquareSize != squareSize ) {
\r
2950 hdc_window = GetDC( hwndMain );
\r
2951 hdc = CreateCompatibleDC( hdc_window );
\r
2953 if( hPieceFont != NULL ) {
\r
2954 DeleteObject( hPieceFont );
\r
2957 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2958 hPieceMask[i] = NULL;
\r
2959 hPieceFace[i] = NULL;
\r
2965 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2966 fontHeight = appData.fontPieceSize;
\r
2969 fontHeight = (fontHeight * squareSize) / 100;
\r
2971 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2973 lf.lfEscapement = 0;
\r
2974 lf.lfOrientation = 0;
\r
2975 lf.lfWeight = FW_NORMAL;
\r
2977 lf.lfUnderline = 0;
\r
2978 lf.lfStrikeOut = 0;
\r
2979 lf.lfCharSet = DEFAULT_CHARSET;
\r
2980 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2981 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2982 lf.lfQuality = PROOF_QUALITY;
\r
2983 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2984 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2985 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2987 hPieceFont = CreateFontIndirect( &lf );
\r
2989 if( hPieceFont == NULL ) {
\r
2990 fontBitmapSquareSize = -2;
\r
2993 /* Setup font-to-piece character table */
\r
2994 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2995 /* No (or wrong) global settings, try to detect the font */
\r
2996 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2998 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3000 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3001 /* DiagramTT* family */
\r
3002 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3004 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3005 /* Fairy symbols */
\r
3006 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3008 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3009 /* Good Companion (Some characters get warped as literal :-( */
\r
3010 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3011 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3012 SetCharTable(pieceToFontChar, s);
\r
3015 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3016 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3020 /* Create bitmaps */
\r
3021 hfont_old = SelectObject( hdc, hPieceFont );
\r
3023 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3024 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3025 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3026 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3027 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3028 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3029 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3030 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3031 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3032 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3033 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3034 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3036 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3037 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3038 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3039 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3040 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3042 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3043 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3048 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3050 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3051 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3055 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3056 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3063 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3064 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3065 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3066 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3067 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3069 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3070 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3071 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3073 SelectObject( hdc, hfont_old );
\r
3075 fontBitmapSquareSize = squareSize;
\r
3079 if( hdc != NULL ) {
\r
3083 if( hdc_window != NULL ) {
\r
3084 ReleaseDC( hwndMain, hdc_window );
\r
3089 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3093 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3094 if (gameInfo.event &&
\r
3095 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3096 strcmp(name, "k80s") == 0) {
\r
3097 strcpy(name, "tim");
\r
3099 return LoadBitmap(hinst, name);
\r
3103 /* Insert a color into the program's logical palette
\r
3104 structure. This code assumes the given color is
\r
3105 the result of the RGB or PALETTERGB macro, and it
\r
3106 knows how those macros work (which is documented).
\r
3109 InsertInPalette(COLORREF color)
\r
3111 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3113 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3114 DisplayFatalError("Too many colors", 0, 1);
\r
3115 pLogPal->palNumEntries--;
\r
3119 pe->peFlags = (char) 0;
\r
3120 pe->peRed = (char) (0xFF & color);
\r
3121 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3122 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3128 InitDrawingColors()
\r
3130 if (pLogPal == NULL) {
\r
3131 /* Allocate enough memory for a logical palette with
\r
3132 * PALETTESIZE entries and set the size and version fields
\r
3133 * of the logical palette structure.
\r
3135 pLogPal = (NPLOGPALETTE)
\r
3136 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3137 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3138 pLogPal->palVersion = 0x300;
\r
3140 pLogPal->palNumEntries = 0;
\r
3142 InsertInPalette(lightSquareColor);
\r
3143 InsertInPalette(darkSquareColor);
\r
3144 InsertInPalette(whitePieceColor);
\r
3145 InsertInPalette(blackPieceColor);
\r
3146 InsertInPalette(highlightSquareColor);
\r
3147 InsertInPalette(premoveHighlightColor);
\r
3149 /* create a logical color palette according the information
\r
3150 * in the LOGPALETTE structure.
\r
3152 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3154 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3155 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3156 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3157 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3158 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3159 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3160 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3161 /* [AS] Force rendering of the font-based pieces */
\r
3162 if( fontBitmapSquareSize > 0 ) {
\r
3163 fontBitmapSquareSize = 0;
\r
3169 BoardWidth(int boardSize, int n)
\r
3170 { /* [HGM] argument n added to allow different width and height */
\r
3171 int lineGap = sizeInfo[boardSize].lineGap;
\r
3173 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3174 lineGap = appData.overrideLineGap;
\r
3177 return (n + 1) * lineGap +
\r
3178 n * sizeInfo[boardSize].squareSize;
\r
3181 /* Respond to board resize by dragging edge */
\r
3183 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3185 BoardSize newSize = NUM_SIZES - 1;
\r
3186 static int recurse = 0;
\r
3187 if (IsIconic(hwndMain)) return;
\r
3188 if (recurse > 0) return;
\r
3190 while (newSize > 0) {
\r
3191 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3192 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3193 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3196 boardSize = newSize;
\r
3197 InitDrawingSizes(boardSize, flags);
\r
3204 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3206 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3207 ChessSquare piece;
\r
3208 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3210 SIZE clockSize, messageSize;
\r
3212 char buf[MSG_SIZ];
\r
3214 HMENU hmenu = GetMenu(hwndMain);
\r
3215 RECT crect, wrect, oldRect;
\r
3217 LOGBRUSH logbrush;
\r
3219 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3220 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3222 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3223 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3225 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3226 oldRect.top = boardY;
\r
3227 oldRect.right = boardX + winWidth;
\r
3228 oldRect.bottom = boardY + winHeight;
\r
3230 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3231 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3232 squareSize = sizeInfo[boardSize].squareSize;
\r
3233 lineGap = sizeInfo[boardSize].lineGap;
\r
3234 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3236 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3237 lineGap = appData.overrideLineGap;
\r
3240 if (tinyLayout != oldTinyLayout) {
\r
3241 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3243 style &= ~WS_SYSMENU;
\r
3244 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3245 "&Minimize\tCtrl+F4");
\r
3247 style |= WS_SYSMENU;
\r
3248 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3250 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3252 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3253 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3254 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3256 DrawMenuBar(hwndMain);
\r
3259 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3260 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3262 /* Get text area sizes */
\r
3263 hdc = GetDC(hwndMain);
\r
3264 if (appData.clockMode) {
\r
3265 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3267 sprintf(buf, "White");
\r
3269 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3270 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3271 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3272 str = "We only care about the height here";
\r
3273 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3274 SelectObject(hdc, oldFont);
\r
3275 ReleaseDC(hwndMain, hdc);
\r
3277 /* Compute where everything goes */
\r
3278 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3279 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3280 logoHeight = 2*clockSize.cy;
\r
3281 leftLogoRect.left = OUTER_MARGIN;
\r
3282 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3283 leftLogoRect.top = OUTER_MARGIN;
\r
3284 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3286 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3287 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3288 rightLogoRect.top = OUTER_MARGIN;
\r
3289 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3292 whiteRect.left = leftLogoRect.right;
\r
3293 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3294 whiteRect.top = OUTER_MARGIN;
\r
3295 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3297 blackRect.right = rightLogoRect.left;
\r
3298 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3299 blackRect.top = whiteRect.top;
\r
3300 blackRect.bottom = whiteRect.bottom;
\r
3302 whiteRect.left = OUTER_MARGIN;
\r
3303 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3304 whiteRect.top = OUTER_MARGIN;
\r
3305 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3307 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3308 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3309 blackRect.top = whiteRect.top;
\r
3310 blackRect.bottom = whiteRect.bottom;
\r
3313 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3314 if (appData.showButtonBar) {
\r
3315 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3316 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3318 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3320 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3321 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3323 boardRect.left = OUTER_MARGIN;
\r
3324 boardRect.right = boardRect.left + boardWidth;
\r
3325 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3326 boardRect.bottom = boardRect.top + boardHeight;
\r
3328 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3329 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3330 oldBoardSize = boardSize;
\r
3331 oldTinyLayout = tinyLayout;
\r
3332 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3333 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3334 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3335 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3336 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3337 winHeight = winH; // without disturbing window attachments
\r
3338 GetWindowRect(hwndMain, &wrect);
\r
3339 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3340 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3342 // [HGM] placement: let attached windows follow size change.
\r
3343 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3344 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3345 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3346 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3347 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3349 /* compensate if menu bar wrapped */
\r
3350 GetClientRect(hwndMain, &crect);
\r
3351 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3352 winHeight += offby;
\r
3354 case WMSZ_TOPLEFT:
\r
3355 SetWindowPos(hwndMain, NULL,
\r
3356 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3357 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3360 case WMSZ_TOPRIGHT:
\r
3362 SetWindowPos(hwndMain, NULL,
\r
3363 wrect.left, wrect.bottom - winHeight,
\r
3364 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3367 case WMSZ_BOTTOMLEFT:
\r
3369 SetWindowPos(hwndMain, NULL,
\r
3370 wrect.right - winWidth, wrect.top,
\r
3371 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3374 case WMSZ_BOTTOMRIGHT:
\r
3378 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3379 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3384 for (i = 0; i < N_BUTTONS; i++) {
\r
3385 if (buttonDesc[i].hwnd != NULL) {
\r
3386 DestroyWindow(buttonDesc[i].hwnd);
\r
3387 buttonDesc[i].hwnd = NULL;
\r
3389 if (appData.showButtonBar) {
\r
3390 buttonDesc[i].hwnd =
\r
3391 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3392 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3393 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3394 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3395 (HMENU) buttonDesc[i].id,
\r
3396 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3398 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3399 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3400 MAKELPARAM(FALSE, 0));
\r
3402 if (buttonDesc[i].id == IDM_Pause)
\r
3403 hwndPause = buttonDesc[i].hwnd;
\r
3404 buttonDesc[i].wndproc = (WNDPROC)
\r
3405 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3408 if (gridPen != NULL) DeleteObject(gridPen);
\r
3409 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3410 if (premovePen != NULL) DeleteObject(premovePen);
\r
3411 if (lineGap != 0) {
\r
3412 logbrush.lbStyle = BS_SOLID;
\r
3413 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3415 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3416 lineGap, &logbrush, 0, NULL);
\r
3417 logbrush.lbColor = highlightSquareColor;
\r
3419 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3420 lineGap, &logbrush, 0, NULL);
\r
3422 logbrush.lbColor = premoveHighlightColor;
\r
3424 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3425 lineGap, &logbrush, 0, NULL);
\r
3427 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3428 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3429 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3430 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3431 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3432 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3433 BOARD_WIDTH * (squareSize + lineGap);
\r
3434 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3436 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3437 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3438 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3439 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3440 lineGap / 2 + (i * (squareSize + lineGap));
\r
3441 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3442 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3443 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3447 /* [HGM] Licensing requirement */
\r
3449 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3452 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3454 GothicPopUp( "", VariantNormal);
\r
3457 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3459 /* Load piece bitmaps for this board size */
\r
3460 for (i=0; i<=2; i++) {
\r
3461 for (piece = WhitePawn;
\r
3462 (int) piece < (int) BlackPawn;
\r
3463 piece = (ChessSquare) ((int) piece + 1)) {
\r
3464 if (pieceBitmap[i][piece] != NULL)
\r
3465 DeleteObject(pieceBitmap[i][piece]);
\r
3469 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3470 // Orthodox Chess pieces
\r
3471 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3472 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3473 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3474 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3475 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3476 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3477 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3478 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3479 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3480 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3481 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3482 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3483 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3484 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3485 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3486 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3487 // in Shogi, Hijack the unused Queen for Lance
\r
3488 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3489 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3490 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3492 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3493 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3494 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3497 if(squareSize <= 72 && squareSize >= 33) {
\r
3498 /* A & C are available in most sizes now */
\r
3499 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3500 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3501 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3502 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3503 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3504 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3505 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3506 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3507 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3508 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3509 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3510 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3511 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3512 } else { // Smirf-like
\r
3513 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3514 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3515 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3517 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3518 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3519 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3520 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3521 } else { // WinBoard standard
\r
3522 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3523 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3524 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3529 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3530 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3531 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3532 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3533 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3534 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3535 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3536 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3537 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3538 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3539 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3540 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3541 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3542 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3543 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3544 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3545 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3546 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3547 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3548 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3549 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3550 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3551 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3552 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3553 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3554 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3555 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3556 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3557 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3558 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3559 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3561 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3562 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3563 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3564 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3565 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3566 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3567 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3568 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3569 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3570 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3571 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3572 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3573 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3575 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3576 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3577 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3578 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3579 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3580 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3581 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3582 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3583 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3584 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3585 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3586 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3589 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3590 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3591 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3592 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3593 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3594 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3595 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3596 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3597 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3598 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3599 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3600 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3601 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3602 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3603 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3607 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3608 /* special Shogi support in this size */
\r
3609 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3610 for (piece = WhitePawn;
\r
3611 (int) piece < (int) BlackPawn;
\r
3612 piece = (ChessSquare) ((int) piece + 1)) {
\r
3613 if (pieceBitmap[i][piece] != NULL)
\r
3614 DeleteObject(pieceBitmap[i][piece]);
\r
3617 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3618 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3619 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3620 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3621 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3622 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3623 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3624 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3625 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3626 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3627 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3628 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3629 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3630 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3631 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3632 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3633 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3634 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3635 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3636 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3637 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3638 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3639 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3640 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3641 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3642 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3643 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3644 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3645 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3646 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3647 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3648 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3649 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3650 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3651 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3652 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3653 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3654 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3655 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3656 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3657 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3658 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3664 PieceBitmap(ChessSquare p, int kind)
\r
3666 if ((int) p >= (int) BlackPawn)
\r
3667 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3669 return pieceBitmap[kind][(int) p];
\r
3672 /***************************************************************/
\r
3674 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3675 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3677 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3678 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3682 SquareToPos(int row, int column, int * x, int * y)
\r
3685 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3686 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3688 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3689 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3694 DrawCoordsOnDC(HDC hdc)
\r
3696 static char files[24] = {'0', '1','2','3','4','5','6','7','8','9','0','1','1','0','9','8','7','6','5','4','3','2','1','0'};
\r
3697 static char ranks[24] = {'l', 'k','j','i','h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h','i','j','k','l'};
\r
3698 char str[2] = { NULLCHAR, NULLCHAR };
\r
3699 int oldMode, oldAlign, x, y, start, i;
\r
3703 if (!appData.showCoords)
\r
3706 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3708 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3709 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3710 oldAlign = GetTextAlign(hdc);
\r
3711 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3713 y = boardRect.top + lineGap;
\r
3714 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3716 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3717 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3718 str[0] = files[start + i];
\r
3719 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3720 y += squareSize + lineGap;
\r
3723 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3725 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3726 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3727 str[0] = ranks[start + i];
\r
3728 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3729 x += squareSize + lineGap;
\r
3732 SelectObject(hdc, oldBrush);
\r
3733 SetBkMode(hdc, oldMode);
\r
3734 SetTextAlign(hdc, oldAlign);
\r
3735 SelectObject(hdc, oldFont);
\r
3739 DrawGridOnDC(HDC hdc)
\r
3743 if (lineGap != 0) {
\r
3744 oldPen = SelectObject(hdc, gridPen);
\r
3745 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3746 SelectObject(hdc, oldPen);
\r
3750 #define HIGHLIGHT_PEN 0
\r
3751 #define PREMOVE_PEN 1
\r
3754 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3757 HPEN oldPen, hPen;
\r
3758 if (lineGap == 0) return;
\r
3760 x1 = boardRect.left +
\r
3761 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3762 y1 = boardRect.top +
\r
3763 lineGap/2 + y * (squareSize + lineGap);
\r
3765 x1 = boardRect.left +
\r
3766 lineGap/2 + x * (squareSize + lineGap);
\r
3767 y1 = boardRect.top +
\r
3768 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3770 hPen = pen ? premovePen : highlightPen;
\r
3771 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3772 MoveToEx(hdc, x1, y1, NULL);
\r
3773 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3774 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3775 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3776 LineTo(hdc, x1, y1);
\r
3777 SelectObject(hdc, oldPen);
\r
3781 DrawHighlightsOnDC(HDC hdc)
\r
3784 for (i=0; i<2; i++) {
\r
3785 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3786 DrawHighlightOnDC(hdc, TRUE,
\r
3787 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3790 for (i=0; i<2; i++) {
\r
3791 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3792 premoveHighlightInfo.sq[i].y >= 0) {
\r
3793 DrawHighlightOnDC(hdc, TRUE,
\r
3794 premoveHighlightInfo.sq[i].x,
\r
3795 premoveHighlightInfo.sq[i].y,
\r
3801 /* Note: sqcolor is used only in monoMode */
\r
3802 /* Note that this code is largely duplicated in woptions.c,
\r
3803 function DrawSampleSquare, so that needs to be updated too */
\r
3805 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3807 HBITMAP oldBitmap;
\r
3811 if (appData.blindfold) return;
\r
3813 /* [AS] Use font-based pieces if needed */
\r
3814 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3815 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3816 CreatePiecesFromFont();
\r
3818 if( fontBitmapSquareSize == squareSize ) {
\r
3819 int index = TranslatePieceToFontPiece(piece);
\r
3821 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3825 squareSize, squareSize,
\r
3830 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3834 squareSize, squareSize,
\r
3843 if (appData.monoMode) {
\r
3844 SelectObject(tmphdc, PieceBitmap(piece,
\r
3845 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3846 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3847 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3849 tmpSize = squareSize;
\r
3851 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3852 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3853 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3854 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3855 x += (squareSize - minorSize)>>1;
\r
3856 y += squareSize - minorSize - 2;
\r
3857 tmpSize = minorSize;
\r
3859 if (color || appData.allWhite ) {
\r
3860 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3862 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3863 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3864 if(appData.upsideDown && color==flipView)
\r
3865 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3867 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3869 /* Use black piece color for outline of white pieces */
\r
3870 /* Not sure this looks really good (though xboard does it).
\r
3871 Maybe better to have another selectable color, default black */
\r
3872 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3873 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3874 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3876 /* Use black for outline of white pieces */
\r
3877 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3878 if(appData.upsideDown && color==flipView)
\r
3879 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3881 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3885 /* Use white piece color for details of black pieces */
\r
3886 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3887 WHITE_PIECE ones aren't always the right shape. */
\r
3888 /* Not sure this looks really good (though xboard does it).
\r
3889 Maybe better to have another selectable color, default medium gray? */
\r
3890 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3891 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3892 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3893 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3894 SelectObject(hdc, blackPieceBrush);
\r
3895 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3897 /* Use square color for details of black pieces */
\r
3898 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3899 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3900 if(appData.upsideDown && !flipView)
\r
3901 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3903 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3906 SelectObject(hdc, oldBrush);
\r
3907 SelectObject(tmphdc, oldBitmap);
\r
3911 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3912 int GetBackTextureMode( int algo )
\r
3914 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3918 case BACK_TEXTURE_MODE_PLAIN:
\r
3919 result = 1; /* Always use identity map */
\r
3921 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3922 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3930 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3931 to handle redraws cleanly (as random numbers would always be different).
\r
3933 VOID RebuildTextureSquareInfo()
\r
3943 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3945 if( liteBackTexture != NULL ) {
\r
3946 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3947 lite_w = bi.bmWidth;
\r
3948 lite_h = bi.bmHeight;
\r
3952 if( darkBackTexture != NULL ) {
\r
3953 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3954 dark_w = bi.bmWidth;
\r
3955 dark_h = bi.bmHeight;
\r
3959 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3960 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3961 if( (col + row) & 1 ) {
\r
3963 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3964 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3965 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3966 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3971 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3972 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3973 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3974 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3981 /* [AS] Arrow highlighting support */
\r
3983 static int A_WIDTH = 5; /* Width of arrow body */
\r
3985 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3986 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3988 static double Sqr( double x )
\r
3993 static int Round( double x )
\r
3995 return (int) (x + 0.5);
\r
3998 /* Draw an arrow between two points using current settings */
\r
3999 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
4002 double dx, dy, j, k, x, y;
\r
4004 if( d_x == s_x ) {
\r
4005 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4007 arrow[0].x = s_x + A_WIDTH;
\r
4010 arrow[1].x = s_x + A_WIDTH;
\r
4011 arrow[1].y = d_y - h;
\r
4013 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4014 arrow[2].y = d_y - h;
\r
4019 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4020 arrow[4].y = d_y - h;
\r
4022 arrow[5].x = s_x - A_WIDTH;
\r
4023 arrow[5].y = d_y - h;
\r
4025 arrow[6].x = s_x - A_WIDTH;
\r
4028 else if( d_y == s_y ) {
\r
4029 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4032 arrow[0].y = s_y + A_WIDTH;
\r
4034 arrow[1].x = d_x - w;
\r
4035 arrow[1].y = s_y + A_WIDTH;
\r
4037 arrow[2].x = d_x - w;
\r
4038 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4043 arrow[4].x = d_x - w;
\r
4044 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4046 arrow[5].x = d_x - w;
\r
4047 arrow[5].y = s_y - A_WIDTH;
\r
4050 arrow[6].y = s_y - A_WIDTH;
\r
4053 /* [AS] Needed a lot of paper for this! :-) */
\r
4054 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4055 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4057 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4059 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4064 arrow[0].x = Round(x - j);
\r
4065 arrow[0].y = Round(y + j*dx);
\r
4067 arrow[1].x = Round(x + j);
\r
4068 arrow[1].y = Round(y - j*dx);
\r
4071 x = (double) d_x - k;
\r
4072 y = (double) d_y - k*dy;
\r
4075 x = (double) d_x + k;
\r
4076 y = (double) d_y + k*dy;
\r
4079 arrow[2].x = Round(x + j);
\r
4080 arrow[2].y = Round(y - j*dx);
\r
4082 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4083 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4088 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4089 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4091 arrow[6].x = Round(x - j);
\r
4092 arrow[6].y = Round(y + j*dx);
\r
4095 Polygon( hdc, arrow, 7 );
\r
4098 /* [AS] Draw an arrow between two squares */
\r
4099 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4101 int s_x, s_y, d_x, d_y;
\r
4108 if( s_col == d_col && s_row == d_row ) {
\r
4112 /* Get source and destination points */
\r
4113 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4114 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4117 d_y += squareSize / 4;
\r
4119 else if( d_y < s_y ) {
\r
4120 d_y += 3 * squareSize / 4;
\r
4123 d_y += squareSize / 2;
\r
4127 d_x += squareSize / 4;
\r
4129 else if( d_x < s_x ) {
\r
4130 d_x += 3 * squareSize / 4;
\r
4133 d_x += squareSize / 2;
\r
4136 s_x += squareSize / 2;
\r
4137 s_y += squareSize / 2;
\r
4139 /* Adjust width */
\r
4140 A_WIDTH = squareSize / 14;
\r
4143 stLB.lbStyle = BS_SOLID;
\r
4144 stLB.lbColor = appData.highlightArrowColor;
\r
4147 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4148 holdpen = SelectObject( hdc, hpen );
\r
4149 hbrush = CreateBrushIndirect( &stLB );
\r
4150 holdbrush = SelectObject( hdc, hbrush );
\r
4152 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4154 SelectObject( hdc, holdpen );
\r
4155 SelectObject( hdc, holdbrush );
\r
4156 DeleteObject( hpen );
\r
4157 DeleteObject( hbrush );
\r
4160 BOOL HasHighlightInfo()
\r
4162 BOOL result = FALSE;
\r
4164 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4165 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4173 BOOL IsDrawArrowEnabled()
\r
4175 BOOL result = FALSE;
\r
4177 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4184 VOID DrawArrowHighlight( HDC hdc )
\r
4186 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4187 DrawArrowBetweenSquares( hdc,
\r
4188 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4189 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4193 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4195 HRGN result = NULL;
\r
4197 if( HasHighlightInfo() ) {
\r
4198 int x1, y1, x2, y2;
\r
4199 int sx, sy, dx, dy;
\r
4201 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4202 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4204 sx = MIN( x1, x2 );
\r
4205 sy = MIN( y1, y2 );
\r
4206 dx = MAX( x1, x2 ) + squareSize;
\r
4207 dy = MAX( y1, y2 ) + squareSize;
\r
4209 result = CreateRectRgn( sx, sy, dx, dy );
\r
4216 Warning: this function modifies the behavior of several other functions.
\r
4218 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4219 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4220 repaint is scattered all over the place, which is not good for features such as
\r
4221 "arrow highlighting" that require a full repaint of the board.
\r
4223 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4224 user interaction, when speed is not so important) but especially to avoid errors
\r
4225 in the displayed graphics.
\r
4227 In such patched places, I always try refer to this function so there is a single
\r
4228 place to maintain knowledge.
\r
4230 To restore the original behavior, just return FALSE unconditionally.
\r
4232 BOOL IsFullRepaintPreferrable()
\r
4234 BOOL result = FALSE;
\r
4236 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4237 /* Arrow may appear on the board */
\r
4245 This function is called by DrawPosition to know whether a full repaint must
\r
4248 Only DrawPosition may directly call this function, which makes use of
\r
4249 some state information. Other function should call DrawPosition specifying
\r
4250 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4252 BOOL DrawPositionNeedsFullRepaint()
\r
4254 BOOL result = FALSE;
\r
4257 Probably a slightly better policy would be to trigger a full repaint
\r
4258 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4259 but animation is fast enough that it's difficult to notice.
\r
4261 if( animInfo.piece == EmptySquare ) {
\r
4262 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4271 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4273 int row, column, x, y, square_color, piece_color;
\r
4274 ChessSquare piece;
\r
4276 HDC texture_hdc = NULL;
\r
4278 /* [AS] Initialize background textures if needed */
\r
4279 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4280 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4281 if( backTextureSquareSize != squareSize
\r
4282 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4283 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4284 backTextureSquareSize = squareSize;
\r
4285 RebuildTextureSquareInfo();
\r
4288 texture_hdc = CreateCompatibleDC( hdc );
\r
4291 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4292 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4294 SquareToPos(row, column, &x, &y);
\r
4296 piece = board[row][column];
\r
4298 square_color = ((column + row) % 2) == 1;
\r
4299 if( gameInfo.variant == VariantXiangqi ) {
\r
4300 square_color = !InPalace(row, column);
\r
4301 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4302 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4304 piece_color = (int) piece < (int) BlackPawn;
\r
4307 /* [HGM] holdings file: light square or black */
\r
4308 if(column == BOARD_LEFT-2) {
\r
4309 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4312 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4316 if(column == BOARD_RGHT + 1 ) {
\r
4317 if( row < gameInfo.holdingsSize )
\r
4320 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4324 if(column == BOARD_LEFT-1 ) /* left align */
\r
4325 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4326 else if( column == BOARD_RGHT) /* right align */
\r
4327 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4329 if (appData.monoMode) {
\r
4330 if (piece == EmptySquare) {
\r
4331 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4332 square_color ? WHITENESS : BLACKNESS);
\r
4334 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4337 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4338 /* [AS] Draw the square using a texture bitmap */
\r
4339 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4340 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4341 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4344 squareSize, squareSize,
\r
4347 backTextureSquareInfo[r][c].mode,
\r
4348 backTextureSquareInfo[r][c].x,
\r
4349 backTextureSquareInfo[r][c].y );
\r
4351 SelectObject( texture_hdc, hbm );
\r
4353 if (piece != EmptySquare) {
\r
4354 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4358 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4360 oldBrush = SelectObject(hdc, brush );
\r
4361 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4362 SelectObject(hdc, oldBrush);
\r
4363 if (piece != EmptySquare)
\r
4364 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4369 if( texture_hdc != NULL ) {
\r
4370 DeleteDC( texture_hdc );
\r
4374 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4375 void fputDW(FILE *f, int x)
\r
4377 fputc(x & 255, f);
\r
4378 fputc(x>>8 & 255, f);
\r
4379 fputc(x>>16 & 255, f);
\r
4380 fputc(x>>24 & 255, f);
\r
4383 #define MAX_CLIPS 200 /* more than enough */
\r
4386 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4388 // HBITMAP bufferBitmap;
\r
4393 int w = 100, h = 50;
\r
4395 if(logo == NULL) return;
\r
4396 // GetClientRect(hwndMain, &Rect);
\r
4397 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4398 // Rect.bottom-Rect.top+1);
\r
4399 tmphdc = CreateCompatibleDC(hdc);
\r
4400 hbm = SelectObject(tmphdc, logo);
\r
4401 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4405 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4406 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4407 SelectObject(tmphdc, hbm);
\r
4412 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4414 static Board lastReq, lastDrawn;
\r
4415 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4416 static int lastDrawnFlipView = 0;
\r
4417 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4418 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4421 HBITMAP bufferBitmap;
\r
4422 HBITMAP oldBitmap;
\r
4424 HRGN clips[MAX_CLIPS];
\r
4425 ChessSquare dragged_piece = EmptySquare;
\r
4427 /* I'm undecided on this - this function figures out whether a full
\r
4428 * repaint is necessary on its own, so there's no real reason to have the
\r
4429 * caller tell it that. I think this can safely be set to FALSE - but
\r
4430 * if we trust the callers not to request full repaints unnessesarily, then
\r
4431 * we could skip some clipping work. In other words, only request a full
\r
4432 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4433 * gamestart and similar) --Hawk
\r
4435 Boolean fullrepaint = repaint;
\r
4437 if( DrawPositionNeedsFullRepaint() ) {
\r
4438 fullrepaint = TRUE;
\r
4442 if( fullrepaint ) {
\r
4443 static int repaint_count = 0;
\r
4447 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4448 OutputDebugString( buf );
\r
4452 if (board == NULL) {
\r
4453 if (!lastReqValid) {
\r
4458 CopyBoard(lastReq, board);
\r
4462 if (doingSizing) {
\r
4466 if (IsIconic(hwndMain)) {
\r
4470 if (hdc == NULL) {
\r
4471 hdc = GetDC(hwndMain);
\r
4472 if (!appData.monoMode) {
\r
4473 SelectPalette(hdc, hPal, FALSE);
\r
4474 RealizePalette(hdc);
\r
4478 releaseDC = FALSE;
\r
4482 fprintf(debugFP, "*******************************\n"
\r
4484 "dragInfo.from (%d,%d)\n"
\r
4485 "dragInfo.start (%d,%d)\n"
\r
4486 "dragInfo.pos (%d,%d)\n"
\r
4487 "dragInfo.lastpos (%d,%d)\n",
\r
4488 repaint ? "TRUE" : "FALSE",
\r
4489 dragInfo.from.x, dragInfo.from.y,
\r
4490 dragInfo.start.x, dragInfo.start.y,
\r
4491 dragInfo.pos.x, dragInfo.pos.y,
\r
4492 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4493 fprintf(debugFP, "prev: ");
\r
4494 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4495 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4496 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4499 fprintf(debugFP, "\n");
\r
4500 fprintf(debugFP, "board: ");
\r
4501 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4502 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4503 fprintf(debugFP, "%d ", board[row][column]);
\r
4506 fprintf(debugFP, "\n");
\r
4510 /* Create some work-DCs */
\r
4511 hdcmem = CreateCompatibleDC(hdc);
\r
4512 tmphdc = CreateCompatibleDC(hdc);
\r
4514 /* If dragging is in progress, we temporarely remove the piece */
\r
4515 /* [HGM] or temporarily decrease count if stacked */
\r
4516 /* !! Moved to before board compare !! */
\r
4517 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4518 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4519 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4520 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4521 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4523 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4524 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4525 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4527 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4530 /* Figure out which squares need updating by comparing the
\r
4531 * newest board with the last drawn board and checking if
\r
4532 * flipping has changed.
\r
4534 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4535 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4536 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4537 if (lastDrawn[row][column] != board[row][column]) {
\r
4538 SquareToPos(row, column, &x, &y);
\r
4539 clips[num_clips++] =
\r
4540 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4544 for (i=0; i<2; i++) {
\r
4545 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4546 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4547 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4548 lastDrawnHighlight.sq[i].y >= 0) {
\r
4549 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4550 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4551 clips[num_clips++] =
\r
4552 CreateRectRgn(x - lineGap, y - lineGap,
\r
4553 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4555 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4556 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4557 clips[num_clips++] =
\r
4558 CreateRectRgn(x - lineGap, y - lineGap,
\r
4559 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4563 for (i=0; i<2; i++) {
\r
4564 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4565 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4566 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4567 lastDrawnPremove.sq[i].y >= 0) {
\r
4568 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4569 lastDrawnPremove.sq[i].x, &x, &y);
\r
4570 clips[num_clips++] =
\r
4571 CreateRectRgn(x - lineGap, y - lineGap,
\r
4572 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4574 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4575 premoveHighlightInfo.sq[i].y >= 0) {
\r
4576 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4577 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4578 clips[num_clips++] =
\r
4579 CreateRectRgn(x - lineGap, y - lineGap,
\r
4580 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4585 fullrepaint = TRUE;
\r
4588 /* Create a buffer bitmap - this is the actual bitmap
\r
4589 * being written to. When all the work is done, we can
\r
4590 * copy it to the real DC (the screen). This avoids
\r
4591 * the problems with flickering.
\r
4593 GetClientRect(hwndMain, &Rect);
\r
4594 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4595 Rect.bottom-Rect.top+1);
\r
4596 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4597 if (!appData.monoMode) {
\r
4598 SelectPalette(hdcmem, hPal, FALSE);
\r
4601 /* Create clips for dragging */
\r
4602 if (!fullrepaint) {
\r
4603 if (dragInfo.from.x >= 0) {
\r
4604 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4605 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4607 if (dragInfo.start.x >= 0) {
\r
4608 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4609 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4611 if (dragInfo.pos.x >= 0) {
\r
4612 x = dragInfo.pos.x - squareSize / 2;
\r
4613 y = dragInfo.pos.y - squareSize / 2;
\r
4614 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4616 if (dragInfo.lastpos.x >= 0) {
\r
4617 x = dragInfo.lastpos.x - squareSize / 2;
\r
4618 y = dragInfo.lastpos.y - squareSize / 2;
\r
4619 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4623 /* Are we animating a move?
\r
4625 * - remove the piece from the board (temporarely)
\r
4626 * - calculate the clipping region
\r
4628 if (!fullrepaint) {
\r
4629 if (animInfo.piece != EmptySquare) {
\r
4630 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4631 x = boardRect.left + animInfo.lastpos.x;
\r
4632 y = boardRect.top + animInfo.lastpos.y;
\r
4633 x2 = boardRect.left + animInfo.pos.x;
\r
4634 y2 = boardRect.top + animInfo.pos.y;
\r
4635 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4636 /* Slight kludge. The real problem is that after AnimateMove is
\r
4637 done, the position on the screen does not match lastDrawn.
\r
4638 This currently causes trouble only on e.p. captures in
\r
4639 atomic, where the piece moves to an empty square and then
\r
4640 explodes. The old and new positions both had an empty square
\r
4641 at the destination, but animation has drawn a piece there and
\r
4642 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4643 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4647 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4648 if (num_clips == 0)
\r
4649 fullrepaint = TRUE;
\r
4651 /* Set clipping on the memory DC */
\r
4652 if (!fullrepaint) {
\r
4653 SelectClipRgn(hdcmem, clips[0]);
\r
4654 for (x = 1; x < num_clips; x++) {
\r
4655 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4656 abort(); // this should never ever happen!
\r
4660 /* Do all the drawing to the memory DC */
\r
4661 if(explodeInfo.radius) { // [HGM] atomic
\r
4663 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4664 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4665 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4666 x += squareSize/2;
\r
4667 y += squareSize/2;
\r
4668 if(!fullrepaint) {
\r
4669 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4670 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4672 DrawGridOnDC(hdcmem);
\r
4673 DrawHighlightsOnDC(hdcmem);
\r
4674 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4675 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4676 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4677 SelectObject(hdcmem, oldBrush);
\r
4679 DrawGridOnDC(hdcmem);
\r
4680 DrawHighlightsOnDC(hdcmem);
\r
4681 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4684 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4685 if(appData.autoLogo) {
\r
4687 switch(gameMode) { // pick logos based on game mode
\r
4688 case IcsObserving:
\r
4689 whiteLogo = second.programLogo; // ICS logo
\r
4690 blackLogo = second.programLogo;
\r
4693 case IcsPlayingWhite:
\r
4694 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4695 blackLogo = second.programLogo; // ICS logo
\r
4697 case IcsPlayingBlack:
\r
4698 whiteLogo = second.programLogo; // ICS logo
\r
4699 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4701 case TwoMachinesPlay:
\r
4702 if(first.twoMachinesColor[0] == 'b') {
\r
4703 whiteLogo = second.programLogo;
\r
4704 blackLogo = first.programLogo;
\r
4707 case MachinePlaysWhite:
\r
4708 blackLogo = userLogo;
\r
4710 case MachinePlaysBlack:
\r
4711 whiteLogo = userLogo;
\r
4712 blackLogo = first.programLogo;
\r
4715 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4716 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4719 if( appData.highlightMoveWithArrow ) {
\r
4720 DrawArrowHighlight(hdcmem);
\r
4723 DrawCoordsOnDC(hdcmem);
\r
4725 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4726 /* to make sure lastDrawn contains what is actually drawn */
\r
4728 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4729 if (dragged_piece != EmptySquare) {
\r
4730 /* [HGM] or restack */
\r
4731 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4732 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4734 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4735 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4736 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4737 x = dragInfo.pos.x - squareSize / 2;
\r
4738 y = dragInfo.pos.y - squareSize / 2;
\r
4739 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4740 ((int) dragged_piece < (int) BlackPawn),
\r
4741 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4744 /* Put the animated piece back into place and draw it */
\r
4745 if (animInfo.piece != EmptySquare) {
\r
4746 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4747 x = boardRect.left + animInfo.pos.x;
\r
4748 y = boardRect.top + animInfo.pos.y;
\r
4749 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4750 ((int) animInfo.piece < (int) BlackPawn),
\r
4751 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4754 /* Release the bufferBitmap by selecting in the old bitmap
\r
4755 * and delete the memory DC
\r
4757 SelectObject(hdcmem, oldBitmap);
\r
4760 /* Set clipping on the target DC */
\r
4761 if (!fullrepaint) {
\r
4762 SelectClipRgn(hdc, clips[0]);
\r
4763 for (x = 1; x < num_clips; x++) {
\r
4764 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4765 abort(); // this should never ever happen!
\r
4769 /* Copy the new bitmap onto the screen in one go.
\r
4770 * This way we avoid any flickering
\r
4772 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4773 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4774 boardRect.right - boardRect.left,
\r
4775 boardRect.bottom - boardRect.top,
\r
4776 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4777 if(saveDiagFlag) {
\r
4778 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4779 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4781 GetObject(bufferBitmap, sizeof(b), &b);
\r
4782 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4783 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4784 bih.biWidth = b.bmWidth;
\r
4785 bih.biHeight = b.bmHeight;
\r
4787 bih.biBitCount = b.bmBitsPixel;
\r
4788 bih.biCompression = 0;
\r
4789 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4790 bih.biXPelsPerMeter = 0;
\r
4791 bih.biYPelsPerMeter = 0;
\r
4792 bih.biClrUsed = 0;
\r
4793 bih.biClrImportant = 0;
\r
4794 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4795 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4796 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4797 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4800 wb = b.bmWidthBytes;
\r
4802 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4803 int k = ((int*) pData)[i];
\r
4804 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4805 if(j >= 16) break;
\r
4807 if(j >= nrColors) nrColors = j+1;
\r
4809 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4811 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4812 for(w=0; w<(wb>>2); w+=2) {
\r
4813 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4814 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4815 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4816 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4817 pData[p++] = m | j<<4;
\r
4819 while(p&3) pData[p++] = 0;
\r
4822 wb = ((wb+31)>>5)<<2;
\r
4824 // write BITMAPFILEHEADER
\r
4825 fprintf(diagFile, "BM");
\r
4826 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4827 fputDW(diagFile, 0);
\r
4828 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4829 // write BITMAPINFOHEADER
\r
4830 fputDW(diagFile, 40);
\r
4831 fputDW(diagFile, b.bmWidth);
\r
4832 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4833 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4834 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4835 fputDW(diagFile, 0);
\r
4836 fputDW(diagFile, 0);
\r
4837 fputDW(diagFile, 0);
\r
4838 fputDW(diagFile, 0);
\r
4839 fputDW(diagFile, 0);
\r
4840 fputDW(diagFile, 0);
\r
4841 // write color table
\r
4843 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4844 // write bitmap data
\r
4845 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4846 fputc(pData[i], diagFile);
\r
4851 SelectObject(tmphdc, oldBitmap);
\r
4853 /* Massive cleanup */
\r
4854 for (x = 0; x < num_clips; x++)
\r
4855 DeleteObject(clips[x]);
\r
4858 DeleteObject(bufferBitmap);
\r
4861 ReleaseDC(hwndMain, hdc);
\r
4863 if (lastDrawnFlipView != flipView) {
\r
4865 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4867 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4870 /* CopyBoard(lastDrawn, board);*/
\r
4871 lastDrawnHighlight = highlightInfo;
\r
4872 lastDrawnPremove = premoveHighlightInfo;
\r
4873 lastDrawnFlipView = flipView;
\r
4874 lastDrawnValid = 1;
\r
4877 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4882 saveDiagFlag = 1; diagFile = f;
\r
4883 HDCDrawPosition(NULL, TRUE, NULL);
\r
4887 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4894 /*---------------------------------------------------------------------------*\
\r
4895 | CLIENT PAINT PROCEDURE
\r
4896 | This is the main event-handler for the WM_PAINT message.
\r
4898 \*---------------------------------------------------------------------------*/
\r
4900 PaintProc(HWND hwnd)
\r
4906 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4907 if (IsIconic(hwnd)) {
\r
4908 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4910 if (!appData.monoMode) {
\r
4911 SelectPalette(hdc, hPal, FALSE);
\r
4912 RealizePalette(hdc);
\r
4914 HDCDrawPosition(hdc, 1, NULL);
\r
4916 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4917 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4918 ETO_CLIPPED|ETO_OPAQUE,
\r
4919 &messageRect, messageText, strlen(messageText), NULL);
\r
4920 SelectObject(hdc, oldFont);
\r
4921 DisplayBothClocks();
\r
4923 EndPaint(hwnd,&ps);
\r
4931 * If the user selects on a border boundary, return -1; if off the board,
\r
4932 * return -2. Otherwise map the event coordinate to the square.
\r
4933 * The offset boardRect.left or boardRect.top must already have been
\r
4934 * subtracted from x.
\r
4937 EventToSquare(int x)
\r
4944 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4946 x /= (squareSize + lineGap);
\r
4947 if (x >= BOARD_SIZE)
\r
4958 DropEnable dropEnables[] = {
\r
4959 { 'P', DP_Pawn, "Pawn" },
\r
4960 { 'N', DP_Knight, "Knight" },
\r
4961 { 'B', DP_Bishop, "Bishop" },
\r
4962 { 'R', DP_Rook, "Rook" },
\r
4963 { 'Q', DP_Queen, "Queen" },
\r
4967 SetupDropMenu(HMENU hmenu)
\r
4969 int i, count, enable;
\r
4971 extern char white_holding[], black_holding[];
\r
4972 char item[MSG_SIZ];
\r
4974 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4975 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4976 dropEnables[i].piece);
\r
4978 while (p && *p++ == dropEnables[i].piece) count++;
\r
4979 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4980 enable = count > 0 || !appData.testLegality
\r
4981 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4982 && !appData.icsActive);
\r
4983 ModifyMenu(hmenu, dropEnables[i].command,
\r
4984 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4985 dropEnables[i].command, item);
\r
4989 /* Event handler for mouse messages */
\r
4991 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4995 static int recursive = 0;
\r
4997 // BOOLEAN needsRedraw = FALSE;
\r
4998 BOOLEAN saveAnimate;
\r
4999 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
5000 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
5001 ChessMove moveType;
\r
5004 if (message == WM_MBUTTONUP) {
\r
5005 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5006 to the middle button: we simulate pressing the left button too!
\r
5008 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5009 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5015 pt.x = LOWORD(lParam);
\r
5016 pt.y = HIWORD(lParam);
\r
5017 x = EventToSquare(pt.x - boardRect.left);
\r
5018 y = EventToSquare(pt.y - boardRect.top);
\r
5019 if (!flipView && y >= 0) {
\r
5020 y = BOARD_HEIGHT - 1 - y;
\r
5022 if (flipView && x >= 0) {
\r
5023 x = BOARD_WIDTH - 1 - x;
\r
5026 switch (message) {
\r
5027 case WM_LBUTTONDOWN:
\r
5028 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5029 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5030 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5031 if(gameInfo.holdingsWidth &&
\r
5032 (WhiteOnMove(currentMove)
\r
5033 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5034 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5035 // click in right holdings, for determining promotion piece
\r
5036 ChessSquare p = boards[currentMove][y][x];
\r
5037 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5038 if(p != EmptySquare) {
\r
5039 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5040 fromX = fromY = -1;
\r
5044 DrawPosition(FALSE, boards[currentMove]);
\r
5048 sameAgain = FALSE;
\r
5050 /* Downclick vertically off board; check if on clock */
\r
5051 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5052 if (gameMode == EditPosition) {
\r
5053 SetWhiteToPlayEvent();
\r
5054 } else if (gameMode == IcsPlayingBlack ||
\r
5055 gameMode == MachinePlaysWhite) {
\r
5057 } else if (gameMode == EditGame) {
\r
5058 AdjustClock(flipClock, -1);
\r
5060 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5061 if (gameMode == EditPosition) {
\r
5062 SetBlackToPlayEvent();
\r
5063 } else if (gameMode == IcsPlayingWhite ||
\r
5064 gameMode == MachinePlaysBlack) {
\r
5066 } else if (gameMode == EditGame) {
\r
5067 AdjustClock(!flipClock, -1);
\r
5070 if (!appData.highlightLastMove) {
\r
5071 ClearHighlights();
\r
5072 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5074 fromX = fromY = -1;
\r
5075 dragInfo.start.x = dragInfo.start.y = -1;
\r
5076 dragInfo.from = dragInfo.start;
\r
5078 } else if (x < 0 || y < 0
\r
5079 /* [HGM] block clicks between board and holdings */
\r
5080 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5081 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5082 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5083 /* EditPosition, empty square, or different color piece;
\r
5084 click-click move is possible */
\r
5087 } else if (fromX == x && fromY == y) {
\r
5088 /* Downclick on same square again */
\r
5089 ClearHighlights();
\r
5090 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5091 sameAgain = TRUE;
\r
5092 } else if (fromX != -1 &&
\r
5093 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5095 /* Downclick on different square. */
\r
5096 /* [HGM] if on holdings file, should count as new first click ! */
\r
5097 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5100 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5101 to make sure move is legal before showing promotion popup */
\r
5102 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5103 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5104 fromX = fromY = -1;
\r
5105 ClearHighlights();
\r
5106 DrawPosition(FALSE, boards[currentMove]);
\r
5109 if(moveType != ImpossibleMove) {
\r
5110 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5111 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5112 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5113 appData.alwaysPromoteToQueen)) {
\r
5114 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5115 if (!appData.highlightLastMove) {
\r
5116 ClearHighlights();
\r
5117 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5120 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5121 SetHighlights(fromX, fromY, toX, toY);
\r
5122 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5123 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5124 If promotion to Q is legal, all are legal! */
\r
5125 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5126 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5127 // kludge to temporarily execute move on display, wthout promotng yet
\r
5128 promotionChoice = TRUE;
\r
5129 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5130 boards[currentMove][toY][toX] = p;
\r
5131 DrawPosition(FALSE, boards[currentMove]);
\r
5132 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5133 boards[currentMove][toY][toX] = q;
\r
5135 PromotionPopup(hwnd);
\r
5136 } else { /* not a promotion */
\r
5137 if (appData.animate || appData.highlightLastMove) {
\r
5138 SetHighlights(fromX, fromY, toX, toY);
\r
5140 ClearHighlights();
\r
5142 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5143 fromX = fromY = -1;
\r
5144 if (appData.animate && !appData.highlightLastMove) {
\r
5145 ClearHighlights();
\r
5146 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5152 /* [HGM] it seemed that braces were missing here */
\r
5153 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5154 fromX = fromY = -1;
\r
5158 ClearHighlights();
\r
5159 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5161 /* First downclick, or restart on a square with same color piece */
\r
5162 if (!frozen && OKToStartUserMove(x, y)) {
\r
5165 dragInfo.lastpos = pt;
\r
5166 dragInfo.from.x = fromX;
\r
5167 dragInfo.from.y = fromY;
\r
5168 dragInfo.start = dragInfo.from;
\r
5169 SetCapture(hwndMain);
\r
5171 fromX = fromY = -1;
\r
5172 dragInfo.start.x = dragInfo.start.y = -1;
\r
5173 dragInfo.from = dragInfo.start;
\r
5174 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5178 case WM_LBUTTONUP:
\r
5180 if (fromX == -1) break;
\r
5181 if (x == fromX && y == fromY) {
\r
5182 dragInfo.from.x = dragInfo.from.y = -1;
\r
5183 /* Upclick on same square */
\r
5185 /* Clicked same square twice: abort click-click move */
\r
5186 fromX = fromY = -1;
\r
5188 ClearPremoveHighlights();
\r
5190 /* First square clicked: start click-click move */
\r
5191 SetHighlights(fromX, fromY, -1, -1);
\r
5193 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5194 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5195 /* Errant click; ignore */
\r
5198 /* Finish drag move. */
\r
5199 if (appData.debugMode) {
\r
5200 fprintf(debugFP, "release\n");
\r
5202 dragInfo.from.x = dragInfo.from.y = -1;
\r
5205 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5206 appData.animate = appData.animate && !appData.animateDragging;
\r
5207 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5208 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5209 fromX = fromY = -1;
\r
5210 ClearHighlights();
\r
5211 DrawPosition(FALSE, boards[currentMove]);
\r
5212 appData.animate = saveAnimate;
\r
5215 if(moveType != ImpossibleMove) {
\r
5216 /* [HGM] use move type to determine if move is promotion.
\r
5217 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5218 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5219 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5220 appData.alwaysPromoteToQueen))
\r
5221 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5223 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5224 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5225 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5226 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5227 // kludge to temporarily execute move on display, wthout promotng yet
\r
5228 promotionChoice = TRUE;
\r
5229 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5230 boards[currentMove][toY][toX] = p;
\r
5231 DrawPosition(FALSE, boards[currentMove]);
\r
5232 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5233 boards[currentMove][toY][toX] = q;
\r
5234 appData.animate = saveAnimate;
\r
5237 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5239 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5240 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5241 moveType == WhiteCapturesEnPassant ||
\r
5242 moveType == BlackCapturesEnPassant ) )
\r
5243 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5244 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5247 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5248 appData.animate = saveAnimate;
\r
5249 fromX = fromY = -1;
\r
5250 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5251 ClearHighlights();
\r
5253 if (appData.animate || appData.animateDragging ||
\r
5254 appData.highlightDragging || gotPremove) {
\r
5255 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5258 dragInfo.start.x = dragInfo.start.y = -1;
\r
5259 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5262 case WM_MOUSEMOVE:
\r
5263 if ((appData.animateDragging || appData.highlightDragging)
\r
5264 && (wParam & MK_LBUTTON)
\r
5265 && dragInfo.from.x >= 0)
\r
5267 BOOL full_repaint = FALSE;
\r
5269 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5270 if (appData.animateDragging) {
\r
5271 dragInfo.pos = pt;
\r
5273 if (appData.highlightDragging) {
\r
5274 SetHighlights(fromX, fromY, x, y);
\r
5275 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5276 full_repaint = TRUE;
\r
5280 DrawPosition( full_repaint, NULL);
\r
5282 dragInfo.lastpos = dragInfo.pos;
\r
5286 case WM_MOUSEWHEEL: // [DM]
\r
5287 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5288 /* Mouse Wheel is being rolled forward
\r
5289 * Play moves forward
\r
5291 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5292 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5293 /* Mouse Wheel is being rolled backward
\r
5294 * Play moves backward
\r
5296 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5297 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5301 case WM_MBUTTONDOWN:
\r
5302 case WM_RBUTTONDOWN:
\r
5305 fromX = fromY = -1;
\r
5306 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5307 dragInfo.start.x = dragInfo.start.y = -1;
\r
5308 dragInfo.from = dragInfo.start;
\r
5309 dragInfo.lastpos = dragInfo.pos;
\r
5310 if (appData.highlightDragging) {
\r
5311 ClearHighlights();
\r
5314 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5315 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5316 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5317 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5318 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5321 DrawPosition(TRUE, NULL);
\r
5323 switch (gameMode) {
\r
5324 case EditPosition:
\r
5325 case IcsExamining:
\r
5326 if (x < 0 || y < 0) break;
\r
5329 if (message == WM_MBUTTONDOWN) {
\r
5330 buttonCount = 3; /* even if system didn't think so */
\r
5331 if (wParam & MK_SHIFT)
\r
5332 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5334 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5335 } else { /* message == WM_RBUTTONDOWN */
\r
5337 if (buttonCount == 3) {
\r
5338 if (wParam & MK_SHIFT)
\r
5339 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5341 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5343 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5346 /* Just have one menu, on the right button. Windows users don't
\r
5347 think to try the middle one, and sometimes other software steals
\r
5348 it, or it doesn't really exist. */
\r
5349 if(gameInfo.variant != VariantShogi)
\r
5350 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5352 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5356 case IcsPlayingWhite:
\r
5357 case IcsPlayingBlack:
\r
5359 case MachinePlaysWhite:
\r
5360 case MachinePlaysBlack:
\r
5361 if (appData.testLegality &&
\r
5362 gameInfo.variant != VariantBughouse &&
\r
5363 gameInfo.variant != VariantCrazyhouse) break;
\r
5364 if (x < 0 || y < 0) break;
\r
5367 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5368 SetupDropMenu(hmenu);
\r
5369 MenuPopup(hwnd, pt, hmenu, -1);
\r
5380 /* Preprocess messages for buttons in main window */
\r
5382 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5384 int id = GetWindowLong(hwnd, GWL_ID);
\r
5387 for (i=0; i<N_BUTTONS; i++) {
\r
5388 if (buttonDesc[i].id == id) break;
\r
5390 if (i == N_BUTTONS) return 0;
\r
5391 switch (message) {
\r
5396 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5397 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5404 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5407 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5408 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5409 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5410 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5412 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5414 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5415 PopUpMoveDialog((char)wParam);
\r
5421 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5424 /* Process messages for Promotion dialog box */
\r
5426 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5430 switch (message) {
\r
5431 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5432 /* Center the dialog over the application window */
\r
5433 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5434 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5435 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5436 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5437 SW_SHOW : SW_HIDE);
\r
5438 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5439 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5440 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5441 PieceToChar(WhiteAngel) != '~') ||
\r
5442 (PieceToChar(BlackAngel) >= 'A' &&
\r
5443 PieceToChar(BlackAngel) != '~') ) ?
\r
5444 SW_SHOW : SW_HIDE);
\r
5445 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5446 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5447 PieceToChar(WhiteMarshall) != '~') ||
\r
5448 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5449 PieceToChar(BlackMarshall) != '~') ) ?
\r
5450 SW_SHOW : SW_HIDE);
\r
5451 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5452 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5453 gameInfo.variant != VariantShogi ?
\r
5454 SW_SHOW : SW_HIDE);
\r
5455 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5456 gameInfo.variant != VariantShogi ?
\r
5457 SW_SHOW : SW_HIDE);
\r
5458 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5459 gameInfo.variant == VariantShogi ?
\r
5460 SW_SHOW : SW_HIDE);
\r
5461 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5462 gameInfo.variant == VariantShogi ?
\r
5463 SW_SHOW : SW_HIDE);
\r
5464 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5465 gameInfo.variant == VariantSuper ?
\r
5466 SW_SHOW : SW_HIDE);
\r
5469 case WM_COMMAND: /* message: received a command */
\r
5470 switch (LOWORD(wParam)) {
\r
5472 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5473 ClearHighlights();
\r
5474 DrawPosition(FALSE, NULL);
\r
5477 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5480 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5483 promoChar = PieceToChar(BlackRook);
\r
5486 promoChar = PieceToChar(BlackBishop);
\r
5488 case PB_Chancellor:
\r
5489 promoChar = PieceToChar(BlackMarshall);
\r
5491 case PB_Archbishop:
\r
5492 promoChar = PieceToChar(BlackAngel);
\r
5495 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5500 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5501 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5502 only show the popup when we are already sure the move is valid or
\r
5503 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5504 will figure out it is a promotion from the promoChar. */
\r
5505 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5506 if (!appData.highlightLastMove) {
\r
5507 ClearHighlights();
\r
5508 DrawPosition(FALSE, NULL);
\r
5515 /* Pop up promotion dialog */
\r
5517 PromotionPopup(HWND hwnd)
\r
5521 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5522 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5523 hwnd, (DLGPROC)lpProc);
\r
5524 FreeProcInstance(lpProc);
\r
5527 /* Toggle ShowThinking */
\r
5529 ToggleShowThinking()
\r
5531 appData.showThinking = !appData.showThinking;
\r
5532 ShowThinkingEvent();
\r
5536 LoadGameDialog(HWND hwnd, char* title)
\r
5540 char fileTitle[MSG_SIZ];
\r
5541 f = OpenFileDialog(hwnd, "rb", "",
\r
5542 appData.oldSaveStyle ? "gam" : "pgn",
\r
5544 title, &number, fileTitle, NULL);
\r
5546 cmailMsgLoaded = FALSE;
\r
5547 if (number == 0) {
\r
5548 int error = GameListBuild(f);
\r
5550 DisplayError("Cannot build game list", error);
\r
5551 } else if (!ListEmpty(&gameList) &&
\r
5552 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5553 GameListPopUp(f, fileTitle);
\r
5556 GameListDestroy();
\r
5559 LoadGame(f, number, fileTitle, FALSE);
\r
5564 ChangedConsoleFont()
\r
5567 CHARRANGE tmpsel, sel;
\r
5568 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5569 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5570 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5573 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5574 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5575 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5576 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5577 * size. This was undocumented in the version of MSVC++ that I had
\r
5578 * when I wrote the code, but is apparently documented now.
\r
5580 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5581 cfmt.bCharSet = f->lf.lfCharSet;
\r
5582 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5583 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5584 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5585 /* Why are the following seemingly needed too? */
\r
5586 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5587 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5588 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5590 tmpsel.cpMax = -1; /*999999?*/
\r
5591 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5592 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5593 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5594 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5596 paraf.cbSize = sizeof(paraf);
\r
5597 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5598 paraf.dxStartIndent = 0;
\r
5599 paraf.dxOffset = WRAP_INDENT;
\r
5600 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5601 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5604 /*---------------------------------------------------------------------------*\
\r
5606 * Window Proc for main window
\r
5608 \*---------------------------------------------------------------------------*/
\r
5610 /* Process messages for main window, etc. */
\r
5612 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5615 int wmId, wmEvent;
\r
5619 char fileTitle[MSG_SIZ];
\r
5620 char buf[MSG_SIZ];
\r
5621 static SnapData sd;
\r
5623 switch (message) {
\r
5625 case WM_PAINT: /* message: repaint portion of window */
\r
5629 case WM_ERASEBKGND:
\r
5630 if (IsIconic(hwnd)) {
\r
5631 /* Cheat; change the message */
\r
5632 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5634 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5638 case WM_LBUTTONDOWN:
\r
5639 case WM_MBUTTONDOWN:
\r
5640 case WM_RBUTTONDOWN:
\r
5641 case WM_LBUTTONUP:
\r
5642 case WM_MBUTTONUP:
\r
5643 case WM_RBUTTONUP:
\r
5644 case WM_MOUSEMOVE:
\r
5645 case WM_MOUSEWHEEL:
\r
5646 MouseEvent(hwnd, message, wParam, lParam);
\r
5649 JAWS_KB_NAVIGATION
\r
5653 JAWS_ALT_INTERCEPT
\r
5655 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5656 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5657 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5658 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5660 SendMessage(h, message, wParam, lParam);
\r
5661 } else if(lParam != KF_REPEAT) {
\r
5662 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5663 PopUpMoveDialog((char)wParam);
\r
5664 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5665 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5670 case WM_PALETTECHANGED:
\r
5671 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5673 HDC hdc = GetDC(hwndMain);
\r
5674 SelectPalette(hdc, hPal, TRUE);
\r
5675 nnew = RealizePalette(hdc);
\r
5677 paletteChanged = TRUE;
\r
5679 UpdateColors(hdc);
\r
5681 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5684 ReleaseDC(hwnd, hdc);
\r
5688 case WM_QUERYNEWPALETTE:
\r
5689 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5691 HDC hdc = GetDC(hwndMain);
\r
5692 paletteChanged = FALSE;
\r
5693 SelectPalette(hdc, hPal, FALSE);
\r
5694 nnew = RealizePalette(hdc);
\r
5696 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5698 ReleaseDC(hwnd, hdc);
\r
5703 case WM_COMMAND: /* message: command from application menu */
\r
5704 wmId = LOWORD(wParam);
\r
5705 wmEvent = HIWORD(wParam);
\r
5710 AnalysisPopDown();
\r
5711 SAY("new game enter a move to play against the computer with white");
\r
5714 case IDM_NewGameFRC:
\r
5715 if( NewGameFRC() == 0 ) {
\r
5717 AnalysisPopDown();
\r
5721 case IDM_NewVariant:
\r
5722 NewVariantPopup(hwnd);
\r
5725 case IDM_LoadGame:
\r
5726 LoadGameDialog(hwnd, "Load Game from File");
\r
5729 case IDM_LoadNextGame:
\r
5733 case IDM_LoadPrevGame:
\r
5737 case IDM_ReloadGame:
\r
5741 case IDM_LoadPosition:
\r
5742 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5743 Reset(FALSE, TRUE);
\r
5746 f = OpenFileDialog(hwnd, "rb", "",
\r
5747 appData.oldSaveStyle ? "pos" : "fen",
\r
5749 "Load Position from File", &number, fileTitle, NULL);
\r
5751 LoadPosition(f, number, fileTitle);
\r
5755 case IDM_LoadNextPosition:
\r
5756 ReloadPosition(1);
\r
5759 case IDM_LoadPrevPosition:
\r
5760 ReloadPosition(-1);
\r
5763 case IDM_ReloadPosition:
\r
5764 ReloadPosition(0);
\r
5767 case IDM_SaveGame:
\r
5768 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5769 f = OpenFileDialog(hwnd, "a", defName,
\r
5770 appData.oldSaveStyle ? "gam" : "pgn",
\r
5772 "Save Game to File", NULL, fileTitle, NULL);
\r
5774 SaveGame(f, 0, "");
\r
5778 case IDM_SavePosition:
\r
5779 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5780 f = OpenFileDialog(hwnd, "a", defName,
\r
5781 appData.oldSaveStyle ? "pos" : "fen",
\r
5783 "Save Position to File", NULL, fileTitle, NULL);
\r
5785 SavePosition(f, 0, "");
\r
5789 case IDM_SaveDiagram:
\r
5790 defName = "diagram";
\r
5791 f = OpenFileDialog(hwnd, "wb", defName,
\r
5794 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5800 case IDM_CopyGame:
\r
5801 CopyGameToClipboard();
\r
5804 case IDM_PasteGame:
\r
5805 PasteGameFromClipboard();
\r
5808 case IDM_CopyGameListToClipboard:
\r
5809 CopyGameListToClipboard();
\r
5812 /* [AS] Autodetect FEN or PGN data */
\r
5813 case IDM_PasteAny:
\r
5814 PasteGameOrFENFromClipboard();
\r
5817 /* [AS] Move history */
\r
5818 case IDM_ShowMoveHistory:
\r
5819 if( MoveHistoryIsUp() ) {
\r
5820 MoveHistoryPopDown();
\r
5823 MoveHistoryPopUp();
\r
5827 /* [AS] Eval graph */
\r
5828 case IDM_ShowEvalGraph:
\r
5829 if( EvalGraphIsUp() ) {
\r
5830 EvalGraphPopDown();
\r
5834 SetFocus(hwndMain);
\r
5838 /* [AS] Engine output */
\r
5839 case IDM_ShowEngineOutput:
\r
5840 if( EngineOutputIsUp() ) {
\r
5841 EngineOutputPopDown();
\r
5844 EngineOutputPopUp();
\r
5848 /* [AS] User adjudication */
\r
5849 case IDM_UserAdjudication_White:
\r
5850 UserAdjudicationEvent( +1 );
\r
5853 case IDM_UserAdjudication_Black:
\r
5854 UserAdjudicationEvent( -1 );
\r
5857 case IDM_UserAdjudication_Draw:
\r
5858 UserAdjudicationEvent( 0 );
\r
5861 /* [AS] Game list options dialog */
\r
5862 case IDM_GameListOptions:
\r
5863 GameListOptions();
\r
5866 case IDM_CopyPosition:
\r
5867 CopyFENToClipboard();
\r
5870 case IDM_PastePosition:
\r
5871 PasteFENFromClipboard();
\r
5874 case IDM_MailMove:
\r
5878 case IDM_ReloadCMailMsg:
\r
5879 Reset(TRUE, TRUE);
\r
5880 ReloadCmailMsgEvent(FALSE);
\r
5883 case IDM_Minimize:
\r
5884 ShowWindow(hwnd, SW_MINIMIZE);
\r
5891 case IDM_MachineWhite:
\r
5892 MachineWhiteEvent();
\r
5894 * refresh the tags dialog only if it's visible
\r
5896 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5898 tags = PGNTags(&gameInfo);
\r
5899 TagsPopUp(tags, CmailMsg());
\r
5902 SAY("computer starts playing white");
\r
5905 case IDM_MachineBlack:
\r
5906 MachineBlackEvent();
\r
5908 * refresh the tags dialog only if it's visible
\r
5910 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5912 tags = PGNTags(&gameInfo);
\r
5913 TagsPopUp(tags, CmailMsg());
\r
5916 SAY("computer starts playing black");
\r
5919 case IDM_TwoMachines:
\r
5920 TwoMachinesEvent();
\r
5922 * refresh the tags dialog only if it's visible
\r
5924 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5926 tags = PGNTags(&gameInfo);
\r
5927 TagsPopUp(tags, CmailMsg());
\r
5930 SAY("programs start playing each other");
\r
5933 case IDM_AnalysisMode:
\r
5934 if (!first.analysisSupport) {
\r
5935 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5936 DisplayError(buf, 0);
\r
5938 SAY("analyzing current position");
\r
5939 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5940 if (appData.icsActive) {
\r
5941 if (gameMode != IcsObserving) {
\r
5942 sprintf(buf, "You are not observing a game");
\r
5943 DisplayError(buf, 0);
\r
5944 /* secure check */
\r
5945 if (appData.icsEngineAnalyze) {
\r
5946 if (appData.debugMode)
\r
5947 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5948 ExitAnalyzeMode();
\r
5954 /* if enable, user want disable icsEngineAnalyze */
\r
5955 if (appData.icsEngineAnalyze) {
\r
5956 ExitAnalyzeMode();
\r
5960 appData.icsEngineAnalyze = TRUE;
\r
5961 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5964 if (!appData.showThinking) ToggleShowThinking();
\r
5965 AnalyzeModeEvent();
\r
5969 case IDM_AnalyzeFile:
\r
5970 if (!first.analysisSupport) {
\r
5971 char buf[MSG_SIZ];
\r
5972 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5973 DisplayError(buf, 0);
\r
5975 if (!appData.showThinking) ToggleShowThinking();
\r
5976 AnalyzeFileEvent();
\r
5977 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5978 AnalysisPeriodicEvent(1);
\r
5982 case IDM_IcsClient:
\r
5986 case IDM_EditGame:
\r
5991 case IDM_EditPosition:
\r
5992 EditPositionEvent();
\r
5993 SAY("to set up a position type a FEN");
\r
5996 case IDM_Training:
\r
6000 case IDM_ShowGameList:
\r
6001 ShowGameListProc();
\r
6004 case IDM_EditTags:
\r
6008 case IDM_EditComment:
\r
6009 if (commentDialogUp && editComment) {
\r
6012 EditCommentEvent();
\r
6032 case IDM_CallFlag:
\r
6052 case IDM_StopObserving:
\r
6053 StopObservingEvent();
\r
6056 case IDM_StopExamining:
\r
6057 StopExaminingEvent();
\r
6060 case IDM_TypeInMove:
\r
6061 PopUpMoveDialog('\000');
\r
6064 case IDM_TypeInName:
\r
6065 PopUpNameDialog('\000');
\r
6068 case IDM_Backward:
\r
6070 SetFocus(hwndMain);
\r
6077 SetFocus(hwndMain);
\r
6082 SetFocus(hwndMain);
\r
6087 SetFocus(hwndMain);
\r
6094 case IDM_TruncateGame:
\r
6095 TruncateGameEvent();
\r
6102 case IDM_RetractMove:
\r
6103 RetractMoveEvent();
\r
6106 case IDM_FlipView:
\r
6107 flipView = !flipView;
\r
6108 DrawPosition(FALSE, NULL);
\r
6111 case IDM_FlipClock:
\r
6112 flipClock = !flipClock;
\r
6113 DisplayBothClocks();
\r
6114 DrawPosition(FALSE, NULL);
\r
6117 case IDM_GeneralOptions:
\r
6118 GeneralOptionsPopup(hwnd);
\r
6119 DrawPosition(TRUE, NULL);
\r
6122 case IDM_BoardOptions:
\r
6123 BoardOptionsPopup(hwnd);
\r
6126 case IDM_EnginePlayOptions:
\r
6127 EnginePlayOptionsPopup(hwnd);
\r
6130 case IDM_OptionsUCI:
\r
6131 UciOptionsPopup(hwnd);
\r
6134 case IDM_IcsOptions:
\r
6135 IcsOptionsPopup(hwnd);
\r
6139 FontsOptionsPopup(hwnd);
\r
6143 SoundOptionsPopup(hwnd);
\r
6146 case IDM_CommPort:
\r
6147 CommPortOptionsPopup(hwnd);
\r
6150 case IDM_LoadOptions:
\r
6151 LoadOptionsPopup(hwnd);
\r
6154 case IDM_SaveOptions:
\r
6155 SaveOptionsPopup(hwnd);
\r
6158 case IDM_TimeControl:
\r
6159 TimeControlOptionsPopup(hwnd);
\r
6162 case IDM_SaveSettings:
\r
6163 SaveSettings(settingsFileName);
\r
6166 case IDM_SaveSettingsOnExit:
\r
6167 saveSettingsOnExit = !saveSettingsOnExit;
\r
6168 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6169 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6170 MF_CHECKED : MF_UNCHECKED));
\r
6181 case IDM_AboutGame:
\r
6186 appData.debugMode = !appData.debugMode;
\r
6187 if (appData.debugMode) {
\r
6188 char dir[MSG_SIZ];
\r
6189 GetCurrentDirectory(MSG_SIZ, dir);
\r
6190 SetCurrentDirectory(installDir);
\r
6191 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6192 SetCurrentDirectory(dir);
\r
6193 setbuf(debugFP, NULL);
\r
6200 case IDM_HELPCONTENTS:
\r
6201 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6202 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6203 MessageBox (GetFocus(),
\r
6204 "Unable to activate help",
\r
6205 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6209 case IDM_HELPSEARCH:
\r
6210 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6211 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6212 MessageBox (GetFocus(),
\r
6213 "Unable to activate help",
\r
6214 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6218 case IDM_HELPHELP:
\r
6219 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6220 MessageBox (GetFocus(),
\r
6221 "Unable to activate help",
\r
6222 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6227 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6229 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6230 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6231 FreeProcInstance(lpProc);
\r
6234 case IDM_DirectCommand1:
\r
6235 AskQuestionEvent("Direct Command",
\r
6236 "Send to chess program:", "", "1");
\r
6238 case IDM_DirectCommand2:
\r
6239 AskQuestionEvent("Direct Command",
\r
6240 "Send to second chess program:", "", "2");
\r
6243 case EP_WhitePawn:
\r
6244 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6245 fromX = fromY = -1;
\r
6248 case EP_WhiteKnight:
\r
6249 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6250 fromX = fromY = -1;
\r
6253 case EP_WhiteBishop:
\r
6254 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6255 fromX = fromY = -1;
\r
6258 case EP_WhiteRook:
\r
6259 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6260 fromX = fromY = -1;
\r
6263 case EP_WhiteQueen:
\r
6264 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6265 fromX = fromY = -1;
\r
6268 case EP_WhiteFerz:
\r
6269 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6270 fromX = fromY = -1;
\r
6273 case EP_WhiteWazir:
\r
6274 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6275 fromX = fromY = -1;
\r
6278 case EP_WhiteAlfil:
\r
6279 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6280 fromX = fromY = -1;
\r
6283 case EP_WhiteCannon:
\r
6284 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6285 fromX = fromY = -1;
\r
6288 case EP_WhiteCardinal:
\r
6289 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6290 fromX = fromY = -1;
\r
6293 case EP_WhiteMarshall:
\r
6294 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6295 fromX = fromY = -1;
\r
6298 case EP_WhiteKing:
\r
6299 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6300 fromX = fromY = -1;
\r
6303 case EP_BlackPawn:
\r
6304 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6305 fromX = fromY = -1;
\r
6308 case EP_BlackKnight:
\r
6309 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6310 fromX = fromY = -1;
\r
6313 case EP_BlackBishop:
\r
6314 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6315 fromX = fromY = -1;
\r
6318 case EP_BlackRook:
\r
6319 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6320 fromX = fromY = -1;
\r
6323 case EP_BlackQueen:
\r
6324 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6325 fromX = fromY = -1;
\r
6328 case EP_BlackFerz:
\r
6329 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6330 fromX = fromY = -1;
\r
6333 case EP_BlackWazir:
\r
6334 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6335 fromX = fromY = -1;
\r
6338 case EP_BlackAlfil:
\r
6339 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6340 fromX = fromY = -1;
\r
6343 case EP_BlackCannon:
\r
6344 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6345 fromX = fromY = -1;
\r
6348 case EP_BlackCardinal:
\r
6349 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6350 fromX = fromY = -1;
\r
6353 case EP_BlackMarshall:
\r
6354 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6355 fromX = fromY = -1;
\r
6358 case EP_BlackKing:
\r
6359 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6360 fromX = fromY = -1;
\r
6363 case EP_EmptySquare:
\r
6364 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6365 fromX = fromY = -1;
\r
6368 case EP_ClearBoard:
\r
6369 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6370 fromX = fromY = -1;
\r
6374 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6375 fromX = fromY = -1;
\r
6379 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6380 fromX = fromY = -1;
\r
6384 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6385 fromX = fromY = -1;
\r
6389 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6390 fromX = fromY = -1;
\r
6394 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6395 fromX = fromY = -1;
\r
6399 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6400 fromX = fromY = -1;
\r
6404 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6405 fromX = fromY = -1;
\r
6409 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6410 fromX = fromY = -1;
\r
6414 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6415 fromX = fromY = -1;
\r
6419 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6425 case CLOCK_TIMER_ID:
\r
6426 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6427 clockTimerEvent = 0;
\r
6428 DecrementClocks(); /* call into back end */
\r
6430 case LOAD_GAME_TIMER_ID:
\r
6431 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6432 loadGameTimerEvent = 0;
\r
6433 AutoPlayGameLoop(); /* call into back end */
\r
6435 case ANALYSIS_TIMER_ID:
\r
6436 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6437 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6438 AnalysisPeriodicEvent(0);
\r
6440 KillTimer(hwnd, analysisTimerEvent);
\r
6441 analysisTimerEvent = 0;
\r
6444 case DELAYED_TIMER_ID:
\r
6445 KillTimer(hwnd, delayedTimerEvent);
\r
6446 delayedTimerEvent = 0;
\r
6447 delayedTimerCallback();
\r
6452 case WM_USER_Input:
\r
6453 InputEvent(hwnd, message, wParam, lParam);
\r
6456 /* [AS] Also move "attached" child windows */
\r
6457 case WM_WINDOWPOSCHANGING:
\r
6459 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6460 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6462 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6463 /* Window is moving */
\r
6466 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6467 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6468 rcMain.right = boardX + winWidth;
\r
6469 rcMain.top = boardY;
\r
6470 rcMain.bottom = boardY + winHeight;
\r
6472 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6473 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6474 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6475 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6476 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6483 /* [AS] Snapping */
\r
6484 case WM_ENTERSIZEMOVE:
\r
6485 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6486 if (hwnd == hwndMain) {
\r
6487 doingSizing = TRUE;
\r
6490 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6494 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6495 if (hwnd == hwndMain) {
\r
6496 lastSizing = wParam;
\r
6501 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6502 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6504 case WM_EXITSIZEMOVE:
\r
6505 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6506 if (hwnd == hwndMain) {
\r
6508 doingSizing = FALSE;
\r
6509 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6510 GetClientRect(hwnd, &client);
\r
6511 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6513 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6515 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6518 case WM_DESTROY: /* message: window being destroyed */
\r
6519 PostQuitMessage(0);
\r
6523 if (hwnd == hwndMain) {
\r
6528 default: /* Passes it on if unprocessed */
\r
6529 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6534 /*---------------------------------------------------------------------------*\
\r
6536 * Misc utility routines
\r
6538 \*---------------------------------------------------------------------------*/
\r
6541 * Decent random number generator, at least not as bad as Windows
\r
6542 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6544 unsigned int randstate;
\r
6549 randstate = randstate * 1664525 + 1013904223;
\r
6550 return (int) randstate & 0x7fffffff;
\r
6554 mysrandom(unsigned int seed)
\r
6561 * returns TRUE if user selects a different color, FALSE otherwise
\r
6565 ChangeColor(HWND hwnd, COLORREF *which)
\r
6567 static BOOL firstTime = TRUE;
\r
6568 static DWORD customColors[16];
\r
6570 COLORREF newcolor;
\r
6575 /* Make initial colors in use available as custom colors */
\r
6576 /* Should we put the compiled-in defaults here instead? */
\r
6578 customColors[i++] = lightSquareColor & 0xffffff;
\r
6579 customColors[i++] = darkSquareColor & 0xffffff;
\r
6580 customColors[i++] = whitePieceColor & 0xffffff;
\r
6581 customColors[i++] = blackPieceColor & 0xffffff;
\r
6582 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6583 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6585 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6586 customColors[i++] = textAttribs[ccl].color;
\r
6588 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6589 firstTime = FALSE;
\r
6592 cc.lStructSize = sizeof(cc);
\r
6593 cc.hwndOwner = hwnd;
\r
6594 cc.hInstance = NULL;
\r
6595 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6596 cc.lpCustColors = (LPDWORD) customColors;
\r
6597 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6599 if (!ChooseColor(&cc)) return FALSE;
\r
6601 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6602 if (newcolor == *which) return FALSE;
\r
6603 *which = newcolor;
\r
6607 InitDrawingColors();
\r
6608 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6613 MyLoadSound(MySound *ms)
\r
6619 if (ms->data) free(ms->data);
\r
6622 switch (ms->name[0]) {
\r
6628 /* System sound from Control Panel. Don't preload here. */
\r
6632 if (ms->name[1] == NULLCHAR) {
\r
6633 /* "!" alone = silence */
\r
6636 /* Builtin wave resource. Error if not found. */
\r
6637 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6638 if (h == NULL) break;
\r
6639 ms->data = (void *)LoadResource(hInst, h);
\r
6640 if (h == NULL) break;
\r
6645 /* .wav file. Error if not found. */
\r
6646 f = fopen(ms->name, "rb");
\r
6647 if (f == NULL) break;
\r
6648 if (fstat(fileno(f), &st) < 0) break;
\r
6649 ms->data = malloc(st.st_size);
\r
6650 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6656 char buf[MSG_SIZ];
\r
6657 sprintf(buf, "Error loading sound %s", ms->name);
\r
6658 DisplayError(buf, GetLastError());
\r
6664 MyPlaySound(MySound *ms)
\r
6666 BOOLEAN ok = FALSE;
\r
6668 switch (ms->name[0]) {
\r
6670 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6675 /* System sound from Control Panel (deprecated feature).
\r
6676 "$" alone or an unset sound name gets default beep (still in use). */
\r
6677 if (ms->name[1]) {
\r
6678 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6680 if (!ok) ok = MessageBeep(MB_OK);
\r
6683 /* Builtin wave resource, or "!" alone for silence */
\r
6684 if (ms->name[1]) {
\r
6685 if (ms->data == NULL) return FALSE;
\r
6686 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6692 /* .wav file. Error if not found. */
\r
6693 if (ms->data == NULL) return FALSE;
\r
6694 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6697 /* Don't print an error: this can happen innocently if the sound driver
\r
6698 is busy; for instance, if another instance of WinBoard is playing
\r
6699 a sound at about the same time. */
\r
6702 char buf[MSG_SIZ];
\r
6703 sprintf(buf, "Error playing sound %s", ms->name);
\r
6704 DisplayError(buf, GetLastError());
\r
6712 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6715 OPENFILENAME *ofn;
\r
6716 static UINT *number; /* gross that this is static */
\r
6718 switch (message) {
\r
6719 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6720 /* Center the dialog over the application window */
\r
6721 ofn = (OPENFILENAME *) lParam;
\r
6722 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6723 number = (UINT *) ofn->lCustData;
\r
6724 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6728 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6729 return FALSE; /* Allow for further processing */
\r
6732 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6733 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6735 return FALSE; /* Allow for further processing */
\r
6741 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6743 static UINT *number;
\r
6744 OPENFILENAME *ofname;
\r
6747 case WM_INITDIALOG:
\r
6748 ofname = (OPENFILENAME *)lParam;
\r
6749 number = (UINT *)(ofname->lCustData);
\r
6752 ofnot = (OFNOTIFY *)lParam;
\r
6753 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6754 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6763 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6764 char *nameFilt, char *dlgTitle, UINT *number,
\r
6765 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6767 OPENFILENAME openFileName;
\r
6768 char buf1[MSG_SIZ];
\r
6771 if (fileName == NULL) fileName = buf1;
\r
6772 if (defName == NULL) {
\r
6773 strcpy(fileName, "*.");
\r
6774 strcat(fileName, defExt);
\r
6776 strcpy(fileName, defName);
\r
6778 if (fileTitle) strcpy(fileTitle, "");
\r
6779 if (number) *number = 0;
\r
6781 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6782 openFileName.hwndOwner = hwnd;
\r
6783 openFileName.hInstance = (HANDLE) hInst;
\r
6784 openFileName.lpstrFilter = nameFilt;
\r
6785 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6786 openFileName.nMaxCustFilter = 0L;
\r
6787 openFileName.nFilterIndex = 1L;
\r
6788 openFileName.lpstrFile = fileName;
\r
6789 openFileName.nMaxFile = MSG_SIZ;
\r
6790 openFileName.lpstrFileTitle = fileTitle;
\r
6791 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6792 openFileName.lpstrInitialDir = NULL;
\r
6793 openFileName.lpstrTitle = dlgTitle;
\r
6794 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6795 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6796 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6797 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6798 openFileName.nFileOffset = 0;
\r
6799 openFileName.nFileExtension = 0;
\r
6800 openFileName.lpstrDefExt = defExt;
\r
6801 openFileName.lCustData = (LONG) number;
\r
6802 openFileName.lpfnHook = oldDialog ?
\r
6803 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6804 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6806 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6807 GetOpenFileName(&openFileName)) {
\r
6808 /* open the file */
\r
6809 f = fopen(openFileName.lpstrFile, write);
\r
6811 MessageBox(hwnd, "File open failed", NULL,
\r
6812 MB_OK|MB_ICONEXCLAMATION);
\r
6816 int err = CommDlgExtendedError();
\r
6817 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6826 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6828 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6831 * Get the first pop-up menu in the menu template. This is the
\r
6832 * menu that TrackPopupMenu displays.
\r
6834 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6836 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6839 * TrackPopup uses screen coordinates, so convert the
\r
6840 * coordinates of the mouse click to screen coordinates.
\r
6842 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6844 /* Draw and track the floating pop-up menu. */
\r
6845 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6846 pt.x, pt.y, 0, hwnd, NULL);
\r
6848 /* Destroy the menu.*/
\r
6849 DestroyMenu(hmenu);
\r
6854 int sizeX, sizeY, newSizeX, newSizeY;
\r
6856 } ResizeEditPlusButtonsClosure;
\r
6859 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6861 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6865 if (hChild == cl->hText) return TRUE;
\r
6866 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6867 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6868 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6869 ScreenToClient(cl->hDlg, &pt);
\r
6870 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6871 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6875 /* Resize a dialog that has a (rich) edit field filling most of
\r
6876 the top, with a row of buttons below */
\r
6878 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6881 int newTextHeight, newTextWidth;
\r
6882 ResizeEditPlusButtonsClosure cl;
\r
6884 /*if (IsIconic(hDlg)) return;*/
\r
6885 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6887 cl.hdwp = BeginDeferWindowPos(8);
\r
6889 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6890 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6891 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6892 if (newTextHeight < 0) {
\r
6893 newSizeY += -newTextHeight;
\r
6894 newTextHeight = 0;
\r
6896 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6897 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6903 cl.newSizeX = newSizeX;
\r
6904 cl.newSizeY = newSizeY;
\r
6905 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6907 EndDeferWindowPos(cl.hdwp);
\r
6910 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6912 RECT rChild, rParent;
\r
6913 int wChild, hChild, wParent, hParent;
\r
6914 int wScreen, hScreen, xNew, yNew;
\r
6917 /* Get the Height and Width of the child window */
\r
6918 GetWindowRect (hwndChild, &rChild);
\r
6919 wChild = rChild.right - rChild.left;
\r
6920 hChild = rChild.bottom - rChild.top;
\r
6922 /* Get the Height and Width of the parent window */
\r
6923 GetWindowRect (hwndParent, &rParent);
\r
6924 wParent = rParent.right - rParent.left;
\r
6925 hParent = rParent.bottom - rParent.top;
\r
6927 /* Get the display limits */
\r
6928 hdc = GetDC (hwndChild);
\r
6929 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6930 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6931 ReleaseDC(hwndChild, hdc);
\r
6933 /* Calculate new X position, then adjust for screen */
\r
6934 xNew = rParent.left + ((wParent - wChild) /2);
\r
6937 } else if ((xNew+wChild) > wScreen) {
\r
6938 xNew = wScreen - wChild;
\r
6941 /* Calculate new Y position, then adjust for screen */
\r
6943 yNew = rParent.top + ((hParent - hChild) /2);
\r
6946 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6951 } else if ((yNew+hChild) > hScreen) {
\r
6952 yNew = hScreen - hChild;
\r
6955 /* Set it, and return */
\r
6956 return SetWindowPos (hwndChild, NULL,
\r
6957 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6960 /* Center one window over another */
\r
6961 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6963 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6966 /*---------------------------------------------------------------------------*\
\r
6968 * Startup Dialog functions
\r
6970 \*---------------------------------------------------------------------------*/
\r
6972 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6974 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6976 while (*cd != NULL) {
\r
6977 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6983 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6985 char buf1[ARG_MAX];
\r
6988 if (str[0] == '@') {
\r
6989 FILE* f = fopen(str + 1, "r");
\r
6991 DisplayFatalError(str + 1, errno, 2);
\r
6994 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6996 buf1[len] = NULLCHAR;
\r
7000 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7003 char buf[MSG_SIZ];
\r
7004 char *end = strchr(str, '\n');
\r
7005 if (end == NULL) return;
\r
7006 memcpy(buf, str, end - str);
\r
7007 buf[end - str] = NULLCHAR;
\r
7008 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7014 SetStartupDialogEnables(HWND hDlg)
\r
7016 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7017 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7018 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7019 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7020 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7021 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7022 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7023 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7024 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7025 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7026 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7027 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7028 IsDlgButtonChecked(hDlg, OPT_View));
\r
7032 QuoteForFilename(char *filename)
\r
7034 int dquote, space;
\r
7035 dquote = strchr(filename, '"') != NULL;
\r
7036 space = strchr(filename, ' ') != NULL;
\r
7037 if (dquote || space) {
\r
7049 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7051 char buf[MSG_SIZ];
\r
7054 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7055 q = QuoteForFilename(nthcp);
\r
7056 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7057 if (*nthdir != NULLCHAR) {
\r
7058 q = QuoteForFilename(nthdir);
\r
7059 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7061 if (*nthcp == NULLCHAR) {
\r
7062 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7063 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7064 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7065 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7070 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7072 char buf[MSG_SIZ];
\r
7076 switch (message) {
\r
7077 case WM_INITDIALOG:
\r
7078 /* Center the dialog */
\r
7079 CenterWindow (hDlg, GetDesktopWindow());
\r
7080 /* Initialize the dialog items */
\r
7081 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7082 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7083 firstChessProgramNames);
\r
7084 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7085 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7086 secondChessProgramNames);
\r
7087 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7088 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7089 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7090 if (*appData.icsHelper != NULLCHAR) {
\r
7091 char *q = QuoteForFilename(appData.icsHelper);
\r
7092 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7094 if (*appData.icsHost == NULLCHAR) {
\r
7095 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7096 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7097 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7098 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7099 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7102 if (appData.icsActive) {
\r
7103 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7105 else if (appData.noChessProgram) {
\r
7106 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7109 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7112 SetStartupDialogEnables(hDlg);
\r
7116 switch (LOWORD(wParam)) {
\r
7118 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7119 strcpy(buf, "/fcp=");
\r
7120 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7122 ParseArgs(StringGet, &p);
\r
7123 strcpy(buf, "/scp=");
\r
7124 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7126 ParseArgs(StringGet, &p);
\r
7127 appData.noChessProgram = FALSE;
\r
7128 appData.icsActive = FALSE;
\r
7129 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7130 strcpy(buf, "/ics /icshost=");
\r
7131 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7133 ParseArgs(StringGet, &p);
\r
7134 if (appData.zippyPlay) {
\r
7135 strcpy(buf, "/fcp=");
\r
7136 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7138 ParseArgs(StringGet, &p);
\r
7140 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7141 appData.noChessProgram = TRUE;
\r
7142 appData.icsActive = FALSE;
\r
7144 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7145 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7148 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7149 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7151 ParseArgs(StringGet, &p);
\r
7153 EndDialog(hDlg, TRUE);
\r
7160 case IDM_HELPCONTENTS:
\r
7161 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7162 MessageBox (GetFocus(),
\r
7163 "Unable to activate help",
\r
7164 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7169 SetStartupDialogEnables(hDlg);
\r
7177 /*---------------------------------------------------------------------------*\
\r
7179 * About box dialog functions
\r
7181 \*---------------------------------------------------------------------------*/
\r
7183 /* Process messages for "About" dialog box */
\r
7185 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7187 switch (message) {
\r
7188 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7189 /* Center the dialog over the application window */
\r
7190 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7191 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7195 case WM_COMMAND: /* message: received a command */
\r
7196 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7197 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7198 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7206 /*---------------------------------------------------------------------------*\
\r
7208 * Comment Dialog functions
\r
7210 \*---------------------------------------------------------------------------*/
\r
7213 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7215 static HANDLE hwndText = NULL;
\r
7216 int len, newSizeX, newSizeY, flags;
\r
7217 static int sizeX, sizeY;
\r
7222 switch (message) {
\r
7223 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7224 /* Initialize the dialog items */
\r
7225 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7226 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7227 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7228 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7229 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7230 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7231 SetWindowText(hDlg, commentTitle);
\r
7232 if (editComment) {
\r
7233 SetFocus(hwndText);
\r
7235 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7237 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7238 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7239 MAKELPARAM(FALSE, 0));
\r
7240 /* Size and position the dialog */
\r
7241 if (!commentDialog) {
\r
7242 commentDialog = hDlg;
\r
7243 flags = SWP_NOZORDER;
\r
7244 GetClientRect(hDlg, &rect);
\r
7245 sizeX = rect.right;
\r
7246 sizeY = rect.bottom;
\r
7247 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7248 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7249 WINDOWPLACEMENT wp;
\r
7250 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7251 wp.length = sizeof(WINDOWPLACEMENT);
\r
7253 wp.showCmd = SW_SHOW;
\r
7254 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7255 wp.rcNormalPosition.left = commentX;
\r
7256 wp.rcNormalPosition.right = commentX + commentW;
\r
7257 wp.rcNormalPosition.top = commentY;
\r
7258 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7259 SetWindowPlacement(hDlg, &wp);
\r
7261 GetClientRect(hDlg, &rect);
\r
7262 newSizeX = rect.right;
\r
7263 newSizeY = rect.bottom;
\r
7264 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7265 newSizeX, newSizeY);
\r
7272 case WM_COMMAND: /* message: received a command */
\r
7273 switch (LOWORD(wParam)) {
\r
7275 if (editComment) {
\r
7277 /* Read changed options from the dialog box */
\r
7278 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7279 len = GetWindowTextLength(hwndText);
\r
7280 str = (char *) malloc(len + 1);
\r
7281 GetWindowText(hwndText, str, len + 1);
\r
7290 ReplaceComment(commentIndex, str);
\r
7297 case OPT_CancelComment:
\r
7301 case OPT_ClearComment:
\r
7302 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7305 case OPT_EditComment:
\r
7306 EditCommentEvent();
\r
7315 newSizeX = LOWORD(lParam);
\r
7316 newSizeY = HIWORD(lParam);
\r
7317 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7322 case WM_GETMINMAXINFO:
\r
7323 /* Prevent resizing window too small */
\r
7324 mmi = (MINMAXINFO *) lParam;
\r
7325 mmi->ptMinTrackSize.x = 100;
\r
7326 mmi->ptMinTrackSize.y = 100;
\r
7333 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7338 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7340 if (str == NULL) str = "";
\r
7341 p = (char *) malloc(2 * strlen(str) + 2);
\r
7344 if (*str == '\n') *q++ = '\r';
\r
7348 if (commentText != NULL) free(commentText);
\r
7350 commentIndex = index;
\r
7351 commentTitle = title;
\r
7353 editComment = edit;
\r
7355 if (commentDialog) {
\r
7356 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7357 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7359 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7360 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7361 hwndMain, (DLGPROC)lpProc);
\r
7362 FreeProcInstance(lpProc);
\r
7364 commentDialogUp = TRUE;
\r
7368 /*---------------------------------------------------------------------------*\
\r
7370 * Type-in move dialog functions
\r
7372 \*---------------------------------------------------------------------------*/
\r
7375 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7377 char move[MSG_SIZ];
\r
7379 ChessMove moveType;
\r
7380 int fromX, fromY, toX, toY;
\r
7383 switch (message) {
\r
7384 case WM_INITDIALOG:
\r
7385 move[0] = (char) lParam;
\r
7386 move[1] = NULLCHAR;
\r
7387 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7388 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7389 SetWindowText(hInput, move);
\r
7391 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7395 switch (LOWORD(wParam)) {
\r
7397 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7398 { int n; Board board;
\r
7400 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7401 EditPositionPasteFEN(move);
\r
7402 EndDialog(hDlg, TRUE);
\r
7405 // [HGM] movenum: allow move number to be typed in any mode
\r
7406 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7407 currentMove = 2*n-1;
\r
7408 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7409 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7410 EndDialog(hDlg, TRUE);
\r
7411 DrawPosition(TRUE, boards[currentMove]);
\r
7412 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7413 else DisplayMessage("", "");
\r
7417 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7418 gameMode != Training) {
\r
7419 DisplayMoveError("Displayed move is not current");
\r
7421 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7422 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7423 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7424 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7425 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7426 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7427 if (gameMode != Training)
\r
7428 forwardMostMove = currentMove;
\r
7429 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7431 DisplayMoveError("Could not parse move");
\r
7434 EndDialog(hDlg, TRUE);
\r
7437 EndDialog(hDlg, FALSE);
\r
7448 PopUpMoveDialog(char firstchar)
\r
7452 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7453 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7454 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7455 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7456 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7457 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7458 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7459 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7460 gameMode == Training) {
\r
7461 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7462 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7463 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7464 FreeProcInstance(lpProc);
\r
7468 /*---------------------------------------------------------------------------*\
\r
7470 * Type-in name dialog functions
\r
7472 \*---------------------------------------------------------------------------*/
\r
7475 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7477 char move[MSG_SIZ];
\r
7480 switch (message) {
\r
7481 case WM_INITDIALOG:
\r
7482 move[0] = (char) lParam;
\r
7483 move[1] = NULLCHAR;
\r
7484 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7485 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7486 SetWindowText(hInput, move);
\r
7488 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7492 switch (LOWORD(wParam)) {
\r
7494 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7495 appData.userName = strdup(move);
\r
7498 EndDialog(hDlg, TRUE);
\r
7501 EndDialog(hDlg, FALSE);
\r
7512 PopUpNameDialog(char firstchar)
\r
7516 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7517 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7518 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7519 FreeProcInstance(lpProc);
\r
7522 /*---------------------------------------------------------------------------*\
\r
7526 \*---------------------------------------------------------------------------*/
\r
7528 /* Nonmodal error box */
\r
7529 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7530 WPARAM wParam, LPARAM lParam);
\r
7533 ErrorPopUp(char *title, char *content)
\r
7537 BOOLEAN modal = hwndMain == NULL;
\r
7555 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7556 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7559 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7561 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7562 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7563 hwndMain, (DLGPROC)lpProc);
\r
7564 FreeProcInstance(lpProc);
\r
7571 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7572 if (errorDialog == NULL) return;
\r
7573 DestroyWindow(errorDialog);
\r
7574 errorDialog = NULL;
\r
7578 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7583 switch (message) {
\r
7584 case WM_INITDIALOG:
\r
7585 GetWindowRect(hDlg, &rChild);
\r
7588 SetWindowPos(hDlg, NULL, rChild.left,
\r
7589 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7590 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7594 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7595 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7596 and it doesn't work when you resize the dialog.
\r
7597 For now, just give it a default position.
\r
7599 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7601 errorDialog = hDlg;
\r
7602 SetWindowText(hDlg, errorTitle);
\r
7603 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7604 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7608 switch (LOWORD(wParam)) {
\r
7611 if (errorDialog == hDlg) errorDialog = NULL;
\r
7612 DestroyWindow(hDlg);
\r
7624 HWND gothicDialog = NULL;
\r
7627 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7631 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7633 switch (message) {
\r
7634 case WM_INITDIALOG:
\r
7635 GetWindowRect(hDlg, &rChild);
\r
7637 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7641 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7642 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7643 and it doesn't work when you resize the dialog.
\r
7644 For now, just give it a default position.
\r
7646 gothicDialog = hDlg;
\r
7647 SetWindowText(hDlg, errorTitle);
\r
7648 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7649 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7653 switch (LOWORD(wParam)) {
\r
7656 if (errorDialog == hDlg) errorDialog = NULL;
\r
7657 DestroyWindow(hDlg);
\r
7669 GothicPopUp(char *title, VariantClass variant)
\r
7672 static char *lastTitle;
\r
7674 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7675 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7677 if(lastTitle != title && gothicDialog != NULL) {
\r
7678 DestroyWindow(gothicDialog);
\r
7679 gothicDialog = NULL;
\r
7681 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7682 title = lastTitle;
\r
7683 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7684 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7685 hwndMain, (DLGPROC)lpProc);
\r
7686 FreeProcInstance(lpProc);
\r
7691 /*---------------------------------------------------------------------------*\
\r
7693 * Ics Interaction console functions
\r
7695 \*---------------------------------------------------------------------------*/
\r
7697 #define HISTORY_SIZE 64
\r
7698 static char *history[HISTORY_SIZE];
\r
7699 int histIn = 0, histP = 0;
\r
7702 SaveInHistory(char *cmd)
\r
7704 if (history[histIn] != NULL) {
\r
7705 free(history[histIn]);
\r
7706 history[histIn] = NULL;
\r
7708 if (*cmd == NULLCHAR) return;
\r
7709 history[histIn] = StrSave(cmd);
\r
7710 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7711 if (history[histIn] != NULL) {
\r
7712 free(history[histIn]);
\r
7713 history[histIn] = NULL;
\r
7719 PrevInHistory(char *cmd)
\r
7722 if (histP == histIn) {
\r
7723 if (history[histIn] != NULL) free(history[histIn]);
\r
7724 history[histIn] = StrSave(cmd);
\r
7726 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7727 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7729 return history[histP];
\r
7735 if (histP == histIn) return NULL;
\r
7736 histP = (histP + 1) % HISTORY_SIZE;
\r
7737 return history[histP];
\r
7744 BOOLEAN immediate;
\r
7745 } IcsTextMenuEntry;
\r
7746 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7747 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7750 ParseIcsTextMenu(char *icsTextMenuString)
\r
7753 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7754 char *p = icsTextMenuString;
\r
7755 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7758 if (e->command != NULL) {
\r
7760 e->command = NULL;
\r
7764 e = icsTextMenuEntry;
\r
7765 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7766 if (*p == ';' || *p == '\n') {
\r
7767 e->item = strdup("-");
\r
7768 e->command = NULL;
\r
7770 } else if (*p == '-') {
\r
7771 e->item = strdup("-");
\r
7772 e->command = NULL;
\r
7776 char *q, *r, *s, *t;
\r
7778 q = strchr(p, ',');
\r
7779 if (q == NULL) break;
\r
7781 r = strchr(q + 1, ',');
\r
7782 if (r == NULL) break;
\r
7784 s = strchr(r + 1, ',');
\r
7785 if (s == NULL) break;
\r
7788 t = strchr(s + 1, c);
\r
7791 t = strchr(s + 1, c);
\r
7793 if (t != NULL) *t = NULLCHAR;
\r
7794 e->item = strdup(p);
\r
7795 e->command = strdup(q + 1);
\r
7796 e->getname = *(r + 1) != '0';
\r
7797 e->immediate = *(s + 1) != '0';
\r
7801 if (t == NULL) break;
\r
7810 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7814 hmenu = LoadMenu(hInst, "TextMenu");
\r
7815 h = GetSubMenu(hmenu, 0);
\r
7817 if (strcmp(e->item, "-") == 0) {
\r
7818 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7820 if (e->item[0] == '|') {
\r
7821 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7822 IDM_CommandX + i, &e->item[1]);
\r
7824 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7833 WNDPROC consoleTextWindowProc;
\r
7836 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7838 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7839 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7843 SetWindowText(hInput, command);
\r
7845 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7847 sel.cpMin = 999999;
\r
7848 sel.cpMax = 999999;
\r
7849 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7854 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7855 if (sel.cpMin == sel.cpMax) {
\r
7856 /* Expand to surrounding word */
\r
7859 tr.chrg.cpMax = sel.cpMin;
\r
7860 tr.chrg.cpMin = --sel.cpMin;
\r
7861 if (sel.cpMin < 0) break;
\r
7862 tr.lpstrText = name;
\r
7863 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7864 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7868 tr.chrg.cpMin = sel.cpMax;
\r
7869 tr.chrg.cpMax = ++sel.cpMax;
\r
7870 tr.lpstrText = name;
\r
7871 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7872 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7875 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7876 MessageBeep(MB_ICONEXCLAMATION);
\r
7880 tr.lpstrText = name;
\r
7881 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7883 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7884 MessageBeep(MB_ICONEXCLAMATION);
\r
7887 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7890 sprintf(buf, "%s %s", command, name);
\r
7891 SetWindowText(hInput, buf);
\r
7892 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7894 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7895 SetWindowText(hInput, buf);
\r
7896 sel.cpMin = 999999;
\r
7897 sel.cpMax = 999999;
\r
7898 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7904 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7909 switch (message) {
\r
7911 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7914 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7917 sel.cpMin = 999999;
\r
7918 sel.cpMax = 999999;
\r
7919 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7920 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7925 if(wParam != '\022') {
\r
7926 if (wParam == '\t') {
\r
7927 if (GetKeyState(VK_SHIFT) < 0) {
\r
7929 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7930 if (buttonDesc[0].hwnd) {
\r
7931 SetFocus(buttonDesc[0].hwnd);
\r
7933 SetFocus(hwndMain);
\r
7937 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7940 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7941 JAWS_DELETE( SetFocus(hInput); )
\r
7942 SendMessage(hInput, message, wParam, lParam);
\r
7945 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7946 case WM_RBUTTONUP:
\r
7947 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7948 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7949 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7952 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7953 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7954 if (sel.cpMin == sel.cpMax) {
\r
7955 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7956 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7958 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7959 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7961 pt.x = LOWORD(lParam);
\r
7962 pt.y = HIWORD(lParam);
\r
7963 MenuPopup(hwnd, pt, hmenu, -1);
\r
7967 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7969 return SendMessage(hInput, message, wParam, lParam);
\r
7970 case WM_MBUTTONDOWN:
\r
7971 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7972 case WM_RBUTTONDOWN:
\r
7973 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7974 /* Move selection here if it was empty */
\r
7976 pt.x = LOWORD(lParam);
\r
7977 pt.y = HIWORD(lParam);
\r
7978 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7979 if (sel.cpMin == sel.cpMax) {
\r
7980 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7981 sel.cpMax = sel.cpMin;
\r
7982 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7984 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7988 switch (LOWORD(wParam)) {
\r
7989 case IDM_QuickPaste:
\r
7991 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7992 if (sel.cpMin == sel.cpMax) {
\r
7993 MessageBeep(MB_ICONEXCLAMATION);
\r
7996 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7997 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7998 SendMessage(hInput, WM_PASTE, 0, 0);
\r
8003 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8006 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8009 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8013 int i = LOWORD(wParam) - IDM_CommandX;
\r
8014 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8015 icsTextMenuEntry[i].command != NULL) {
\r
8016 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8017 icsTextMenuEntry[i].getname,
\r
8018 icsTextMenuEntry[i].immediate);
\r
8026 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8029 WNDPROC consoleInputWindowProc;
\r
8032 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8034 char buf[MSG_SIZ];
\r
8036 static BOOL sendNextChar = FALSE;
\r
8037 static BOOL quoteNextChar = FALSE;
\r
8038 InputSource *is = consoleInputSource;
\r
8042 switch (message) {
\r
8044 if (!appData.localLineEditing || sendNextChar) {
\r
8045 is->buf[0] = (CHAR) wParam;
\r
8047 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8048 sendNextChar = FALSE;
\r
8051 if (quoteNextChar) {
\r
8052 buf[0] = (char) wParam;
\r
8053 buf[1] = NULLCHAR;
\r
8054 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8055 quoteNextChar = FALSE;
\r
8059 case '\r': /* Enter key */
\r
8060 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8061 if (consoleEcho) SaveInHistory(is->buf);
\r
8062 is->buf[is->count++] = '\n';
\r
8063 is->buf[is->count] = NULLCHAR;
\r
8064 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8065 if (consoleEcho) {
\r
8066 ConsoleOutput(is->buf, is->count, TRUE);
\r
8067 } else if (appData.localLineEditing) {
\r
8068 ConsoleOutput("\n", 1, TRUE);
\r
8071 case '\033': /* Escape key */
\r
8072 SetWindowText(hwnd, "");
\r
8073 cf.cbSize = sizeof(CHARFORMAT);
\r
8074 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8075 if (consoleEcho) {
\r
8076 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8078 cf.crTextColor = COLOR_ECHOOFF;
\r
8080 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8081 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8083 case '\t': /* Tab key */
\r
8084 if (GetKeyState(VK_SHIFT) < 0) {
\r
8086 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8089 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8090 if (buttonDesc[0].hwnd) {
\r
8091 SetFocus(buttonDesc[0].hwnd);
\r
8093 SetFocus(hwndMain);
\r
8097 case '\023': /* Ctrl+S */
\r
8098 sendNextChar = TRUE;
\r
8100 case '\021': /* Ctrl+Q */
\r
8101 quoteNextChar = TRUE;
\r
8111 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8112 p = PrevInHistory(buf);
\r
8114 SetWindowText(hwnd, p);
\r
8115 sel.cpMin = 999999;
\r
8116 sel.cpMax = 999999;
\r
8117 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8122 p = NextInHistory();
\r
8124 SetWindowText(hwnd, p);
\r
8125 sel.cpMin = 999999;
\r
8126 sel.cpMax = 999999;
\r
8127 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8133 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8137 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8141 case WM_MBUTTONDOWN:
\r
8142 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8143 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8145 case WM_RBUTTONUP:
\r
8146 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8147 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8148 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8152 hmenu = LoadMenu(hInst, "InputMenu");
\r
8153 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8154 if (sel.cpMin == sel.cpMax) {
\r
8155 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8156 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8158 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8159 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8161 pt.x = LOWORD(lParam);
\r
8162 pt.y = HIWORD(lParam);
\r
8163 MenuPopup(hwnd, pt, hmenu, -1);
\r
8167 switch (LOWORD(wParam)) {
\r
8169 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8171 case IDM_SelectAll:
\r
8173 sel.cpMax = -1; /*999999?*/
\r
8174 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8177 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8180 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8183 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8188 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8191 #define CO_MAX 100000
\r
8192 #define CO_TRIM 1000
\r
8195 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8197 static SnapData sd;
\r
8198 static HWND hText, hInput /*, hFocus*/;
\r
8199 // InputSource *is = consoleInputSource;
\r
8201 static int sizeX, sizeY;
\r
8202 int newSizeX, newSizeY;
\r
8205 switch (message) {
\r
8206 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8207 hwndConsole = hDlg;
\r
8208 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8209 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8211 consoleTextWindowProc = (WNDPROC)
\r
8212 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8213 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8214 consoleInputWindowProc = (WNDPROC)
\r
8215 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8216 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8217 Colorize(ColorNormal, TRUE);
\r
8218 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8219 ChangedConsoleFont();
\r
8220 GetClientRect(hDlg, &rect);
\r
8221 sizeX = rect.right;
\r
8222 sizeY = rect.bottom;
\r
8223 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8224 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8225 WINDOWPLACEMENT wp;
\r
8226 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8227 wp.length = sizeof(WINDOWPLACEMENT);
\r
8229 wp.showCmd = SW_SHOW;
\r
8230 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8231 wp.rcNormalPosition.left = wpConsole.x;
\r
8232 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8233 wp.rcNormalPosition.top = wpConsole.y;
\r
8234 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8235 SetWindowPlacement(hDlg, &wp);
\r
8238 // [HGM] Chessknight's change 2004-07-13
\r
8239 else { /* Determine Defaults */
\r
8240 WINDOWPLACEMENT wp;
\r
8241 wpConsole.x = winWidth + 1;
\r
8242 wpConsole.y = boardY;
\r
8243 wpConsole.width = screenWidth - winWidth;
\r
8244 wpConsole.height = winHeight;
\r
8245 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8246 wp.length = sizeof(WINDOWPLACEMENT);
\r
8248 wp.showCmd = SW_SHOW;
\r
8249 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8250 wp.rcNormalPosition.left = wpConsole.x;
\r
8251 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8252 wp.rcNormalPosition.top = wpConsole.y;
\r
8253 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8254 SetWindowPlacement(hDlg, &wp);
\r
8269 if (IsIconic(hDlg)) break;
\r
8270 newSizeX = LOWORD(lParam);
\r
8271 newSizeY = HIWORD(lParam);
\r
8272 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8273 RECT rectText, rectInput;
\r
8275 int newTextHeight, newTextWidth;
\r
8276 GetWindowRect(hText, &rectText);
\r
8277 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8278 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8279 if (newTextHeight < 0) {
\r
8280 newSizeY += -newTextHeight;
\r
8281 newTextHeight = 0;
\r
8283 SetWindowPos(hText, NULL, 0, 0,
\r
8284 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8285 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8286 pt.x = rectInput.left;
\r
8287 pt.y = rectInput.top + newSizeY - sizeY;
\r
8288 ScreenToClient(hDlg, &pt);
\r
8289 SetWindowPos(hInput, NULL,
\r
8290 pt.x, pt.y, /* needs client coords */
\r
8291 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8292 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8298 case WM_GETMINMAXINFO:
\r
8299 /* Prevent resizing window too small */
\r
8300 mmi = (MINMAXINFO *) lParam;
\r
8301 mmi->ptMinTrackSize.x = 100;
\r
8302 mmi->ptMinTrackSize.y = 100;
\r
8305 /* [AS] Snapping */
\r
8306 case WM_ENTERSIZEMOVE:
\r
8307 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8310 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8313 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8315 case WM_EXITSIZEMOVE:
\r
8316 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8319 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8327 if (hwndConsole) return;
\r
8328 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8329 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8334 ConsoleOutput(char* data, int length, int forceVisible)
\r
8339 char buf[CO_MAX+1];
\r
8342 static int delayLF = 0;
\r
8343 CHARRANGE savesel, sel;
\r
8345 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8353 while (length--) {
\r
8361 } else if (*p == '\007') {
\r
8362 MyPlaySound(&sounds[(int)SoundBell]);
\r
8369 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8370 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8371 /* Save current selection */
\r
8372 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8373 exlen = GetWindowTextLength(hText);
\r
8374 /* Find out whether current end of text is visible */
\r
8375 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8376 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8377 /* Trim existing text if it's too long */
\r
8378 if (exlen + (q - buf) > CO_MAX) {
\r
8379 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8382 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8383 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8385 savesel.cpMin -= trim;
\r
8386 savesel.cpMax -= trim;
\r
8387 if (exlen < 0) exlen = 0;
\r
8388 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8389 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8391 /* Append the new text */
\r
8392 sel.cpMin = exlen;
\r
8393 sel.cpMax = exlen;
\r
8394 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8395 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8396 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8397 if (forceVisible || exlen == 0 ||
\r
8398 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8399 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8400 /* Scroll to make new end of text visible if old end of text
\r
8401 was visible or new text is an echo of user typein */
\r
8402 sel.cpMin = 9999999;
\r
8403 sel.cpMax = 9999999;
\r
8404 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8405 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8406 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8407 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8409 if (savesel.cpMax == exlen || forceVisible) {
\r
8410 /* Move insert point to new end of text if it was at the old
\r
8411 end of text or if the new text is an echo of user typein */
\r
8412 sel.cpMin = 9999999;
\r
8413 sel.cpMax = 9999999;
\r
8414 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8416 /* Restore previous selection */
\r
8417 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8419 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8426 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8430 COLORREF oldFg, oldBg;
\r
8434 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8436 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8437 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8438 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8441 rect.right = x + squareSize;
\r
8443 rect.bottom = y + squareSize;
\r
8446 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8447 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8448 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8449 &rect, str, strlen(str), NULL);
\r
8451 (void) SetTextColor(hdc, oldFg);
\r
8452 (void) SetBkColor(hdc, oldBg);
\r
8453 (void) SelectObject(hdc, oldFont);
\r
8457 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8458 RECT *rect, char *color, char *flagFell)
\r
8462 COLORREF oldFg, oldBg;
\r
8465 if (appData.clockMode) {
\r
8467 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8469 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8476 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8477 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8479 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8480 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8482 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8486 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8487 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8488 rect, str, strlen(str), NULL);
\r
8489 if(logoHeight > 0 && appData.clockMode) {
\r
8491 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8492 r.top = rect->top + logoHeight/2;
\r
8493 r.left = rect->left;
\r
8494 r.right = rect->right;
\r
8495 r.bottom = rect->bottom;
\r
8496 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8497 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8498 &r, str, strlen(str), NULL);
\r
8500 (void) SetTextColor(hdc, oldFg);
\r
8501 (void) SetBkColor(hdc, oldBg);
\r
8502 (void) SelectObject(hdc, oldFont);
\r
8507 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8513 if( count <= 0 ) {
\r
8514 if (appData.debugMode) {
\r
8515 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8518 return ERROR_INVALID_USER_BUFFER;
\r
8521 ResetEvent(ovl->hEvent);
\r
8522 ovl->Offset = ovl->OffsetHigh = 0;
\r
8523 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8527 err = GetLastError();
\r
8528 if (err == ERROR_IO_PENDING) {
\r
8529 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8533 err = GetLastError();
\r
8540 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8545 ResetEvent(ovl->hEvent);
\r
8546 ovl->Offset = ovl->OffsetHigh = 0;
\r
8547 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8551 err = GetLastError();
\r
8552 if (err == ERROR_IO_PENDING) {
\r
8553 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8557 err = GetLastError();
\r
8563 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8564 void CheckForInputBufferFull( InputSource * is )
\r
8566 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8567 /* Look for end of line */
\r
8568 char * p = is->buf;
\r
8570 while( p < is->next && *p != '\n' ) {
\r
8574 if( p >= is->next ) {
\r
8575 if (appData.debugMode) {
\r
8576 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8579 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8580 is->count = (DWORD) -1;
\r
8581 is->next = is->buf;
\r
8587 InputThread(LPVOID arg)
\r
8592 is = (InputSource *) arg;
\r
8593 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8594 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8595 while (is->hThread != NULL) {
\r
8596 is->error = DoReadFile(is->hFile, is->next,
\r
8597 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8598 &is->count, &ovl);
\r
8599 if (is->error == NO_ERROR) {
\r
8600 is->next += is->count;
\r
8602 if (is->error == ERROR_BROKEN_PIPE) {
\r
8603 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8606 is->count = (DWORD) -1;
\r
8607 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8612 CheckForInputBufferFull( is );
\r
8614 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8616 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8618 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8621 CloseHandle(ovl.hEvent);
\r
8622 CloseHandle(is->hFile);
\r
8624 if (appData.debugMode) {
\r
8625 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8632 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8634 NonOvlInputThread(LPVOID arg)
\r
8641 is = (InputSource *) arg;
\r
8642 while (is->hThread != NULL) {
\r
8643 is->error = ReadFile(is->hFile, is->next,
\r
8644 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8645 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8646 if (is->error == NO_ERROR) {
\r
8647 /* Change CRLF to LF */
\r
8648 if (is->next > is->buf) {
\r
8650 i = is->count + 1;
\r
8658 if (prev == '\r' && *p == '\n') {
\r
8670 if (is->error == ERROR_BROKEN_PIPE) {
\r
8671 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8674 is->count = (DWORD) -1;
\r
8678 CheckForInputBufferFull( is );
\r
8680 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8682 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8684 if (is->count < 0) break; /* Quit on error */
\r
8686 CloseHandle(is->hFile);
\r
8691 SocketInputThread(LPVOID arg)
\r
8695 is = (InputSource *) arg;
\r
8696 while (is->hThread != NULL) {
\r
8697 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8698 if ((int)is->count == SOCKET_ERROR) {
\r
8699 is->count = (DWORD) -1;
\r
8700 is->error = WSAGetLastError();
\r
8702 is->error = NO_ERROR;
\r
8703 is->next += is->count;
\r
8704 if (is->count == 0 && is->second == is) {
\r
8705 /* End of file on stderr; quit with no message */
\r
8709 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8711 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8713 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8719 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8723 is = (InputSource *) lParam;
\r
8724 if (is->lineByLine) {
\r
8725 /* Feed in lines one by one */
\r
8726 char *p = is->buf;
\r
8728 while (q < is->next) {
\r
8729 if (*q++ == '\n') {
\r
8730 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8735 /* Move any partial line to the start of the buffer */
\r
8737 while (p < is->next) {
\r
8742 if (is->error != NO_ERROR || is->count == 0) {
\r
8743 /* Notify backend of the error. Note: If there was a partial
\r
8744 line at the end, it is not flushed through. */
\r
8745 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8748 /* Feed in the whole chunk of input at once */
\r
8749 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8750 is->next = is->buf;
\r
8754 /*---------------------------------------------------------------------------*\
\r
8756 * Menu enables. Used when setting various modes.
\r
8758 \*---------------------------------------------------------------------------*/
\r
8766 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8768 while (enab->item > 0) {
\r
8769 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8774 Enables gnuEnables[] = {
\r
8775 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8776 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8777 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8778 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8779 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8780 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8781 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8782 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8783 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8784 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8788 Enables icsEnables[] = {
\r
8789 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8790 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8791 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8792 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8793 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8794 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8795 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8796 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8797 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8798 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8799 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8800 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8805 Enables zippyEnables[] = {
\r
8806 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8807 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8808 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8813 Enables ncpEnables[] = {
\r
8814 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8815 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8816 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8817 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8818 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8819 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8820 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8822 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8823 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8824 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8825 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8826 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8827 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8828 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8832 Enables trainingOnEnables[] = {
\r
8833 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8834 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8835 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8836 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8837 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8838 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8839 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8840 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8844 Enables trainingOffEnables[] = {
\r
8845 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8846 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8847 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8848 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8849 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8850 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8851 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8852 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8856 /* These modify either ncpEnables or gnuEnables */
\r
8857 Enables cmailEnables[] = {
\r
8858 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8859 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8860 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8861 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8862 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8863 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8864 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8868 Enables machineThinkingEnables[] = {
\r
8869 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8870 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8871 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8872 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8873 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8874 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8875 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8876 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8877 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8878 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8879 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8880 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8881 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8882 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8883 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8887 Enables userThinkingEnables[] = {
\r
8888 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8889 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8890 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8891 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8892 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8893 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8894 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8895 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8896 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8897 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8898 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8899 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8900 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8901 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8902 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8906 /*---------------------------------------------------------------------------*\
\r
8908 * Front-end interface functions exported by XBoard.
\r
8909 * Functions appear in same order as prototypes in frontend.h.
\r
8911 \*---------------------------------------------------------------------------*/
\r
8915 static UINT prevChecked = 0;
\r
8916 static int prevPausing = 0;
\r
8919 if (pausing != prevPausing) {
\r
8920 prevPausing = pausing;
\r
8921 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8922 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8923 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8926 switch (gameMode) {
\r
8927 case BeginningOfGame:
\r
8928 if (appData.icsActive)
\r
8929 nowChecked = IDM_IcsClient;
\r
8930 else if (appData.noChessProgram)
\r
8931 nowChecked = IDM_EditGame;
\r
8933 nowChecked = IDM_MachineBlack;
\r
8935 case MachinePlaysBlack:
\r
8936 nowChecked = IDM_MachineBlack;
\r
8938 case MachinePlaysWhite:
\r
8939 nowChecked = IDM_MachineWhite;
\r
8941 case TwoMachinesPlay:
\r
8942 nowChecked = IDM_TwoMachines;
\r
8945 nowChecked = IDM_AnalysisMode;
\r
8948 nowChecked = IDM_AnalyzeFile;
\r
8951 nowChecked = IDM_EditGame;
\r
8953 case PlayFromGameFile:
\r
8954 nowChecked = IDM_LoadGame;
\r
8956 case EditPosition:
\r
8957 nowChecked = IDM_EditPosition;
\r
8960 nowChecked = IDM_Training;
\r
8962 case IcsPlayingWhite:
\r
8963 case IcsPlayingBlack:
\r
8964 case IcsObserving:
\r
8966 nowChecked = IDM_IcsClient;
\r
8973 if (prevChecked != 0)
\r
8974 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8975 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8976 if (nowChecked != 0)
\r
8977 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8978 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8980 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8981 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8982 MF_BYCOMMAND|MF_ENABLED);
\r
8984 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8985 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8988 prevChecked = nowChecked;
\r
8990 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8991 if (appData.icsActive) {
\r
8992 if (appData.icsEngineAnalyze) {
\r
8993 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8994 MF_BYCOMMAND|MF_CHECKED);
\r
8996 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8997 MF_BYCOMMAND|MF_UNCHECKED);
\r
9005 HMENU hmenu = GetMenu(hwndMain);
\r
9006 SetMenuEnables(hmenu, icsEnables);
\r
9007 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9008 MF_BYPOSITION|MF_ENABLED);
\r
9010 if (appData.zippyPlay) {
\r
9011 SetMenuEnables(hmenu, zippyEnables);
\r
9012 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9013 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9014 MF_BYCOMMAND|MF_ENABLED);
\r
9022 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9028 HMENU hmenu = GetMenu(hwndMain);
\r
9029 SetMenuEnables(hmenu, ncpEnables);
\r
9030 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9031 MF_BYPOSITION|MF_GRAYED);
\r
9032 DrawMenuBar(hwndMain);
\r
9038 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9042 SetTrainingModeOn()
\r
9045 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9046 for (i = 0; i < N_BUTTONS; i++) {
\r
9047 if (buttonDesc[i].hwnd != NULL)
\r
9048 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9053 VOID SetTrainingModeOff()
\r
9056 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9057 for (i = 0; i < N_BUTTONS; i++) {
\r
9058 if (buttonDesc[i].hwnd != NULL)
\r
9059 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9065 SetUserThinkingEnables()
\r
9067 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9071 SetMachineThinkingEnables()
\r
9073 HMENU hMenu = GetMenu(hwndMain);
\r
9074 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9076 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9078 if (gameMode == MachinePlaysBlack) {
\r
9079 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9080 } else if (gameMode == MachinePlaysWhite) {
\r
9081 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9082 } else if (gameMode == TwoMachinesPlay) {
\r
9083 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9089 DisplayTitle(char *str)
\r
9091 char title[MSG_SIZ], *host;
\r
9092 if (str[0] != NULLCHAR) {
\r
9093 strcpy(title, str);
\r
9094 } else if (appData.icsActive) {
\r
9095 if (appData.icsCommPort[0] != NULLCHAR)
\r
9098 host = appData.icsHost;
\r
9099 sprintf(title, "%s: %s", szTitle, host);
\r
9100 } else if (appData.noChessProgram) {
\r
9101 strcpy(title, szTitle);
\r
9103 strcpy(title, szTitle);
\r
9104 strcat(title, ": ");
\r
9105 strcat(title, first.tidy);
\r
9107 SetWindowText(hwndMain, title);
\r
9112 DisplayMessage(char *str1, char *str2)
\r
9116 int remain = MESSAGE_TEXT_MAX - 1;
\r
9119 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9120 messageText[0] = NULLCHAR;
\r
9122 len = strlen(str1);
\r
9123 if (len > remain) len = remain;
\r
9124 strncpy(messageText, str1, len);
\r
9125 messageText[len] = NULLCHAR;
\r
9128 if (*str2 && remain >= 2) {
\r
9130 strcat(messageText, " ");
\r
9133 len = strlen(str2);
\r
9134 if (len > remain) len = remain;
\r
9135 strncat(messageText, str2, len);
\r
9137 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9139 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9143 hdc = GetDC(hwndMain);
\r
9144 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9145 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9146 &messageRect, messageText, strlen(messageText), NULL);
\r
9147 (void) SelectObject(hdc, oldFont);
\r
9148 (void) ReleaseDC(hwndMain, hdc);
\r
9152 DisplayError(char *str, int error)
\r
9154 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9160 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9161 NULL, error, LANG_NEUTRAL,
\r
9162 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9164 sprintf(buf, "%s:\n%s", str, buf2);
\r
9166 ErrorMap *em = errmap;
\r
9167 while (em->err != 0 && em->err != error) em++;
\r
9168 if (em->err != 0) {
\r
9169 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9171 sprintf(buf, "%s:\nError code %d", str, error);
\r
9176 ErrorPopUp("Error", buf);
\r
9181 DisplayMoveError(char *str)
\r
9183 fromX = fromY = -1;
\r
9184 ClearHighlights();
\r
9185 DrawPosition(FALSE, NULL);
\r
9186 if (appData.popupMoveErrors) {
\r
9187 ErrorPopUp("Error", str);
\r
9189 DisplayMessage(str, "");
\r
9190 moveErrorMessageUp = TRUE;
\r
9195 DisplayFatalError(char *str, int error, int exitStatus)
\r
9197 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9199 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9202 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9203 NULL, error, LANG_NEUTRAL,
\r
9204 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9206 sprintf(buf, "%s:\n%s", str, buf2);
\r
9208 ErrorMap *em = errmap;
\r
9209 while (em->err != 0 && em->err != error) em++;
\r
9210 if (em->err != 0) {
\r
9211 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9213 sprintf(buf, "%s:\nError code %d", str, error);
\r
9218 if (appData.debugMode) {
\r
9219 fprintf(debugFP, "%s: %s\n", label, str);
\r
9221 if (appData.popupExitMessage) {
\r
9222 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9223 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9225 ExitEvent(exitStatus);
\r
9230 DisplayInformation(char *str)
\r
9232 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9237 DisplayNote(char *str)
\r
9239 ErrorPopUp("Note", str);
\r
9244 char *title, *question, *replyPrefix;
\r
9249 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9251 static QuestionParams *qp;
\r
9252 char reply[MSG_SIZ];
\r
9255 switch (message) {
\r
9256 case WM_INITDIALOG:
\r
9257 qp = (QuestionParams *) lParam;
\r
9258 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9259 SetWindowText(hDlg, qp->title);
\r
9260 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9261 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9265 switch (LOWORD(wParam)) {
\r
9267 strcpy(reply, qp->replyPrefix);
\r
9268 if (*reply) strcat(reply, " ");
\r
9269 len = strlen(reply);
\r
9270 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9271 strcat(reply, "\n");
\r
9272 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9273 EndDialog(hDlg, TRUE);
\r
9274 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9277 EndDialog(hDlg, FALSE);
\r
9288 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9290 QuestionParams qp;
\r
9294 qp.question = question;
\r
9295 qp.replyPrefix = replyPrefix;
\r
9297 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9298 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9299 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9300 FreeProcInstance(lpProc);
\r
9303 /* [AS] Pick FRC position */
\r
9304 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9306 static int * lpIndexFRC;
\r
9312 case WM_INITDIALOG:
\r
9313 lpIndexFRC = (int *) lParam;
\r
9315 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9317 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9318 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9319 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9320 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9325 switch( LOWORD(wParam) ) {
\r
9327 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9328 EndDialog( hDlg, 0 );
\r
9329 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9332 EndDialog( hDlg, 1 );
\r
9334 case IDC_NFG_Edit:
\r
9335 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9336 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9338 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9341 case IDC_NFG_Random:
\r
9342 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9343 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9356 int index = appData.defaultFrcPosition;
\r
9357 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9359 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9361 if( result == 0 ) {
\r
9362 appData.defaultFrcPosition = index;
\r
9368 /* [AS] Game list options */
\r
9374 static GLT_Item GLT_ItemInfo[] = {
\r
9375 { GLT_EVENT, "Event" },
\r
9376 { GLT_SITE, "Site" },
\r
9377 { GLT_DATE, "Date" },
\r
9378 { GLT_ROUND, "Round" },
\r
9379 { GLT_PLAYERS, "Players" },
\r
9380 { GLT_RESULT, "Result" },
\r
9381 { GLT_WHITE_ELO, "White Rating" },
\r
9382 { GLT_BLACK_ELO, "Black Rating" },
\r
9383 { GLT_TIME_CONTROL,"Time Control" },
\r
9384 { GLT_VARIANT, "Variant" },
\r
9385 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9389 const char * GLT_FindItem( char id )
\r
9391 const char * result = 0;
\r
9393 GLT_Item * list = GLT_ItemInfo;
\r
9395 while( list->id != 0 ) {
\r
9396 if( list->id == id ) {
\r
9397 result = list->name;
\r
9407 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9409 const char * name = GLT_FindItem( id );
\r
9412 if( index >= 0 ) {
\r
9413 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9416 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9421 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9425 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9428 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9432 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9434 pc = GLT_ALL_TAGS;
\r
9437 if( strchr( tags, *pc ) == 0 ) {
\r
9438 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9443 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9446 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9448 char result = '\0';
\r
9451 GLT_Item * list = GLT_ItemInfo;
\r
9453 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9454 while( list->id != 0 ) {
\r
9455 if( strcmp( list->name, name ) == 0 ) {
\r
9456 result = list->id;
\r
9467 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9469 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9470 int idx2 = idx1 + delta;
\r
9471 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9473 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9476 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9477 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9478 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9479 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9483 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9485 static char glt[64];
\r
9486 static char * lpUserGLT;
\r
9490 case WM_INITDIALOG:
\r
9491 lpUserGLT = (char *) lParam;
\r
9493 strcpy( glt, lpUserGLT );
\r
9495 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9497 /* Initialize list */
\r
9498 GLT_TagsToList( hDlg, glt );
\r
9500 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9505 switch( LOWORD(wParam) ) {
\r
9508 char * pc = lpUserGLT;
\r
9510 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9514 id = GLT_ListItemToTag( hDlg, idx );
\r
9518 } while( id != '\0' );
\r
9520 EndDialog( hDlg, 0 );
\r
9523 EndDialog( hDlg, 1 );
\r
9526 case IDC_GLT_Default:
\r
9527 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9528 GLT_TagsToList( hDlg, glt );
\r
9531 case IDC_GLT_Restore:
\r
9532 strcpy( glt, lpUserGLT );
\r
9533 GLT_TagsToList( hDlg, glt );
\r
9537 GLT_MoveSelection( hDlg, -1 );
\r
9540 case IDC_GLT_Down:
\r
9541 GLT_MoveSelection( hDlg, +1 );
\r
9551 int GameListOptions()
\r
9555 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9557 strcpy( glt, appData.gameListTags );
\r
9559 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9561 if( result == 0 ) {
\r
9562 /* [AS] Memory leak here! */
\r
9563 appData.gameListTags = strdup( glt );
\r
9571 DisplayIcsInteractionTitle(char *str)
\r
9573 char consoleTitle[MSG_SIZ];
\r
9575 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9576 SetWindowText(hwndConsole, consoleTitle);
\r
9580 DrawPosition(int fullRedraw, Board board)
\r
9582 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9589 fromX = fromY = -1;
\r
9590 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9591 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9592 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9593 dragInfo.lastpos = dragInfo.pos;
\r
9594 dragInfo.start.x = dragInfo.start.y = -1;
\r
9595 dragInfo.from = dragInfo.start;
\r
9597 DrawPosition(TRUE, NULL);
\r
9603 CommentPopUp(char *title, char *str)
\r
9605 HWND hwnd = GetActiveWindow();
\r
9606 EitherCommentPopUp(0, title, str, FALSE);
\r
9607 SetActiveWindow(hwnd);
\r
9611 CommentPopDown(void)
\r
9613 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9614 if (commentDialog) {
\r
9615 ShowWindow(commentDialog, SW_HIDE);
\r
9617 commentDialogUp = FALSE;
\r
9621 EditCommentPopUp(int index, char *title, char *str)
\r
9623 EitherCommentPopUp(index, title, str, TRUE);
\r
9630 MyPlaySound(&sounds[(int)SoundMove]);
\r
9633 VOID PlayIcsWinSound()
\r
9635 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9638 VOID PlayIcsLossSound()
\r
9640 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9643 VOID PlayIcsDrawSound()
\r
9645 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9648 VOID PlayIcsUnfinishedSound()
\r
9650 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9656 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9664 consoleEcho = TRUE;
\r
9665 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9666 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9667 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9676 consoleEcho = FALSE;
\r
9677 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9678 /* This works OK: set text and background both to the same color */
\r
9680 cf.crTextColor = COLOR_ECHOOFF;
\r
9681 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9682 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9685 /* No Raw()...? */
\r
9687 void Colorize(ColorClass cc, int continuation)
\r
9689 currentColorClass = cc;
\r
9690 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9691 consoleCF.crTextColor = textAttribs[cc].color;
\r
9692 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9693 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9699 static char buf[MSG_SIZ];
\r
9700 DWORD bufsiz = MSG_SIZ;
\r
9702 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9703 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9705 if (!GetUserName(buf, &bufsiz)) {
\r
9706 /*DisplayError("Error getting user name", GetLastError());*/
\r
9707 strcpy(buf, "User");
\r
9715 static char buf[MSG_SIZ];
\r
9716 DWORD bufsiz = MSG_SIZ;
\r
9718 if (!GetComputerName(buf, &bufsiz)) {
\r
9719 /*DisplayError("Error getting host name", GetLastError());*/
\r
9720 strcpy(buf, "Unknown");
\r
9727 ClockTimerRunning()
\r
9729 return clockTimerEvent != 0;
\r
9735 if (clockTimerEvent == 0) return FALSE;
\r
9736 KillTimer(hwndMain, clockTimerEvent);
\r
9737 clockTimerEvent = 0;
\r
9742 StartClockTimer(long millisec)
\r
9744 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9745 (UINT) millisec, NULL);
\r
9749 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9752 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9754 if(appData.noGUI) return;
\r
9755 hdc = GetDC(hwndMain);
\r
9756 if (!IsIconic(hwndMain)) {
\r
9757 DisplayAClock(hdc, timeRemaining, highlight,
\r
9758 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9760 if (highlight && iconCurrent == iconBlack) {
\r
9761 iconCurrent = iconWhite;
\r
9762 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9763 if (IsIconic(hwndMain)) {
\r
9764 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9767 (void) ReleaseDC(hwndMain, hdc);
\r
9769 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9773 DisplayBlackClock(long timeRemaining, int highlight)
\r
9776 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9778 if(appData.noGUI) return;
\r
9779 hdc = GetDC(hwndMain);
\r
9780 if (!IsIconic(hwndMain)) {
\r
9781 DisplayAClock(hdc, timeRemaining, highlight,
\r
9782 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9784 if (highlight && iconCurrent == iconWhite) {
\r
9785 iconCurrent = iconBlack;
\r
9786 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9787 if (IsIconic(hwndMain)) {
\r
9788 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9791 (void) ReleaseDC(hwndMain, hdc);
\r
9793 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9798 LoadGameTimerRunning()
\r
9800 return loadGameTimerEvent != 0;
\r
9804 StopLoadGameTimer()
\r
9806 if (loadGameTimerEvent == 0) return FALSE;
\r
9807 KillTimer(hwndMain, loadGameTimerEvent);
\r
9808 loadGameTimerEvent = 0;
\r
9813 StartLoadGameTimer(long millisec)
\r
9815 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9816 (UINT) millisec, NULL);
\r
9824 char fileTitle[MSG_SIZ];
\r
9826 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9827 f = OpenFileDialog(hwndMain, "a", defName,
\r
9828 appData.oldSaveStyle ? "gam" : "pgn",
\r
9830 "Save Game to File", NULL, fileTitle, NULL);
\r
9832 SaveGame(f, 0, "");
\r
9839 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9841 if (delayedTimerEvent != 0) {
\r
9842 if (appData.debugMode) {
\r
9843 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9845 KillTimer(hwndMain, delayedTimerEvent);
\r
9846 delayedTimerEvent = 0;
\r
9847 delayedTimerCallback();
\r
9849 delayedTimerCallback = cb;
\r
9850 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9851 (UINT) millisec, NULL);
\r
9854 DelayedEventCallback
\r
9857 if (delayedTimerEvent) {
\r
9858 return delayedTimerCallback;
\r
9865 CancelDelayedEvent()
\r
9867 if (delayedTimerEvent) {
\r
9868 KillTimer(hwndMain, delayedTimerEvent);
\r
9869 delayedTimerEvent = 0;
\r
9873 DWORD GetWin32Priority(int nice)
\r
9874 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9876 REALTIME_PRIORITY_CLASS 0x00000100
\r
9877 HIGH_PRIORITY_CLASS 0x00000080
\r
9878 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9879 NORMAL_PRIORITY_CLASS 0x00000020
\r
9880 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9881 IDLE_PRIORITY_CLASS 0x00000040
\r
9883 if (nice < -15) return 0x00000080;
\r
9884 if (nice < 0) return 0x00008000;
\r
9885 if (nice == 0) return 0x00000020;
\r
9886 if (nice < 15) return 0x00004000;
\r
9887 return 0x00000040;
\r
9890 /* Start a child process running the given program.
\r
9891 The process's standard output can be read from "from", and its
\r
9892 standard input can be written to "to".
\r
9893 Exit with fatal error if anything goes wrong.
\r
9894 Returns an opaque pointer that can be used to destroy the process
\r
9898 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9900 #define BUFSIZE 4096
\r
9902 HANDLE hChildStdinRd, hChildStdinWr,
\r
9903 hChildStdoutRd, hChildStdoutWr;
\r
9904 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9905 SECURITY_ATTRIBUTES saAttr;
\r
9907 PROCESS_INFORMATION piProcInfo;
\r
9908 STARTUPINFO siStartInfo;
\r
9910 char buf[MSG_SIZ];
\r
9913 if (appData.debugMode) {
\r
9914 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9919 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9920 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9921 saAttr.bInheritHandle = TRUE;
\r
9922 saAttr.lpSecurityDescriptor = NULL;
\r
9925 * The steps for redirecting child's STDOUT:
\r
9926 * 1. Create anonymous pipe to be STDOUT for child.
\r
9927 * 2. Create a noninheritable duplicate of read handle,
\r
9928 * and close the inheritable read handle.
\r
9931 /* Create a pipe for the child's STDOUT. */
\r
9932 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9933 return GetLastError();
\r
9936 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9937 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9938 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9939 FALSE, /* not inherited */
\r
9940 DUPLICATE_SAME_ACCESS);
\r
9942 return GetLastError();
\r
9944 CloseHandle(hChildStdoutRd);
\r
9947 * The steps for redirecting child's STDIN:
\r
9948 * 1. Create anonymous pipe to be STDIN for child.
\r
9949 * 2. Create a noninheritable duplicate of write handle,
\r
9950 * and close the inheritable write handle.
\r
9953 /* Create a pipe for the child's STDIN. */
\r
9954 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9955 return GetLastError();
\r
9958 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9959 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9960 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9961 FALSE, /* not inherited */
\r
9962 DUPLICATE_SAME_ACCESS);
\r
9964 return GetLastError();
\r
9966 CloseHandle(hChildStdinWr);
\r
9968 /* Arrange to (1) look in dir for the child .exe file, and
\r
9969 * (2) have dir be the child's working directory. Interpret
\r
9970 * dir relative to the directory WinBoard loaded from. */
\r
9971 GetCurrentDirectory(MSG_SIZ, buf);
\r
9972 SetCurrentDirectory(installDir);
\r
9973 SetCurrentDirectory(dir);
\r
9975 /* Now create the child process. */
\r
9977 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9978 siStartInfo.lpReserved = NULL;
\r
9979 siStartInfo.lpDesktop = NULL;
\r
9980 siStartInfo.lpTitle = NULL;
\r
9981 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9982 siStartInfo.cbReserved2 = 0;
\r
9983 siStartInfo.lpReserved2 = NULL;
\r
9984 siStartInfo.hStdInput = hChildStdinRd;
\r
9985 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9986 siStartInfo.hStdError = hChildStdoutWr;
\r
9988 fSuccess = CreateProcess(NULL,
\r
9989 cmdLine, /* command line */
\r
9990 NULL, /* process security attributes */
\r
9991 NULL, /* primary thread security attrs */
\r
9992 TRUE, /* handles are inherited */
\r
9993 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9994 NULL, /* use parent's environment */
\r
9996 &siStartInfo, /* STARTUPINFO pointer */
\r
9997 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9999 err = GetLastError();
\r
10000 SetCurrentDirectory(buf); /* return to prev directory */
\r
10001 if (! fSuccess) {
\r
10005 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10006 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10007 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10010 /* Close the handles we don't need in the parent */
\r
10011 CloseHandle(piProcInfo.hThread);
\r
10012 CloseHandle(hChildStdinRd);
\r
10013 CloseHandle(hChildStdoutWr);
\r
10015 /* Prepare return value */
\r
10016 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10017 cp->kind = CPReal;
\r
10018 cp->hProcess = piProcInfo.hProcess;
\r
10019 cp->pid = piProcInfo.dwProcessId;
\r
10020 cp->hFrom = hChildStdoutRdDup;
\r
10021 cp->hTo = hChildStdinWrDup;
\r
10023 *pr = (void *) cp;
\r
10025 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10026 2000 where engines sometimes don't see the initial command(s)
\r
10027 from WinBoard and hang. I don't understand how that can happen,
\r
10028 but the Sleep is harmless, so I've put it in. Others have also
\r
10029 reported what may be the same problem, so hopefully this will fix
\r
10030 it for them too. */
\r
10038 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10040 ChildProc *cp; int result;
\r
10042 cp = (ChildProc *) pr;
\r
10043 if (cp == NULL) return;
\r
10045 switch (cp->kind) {
\r
10047 /* TerminateProcess is considered harmful, so... */
\r
10048 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10049 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10050 /* The following doesn't work because the chess program
\r
10051 doesn't "have the same console" as WinBoard. Maybe
\r
10052 we could arrange for this even though neither WinBoard
\r
10053 nor the chess program uses a console for stdio? */
\r
10054 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10056 /* [AS] Special termination modes for misbehaving programs... */
\r
10057 if( signal == 9 ) {
\r
10058 result = TerminateProcess( cp->hProcess, 0 );
\r
10060 if ( appData.debugMode) {
\r
10061 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10064 else if( signal == 10 ) {
\r
10065 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10067 if( dw != WAIT_OBJECT_0 ) {
\r
10068 result = TerminateProcess( cp->hProcess, 0 );
\r
10070 if ( appData.debugMode) {
\r
10071 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10077 CloseHandle(cp->hProcess);
\r
10081 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10085 closesocket(cp->sock);
\r
10090 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10091 closesocket(cp->sock);
\r
10092 closesocket(cp->sock2);
\r
10100 InterruptChildProcess(ProcRef pr)
\r
10104 cp = (ChildProc *) pr;
\r
10105 if (cp == NULL) return;
\r
10106 switch (cp->kind) {
\r
10108 /* The following doesn't work because the chess program
\r
10109 doesn't "have the same console" as WinBoard. Maybe
\r
10110 we could arrange for this even though neither WinBoard
\r
10111 nor the chess program uses a console for stdio */
\r
10112 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10117 /* Can't interrupt */
\r
10121 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10128 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10130 char cmdLine[MSG_SIZ];
\r
10132 if (port[0] == NULLCHAR) {
\r
10133 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10135 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10137 return StartChildProcess(cmdLine, "", pr);
\r
10141 /* Code to open TCP sockets */
\r
10144 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10149 struct sockaddr_in sa, mysa;
\r
10150 struct hostent FAR *hp;
\r
10151 unsigned short uport;
\r
10152 WORD wVersionRequested;
\r
10155 /* Initialize socket DLL */
\r
10156 wVersionRequested = MAKEWORD(1, 1);
\r
10157 err = WSAStartup(wVersionRequested, &wsaData);
\r
10158 if (err != 0) return err;
\r
10160 /* Make socket */
\r
10161 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10162 err = WSAGetLastError();
\r
10167 /* Bind local address using (mostly) don't-care values.
\r
10169 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10170 mysa.sin_family = AF_INET;
\r
10171 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10172 uport = (unsigned short) 0;
\r
10173 mysa.sin_port = htons(uport);
\r
10174 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10175 == SOCKET_ERROR) {
\r
10176 err = WSAGetLastError();
\r
10181 /* Resolve remote host name */
\r
10182 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10183 if (!(hp = gethostbyname(host))) {
\r
10184 unsigned int b0, b1, b2, b3;
\r
10186 err = WSAGetLastError();
\r
10188 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10189 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10190 hp->h_addrtype = AF_INET;
\r
10191 hp->h_length = 4;
\r
10192 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10193 hp->h_addr_list[0] = (char *) malloc(4);
\r
10194 hp->h_addr_list[0][0] = (char) b0;
\r
10195 hp->h_addr_list[0][1] = (char) b1;
\r
10196 hp->h_addr_list[0][2] = (char) b2;
\r
10197 hp->h_addr_list[0][3] = (char) b3;
\r
10203 sa.sin_family = hp->h_addrtype;
\r
10204 uport = (unsigned short) atoi(port);
\r
10205 sa.sin_port = htons(uport);
\r
10206 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10208 /* Make connection */
\r
10209 if (connect(s, (struct sockaddr *) &sa,
\r
10210 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10211 err = WSAGetLastError();
\r
10216 /* Prepare return value */
\r
10217 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10218 cp->kind = CPSock;
\r
10220 *pr = (ProcRef *) cp;
\r
10226 OpenCommPort(char *name, ProcRef *pr)
\r
10231 char fullname[MSG_SIZ];
\r
10233 if (*name != '\\')
\r
10234 sprintf(fullname, "\\\\.\\%s", name);
\r
10236 strcpy(fullname, name);
\r
10238 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10239 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10240 if (h == (HANDLE) -1) {
\r
10241 return GetLastError();
\r
10245 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10247 /* Accumulate characters until a 100ms pause, then parse */
\r
10248 ct.ReadIntervalTimeout = 100;
\r
10249 ct.ReadTotalTimeoutMultiplier = 0;
\r
10250 ct.ReadTotalTimeoutConstant = 0;
\r
10251 ct.WriteTotalTimeoutMultiplier = 0;
\r
10252 ct.WriteTotalTimeoutConstant = 0;
\r
10253 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10255 /* Prepare return value */
\r
10256 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10257 cp->kind = CPComm;
\r
10260 *pr = (ProcRef *) cp;
\r
10266 OpenLoopback(ProcRef *pr)
\r
10268 DisplayFatalError("Not implemented", 0, 1);
\r
10274 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10278 SOCKET s, s2, s3;
\r
10279 struct sockaddr_in sa, mysa;
\r
10280 struct hostent FAR *hp;
\r
10281 unsigned short uport;
\r
10282 WORD wVersionRequested;
\r
10285 char stderrPortStr[MSG_SIZ];
\r
10287 /* Initialize socket DLL */
\r
10288 wVersionRequested = MAKEWORD(1, 1);
\r
10289 err = WSAStartup(wVersionRequested, &wsaData);
\r
10290 if (err != 0) return err;
\r
10292 /* Resolve remote host name */
\r
10293 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10294 if (!(hp = gethostbyname(host))) {
\r
10295 unsigned int b0, b1, b2, b3;
\r
10297 err = WSAGetLastError();
\r
10299 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10300 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10301 hp->h_addrtype = AF_INET;
\r
10302 hp->h_length = 4;
\r
10303 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10304 hp->h_addr_list[0] = (char *) malloc(4);
\r
10305 hp->h_addr_list[0][0] = (char) b0;
\r
10306 hp->h_addr_list[0][1] = (char) b1;
\r
10307 hp->h_addr_list[0][2] = (char) b2;
\r
10308 hp->h_addr_list[0][3] = (char) b3;
\r
10314 sa.sin_family = hp->h_addrtype;
\r
10315 uport = (unsigned short) 514;
\r
10316 sa.sin_port = htons(uport);
\r
10317 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10319 /* Bind local socket to unused "privileged" port address
\r
10321 s = INVALID_SOCKET;
\r
10322 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10323 mysa.sin_family = AF_INET;
\r
10324 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10325 for (fromPort = 1023;; fromPort--) {
\r
10326 if (fromPort < 0) {
\r
10328 return WSAEADDRINUSE;
\r
10330 if (s == INVALID_SOCKET) {
\r
10331 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10332 err = WSAGetLastError();
\r
10337 uport = (unsigned short) fromPort;
\r
10338 mysa.sin_port = htons(uport);
\r
10339 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10340 == SOCKET_ERROR) {
\r
10341 err = WSAGetLastError();
\r
10342 if (err == WSAEADDRINUSE) continue;
\r
10346 if (connect(s, (struct sockaddr *) &sa,
\r
10347 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10348 err = WSAGetLastError();
\r
10349 if (err == WSAEADDRINUSE) {
\r
10360 /* Bind stderr local socket to unused "privileged" port address
\r
10362 s2 = INVALID_SOCKET;
\r
10363 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10364 mysa.sin_family = AF_INET;
\r
10365 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10366 for (fromPort = 1023;; fromPort--) {
\r
10367 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10368 if (fromPort < 0) {
\r
10369 (void) closesocket(s);
\r
10371 return WSAEADDRINUSE;
\r
10373 if (s2 == INVALID_SOCKET) {
\r
10374 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10375 err = WSAGetLastError();
\r
10381 uport = (unsigned short) fromPort;
\r
10382 mysa.sin_port = htons(uport);
\r
10383 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10384 == SOCKET_ERROR) {
\r
10385 err = WSAGetLastError();
\r
10386 if (err == WSAEADDRINUSE) continue;
\r
10387 (void) closesocket(s);
\r
10391 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10392 err = WSAGetLastError();
\r
10393 if (err == WSAEADDRINUSE) {
\r
10395 s2 = INVALID_SOCKET;
\r
10398 (void) closesocket(s);
\r
10399 (void) closesocket(s2);
\r
10405 prevStderrPort = fromPort; // remember port used
\r
10406 sprintf(stderrPortStr, "%d", fromPort);
\r
10408 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10409 err = WSAGetLastError();
\r
10410 (void) closesocket(s);
\r
10411 (void) closesocket(s2);
\r
10416 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10417 err = WSAGetLastError();
\r
10418 (void) closesocket(s);
\r
10419 (void) closesocket(s2);
\r
10423 if (*user == NULLCHAR) user = UserName();
\r
10424 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10425 err = WSAGetLastError();
\r
10426 (void) closesocket(s);
\r
10427 (void) closesocket(s2);
\r
10431 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10432 err = WSAGetLastError();
\r
10433 (void) closesocket(s);
\r
10434 (void) closesocket(s2);
\r
10439 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10440 err = WSAGetLastError();
\r
10441 (void) closesocket(s);
\r
10442 (void) closesocket(s2);
\r
10446 (void) closesocket(s2); /* Stop listening */
\r
10448 /* Prepare return value */
\r
10449 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10450 cp->kind = CPRcmd;
\r
10453 *pr = (ProcRef *) cp;
\r
10460 AddInputSource(ProcRef pr, int lineByLine,
\r
10461 InputCallback func, VOIDSTAR closure)
\r
10463 InputSource *is, *is2 = NULL;
\r
10464 ChildProc *cp = (ChildProc *) pr;
\r
10466 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10467 is->lineByLine = lineByLine;
\r
10469 is->closure = closure;
\r
10470 is->second = NULL;
\r
10471 is->next = is->buf;
\r
10472 if (pr == NoProc) {
\r
10473 is->kind = CPReal;
\r
10474 consoleInputSource = is;
\r
10476 is->kind = cp->kind;
\r
10478 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10479 we create all threads suspended so that the is->hThread variable can be
\r
10480 safely assigned, then let the threads start with ResumeThread.
\r
10482 switch (cp->kind) {
\r
10484 is->hFile = cp->hFrom;
\r
10485 cp->hFrom = NULL; /* now owned by InputThread */
\r
10487 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10488 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10492 is->hFile = cp->hFrom;
\r
10493 cp->hFrom = NULL; /* now owned by InputThread */
\r
10495 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10496 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10500 is->sock = cp->sock;
\r
10502 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10503 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10507 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10509 is->sock = cp->sock;
\r
10510 is->second = is2;
\r
10511 is2->sock = cp->sock2;
\r
10512 is2->second = is2;
\r
10514 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10515 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10517 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10518 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10522 if( is->hThread != NULL ) {
\r
10523 ResumeThread( is->hThread );
\r
10526 if( is2 != NULL && is2->hThread != NULL ) {
\r
10527 ResumeThread( is2->hThread );
\r
10531 return (InputSourceRef) is;
\r
10535 RemoveInputSource(InputSourceRef isr)
\r
10539 is = (InputSource *) isr;
\r
10540 is->hThread = NULL; /* tell thread to stop */
\r
10541 CloseHandle(is->hThread);
\r
10542 if (is->second != NULL) {
\r
10543 is->second->hThread = NULL;
\r
10544 CloseHandle(is->second->hThread);
\r
10550 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10553 int outCount = SOCKET_ERROR;
\r
10554 ChildProc *cp = (ChildProc *) pr;
\r
10555 static OVERLAPPED ovl;
\r
10557 if (pr == NoProc) {
\r
10558 ConsoleOutput(message, count, FALSE);
\r
10562 if (ovl.hEvent == NULL) {
\r
10563 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10565 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10567 switch (cp->kind) {
\r
10570 outCount = send(cp->sock, message, count, 0);
\r
10571 if (outCount == SOCKET_ERROR) {
\r
10572 *outError = WSAGetLastError();
\r
10574 *outError = NO_ERROR;
\r
10579 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10580 &dOutCount, NULL)) {
\r
10581 *outError = NO_ERROR;
\r
10582 outCount = (int) dOutCount;
\r
10584 *outError = GetLastError();
\r
10589 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10590 &dOutCount, &ovl);
\r
10591 if (*outError == NO_ERROR) {
\r
10592 outCount = (int) dOutCount;
\r
10600 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10603 /* Ignore delay, not implemented for WinBoard */
\r
10604 return OutputToProcess(pr, message, count, outError);
\r
10609 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10610 char *buf, int count, int error)
\r
10612 DisplayFatalError("Not implemented", 0, 1);
\r
10615 /* see wgamelist.c for Game List functions */
\r
10616 /* see wedittags.c for Edit Tags functions */
\r
10623 char buf[MSG_SIZ];
\r
10626 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10627 f = fopen(buf, "r");
\r
10629 ProcessICSInitScript(f);
\r
10637 StartAnalysisClock()
\r
10639 if (analysisTimerEvent) return;
\r
10640 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10641 (UINT) 2000, NULL);
\r
10645 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10647 static HANDLE hwndText;
\r
10649 static int sizeX, sizeY;
\r
10650 int newSizeX, newSizeY, flags;
\r
10653 switch (message) {
\r
10654 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10655 /* Initialize the dialog items */
\r
10656 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10657 SetWindowText(hDlg, analysisTitle);
\r
10658 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10659 /* Size and position the dialog */
\r
10660 if (!analysisDialog) {
\r
10661 analysisDialog = hDlg;
\r
10662 flags = SWP_NOZORDER;
\r
10663 GetClientRect(hDlg, &rect);
\r
10664 sizeX = rect.right;
\r
10665 sizeY = rect.bottom;
\r
10666 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10667 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10668 WINDOWPLACEMENT wp;
\r
10669 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10670 wp.length = sizeof(WINDOWPLACEMENT);
\r
10672 wp.showCmd = SW_SHOW;
\r
10673 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10674 wp.rcNormalPosition.left = analysisX;
\r
10675 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10676 wp.rcNormalPosition.top = analysisY;
\r
10677 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10678 SetWindowPlacement(hDlg, &wp);
\r
10680 GetClientRect(hDlg, &rect);
\r
10681 newSizeX = rect.right;
\r
10682 newSizeY = rect.bottom;
\r
10683 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10684 newSizeX, newSizeY);
\r
10685 sizeX = newSizeX;
\r
10686 sizeY = newSizeY;
\r
10691 case WM_COMMAND: /* message: received a command */
\r
10692 switch (LOWORD(wParam)) {
\r
10694 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10695 ExitAnalyzeMode();
\r
10707 newSizeX = LOWORD(lParam);
\r
10708 newSizeY = HIWORD(lParam);
\r
10709 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10710 sizeX = newSizeX;
\r
10711 sizeY = newSizeY;
\r
10714 case WM_GETMINMAXINFO:
\r
10715 /* Prevent resizing window too small */
\r
10716 mmi = (MINMAXINFO *) lParam;
\r
10717 mmi->ptMinTrackSize.x = 100;
\r
10718 mmi->ptMinTrackSize.y = 100;
\r
10725 AnalysisPopUp(char* title, char* str)
\r
10731 EngineOutputPopUp();
\r
10734 if (str == NULL) str = "";
\r
10735 p = (char *) malloc(2 * strlen(str) + 2);
\r
10738 if (*str == '\n') *q++ = '\r';
\r
10742 if (analysisText != NULL) free(analysisText);
\r
10743 analysisText = p;
\r
10745 if (analysisDialog) {
\r
10746 SetWindowText(analysisDialog, title);
\r
10747 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10748 ShowWindow(analysisDialog, SW_SHOW);
\r
10750 analysisTitle = title;
\r
10751 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10752 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10753 hwndMain, (DLGPROC)lpProc);
\r
10754 FreeProcInstance(lpProc);
\r
10756 analysisDialogUp = TRUE;
\r
10760 AnalysisPopDown()
\r
10762 if (analysisDialog) {
\r
10763 ShowWindow(analysisDialog, SW_HIDE);
\r
10765 analysisDialogUp = FALSE;
\r
10770 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10772 highlightInfo.sq[0].x = fromX;
\r
10773 highlightInfo.sq[0].y = fromY;
\r
10774 highlightInfo.sq[1].x = toX;
\r
10775 highlightInfo.sq[1].y = toY;
\r
10779 ClearHighlights()
\r
10781 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10782 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10786 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10788 premoveHighlightInfo.sq[0].x = fromX;
\r
10789 premoveHighlightInfo.sq[0].y = fromY;
\r
10790 premoveHighlightInfo.sq[1].x = toX;
\r
10791 premoveHighlightInfo.sq[1].y = toY;
\r
10795 ClearPremoveHighlights()
\r
10797 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10798 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10802 ShutDownFrontEnd()
\r
10804 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10805 DeleteClipboardTempFiles();
\r
10811 if (IsIconic(hwndMain))
\r
10812 ShowWindow(hwndMain, SW_RESTORE);
\r
10814 SetActiveWindow(hwndMain);
\r
10818 * Prototypes for animation support routines
\r
10820 static void ScreenSquare(int column, int row, POINT * pt);
\r
10821 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10822 POINT frames[], int * nFrames);
\r
10826 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10827 { // [HGM] atomic: animate blast wave
\r
10829 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10830 explodeInfo.fromX = fromX;
\r
10831 explodeInfo.fromY = fromY;
\r
10832 explodeInfo.toX = toX;
\r
10833 explodeInfo.toY = toY;
\r
10834 for(i=1; i<nFrames; i++) {
\r
10835 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10836 DrawPosition(FALSE, NULL);
\r
10837 Sleep(appData.animSpeed);
\r
10839 explodeInfo.radius = 0;
\r
10840 DrawPosition(TRUE, NULL);
\r
10843 #define kFactor 4
\r
10846 AnimateMove(board, fromX, fromY, toX, toY)
\r
10853 ChessSquare piece;
\r
10854 POINT start, finish, mid;
\r
10855 POINT frames[kFactor * 2 + 1];
\r
10858 if (!appData.animate) return;
\r
10859 if (doingSizing) return;
\r
10860 if (fromY < 0 || fromX < 0) return;
\r
10861 piece = board[fromY][fromX];
\r
10862 if (piece >= EmptySquare) return;
\r
10864 ScreenSquare(fromX, fromY, &start);
\r
10865 ScreenSquare(toX, toY, &finish);
\r
10867 /* All pieces except knights move in straight line */
\r
10868 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10869 mid.x = start.x + (finish.x - start.x) / 2;
\r
10870 mid.y = start.y + (finish.y - start.y) / 2;
\r
10872 /* Knight: make diagonal movement then straight */
\r
10873 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10874 mid.x = start.x + (finish.x - start.x) / 2;
\r
10875 mid.y = finish.y;
\r
10877 mid.x = finish.x;
\r
10878 mid.y = start.y + (finish.y - start.y) / 2;
\r
10882 /* Don't use as many frames for very short moves */
\r
10883 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10884 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10886 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10888 animInfo.from.x = fromX;
\r
10889 animInfo.from.y = fromY;
\r
10890 animInfo.to.x = toX;
\r
10891 animInfo.to.y = toY;
\r
10892 animInfo.lastpos = start;
\r
10893 animInfo.piece = piece;
\r
10894 for (n = 0; n < nFrames; n++) {
\r
10895 animInfo.pos = frames[n];
\r
10896 DrawPosition(FALSE, NULL);
\r
10897 animInfo.lastpos = animInfo.pos;
\r
10898 Sleep(appData.animSpeed);
\r
10900 animInfo.pos = finish;
\r
10901 DrawPosition(FALSE, NULL);
\r
10902 animInfo.piece = EmptySquare;
\r
10903 if(gameInfo.variant == VariantAtomic &&
\r
10904 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10905 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10908 /* Convert board position to corner of screen rect and color */
\r
10911 ScreenSquare(column, row, pt)
\r
10912 int column; int row; POINT * pt;
\r
10915 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10916 pt->y = lineGap + row * (squareSize + lineGap);
\r
10918 pt->x = lineGap + column * (squareSize + lineGap);
\r
10919 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10923 /* Generate a series of frame coords from start->mid->finish.
\r
10924 The movement rate doubles until the half way point is
\r
10925 reached, then halves back down to the final destination,
\r
10926 which gives a nice slow in/out effect. The algorithmn
\r
10927 may seem to generate too many intermediates for short
\r
10928 moves, but remember that the purpose is to attract the
\r
10929 viewers attention to the piece about to be moved and
\r
10930 then to where it ends up. Too few frames would be less
\r
10934 Tween(start, mid, finish, factor, frames, nFrames)
\r
10935 POINT * start; POINT * mid;
\r
10936 POINT * finish; int factor;
\r
10937 POINT frames[]; int * nFrames;
\r
10939 int n, fraction = 1, count = 0;
\r
10941 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10942 for (n = 0; n < factor; n++)
\r
10944 for (n = 0; n < factor; n++) {
\r
10945 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10946 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10948 fraction = fraction / 2;
\r
10952 frames[count] = *mid;
\r
10955 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10957 for (n = 0; n < factor; n++) {
\r
10958 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10959 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10961 fraction = fraction * 2;
\r
10963 *nFrames = count;
\r
10967 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10972 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10973 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10975 OutputDebugString( buf );
\r
10978 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10980 EvalGraphSet( first, last, current, pvInfoList );
\r
10983 void SetProgramStats( FrontEndProgramStats * stats )
\r
10988 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10989 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10991 OutputDebugString( buf );
\r
10994 EngineOutputUpdate( stats );
\r