2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
83 #include "winboard.h"
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
87 #include "wclipbrd.h"
\r
88 #include "wgamelist.h"
\r
89 #include "wedittags.h"
\r
90 #include "woptions.h"
\r
91 #include "wsockerr.h"
\r
92 #include "defaults.h"
\r
96 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
99 void mysrandom(unsigned int seed);
\r
101 extern int whiteFlag, blackFlag;
\r
102 Boolean flipClock = FALSE;
\r
104 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
105 VOID NewVariantPopup(HWND hwnd);
\r
106 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
107 /*char*/int promoChar));
\r
108 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
109 void DisplayMove P((int moveNumber));
\r
110 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
112 ChessSquare piece;
\r
113 POINT pos; /* window coordinates of current pos */
\r
114 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
115 POINT from; /* board coordinates of the piece's orig pos */
\r
116 POINT to; /* board coordinates of the piece's new pos */
\r
119 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
122 POINT start; /* window coordinates of start pos */
\r
123 POINT pos; /* window coordinates of current pos */
\r
124 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
125 POINT from; /* board coordinates of the piece's orig pos */
\r
128 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
131 POINT sq[2]; /* board coordinates of from, to squares */
\r
134 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
135 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
137 typedef struct { // [HGM] atomic
\r
138 int fromX, fromY, toX, toY, radius;
\r
141 static ExplodeInfo explodeInfo;
\r
143 /* Window class names */
\r
144 char szAppName[] = "WinBoard";
\r
145 char szConsoleName[] = "WBConsole";
\r
147 /* Title bar text */
\r
148 char szTitle[] = "WinBoard";
\r
149 char szConsoleTitle[] = "I C S Interaction";
\r
152 char *settingsFileName;
\r
153 BOOLEAN saveSettingsOnExit;
\r
154 char installDir[MSG_SIZ];
\r
156 BoardSize boardSize;
\r
157 BOOLEAN chessProgram;
\r
158 static int boardX, boardY;
\r
159 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
160 static int squareSize, lineGap, minorSize;
\r
161 static int winWidth, winHeight, winW, winH;
\r
162 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
163 static int logoHeight = 0;
\r
164 static char messageText[MESSAGE_TEXT_MAX];
\r
165 static int clockTimerEvent = 0;
\r
166 static int loadGameTimerEvent = 0;
\r
167 static int analysisTimerEvent = 0;
\r
168 static DelayedEventCallback delayedTimerCallback;
\r
169 static int delayedTimerEvent = 0;
\r
170 static int buttonCount = 2;
\r
171 char *icsTextMenuString;
\r
173 char *firstChessProgramNames;
\r
174 char *secondChessProgramNames;
\r
176 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
178 #define PALETTESIZE 256
\r
180 HINSTANCE hInst; /* current instance */
\r
181 HWND hwndMain = NULL; /* root window*/
\r
182 HWND hwndConsole = NULL;
\r
183 BOOLEAN alwaysOnTop = FALSE;
\r
185 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
186 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
188 ColorClass currentColorClass;
\r
190 HWND hCommPort = NULL; /* currently open comm port */
\r
191 static HWND hwndPause; /* pause button */
\r
192 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
193 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
194 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
195 explodeBrush, /* [HGM] atomic */
\r
196 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
197 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
198 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
199 static HPEN gridPen = NULL;
\r
200 static HPEN highlightPen = NULL;
\r
201 static HPEN premovePen = NULL;
\r
202 static NPLOGPALETTE pLogPal;
\r
203 static BOOL paletteChanged = FALSE;
\r
204 static HICON iconWhite, iconBlack, iconCurrent;
\r
205 static int doingSizing = FALSE;
\r
206 static int lastSizing = 0;
\r
207 static int prevStderrPort;
\r
208 static HBITMAP userLogo;
\r
210 /* [AS] Support for background textures */
\r
211 #define BACK_TEXTURE_MODE_DISABLED 0
\r
212 #define BACK_TEXTURE_MODE_PLAIN 1
\r
213 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
215 static HBITMAP liteBackTexture = NULL;
\r
216 static HBITMAP darkBackTexture = NULL;
\r
217 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
218 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
219 static int backTextureSquareSize = 0;
\r
220 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
222 #if __GNUC__ && !defined(_winmajor)
\r
223 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
225 #define oldDialog (_winmajor < 4)
\r
228 char *defaultTextAttribs[] =
\r
230 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
231 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
241 int cliWidth, cliHeight;
\r
244 SizeInfo sizeInfo[] =
\r
246 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
247 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
248 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
249 { "petite", 33, 1, 1, 1, 0, 0 },
\r
250 { "slim", 37, 2, 1, 0, 0, 0 },
\r
251 { "small", 40, 2, 1, 0, 0, 0 },
\r
252 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
253 { "middling", 49, 2, 0, 0, 0, 0 },
\r
254 { "average", 54, 2, 0, 0, 0, 0 },
\r
255 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
256 { "medium", 64, 3, 0, 0, 0, 0 },
\r
257 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
258 { "large", 80, 3, 0, 0, 0, 0 },
\r
259 { "big", 87, 3, 0, 0, 0, 0 },
\r
260 { "huge", 95, 3, 0, 0, 0, 0 },
\r
261 { "giant", 108, 3, 0, 0, 0, 0 },
\r
262 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
263 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
264 { NULL, 0, 0, 0, 0, 0, 0 }
\r
267 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
268 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
270 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
271 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
272 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
273 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
274 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
275 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
276 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
277 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
278 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
279 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
280 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
281 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
282 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
283 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
284 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
285 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
286 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
287 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
290 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
299 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
300 #define N_BUTTONS 5
\r
302 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
304 {"<<", IDM_ToStart, NULL, NULL},
\r
305 {"<", IDM_Backward, NULL, NULL},
\r
306 {"P", IDM_Pause, NULL, NULL},
\r
307 {">", IDM_Forward, NULL, NULL},
\r
308 {">>", IDM_ToEnd, NULL, NULL},
\r
311 int tinyLayout = 0, smallLayout = 0;
\r
312 #define MENU_BAR_ITEMS 7
\r
313 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
314 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
315 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
319 MySound sounds[(int)NSoundClasses];
\r
320 MyTextAttribs textAttribs[(int)NColorClasses];
\r
322 MyColorizeAttribs colorizeAttribs[] = {
\r
323 { (COLORREF)0, 0, "Shout Text" },
\r
324 { (COLORREF)0, 0, "SShout/CShout" },
\r
325 { (COLORREF)0, 0, "Channel 1 Text" },
\r
326 { (COLORREF)0, 0, "Channel Text" },
\r
327 { (COLORREF)0, 0, "Kibitz Text" },
\r
328 { (COLORREF)0, 0, "Tell Text" },
\r
329 { (COLORREF)0, 0, "Challenge Text" },
\r
330 { (COLORREF)0, 0, "Request Text" },
\r
331 { (COLORREF)0, 0, "Seek Text" },
\r
332 { (COLORREF)0, 0, "Normal Text" },
\r
333 { (COLORREF)0, 0, "None" }
\r
338 static char *commentTitle;
\r
339 static char *commentText;
\r
340 static int commentIndex;
\r
341 static Boolean editComment = FALSE;
\r
342 HWND commentDialog = NULL;
\r
343 BOOLEAN commentDialogUp = FALSE;
\r
344 static int commentX, commentY, commentH, commentW;
\r
346 static char *analysisTitle;
\r
347 static char *analysisText;
\r
348 HWND analysisDialog = NULL;
\r
349 BOOLEAN analysisDialogUp = FALSE;
\r
350 static int analysisX, analysisY, analysisH, analysisW;
\r
352 char errorTitle[MSG_SIZ];
\r
353 char errorMessage[2*MSG_SIZ];
\r
354 HWND errorDialog = NULL;
\r
355 BOOLEAN moveErrorMessageUp = FALSE;
\r
356 BOOLEAN consoleEcho = TRUE;
\r
357 CHARFORMAT consoleCF;
\r
358 COLORREF consoleBackgroundColor;
\r
360 char *programVersion;
\r
366 typedef int CPKind;
\r
375 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
378 #define INPUT_SOURCE_BUF_SIZE 4096
\r
380 typedef struct _InputSource {
\r
387 char buf[INPUT_SOURCE_BUF_SIZE];
\r
391 InputCallback func;
\r
392 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
396 InputSource *consoleInputSource;
\r
401 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
402 VOID ConsoleCreate();
\r
404 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
405 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
406 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
407 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
409 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
410 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
411 void ParseIcsTextMenu(char *icsTextMenuString);
\r
412 VOID PopUpMoveDialog(char firstchar);
\r
413 VOID PopUpNameDialog(char firstchar);
\r
414 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
418 int GameListOptions();
\r
420 HWND moveHistoryDialog = NULL;
\r
421 BOOLEAN moveHistoryDialogUp = FALSE;
\r
423 WindowPlacement wpMoveHistory;
\r
425 HWND evalGraphDialog = NULL;
\r
426 BOOLEAN evalGraphDialogUp = FALSE;
\r
428 WindowPlacement wpEvalGraph;
\r
430 HWND engineOutputDialog = NULL;
\r
431 BOOLEAN engineOutputDialogUp = FALSE;
\r
433 WindowPlacement wpEngineOutput;
\r
434 WindowPlacement wpGameList;
\r
435 WindowPlacement wpConsole;
\r
437 VOID MoveHistoryPopUp();
\r
438 VOID MoveHistoryPopDown();
\r
439 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
440 BOOL MoveHistoryIsUp();
\r
442 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
443 VOID EvalGraphPopUp();
\r
444 VOID EvalGraphPopDown();
\r
445 BOOL EvalGraphIsUp();
\r
447 VOID EngineOutputPopUp();
\r
448 VOID EngineOutputPopDown();
\r
449 BOOL EngineOutputIsUp();
\r
450 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
452 VOID GothicPopUp(char *title, VariantClass variant);
\r
454 * Setting "frozen" should disable all user input other than deleting
\r
455 * the window. We do this while engines are initializing themselves.
\r
457 static int frozen = 0;
\r
458 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
464 if (frozen) return;
\r
466 hmenu = GetMenu(hwndMain);
\r
467 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
468 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
470 DrawMenuBar(hwndMain);
\r
473 /* Undo a FreezeUI */
\r
479 if (!frozen) return;
\r
481 hmenu = GetMenu(hwndMain);
\r
482 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
483 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
485 DrawMenuBar(hwndMain);
\r
488 static int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
490 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
495 #define JAWS_ALT_INTERCEPT
\r
496 #define JAWS_KB_NAVIGATION
\r
497 #define JAWS_MENU_ITEMS
\r
498 #define JAWS_SILENCE
\r
499 #define JAWS_REPLAY
\r
501 #define JAWS_COPYRIGHT
\r
502 #define JAWS_DELETE(X) X
\r
503 #define SAYMACHINEMOVE()
\r
507 /*---------------------------------------------------------------------------*\
\r
511 \*---------------------------------------------------------------------------*/
\r
514 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
515 LPSTR lpCmdLine, int nCmdShow)
\r
518 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
519 // INITCOMMONCONTROLSEX ex;
\r
523 LoadLibrary("RICHED32.DLL");
\r
524 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
526 if (!InitApplication(hInstance)) {
\r
529 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
535 // InitCommonControlsEx(&ex);
\r
536 InitCommonControls();
\r
538 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
539 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
540 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
542 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
544 while (GetMessage(&msg, /* message structure */
\r
545 NULL, /* handle of window receiving the message */
\r
546 0, /* lowest message to examine */
\r
547 0)) /* highest message to examine */
\r
550 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
551 // [HGM] navigate: switch between all windows with tab
\r
552 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
553 int i, currentElement = 0;
\r
555 // first determine what element of the chain we come from (if any)
\r
556 if(appData.icsActive) {
\r
557 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
558 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
560 if(engineOutputDialog && EngineOutputIsUp()) {
\r
561 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
562 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
564 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
565 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
567 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
568 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
569 if(msg.hwnd == e1) currentElement = 2; else
\r
570 if(msg.hwnd == e2) currentElement = 3; else
\r
571 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
572 if(msg.hwnd == mh) currentElement = 4; else
\r
573 if(msg.hwnd == evalGraphDialog) currentElement = 7; else
\r
574 if(msg.hwnd == hText) currentElement = 5; else
\r
575 if(msg.hwnd == hInput) currentElement = 6; else
\r
576 for (i = 0; i < N_BUTTONS; i++) {
\r
577 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
580 // determine where to go to
\r
581 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
583 currentElement = (currentElement + direction) % 7;
\r
584 switch(currentElement) {
\r
586 h = hwndMain; break; // passing this case always makes the loop exit
\r
588 h = buttonDesc[0].hwnd; break; // could be NULL
\r
590 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
593 if(!EngineOutputIsUp()) continue;
\r
596 if(!MoveHistoryIsUp()) continue;
\r
598 // case 5: // input to eval graph does not seem to get here!
\r
599 // if(!EvalGraphIsUp()) continue;
\r
600 // h = evalGraphDialog; break;
\r
602 if(!appData.icsActive) continue;
\r
606 if(!appData.icsActive) continue;
\r
612 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
613 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
616 continue; // this message now has been processed
\r
620 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
621 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
622 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
623 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
624 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
625 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
626 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
627 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
628 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
629 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
630 TranslateMessage(&msg); /* Translates virtual key codes */
\r
631 DispatchMessage(&msg); /* Dispatches message to window */
\r
636 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
639 /*---------------------------------------------------------------------------*\
\r
641 * Initialization functions
\r
643 \*---------------------------------------------------------------------------*/
\r
647 { // update user logo if necessary
\r
648 static char oldUserName[MSG_SIZ], *curName;
\r
650 if(appData.autoLogo) {
\r
651 curName = UserName();
\r
652 if(strcmp(curName, oldUserName)) {
\r
653 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
654 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
655 strcpy(oldUserName, curName);
\r
661 InitApplication(HINSTANCE hInstance)
\r
665 /* Fill in window class structure with parameters that describe the */
\r
668 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
669 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
670 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
671 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
672 wc.hInstance = hInstance; /* Owner of this class */
\r
673 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
674 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
675 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
676 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
677 wc.lpszClassName = szAppName; /* Name to register as */
\r
679 /* Register the window class and return success/failure code. */
\r
680 if (!RegisterClass(&wc)) return FALSE;
\r
682 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
683 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
685 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
686 wc.hInstance = hInstance;
\r
687 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
688 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
689 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
690 wc.lpszMenuName = NULL;
\r
691 wc.lpszClassName = szConsoleName;
\r
693 if (!RegisterClass(&wc)) return FALSE;
\r
698 /* Set by InitInstance, used by EnsureOnScreen */
\r
699 int screenHeight, screenWidth;
\r
702 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
704 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
705 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
706 if (*x > screenWidth - 32) *x = 0;
\r
707 if (*y > screenHeight - 32) *y = 0;
\r
708 if (*x < minX) *x = minX;
\r
709 if (*y < minY) *y = minY;
\r
713 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
715 HWND hwnd; /* Main window handle. */
\r
717 WINDOWPLACEMENT wp;
\r
720 hInst = hInstance; /* Store instance handle in our global variable */
\r
722 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
723 *filepart = NULLCHAR;
\r
725 GetCurrentDirectory(MSG_SIZ, installDir);
\r
727 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
728 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
729 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
730 if (appData.debugMode) {
\r
731 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
732 setbuf(debugFP, NULL);
\r
737 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
738 // InitEngineUCI( installDir, &second );
\r
740 /* Create a main window for this application instance. */
\r
741 hwnd = CreateWindow(szAppName, szTitle,
\r
742 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
743 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
744 NULL, NULL, hInstance, NULL);
\r
747 /* If window could not be created, return "failure" */
\r
752 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
753 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
754 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
756 if (first.programLogo == NULL && appData.debugMode) {
\r
757 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
759 } else if(appData.autoLogo) {
\r
760 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
762 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
763 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
767 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
768 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
770 if (second.programLogo == NULL && appData.debugMode) {
\r
771 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
773 } else if(appData.autoLogo) {
\r
775 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
776 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
777 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
779 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
780 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
781 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
787 iconWhite = LoadIcon(hInstance, "icon_white");
\r
788 iconBlack = LoadIcon(hInstance, "icon_black");
\r
789 iconCurrent = iconWhite;
\r
790 InitDrawingColors();
\r
791 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
792 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
793 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
794 /* Compute window size for each board size, and use the largest
\r
795 size that fits on this screen as the default. */
\r
796 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
797 if (boardSize == (BoardSize)-1 &&
\r
798 winH <= screenHeight
\r
799 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
800 && winW <= screenWidth) {
\r
801 boardSize = (BoardSize)ibs;
\r
805 InitDrawingSizes(boardSize, 0);
\r
807 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
809 /* [AS] Load textures if specified */
\r
810 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
812 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
813 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
814 liteBackTextureMode = appData.liteBackTextureMode;
\r
816 if (liteBackTexture == NULL && appData.debugMode) {
\r
817 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
821 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
822 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
823 darkBackTextureMode = appData.darkBackTextureMode;
\r
825 if (darkBackTexture == NULL && appData.debugMode) {
\r
826 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
830 mysrandom( (unsigned) time(NULL) );
\r
832 /* [AS] Restore layout */
\r
833 if( wpMoveHistory.visible ) {
\r
834 MoveHistoryPopUp();
\r
837 if( wpEvalGraph.visible ) {
\r
841 if( wpEngineOutput.visible ) {
\r
842 EngineOutputPopUp();
\r
847 /* Make the window visible; update its client area; and return "success" */
\r
848 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
849 wp.length = sizeof(WINDOWPLACEMENT);
\r
851 wp.showCmd = nCmdShow;
\r
852 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
853 wp.rcNormalPosition.left = boardX;
\r
854 wp.rcNormalPosition.right = boardX + winWidth;
\r
855 wp.rcNormalPosition.top = boardY;
\r
856 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
857 SetWindowPlacement(hwndMain, &wp);
\r
859 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
860 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
864 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
865 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
867 ShowWindow(hwndConsole, nCmdShow);
\r
869 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
877 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
878 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
879 ArgSettingsFilename,
\r
880 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
888 String *pString; // ArgString
\r
889 int *pInt; // ArgInt
\r
890 float *pFloat; // ArgFloat
\r
891 Boolean *pBoolean; // ArgBoolean
\r
892 COLORREF *pColor; // ArgColor
\r
893 ColorClass cc; // ArgAttribs
\r
894 String *pFilename; // ArgFilename
\r
895 BoardSize *pBoardSize; // ArgBoardSize
\r
896 int whichFont; // ArgFont
\r
897 DCB *pDCB; // ArgCommSettings
\r
898 String *pFilename; // ArgSettingsFilename
\r
906 ArgDescriptor argDescriptors[] = {
\r
907 /* positional arguments */
\r
908 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
909 { "", ArgNone, NULL },
\r
910 /* keyword arguments */
\r
911 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
912 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
913 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
914 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
915 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
916 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
917 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
918 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
919 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
920 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
921 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
922 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
923 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
924 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
925 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
926 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
927 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
928 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
930 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
932 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
934 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
935 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
937 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
938 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
939 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
940 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
941 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
942 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
943 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
944 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
945 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
946 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
947 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
948 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
949 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
950 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
951 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
952 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
953 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
954 /*!!bitmapDirectory?*/
\r
955 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
956 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
957 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
958 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
959 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
960 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
961 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
962 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
963 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
964 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
965 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
966 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
967 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
968 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
969 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
970 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
971 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
972 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
973 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
974 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
975 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
976 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
977 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
978 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
979 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
980 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
981 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
982 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
983 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
984 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
985 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
986 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
987 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
988 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
989 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
990 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
991 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
992 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
993 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
994 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
995 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
996 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
997 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
998 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
999 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1000 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1001 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1002 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1003 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1004 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1005 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1006 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1007 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1008 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1009 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1010 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1011 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1012 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1013 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1014 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1015 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1016 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1017 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1018 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1019 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1020 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1021 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1022 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1023 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1024 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1025 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1026 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1027 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1028 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1029 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1030 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1031 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1032 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1033 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1034 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1035 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1036 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1037 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1038 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1039 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1040 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1041 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1042 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1043 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1044 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1045 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1046 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1047 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1048 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1049 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1050 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1051 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1052 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1053 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1054 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1055 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1056 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1057 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1058 TRUE }, /* must come after all fonts */
\r
1059 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1060 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1061 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1062 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1063 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1064 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1065 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1066 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1067 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1068 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1069 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1070 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1071 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1072 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1073 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1074 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1075 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1076 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1077 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1078 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1079 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1080 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1081 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1082 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1083 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1084 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1085 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1086 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1087 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1088 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1089 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1091 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1092 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1094 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1095 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1096 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1097 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1098 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1099 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1100 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1101 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1102 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1103 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1104 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1105 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1106 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1107 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1108 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1109 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1110 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1111 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1112 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1113 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1114 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1115 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1116 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1117 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1118 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1119 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1120 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1121 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1122 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1123 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1124 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1125 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1126 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1127 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1128 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1129 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1130 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1131 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1132 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1133 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1134 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1135 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1136 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1137 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1138 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1139 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1140 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1141 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1142 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1143 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1144 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1145 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1146 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1147 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1148 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1149 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1150 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1151 { "highlightLastMove", ArgBoolean,
\r
1152 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1153 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1154 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1155 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1156 { "highlightDragging", ArgBoolean,
\r
1157 (LPVOID) &appData.highlightDragging, TRUE },
\r
1158 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1159 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1160 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1161 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1162 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1163 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1164 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1165 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1166 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1167 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1168 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1169 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1170 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1171 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1172 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1173 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1174 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1175 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1176 { "soundShout", ArgFilename,
\r
1177 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1178 { "soundSShout", ArgFilename,
\r
1179 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1180 { "soundChannel1", ArgFilename,
\r
1181 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1182 { "soundChannel", ArgFilename,
\r
1183 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1184 { "soundKibitz", ArgFilename,
\r
1185 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1186 { "soundTell", ArgFilename,
\r
1187 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1188 { "soundChallenge", ArgFilename,
\r
1189 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1190 { "soundRequest", ArgFilename,
\r
1191 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1192 { "soundSeek", ArgFilename,
\r
1193 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1194 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1195 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1196 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1197 { "soundIcsLoss", ArgFilename,
\r
1198 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1199 { "soundIcsDraw", ArgFilename,
\r
1200 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1201 { "soundIcsUnfinished", ArgFilename,
\r
1202 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1203 { "soundIcsAlarm", ArgFilename,
\r
1204 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1205 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1206 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1207 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1208 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1209 { "reuseChessPrograms", ArgBoolean,
\r
1210 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1211 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1212 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1213 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1214 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1215 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1216 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1217 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1218 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1219 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1220 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1221 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1222 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1223 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1224 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1225 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1227 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1229 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1230 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1231 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1232 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1233 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1234 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1235 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1236 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1237 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1238 /* [AS] New features */
\r
1239 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1240 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1241 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1242 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1243 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1244 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1245 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1246 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1247 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1248 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1249 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1250 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1251 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1252 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1253 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1254 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1255 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1256 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1257 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1258 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1259 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1260 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1261 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1262 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1263 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1264 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1265 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1266 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1267 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1268 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1269 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1270 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1271 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1272 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1273 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1274 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1275 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1276 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1277 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1278 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1279 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1280 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1281 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1282 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1283 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1284 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1285 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1286 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1287 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1288 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1290 /* [HGM] board-size, adjudication and misc. options */
\r
1291 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1292 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1293 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1294 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1295 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1296 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1297 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1298 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1299 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1300 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1301 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1302 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1303 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1304 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1305 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1306 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1307 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1308 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1309 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1310 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1311 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1312 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1313 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1314 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1315 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1316 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1317 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1318 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1319 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1320 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1321 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1324 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1325 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1326 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1327 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1328 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1329 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1330 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1331 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1332 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1333 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1334 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1335 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1336 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1338 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1339 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1340 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1341 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1342 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1343 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1344 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1346 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1347 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1348 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1349 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1350 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1351 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1352 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1353 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1354 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1355 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1356 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1357 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1358 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1359 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1360 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1361 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1362 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1363 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1364 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1366 /* [HGM] options for broadcasting and time odds */
\r
1367 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1368 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1369 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1370 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1371 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1372 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1373 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1374 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1375 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1376 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1377 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1379 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1380 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1381 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1382 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1383 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1384 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1385 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1386 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1387 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1388 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1389 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1390 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1391 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1392 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1393 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1394 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1395 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1396 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1397 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1398 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1399 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1400 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1401 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1402 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1403 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1404 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1405 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1406 /* [AS] Layout stuff */
\r
1407 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1408 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1409 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1410 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1411 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1413 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1414 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1415 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1416 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1417 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1419 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1420 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1421 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1422 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1423 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1425 { NULL, ArgNone, NULL, FALSE }
\r
1429 /* Kludge for indirection files on command line */
\r
1430 char* lastIndirectionFilename;
\r
1431 ArgDescriptor argDescriptorIndirection =
\r
1432 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1436 ExitArgError(char *msg, char *badArg)
\r
1438 char buf[MSG_SIZ];
\r
1440 sprintf(buf, "%s %s", msg, badArg);
\r
1441 DisplayFatalError(buf, 0, 2);
\r
1445 /* Command line font name parser. NULL name means do nothing.
\r
1446 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1447 For backward compatibility, syntax without the colon is also
\r
1448 accepted, but font names with digits in them won't work in that case.
\r
1451 ParseFontName(char *name, MyFontParams *mfp)
\r
1454 if (name == NULL) return;
\r
1456 q = strchr(p, ':');
\r
1458 if (q - p >= sizeof(mfp->faceName))
\r
1459 ExitArgError("Font name too long:", name);
\r
1460 memcpy(mfp->faceName, p, q - p);
\r
1461 mfp->faceName[q - p] = NULLCHAR;
\r
1464 q = mfp->faceName;
\r
1465 while (*p && !isdigit(*p)) {
\r
1467 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1468 ExitArgError("Font name too long:", name);
\r
1470 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1473 if (!*p) ExitArgError("Font point size missing:", name);
\r
1474 mfp->pointSize = (float) atof(p);
\r
1475 mfp->bold = (strchr(p, 'b') != NULL);
\r
1476 mfp->italic = (strchr(p, 'i') != NULL);
\r
1477 mfp->underline = (strchr(p, 'u') != NULL);
\r
1478 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1481 /* Color name parser.
\r
1482 X version accepts X color names, but this one
\r
1483 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1485 ParseColorName(char *name)
\r
1487 int red, green, blue, count;
\r
1488 char buf[MSG_SIZ];
\r
1490 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1492 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1493 &red, &green, &blue);
\r
1496 sprintf(buf, "Can't parse color name %s", name);
\r
1497 DisplayError(buf, 0);
\r
1498 return RGB(0, 0, 0);
\r
1500 return PALETTERGB(red, green, blue);
\r
1504 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1506 char *e = argValue;
\r
1510 if (*e == 'b') eff |= CFE_BOLD;
\r
1511 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1512 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1513 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1514 else if (*e == '#' || isdigit(*e)) break;
\r
1518 *color = ParseColorName(e);
\r
1523 ParseBoardSize(char *name)
\r
1525 BoardSize bs = SizeTiny;
\r
1526 while (sizeInfo[bs].name != NULL) {
\r
1527 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1530 ExitArgError("Unrecognized board size value", name);
\r
1531 return bs; /* not reached */
\r
1536 StringGet(void *getClosure)
\r
1538 char **p = (char **) getClosure;
\r
1543 FileGet(void *getClosure)
\r
1546 FILE* f = (FILE*) getClosure;
\r
1549 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1556 /* Parse settings file named "name". If file found, return the
\r
1557 full name in fullname and return TRUE; else return FALSE */
\r
1559 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1563 int ok; char buf[MSG_SIZ];
\r
1565 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1566 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1567 sprintf(buf, "%s.ini", name);
\r
1568 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1571 f = fopen(fullname, "r");
\r
1573 ParseArgs(FileGet, f);
\r
1582 ParseArgs(GetFunc get, void *cl)
\r
1584 char argName[ARG_MAX];
\r
1585 char argValue[ARG_MAX];
\r
1586 ArgDescriptor *ad;
\r
1595 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1596 if (ch == NULLCHAR) break;
\r
1598 /* Comment to end of line */
\r
1600 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1602 } else if (ch == '/' || ch == '-') {
\r
1605 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1606 ch != '\n' && ch != '\t') {
\r
1612 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1613 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1615 if (ad->argName == NULL)
\r
1616 ExitArgError("Unrecognized argument", argName);
\r
1618 } else if (ch == '@') {
\r
1619 /* Indirection file */
\r
1620 ad = &argDescriptorIndirection;
\r
1623 /* Positional argument */
\r
1624 ad = &argDescriptors[posarg++];
\r
1625 strcpy(argName, ad->argName);
\r
1628 if (ad->argType == ArgTrue) {
\r
1629 *(Boolean *) ad->argLoc = TRUE;
\r
1632 if (ad->argType == ArgFalse) {
\r
1633 *(Boolean *) ad->argLoc = FALSE;
\r
1637 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1638 if (ch == NULLCHAR || ch == '\n') {
\r
1639 ExitArgError("No value provided for argument", argName);
\r
1643 // Quoting with { }. No characters have to (or can) be escaped.
\r
1644 // Thus the string cannot contain a '}' character.
\r
1664 } else if (ch == '\'' || ch == '"') {
\r
1665 // Quoting with ' ' or " ", with \ as escape character.
\r
1666 // Inconvenient for long strings that may contain Windows filenames.
\r
1683 if (ch == start) {
\r
1692 if (ad->argType == ArgFilename
\r
1693 || ad->argType == ArgSettingsFilename) {
\r
1699 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1723 for (i = 0; i < 3; i++) {
\r
1724 if (ch >= '0' && ch <= '7') {
\r
1725 octval = octval*8 + (ch - '0');
\r
1732 *q++ = (char) octval;
\r
1743 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1750 switch (ad->argType) {
\r
1752 *(int *) ad->argLoc = atoi(argValue);
\r
1756 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1760 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1764 *(int *) ad->argLoc = atoi(argValue);
\r
1765 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1769 *(float *) ad->argLoc = (float) atof(argValue);
\r
1774 *(char **) ad->argLoc = strdup(argValue);
\r
1777 case ArgSettingsFilename:
\r
1779 char fullname[MSG_SIZ];
\r
1780 if (ParseSettingsFile(argValue, fullname)) {
\r
1781 if (ad->argLoc != NULL) {
\r
1782 *(char **) ad->argLoc = strdup(fullname);
\r
1785 if (ad->argLoc != NULL) {
\r
1787 ExitArgError("Failed to open indirection file", argValue);
\r
1794 switch (argValue[0]) {
\r
1797 *(Boolean *) ad->argLoc = TRUE;
\r
1801 *(Boolean *) ad->argLoc = FALSE;
\r
1804 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1810 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1813 case ArgAttribs: {
\r
1814 ColorClass cc = (ColorClass)ad->argLoc;
\r
1815 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1819 case ArgBoardSize:
\r
1820 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1824 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1827 case ArgCommSettings:
\r
1828 ParseCommSettings(argValue, &dcb);
\r
1832 ExitArgError("Unrecognized argument", argValue);
\r
1841 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1843 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1844 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1847 lf->lfEscapement = 0;
\r
1848 lf->lfOrientation = 0;
\r
1849 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1850 lf->lfItalic = mfp->italic;
\r
1851 lf->lfUnderline = mfp->underline;
\r
1852 lf->lfStrikeOut = mfp->strikeout;
\r
1853 lf->lfCharSet = DEFAULT_CHARSET;
\r
1854 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1855 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1856 lf->lfQuality = DEFAULT_QUALITY;
\r
1857 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1858 strcpy(lf->lfFaceName, mfp->faceName);
\r
1862 CreateFontInMF(MyFont *mf)
\r
1864 LFfromMFP(&mf->lf, &mf->mfp);
\r
1865 if (mf->hf) DeleteObject(mf->hf);
\r
1866 mf->hf = CreateFontIndirect(&mf->lf);
\r
1870 SetDefaultTextAttribs()
\r
1873 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1874 ParseAttribs(&textAttribs[cc].color,
\r
1875 &textAttribs[cc].effects,
\r
1876 defaultTextAttribs[cc]);
\r
1881 SetDefaultSounds()
\r
1885 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1886 textAttribs[cc].sound.name = strdup("");
\r
1887 textAttribs[cc].sound.data = NULL;
\r
1889 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1890 sounds[sc].name = strdup("");
\r
1891 sounds[sc].data = NULL;
\r
1893 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1901 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1902 MyLoadSound(&textAttribs[cc].sound);
\r
1904 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1905 MyLoadSound(&sounds[sc]);
\r
1910 InitAppData(LPSTR lpCmdLine)
\r
1913 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1916 programName = szAppName;
\r
1918 /* Initialize to defaults */
\r
1919 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1920 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1921 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1922 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1923 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1924 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1925 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1926 SetDefaultTextAttribs();
\r
1927 SetDefaultSounds();
\r
1928 appData.movesPerSession = MOVES_PER_SESSION;
\r
1929 appData.initString = INIT_STRING;
\r
1930 appData.secondInitString = INIT_STRING;
\r
1931 appData.firstComputerString = COMPUTER_STRING;
\r
1932 appData.secondComputerString = COMPUTER_STRING;
\r
1933 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1934 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1935 appData.firstPlaysBlack = FALSE;
\r
1936 appData.noChessProgram = FALSE;
\r
1937 chessProgram = FALSE;
\r
1938 appData.firstHost = FIRST_HOST;
\r
1939 appData.secondHost = SECOND_HOST;
\r
1940 appData.firstDirectory = FIRST_DIRECTORY;
\r
1941 appData.secondDirectory = SECOND_DIRECTORY;
\r
1942 appData.bitmapDirectory = "";
\r
1943 appData.remoteShell = REMOTE_SHELL;
\r
1944 appData.remoteUser = "";
\r
1945 appData.timeDelay = TIME_DELAY;
\r
1946 appData.timeControl = TIME_CONTROL;
\r
1947 appData.timeIncrement = TIME_INCREMENT;
\r
1948 appData.icsActive = FALSE;
\r
1949 appData.icsHost = "";
\r
1950 appData.icsPort = ICS_PORT;
\r
1951 appData.icsCommPort = ICS_COMM_PORT;
\r
1952 appData.icsLogon = ICS_LOGON;
\r
1953 appData.icsHelper = "";
\r
1954 appData.useTelnet = FALSE;
\r
1955 appData.telnetProgram = TELNET_PROGRAM;
\r
1956 appData.gateway = "";
\r
1957 appData.loadGameFile = "";
\r
1958 appData.loadGameIndex = 0;
\r
1959 appData.saveGameFile = "";
\r
1960 appData.autoSaveGames = FALSE;
\r
1961 appData.loadPositionFile = "";
\r
1962 appData.loadPositionIndex = 1;
\r
1963 appData.savePositionFile = "";
\r
1964 appData.matchMode = FALSE;
\r
1965 appData.matchGames = 0;
\r
1966 appData.monoMode = FALSE;
\r
1967 appData.debugMode = FALSE;
\r
1968 appData.clockMode = TRUE;
\r
1969 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1970 appData.Iconic = FALSE; /*unused*/
\r
1971 appData.searchTime = "";
\r
1972 appData.searchDepth = 0;
\r
1973 appData.showCoords = FALSE;
\r
1974 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1975 appData.autoCallFlag = FALSE;
\r
1976 appData.flipView = FALSE;
\r
1977 appData.autoFlipView = TRUE;
\r
1978 appData.cmailGameName = "";
\r
1979 appData.alwaysPromoteToQueen = FALSE;
\r
1980 appData.oldSaveStyle = FALSE;
\r
1981 appData.quietPlay = FALSE;
\r
1982 appData.showThinking = FALSE;
\r
1983 appData.ponderNextMove = TRUE;
\r
1984 appData.periodicUpdates = TRUE;
\r
1985 appData.popupExitMessage = TRUE;
\r
1986 appData.popupMoveErrors = FALSE;
\r
1987 appData.autoObserve = FALSE;
\r
1988 appData.autoComment = FALSE;
\r
1989 appData.animate = TRUE;
\r
1990 appData.animSpeed = 10;
\r
1991 appData.animateDragging = TRUE;
\r
1992 appData.highlightLastMove = TRUE;
\r
1993 appData.getMoveList = TRUE;
\r
1994 appData.testLegality = TRUE;
\r
1995 appData.premove = TRUE;
\r
1996 appData.premoveWhite = FALSE;
\r
1997 appData.premoveWhiteText = "";
\r
1998 appData.premoveBlack = FALSE;
\r
1999 appData.premoveBlackText = "";
\r
2000 appData.icsAlarm = TRUE;
\r
2001 appData.icsAlarmTime = 5000;
\r
2002 appData.autoRaiseBoard = TRUE;
\r
2003 appData.localLineEditing = TRUE;
\r
2004 appData.colorize = TRUE;
\r
2005 appData.reuseFirst = TRUE;
\r
2006 appData.reuseSecond = TRUE;
\r
2007 appData.blindfold = FALSE;
\r
2008 appData.icsEngineAnalyze = FALSE;
\r
2009 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2010 dcb.DCBlength = sizeof(DCB);
\r
2011 dcb.BaudRate = 9600;
\r
2012 dcb.fBinary = TRUE;
\r
2013 dcb.fParity = FALSE;
\r
2014 dcb.fOutxCtsFlow = FALSE;
\r
2015 dcb.fOutxDsrFlow = FALSE;
\r
2016 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2017 dcb.fDsrSensitivity = FALSE;
\r
2018 dcb.fTXContinueOnXoff = TRUE;
\r
2019 dcb.fOutX = FALSE;
\r
2021 dcb.fNull = FALSE;
\r
2022 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2023 dcb.fAbortOnError = FALSE;
\r
2025 dcb.Parity = SPACEPARITY;
\r
2026 dcb.StopBits = ONESTOPBIT;
\r
2027 settingsFileName = SETTINGS_FILE;
\r
2028 saveSettingsOnExit = TRUE;
\r
2029 boardX = CW_USEDEFAULT;
\r
2030 boardY = CW_USEDEFAULT;
\r
2031 analysisX = CW_USEDEFAULT;
\r
2032 analysisY = CW_USEDEFAULT;
\r
2033 analysisW = CW_USEDEFAULT;
\r
2034 analysisH = CW_USEDEFAULT;
\r
2035 commentX = CW_USEDEFAULT;
\r
2036 commentY = CW_USEDEFAULT;
\r
2037 commentW = CW_USEDEFAULT;
\r
2038 commentH = CW_USEDEFAULT;
\r
2039 editTagsX = CW_USEDEFAULT;
\r
2040 editTagsY = CW_USEDEFAULT;
\r
2041 editTagsW = CW_USEDEFAULT;
\r
2042 editTagsH = CW_USEDEFAULT;
\r
2043 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2044 icsNames = ICS_NAMES;
\r
2045 firstChessProgramNames = FCP_NAMES;
\r
2046 secondChessProgramNames = SCP_NAMES;
\r
2047 appData.initialMode = "";
\r
2048 appData.variant = "normal";
\r
2049 appData.firstProtocolVersion = PROTOVER;
\r
2050 appData.secondProtocolVersion = PROTOVER;
\r
2051 appData.showButtonBar = TRUE;
\r
2053 /* [AS] New properties (see comments in header file) */
\r
2054 appData.firstScoreIsAbsolute = FALSE;
\r
2055 appData.secondScoreIsAbsolute = FALSE;
\r
2056 appData.saveExtendedInfoInPGN = FALSE;
\r
2057 appData.hideThinkingFromHuman = FALSE;
\r
2058 appData.liteBackTextureFile = "";
\r
2059 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2060 appData.darkBackTextureFile = "";
\r
2061 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2062 appData.renderPiecesWithFont = "";
\r
2063 appData.fontToPieceTable = "";
\r
2064 appData.fontBackColorWhite = 0;
\r
2065 appData.fontForeColorWhite = 0;
\r
2066 appData.fontBackColorBlack = 0;
\r
2067 appData.fontForeColorBlack = 0;
\r
2068 appData.fontPieceSize = 80;
\r
2069 appData.overrideLineGap = 1;
\r
2070 appData.adjudicateLossThreshold = 0;
\r
2071 appData.delayBeforeQuit = 0;
\r
2072 appData.delayAfterQuit = 0;
\r
2073 appData.nameOfDebugFile = "winboard.debug";
\r
2074 appData.pgnEventHeader = "Computer Chess Game";
\r
2075 appData.defaultFrcPosition = -1;
\r
2076 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2077 appData.saveOutOfBookInfo = TRUE;
\r
2078 appData.showEvalInMoveHistory = TRUE;
\r
2079 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2080 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2081 appData.highlightMoveWithArrow = FALSE;
\r
2082 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2083 appData.useStickyWindows = TRUE;
\r
2084 appData.adjudicateDrawMoves = 0;
\r
2085 appData.autoDisplayComment = TRUE;
\r
2086 appData.autoDisplayTags = TRUE;
\r
2087 appData.firstIsUCI = FALSE;
\r
2088 appData.secondIsUCI = FALSE;
\r
2089 appData.firstHasOwnBookUCI = TRUE;
\r
2090 appData.secondHasOwnBookUCI = TRUE;
\r
2091 appData.polyglotDir = "";
\r
2092 appData.usePolyglotBook = FALSE;
\r
2093 appData.polyglotBook = "";
\r
2094 appData.defaultHashSize = 64;
\r
2095 appData.defaultCacheSizeEGTB = 4;
\r
2096 appData.defaultPathEGTB = "c:\\egtb";
\r
2097 appData.firstOptions = "";
\r
2098 appData.secondOptions = "";
\r
2100 InitWindowPlacement( &wpGameList );
\r
2101 InitWindowPlacement( &wpMoveHistory );
\r
2102 InitWindowPlacement( &wpEvalGraph );
\r
2103 InitWindowPlacement( &wpEngineOutput );
\r
2104 InitWindowPlacement( &wpConsole );
\r
2106 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2107 appData.NrFiles = -1;
\r
2108 appData.NrRanks = -1;
\r
2109 appData.holdingsSize = -1;
\r
2110 appData.testClaims = FALSE;
\r
2111 appData.checkMates = FALSE;
\r
2112 appData.materialDraws= FALSE;
\r
2113 appData.trivialDraws = FALSE;
\r
2114 appData.ruleMoves = 51;
\r
2115 appData.drawRepeats = 6;
\r
2116 appData.matchPause = 10000;
\r
2117 appData.alphaRank = FALSE;
\r
2118 appData.allWhite = FALSE;
\r
2119 appData.upsideDown = FALSE;
\r
2120 appData.serverPause = 15;
\r
2121 appData.serverMovesName = NULL;
\r
2122 appData.suppressLoadMoves = FALSE;
\r
2123 appData.firstTimeOdds = 1;
\r
2124 appData.secondTimeOdds = 1;
\r
2125 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2126 appData.secondAccumulateTC = 1;
\r
2127 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2128 appData.secondNPS = -1;
\r
2129 appData.engineComments = 1;
\r
2130 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2131 appData.egtFormats = "";
\r
2134 appData.zippyTalk = ZIPPY_TALK;
\r
2135 appData.zippyPlay = ZIPPY_PLAY;
\r
2136 appData.zippyLines = ZIPPY_LINES;
\r
2137 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2138 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2139 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2140 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2141 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2142 appData.zippyUseI = ZIPPY_USE_I;
\r
2143 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2144 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2145 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2146 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2147 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2148 appData.zippyAbort = ZIPPY_ABORT;
\r
2149 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2150 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2151 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2154 /* Point font array elements to structures and
\r
2155 parse default font names */
\r
2156 for (i=0; i<NUM_FONTS; i++) {
\r
2157 for (j=0; j<NUM_SIZES; j++) {
\r
2158 font[j][i] = &fontRec[j][i];
\r
2159 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2163 /* Parse default settings file if any */
\r
2164 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2165 settingsFileName = strdup(buf);
\r
2168 /* Parse command line */
\r
2169 ParseArgs(StringGet, &lpCmdLine);
\r
2171 /* [HGM] make sure board size is acceptable */
\r
2172 if(appData.NrFiles > BOARD_SIZE ||
\r
2173 appData.NrRanks > BOARD_SIZE )
\r
2174 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2176 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2177 * with options from the command line, we now make an even higher priority
\r
2178 * overrule by WB options attached to the engine command line. This so that
\r
2179 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2182 if(appData.firstChessProgram != NULL) {
\r
2183 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2184 static char *f = "first";
\r
2185 char buf[MSG_SIZ], *q = buf;
\r
2186 if(p != NULL) { // engine command line contains WinBoard options
\r
2187 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2188 ParseArgs(StringGet, &q);
\r
2189 p[-1] = 0; // cut them offengine command line
\r
2192 // now do same for second chess program
\r
2193 if(appData.secondChessProgram != NULL) {
\r
2194 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2195 static char *s = "second";
\r
2196 char buf[MSG_SIZ], *q = buf;
\r
2197 if(p != NULL) { // engine command line contains WinBoard options
\r
2198 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2199 ParseArgs(StringGet, &q);
\r
2200 p[-1] = 0; // cut them offengine command line
\r
2205 /* Propagate options that affect others */
\r
2206 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2207 if (appData.icsActive || appData.noChessProgram) {
\r
2208 chessProgram = FALSE; /* not local chess program mode */
\r
2211 /* Open startup dialog if needed */
\r
2212 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2213 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2214 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2215 *appData.secondChessProgram == NULLCHAR))) {
\r
2218 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2219 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2220 FreeProcInstance(lpProc);
\r
2223 /* Make sure save files land in the right (?) directory */
\r
2224 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2225 appData.saveGameFile = strdup(buf);
\r
2227 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2228 appData.savePositionFile = strdup(buf);
\r
2231 /* Finish initialization for fonts and sounds */
\r
2232 for (i=0; i<NUM_FONTS; i++) {
\r
2233 for (j=0; j<NUM_SIZES; j++) {
\r
2234 CreateFontInMF(font[j][i]);
\r
2237 /* xboard, and older WinBoards, controlled the move sound with the
\r
2238 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2239 always turn the option on (so that the backend will call us),
\r
2240 then let the user turn the sound off by setting it to silence if
\r
2241 desired. To accommodate old winboard.ini files saved by old
\r
2242 versions of WinBoard, we also turn off the sound if the option
\r
2243 was initially set to false. */
\r
2244 if (!appData.ringBellAfterMoves) {
\r
2245 sounds[(int)SoundMove].name = strdup("");
\r
2246 appData.ringBellAfterMoves = TRUE;
\r
2248 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2249 SetCurrentDirectory(installDir);
\r
2251 SetCurrentDirectory(currDir);
\r
2253 p = icsTextMenuString;
\r
2254 if (p[0] == '@') {
\r
2255 FILE* f = fopen(p + 1, "r");
\r
2257 DisplayFatalError(p + 1, errno, 2);
\r
2260 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2262 buf[i] = NULLCHAR;
\r
2265 ParseIcsTextMenu(strdup(p));
\r
2272 HMENU hmenu = GetMenu(hwndMain);
\r
2274 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2275 MF_BYCOMMAND|((appData.icsActive &&
\r
2276 *appData.icsCommPort != NULLCHAR) ?
\r
2277 MF_ENABLED : MF_GRAYED));
\r
2278 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2279 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2280 MF_CHECKED : MF_UNCHECKED));
\r
2285 SaveSettings(char* name)
\r
2288 ArgDescriptor *ad;
\r
2289 WINDOWPLACEMENT wp;
\r
2290 char dir[MSG_SIZ];
\r
2292 if (!hwndMain) return;
\r
2294 GetCurrentDirectory(MSG_SIZ, dir);
\r
2295 SetCurrentDirectory(installDir);
\r
2296 f = fopen(name, "w");
\r
2297 SetCurrentDirectory(dir);
\r
2299 DisplayError(name, errno);
\r
2302 fprintf(f, ";\n");
\r
2303 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2304 fprintf(f, ";\n");
\r
2305 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2306 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2307 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2308 fprintf(f, ";\n");
\r
2310 wp.length = sizeof(WINDOWPLACEMENT);
\r
2311 GetWindowPlacement(hwndMain, &wp);
\r
2312 boardX = wp.rcNormalPosition.left;
\r
2313 boardY = wp.rcNormalPosition.top;
\r
2315 if (hwndConsole) {
\r
2316 GetWindowPlacement(hwndConsole, &wp);
\r
2317 wpConsole.x = wp.rcNormalPosition.left;
\r
2318 wpConsole.y = wp.rcNormalPosition.top;
\r
2319 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2320 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2323 if (analysisDialog) {
\r
2324 GetWindowPlacement(analysisDialog, &wp);
\r
2325 analysisX = wp.rcNormalPosition.left;
\r
2326 analysisY = wp.rcNormalPosition.top;
\r
2327 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2328 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2331 if (commentDialog) {
\r
2332 GetWindowPlacement(commentDialog, &wp);
\r
2333 commentX = wp.rcNormalPosition.left;
\r
2334 commentY = wp.rcNormalPosition.top;
\r
2335 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2336 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2339 if (editTagsDialog) {
\r
2340 GetWindowPlacement(editTagsDialog, &wp);
\r
2341 editTagsX = wp.rcNormalPosition.left;
\r
2342 editTagsY = wp.rcNormalPosition.top;
\r
2343 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2344 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2347 if (gameListDialog) {
\r
2348 GetWindowPlacement(gameListDialog, &wp);
\r
2349 wpGameList.x = wp.rcNormalPosition.left;
\r
2350 wpGameList.y = wp.rcNormalPosition.top;
\r
2351 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2352 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2355 /* [AS] Move history */
\r
2356 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2358 if( moveHistoryDialog ) {
\r
2359 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2360 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2361 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2362 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2363 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2366 /* [AS] Eval graph */
\r
2367 wpEvalGraph.visible = EvalGraphIsUp();
\r
2369 if( evalGraphDialog ) {
\r
2370 GetWindowPlacement(evalGraphDialog, &wp);
\r
2371 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2372 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2373 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2374 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2377 /* [AS] Engine output */
\r
2378 wpEngineOutput.visible = EngineOutputIsUp();
\r
2380 if( engineOutputDialog ) {
\r
2381 GetWindowPlacement(engineOutputDialog, &wp);
\r
2382 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2383 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2384 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2385 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2388 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2389 if (!ad->save) continue;
\r
2390 switch (ad->argType) {
\r
2393 char *p = *(char **)ad->argLoc;
\r
2394 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2395 /* Quote multiline values or \-containing values
\r
2396 with { } if possible */
\r
2397 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2399 /* Else quote with " " */
\r
2400 fprintf(f, "/%s=\"", ad->argName);
\r
2402 if (*p == '\n') fprintf(f, "\n");
\r
2403 else if (*p == '\r') fprintf(f, "\\r");
\r
2404 else if (*p == '\t') fprintf(f, "\\t");
\r
2405 else if (*p == '\b') fprintf(f, "\\b");
\r
2406 else if (*p == '\f') fprintf(f, "\\f");
\r
2407 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2408 else if (*p == '\"') fprintf(f, "\\\"");
\r
2409 else if (*p == '\\') fprintf(f, "\\\\");
\r
2413 fprintf(f, "\"\n");
\r
2419 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2422 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2425 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2428 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2431 fprintf(f, "/%s=%s\n", ad->argName,
\r
2432 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2435 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2438 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2442 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2443 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2444 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2449 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2450 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2451 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2452 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2453 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2454 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2455 (ta->effects) ? " " : "",
\r
2456 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2460 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2461 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2463 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2466 case ArgBoardSize:
\r
2467 fprintf(f, "/%s=%s\n", ad->argName,
\r
2468 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2473 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2474 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2475 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2476 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2477 ad->argName, mfp->faceName, mfp->pointSize,
\r
2478 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2479 mfp->bold ? "b" : "",
\r
2480 mfp->italic ? "i" : "",
\r
2481 mfp->underline ? "u" : "",
\r
2482 mfp->strikeout ? "s" : "");
\r
2486 case ArgCommSettings:
\r
2487 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2489 case ArgSettingsFilename: ;
\r
2497 /*---------------------------------------------------------------------------*\
\r
2499 * GDI board drawing routines
\r
2501 \*---------------------------------------------------------------------------*/
\r
2503 /* [AS] Draw square using background texture */
\r
2504 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2509 return; /* Should never happen! */
\r
2512 SetGraphicsMode( dst, GM_ADVANCED );
\r
2519 /* X reflection */
\r
2524 x.eDx = (FLOAT) dw + dx - 1;
\r
2527 SetWorldTransform( dst, &x );
\r
2530 /* Y reflection */
\r
2536 x.eDy = (FLOAT) dh + dy - 1;
\r
2538 SetWorldTransform( dst, &x );
\r
2546 x.eDx = (FLOAT) dx;
\r
2547 x.eDy = (FLOAT) dy;
\r
2550 SetWorldTransform( dst, &x );
\r
2554 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2562 SetWorldTransform( dst, &x );
\r
2564 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2567 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2569 PM_WP = (int) WhitePawn,
\r
2570 PM_WN = (int) WhiteKnight,
\r
2571 PM_WB = (int) WhiteBishop,
\r
2572 PM_WR = (int) WhiteRook,
\r
2573 PM_WQ = (int) WhiteQueen,
\r
2574 PM_WF = (int) WhiteFerz,
\r
2575 PM_WW = (int) WhiteWazir,
\r
2576 PM_WE = (int) WhiteAlfil,
\r
2577 PM_WM = (int) WhiteMan,
\r
2578 PM_WO = (int) WhiteCannon,
\r
2579 PM_WU = (int) WhiteUnicorn,
\r
2580 PM_WH = (int) WhiteNightrider,
\r
2581 PM_WA = (int) WhiteAngel,
\r
2582 PM_WC = (int) WhiteMarshall,
\r
2583 PM_WAB = (int) WhiteCardinal,
\r
2584 PM_WD = (int) WhiteDragon,
\r
2585 PM_WL = (int) WhiteLance,
\r
2586 PM_WS = (int) WhiteCobra,
\r
2587 PM_WV = (int) WhiteFalcon,
\r
2588 PM_WSG = (int) WhiteSilver,
\r
2589 PM_WG = (int) WhiteGrasshopper,
\r
2590 PM_WK = (int) WhiteKing,
\r
2591 PM_BP = (int) BlackPawn,
\r
2592 PM_BN = (int) BlackKnight,
\r
2593 PM_BB = (int) BlackBishop,
\r
2594 PM_BR = (int) BlackRook,
\r
2595 PM_BQ = (int) BlackQueen,
\r
2596 PM_BF = (int) BlackFerz,
\r
2597 PM_BW = (int) BlackWazir,
\r
2598 PM_BE = (int) BlackAlfil,
\r
2599 PM_BM = (int) BlackMan,
\r
2600 PM_BO = (int) BlackCannon,
\r
2601 PM_BU = (int) BlackUnicorn,
\r
2602 PM_BH = (int) BlackNightrider,
\r
2603 PM_BA = (int) BlackAngel,
\r
2604 PM_BC = (int) BlackMarshall,
\r
2605 PM_BG = (int) BlackGrasshopper,
\r
2606 PM_BAB = (int) BlackCardinal,
\r
2607 PM_BD = (int) BlackDragon,
\r
2608 PM_BL = (int) BlackLance,
\r
2609 PM_BS = (int) BlackCobra,
\r
2610 PM_BV = (int) BlackFalcon,
\r
2611 PM_BSG = (int) BlackSilver,
\r
2612 PM_BK = (int) BlackKing
\r
2615 static HFONT hPieceFont = NULL;
\r
2616 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2617 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2618 static int fontBitmapSquareSize = 0;
\r
2619 static char pieceToFontChar[(int) EmptySquare] =
\r
2620 { 'p', 'n', 'b', 'r', 'q',
\r
2621 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2622 'k', 'o', 'm', 'v', 't', 'w',
\r
2623 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2626 extern BOOL SetCharTable( char *table, const char * map );
\r
2627 /* [HGM] moved to backend.c */
\r
2629 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2632 BYTE r1 = GetRValue( color );
\r
2633 BYTE g1 = GetGValue( color );
\r
2634 BYTE b1 = GetBValue( color );
\r
2640 /* Create a uniform background first */
\r
2641 hbrush = CreateSolidBrush( color );
\r
2642 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2643 FillRect( hdc, &rc, hbrush );
\r
2644 DeleteObject( hbrush );
\r
2647 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2648 int steps = squareSize / 2;
\r
2651 for( i=0; i<steps; i++ ) {
\r
2652 BYTE r = r1 - (r1-r2) * i / steps;
\r
2653 BYTE g = g1 - (g1-g2) * i / steps;
\r
2654 BYTE b = b1 - (b1-b2) * i / steps;
\r
2656 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2657 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2658 FillRect( hdc, &rc, hbrush );
\r
2659 DeleteObject(hbrush);
\r
2662 else if( mode == 2 ) {
\r
2663 /* Diagonal gradient, good more or less for every piece */
\r
2664 POINT triangle[3];
\r
2665 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2666 HBRUSH hbrush_old;
\r
2667 int steps = squareSize;
\r
2670 triangle[0].x = squareSize - steps;
\r
2671 triangle[0].y = squareSize;
\r
2672 triangle[1].x = squareSize;
\r
2673 triangle[1].y = squareSize;
\r
2674 triangle[2].x = squareSize;
\r
2675 triangle[2].y = squareSize - steps;
\r
2677 for( i=0; i<steps; i++ ) {
\r
2678 BYTE r = r1 - (r1-r2) * i / steps;
\r
2679 BYTE g = g1 - (g1-g2) * i / steps;
\r
2680 BYTE b = b1 - (b1-b2) * i / steps;
\r
2682 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2683 hbrush_old = SelectObject( hdc, hbrush );
\r
2684 Polygon( hdc, triangle, 3 );
\r
2685 SelectObject( hdc, hbrush_old );
\r
2686 DeleteObject(hbrush);
\r
2691 SelectObject( hdc, hpen );
\r
2696 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2697 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2698 piece: follow the steps as explained below.
\r
2700 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2704 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2708 int backColor = whitePieceColor;
\r
2709 int foreColor = blackPieceColor;
\r
2711 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2712 backColor = appData.fontBackColorWhite;
\r
2713 foreColor = appData.fontForeColorWhite;
\r
2715 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2716 backColor = appData.fontBackColorBlack;
\r
2717 foreColor = appData.fontForeColorBlack;
\r
2721 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2723 hbm_old = SelectObject( hdc, hbm );
\r
2727 rc.right = squareSize;
\r
2728 rc.bottom = squareSize;
\r
2730 /* Step 1: background is now black */
\r
2731 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2733 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2735 pt.x = (squareSize - sz.cx) / 2;
\r
2736 pt.y = (squareSize - sz.cy) / 2;
\r
2738 SetBkMode( hdc, TRANSPARENT );
\r
2739 SetTextColor( hdc, chroma );
\r
2740 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2741 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2743 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2744 /* Step 3: the area outside the piece is filled with white */
\r
2745 // FloodFill( hdc, 0, 0, chroma );
\r
2746 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2747 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2748 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2749 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2750 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2752 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2753 but if the start point is not inside the piece we're lost!
\r
2754 There should be a better way to do this... if we could create a region or path
\r
2755 from the fill operation we would be fine for example.
\r
2757 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2758 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2760 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2761 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2762 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2764 SelectObject( dc2, bm2 );
\r
2765 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2766 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2767 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2768 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2769 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2772 DeleteObject( bm2 );
\r
2775 SetTextColor( hdc, 0 );
\r
2777 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2778 draw the piece again in black for safety.
\r
2780 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2782 SelectObject( hdc, hbm_old );
\r
2784 if( hPieceMask[index] != NULL ) {
\r
2785 DeleteObject( hPieceMask[index] );
\r
2788 hPieceMask[index] = hbm;
\r
2791 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2793 SelectObject( hdc, hbm );
\r
2796 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2797 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2798 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2800 SelectObject( dc1, hPieceMask[index] );
\r
2801 SelectObject( dc2, bm2 );
\r
2802 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2803 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2806 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2807 the piece background and deletes (makes transparent) the rest.
\r
2808 Thanks to that mask, we are free to paint the background with the greates
\r
2809 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2810 We use this, to make gradients and give the pieces a "roundish" look.
\r
2812 SetPieceBackground( hdc, backColor, 2 );
\r
2813 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2817 DeleteObject( bm2 );
\r
2820 SetTextColor( hdc, foreColor );
\r
2821 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2823 SelectObject( hdc, hbm_old );
\r
2825 if( hPieceFace[index] != NULL ) {
\r
2826 DeleteObject( hPieceFace[index] );
\r
2829 hPieceFace[index] = hbm;
\r
2832 static int TranslatePieceToFontPiece( int piece )
\r
2862 case BlackMarshall:
\r
2866 case BlackNightrider:
\r
2872 case BlackUnicorn:
\r
2876 case BlackGrasshopper:
\r
2888 case BlackCardinal:
\r
2895 case WhiteMarshall:
\r
2899 case WhiteNightrider:
\r
2905 case WhiteUnicorn:
\r
2909 case WhiteGrasshopper:
\r
2921 case WhiteCardinal:
\r
2930 void CreatePiecesFromFont()
\r
2933 HDC hdc_window = NULL;
\r
2939 if( fontBitmapSquareSize < 0 ) {
\r
2940 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2944 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2945 fontBitmapSquareSize = -1;
\r
2949 if( fontBitmapSquareSize != squareSize ) {
\r
2950 hdc_window = GetDC( hwndMain );
\r
2951 hdc = CreateCompatibleDC( hdc_window );
\r
2953 if( hPieceFont != NULL ) {
\r
2954 DeleteObject( hPieceFont );
\r
2957 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2958 hPieceMask[i] = NULL;
\r
2959 hPieceFace[i] = NULL;
\r
2965 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2966 fontHeight = appData.fontPieceSize;
\r
2969 fontHeight = (fontHeight * squareSize) / 100;
\r
2971 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2973 lf.lfEscapement = 0;
\r
2974 lf.lfOrientation = 0;
\r
2975 lf.lfWeight = FW_NORMAL;
\r
2977 lf.lfUnderline = 0;
\r
2978 lf.lfStrikeOut = 0;
\r
2979 lf.lfCharSet = DEFAULT_CHARSET;
\r
2980 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2981 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2982 lf.lfQuality = PROOF_QUALITY;
\r
2983 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2984 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2985 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2987 hPieceFont = CreateFontIndirect( &lf );
\r
2989 if( hPieceFont == NULL ) {
\r
2990 fontBitmapSquareSize = -2;
\r
2993 /* Setup font-to-piece character table */
\r
2994 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2995 /* No (or wrong) global settings, try to detect the font */
\r
2996 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2998 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3000 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3001 /* DiagramTT* family */
\r
3002 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3004 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3005 /* Fairy symbols */
\r
3006 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3008 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3009 /* Good Companion (Some characters get warped as literal :-( */
\r
3010 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3011 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3012 SetCharTable(pieceToFontChar, s);
\r
3015 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3016 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3020 /* Create bitmaps */
\r
3021 hfont_old = SelectObject( hdc, hPieceFont );
\r
3023 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3024 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3025 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3026 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3027 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3028 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3029 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3030 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3031 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3032 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3033 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3034 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3036 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3037 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3038 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3039 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3040 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3042 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3043 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3048 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3050 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3051 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3055 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3056 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3063 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3064 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3065 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3066 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3067 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3069 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3070 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3071 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3073 SelectObject( hdc, hfont_old );
\r
3075 fontBitmapSquareSize = squareSize;
\r
3079 if( hdc != NULL ) {
\r
3083 if( hdc_window != NULL ) {
\r
3084 ReleaseDC( hwndMain, hdc_window );
\r
3089 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3093 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3094 if (gameInfo.event &&
\r
3095 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3096 strcmp(name, "k80s") == 0) {
\r
3097 strcpy(name, "tim");
\r
3099 return LoadBitmap(hinst, name);
\r
3103 /* Insert a color into the program's logical palette
\r
3104 structure. This code assumes the given color is
\r
3105 the result of the RGB or PALETTERGB macro, and it
\r
3106 knows how those macros work (which is documented).
\r
3109 InsertInPalette(COLORREF color)
\r
3111 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3113 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3114 DisplayFatalError("Too many colors", 0, 1);
\r
3115 pLogPal->palNumEntries--;
\r
3119 pe->peFlags = (char) 0;
\r
3120 pe->peRed = (char) (0xFF & color);
\r
3121 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3122 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3128 InitDrawingColors()
\r
3130 if (pLogPal == NULL) {
\r
3131 /* Allocate enough memory for a logical palette with
\r
3132 * PALETTESIZE entries and set the size and version fields
\r
3133 * of the logical palette structure.
\r
3135 pLogPal = (NPLOGPALETTE)
\r
3136 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3137 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3138 pLogPal->palVersion = 0x300;
\r
3140 pLogPal->palNumEntries = 0;
\r
3142 InsertInPalette(lightSquareColor);
\r
3143 InsertInPalette(darkSquareColor);
\r
3144 InsertInPalette(whitePieceColor);
\r
3145 InsertInPalette(blackPieceColor);
\r
3146 InsertInPalette(highlightSquareColor);
\r
3147 InsertInPalette(premoveHighlightColor);
\r
3149 /* create a logical color palette according the information
\r
3150 * in the LOGPALETTE structure.
\r
3152 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3154 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3155 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3156 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3157 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3158 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3159 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3160 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3161 /* [AS] Force rendering of the font-based pieces */
\r
3162 if( fontBitmapSquareSize > 0 ) {
\r
3163 fontBitmapSquareSize = 0;
\r
3169 BoardWidth(int boardSize, int n)
\r
3170 { /* [HGM] argument n added to allow different width and height */
\r
3171 int lineGap = sizeInfo[boardSize].lineGap;
\r
3173 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3174 lineGap = appData.overrideLineGap;
\r
3177 return (n + 1) * lineGap +
\r
3178 n * sizeInfo[boardSize].squareSize;
\r
3181 /* Respond to board resize by dragging edge */
\r
3183 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3185 BoardSize newSize = NUM_SIZES - 1;
\r
3186 static int recurse = 0;
\r
3187 if (IsIconic(hwndMain)) return;
\r
3188 if (recurse > 0) return;
\r
3190 while (newSize > 0) {
\r
3191 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3192 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3193 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3196 boardSize = newSize;
\r
3197 InitDrawingSizes(boardSize, flags);
\r
3204 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3206 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3207 ChessSquare piece;
\r
3208 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3210 SIZE clockSize, messageSize;
\r
3212 char buf[MSG_SIZ];
\r
3214 HMENU hmenu = GetMenu(hwndMain);
\r
3215 RECT crect, wrect, oldRect;
\r
3217 LOGBRUSH logbrush;
\r
3219 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3220 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3222 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3223 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3225 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3226 oldRect.top = boardY;
\r
3227 oldRect.right = boardX + winWidth;
\r
3228 oldRect.bottom = boardY + winHeight;
\r
3230 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3231 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3232 squareSize = sizeInfo[boardSize].squareSize;
\r
3233 lineGap = sizeInfo[boardSize].lineGap;
\r
3234 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3236 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3237 lineGap = appData.overrideLineGap;
\r
3240 if (tinyLayout != oldTinyLayout) {
\r
3241 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3243 style &= ~WS_SYSMENU;
\r
3244 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3245 "&Minimize\tCtrl+F4");
\r
3247 style |= WS_SYSMENU;
\r
3248 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3250 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3252 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3253 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3254 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3256 DrawMenuBar(hwndMain);
\r
3259 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3260 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3262 /* Get text area sizes */
\r
3263 hdc = GetDC(hwndMain);
\r
3264 if (appData.clockMode) {
\r
3265 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3267 sprintf(buf, "White");
\r
3269 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3270 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3271 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3272 str = "We only care about the height here";
\r
3273 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3274 SelectObject(hdc, oldFont);
\r
3275 ReleaseDC(hwndMain, hdc);
\r
3277 /* Compute where everything goes */
\r
3278 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3279 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3280 logoHeight = 2*clockSize.cy;
\r
3281 leftLogoRect.left = OUTER_MARGIN;
\r
3282 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3283 leftLogoRect.top = OUTER_MARGIN;
\r
3284 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3286 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3287 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3288 rightLogoRect.top = OUTER_MARGIN;
\r
3289 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3292 whiteRect.left = leftLogoRect.right;
\r
3293 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3294 whiteRect.top = OUTER_MARGIN;
\r
3295 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3297 blackRect.right = rightLogoRect.left;
\r
3298 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3299 blackRect.top = whiteRect.top;
\r
3300 blackRect.bottom = whiteRect.bottom;
\r
3302 whiteRect.left = OUTER_MARGIN;
\r
3303 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3304 whiteRect.top = OUTER_MARGIN;
\r
3305 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3307 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3308 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3309 blackRect.top = whiteRect.top;
\r
3310 blackRect.bottom = whiteRect.bottom;
\r
3313 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3314 if (appData.showButtonBar) {
\r
3315 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3316 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3318 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3320 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3321 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3323 boardRect.left = OUTER_MARGIN;
\r
3324 boardRect.right = boardRect.left + boardWidth;
\r
3325 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3326 boardRect.bottom = boardRect.top + boardHeight;
\r
3328 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3329 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3330 oldBoardSize = boardSize;
\r
3331 oldTinyLayout = tinyLayout;
\r
3332 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3333 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3334 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3335 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3336 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3337 winHeight = winH; // without disturbing window attachments
\r
3338 GetWindowRect(hwndMain, &wrect);
\r
3339 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3340 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3342 // [HGM] placement: let attached windows follow size change.
\r
3343 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3344 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3345 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3346 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3347 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3349 /* compensate if menu bar wrapped */
\r
3350 GetClientRect(hwndMain, &crect);
\r
3351 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3352 winHeight += offby;
\r
3354 case WMSZ_TOPLEFT:
\r
3355 SetWindowPos(hwndMain, NULL,
\r
3356 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3357 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3360 case WMSZ_TOPRIGHT:
\r
3362 SetWindowPos(hwndMain, NULL,
\r
3363 wrect.left, wrect.bottom - winHeight,
\r
3364 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3367 case WMSZ_BOTTOMLEFT:
\r
3369 SetWindowPos(hwndMain, NULL,
\r
3370 wrect.right - winWidth, wrect.top,
\r
3371 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3374 case WMSZ_BOTTOMRIGHT:
\r
3378 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3379 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3384 for (i = 0; i < N_BUTTONS; i++) {
\r
3385 if (buttonDesc[i].hwnd != NULL) {
\r
3386 DestroyWindow(buttonDesc[i].hwnd);
\r
3387 buttonDesc[i].hwnd = NULL;
\r
3389 if (appData.showButtonBar) {
\r
3390 buttonDesc[i].hwnd =
\r
3391 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3392 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3393 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3394 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3395 (HMENU) buttonDesc[i].id,
\r
3396 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3398 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3399 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3400 MAKELPARAM(FALSE, 0));
\r
3402 if (buttonDesc[i].id == IDM_Pause)
\r
3403 hwndPause = buttonDesc[i].hwnd;
\r
3404 buttonDesc[i].wndproc = (WNDPROC)
\r
3405 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3408 if (gridPen != NULL) DeleteObject(gridPen);
\r
3409 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3410 if (premovePen != NULL) DeleteObject(premovePen);
\r
3411 if (lineGap != 0) {
\r
3412 logbrush.lbStyle = BS_SOLID;
\r
3413 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3415 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3416 lineGap, &logbrush, 0, NULL);
\r
3417 logbrush.lbColor = highlightSquareColor;
\r
3419 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3420 lineGap, &logbrush, 0, NULL);
\r
3422 logbrush.lbColor = premoveHighlightColor;
\r
3424 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3425 lineGap, &logbrush, 0, NULL);
\r
3427 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3428 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3429 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3430 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3431 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3432 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3433 BOARD_WIDTH * (squareSize + lineGap);
\r
3434 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3436 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3437 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3438 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3439 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3440 lineGap / 2 + (i * (squareSize + lineGap));
\r
3441 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3442 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3443 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3447 /* [HGM] Licensing requirement */
\r
3449 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3452 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3454 GothicPopUp( "", VariantNormal);
\r
3457 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3459 /* Load piece bitmaps for this board size */
\r
3460 for (i=0; i<=2; i++) {
\r
3461 for (piece = WhitePawn;
\r
3462 (int) piece < (int) BlackPawn;
\r
3463 piece = (ChessSquare) ((int) piece + 1)) {
\r
3464 if (pieceBitmap[i][piece] != NULL)
\r
3465 DeleteObject(pieceBitmap[i][piece]);
\r
3469 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3470 // Orthodox Chess pieces
\r
3471 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3472 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3473 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3474 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3475 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3476 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3477 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3478 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3479 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3480 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3481 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3482 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3483 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3484 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3485 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3486 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3487 // in Shogi, Hijack the unused Queen for Lance
\r
3488 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3489 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3490 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3492 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3493 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3494 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3497 if(squareSize <= 72 && squareSize >= 33) {
\r
3498 /* A & C are available in most sizes now */
\r
3499 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3500 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3501 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3502 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3503 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3504 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3505 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3506 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3507 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3508 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3509 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3510 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3511 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3512 } else { // Smirf-like
\r
3513 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3514 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3515 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3517 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3518 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3519 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3520 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3521 } else { // WinBoard standard
\r
3522 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3523 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3524 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3529 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3530 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3531 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3532 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3533 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3534 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3535 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3536 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3537 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3538 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3539 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3540 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3541 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3542 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3543 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3544 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3545 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3546 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3547 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3548 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3549 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3550 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3551 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3552 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3553 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3554 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3555 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3556 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3557 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3558 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3559 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3561 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3562 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3563 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3564 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3565 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3566 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3567 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3568 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3569 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3570 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3571 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3572 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3573 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3575 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3576 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3577 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3578 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3579 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3580 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3581 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3582 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3583 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3584 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3585 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3586 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3589 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3590 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3591 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3592 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3593 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3594 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3595 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3596 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3597 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3598 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3599 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3600 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3601 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3602 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3603 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3607 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3608 /* special Shogi support in this size */
\r
3609 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3610 for (piece = WhitePawn;
\r
3611 (int) piece < (int) BlackPawn;
\r
3612 piece = (ChessSquare) ((int) piece + 1)) {
\r
3613 if (pieceBitmap[i][piece] != NULL)
\r
3614 DeleteObject(pieceBitmap[i][piece]);
\r
3617 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3618 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3619 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3620 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3621 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3622 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3623 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3624 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3625 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3626 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3627 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3628 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3629 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3630 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3631 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3632 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3633 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3634 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3635 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3636 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3637 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3638 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3639 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3640 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3641 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3642 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3643 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3644 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3645 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3646 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3647 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3648 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3649 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3650 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3651 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3652 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3653 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3654 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3655 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3656 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3657 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3658 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3664 PieceBitmap(ChessSquare p, int kind)
\r
3666 if ((int) p >= (int) BlackPawn)
\r
3667 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3669 return pieceBitmap[kind][(int) p];
\r
3672 /***************************************************************/
\r
3674 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3675 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3677 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3678 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3682 SquareToPos(int row, int column, int * x, int * y)
\r
3685 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3686 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3688 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3689 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3694 DrawCoordsOnDC(HDC hdc)
\r
3696 static char files[24] = {'0', '1','2','3','4','5','6','7','8','9','0','1','1','0','9','8','7','6','5','4','3','2','1','0'};
\r
3697 static char ranks[24] = {'l', 'k','j','i','h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h','i','j','k','l'};
\r
3698 char str[2] = { NULLCHAR, NULLCHAR };
\r
3699 int oldMode, oldAlign, x, y, start, i;
\r
3703 if (!appData.showCoords)
\r
3706 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3708 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3709 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3710 oldAlign = GetTextAlign(hdc);
\r
3711 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3713 y = boardRect.top + lineGap;
\r
3714 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3716 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3717 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3718 str[0] = files[start + i];
\r
3719 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3720 y += squareSize + lineGap;
\r
3723 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3725 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3726 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3727 str[0] = ranks[start + i];
\r
3728 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3729 x += squareSize + lineGap;
\r
3732 SelectObject(hdc, oldBrush);
\r
3733 SetBkMode(hdc, oldMode);
\r
3734 SetTextAlign(hdc, oldAlign);
\r
3735 SelectObject(hdc, oldFont);
\r
3739 DrawGridOnDC(HDC hdc)
\r
3743 if (lineGap != 0) {
\r
3744 oldPen = SelectObject(hdc, gridPen);
\r
3745 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3746 SelectObject(hdc, oldPen);
\r
3750 #define HIGHLIGHT_PEN 0
\r
3751 #define PREMOVE_PEN 1
\r
3754 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3757 HPEN oldPen, hPen;
\r
3758 if (lineGap == 0) return;
\r
3760 x1 = boardRect.left +
\r
3761 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3762 y1 = boardRect.top +
\r
3763 lineGap/2 + y * (squareSize + lineGap);
\r
3765 x1 = boardRect.left +
\r
3766 lineGap/2 + x * (squareSize + lineGap);
\r
3767 y1 = boardRect.top +
\r
3768 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3770 hPen = pen ? premovePen : highlightPen;
\r
3771 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3772 MoveToEx(hdc, x1, y1, NULL);
\r
3773 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3774 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3775 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3776 LineTo(hdc, x1, y1);
\r
3777 SelectObject(hdc, oldPen);
\r
3781 DrawHighlightsOnDC(HDC hdc)
\r
3784 for (i=0; i<2; i++) {
\r
3785 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3786 DrawHighlightOnDC(hdc, TRUE,
\r
3787 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3790 for (i=0; i<2; i++) {
\r
3791 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3792 premoveHighlightInfo.sq[i].y >= 0) {
\r
3793 DrawHighlightOnDC(hdc, TRUE,
\r
3794 premoveHighlightInfo.sq[i].x,
\r
3795 premoveHighlightInfo.sq[i].y,
\r
3801 /* Note: sqcolor is used only in monoMode */
\r
3802 /* Note that this code is largely duplicated in woptions.c,
\r
3803 function DrawSampleSquare, so that needs to be updated too */
\r
3805 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3807 HBITMAP oldBitmap;
\r
3811 if (appData.blindfold) return;
\r
3813 /* [AS] Use font-based pieces if needed */
\r
3814 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3815 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3816 CreatePiecesFromFont();
\r
3818 if( fontBitmapSquareSize == squareSize ) {
\r
3819 int index = TranslatePieceToFontPiece(piece);
\r
3821 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3825 squareSize, squareSize,
\r
3830 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3834 squareSize, squareSize,
\r
3843 if (appData.monoMode) {
\r
3844 SelectObject(tmphdc, PieceBitmap(piece,
\r
3845 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3846 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3847 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3849 tmpSize = squareSize;
\r
3851 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3852 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3853 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3854 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3855 x += (squareSize - minorSize)>>1;
\r
3856 y += squareSize - minorSize - 2;
\r
3857 tmpSize = minorSize;
\r
3859 if (color || appData.allWhite ) {
\r
3860 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3862 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3863 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3864 if(appData.upsideDown && color==flipView)
\r
3865 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3867 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3869 /* Use black piece color for outline of white pieces */
\r
3870 /* Not sure this looks really good (though xboard does it).
\r
3871 Maybe better to have another selectable color, default black */
\r
3872 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3873 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3874 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3876 /* Use black for outline of white pieces */
\r
3877 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3878 if(appData.upsideDown && color==flipView)
\r
3879 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3881 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3885 /* Use white piece color for details of black pieces */
\r
3886 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3887 WHITE_PIECE ones aren't always the right shape. */
\r
3888 /* Not sure this looks really good (though xboard does it).
\r
3889 Maybe better to have another selectable color, default medium gray? */
\r
3890 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3891 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3892 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3893 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3894 SelectObject(hdc, blackPieceBrush);
\r
3895 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3897 /* Use square color for details of black pieces */
\r
3898 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3899 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3900 if(appData.upsideDown && !flipView)
\r
3901 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3903 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3906 SelectObject(hdc, oldBrush);
\r
3907 SelectObject(tmphdc, oldBitmap);
\r
3911 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3912 int GetBackTextureMode( int algo )
\r
3914 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3918 case BACK_TEXTURE_MODE_PLAIN:
\r
3919 result = 1; /* Always use identity map */
\r
3921 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3922 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3930 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3931 to handle redraws cleanly (as random numbers would always be different).
\r
3933 VOID RebuildTextureSquareInfo()
\r
3943 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3945 if( liteBackTexture != NULL ) {
\r
3946 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3947 lite_w = bi.bmWidth;
\r
3948 lite_h = bi.bmHeight;
\r
3952 if( darkBackTexture != NULL ) {
\r
3953 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3954 dark_w = bi.bmWidth;
\r
3955 dark_h = bi.bmHeight;
\r
3959 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3960 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3961 if( (col + row) & 1 ) {
\r
3963 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3964 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3965 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3966 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3971 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3972 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3973 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3974 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3981 /* [AS] Arrow highlighting support */
\r
3983 static int A_WIDTH = 5; /* Width of arrow body */
\r
3985 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3986 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3988 static double Sqr( double x )
\r
3993 static int Round( double x )
\r
3995 return (int) (x + 0.5);
\r
3998 /* Draw an arrow between two points using current settings */
\r
3999 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
4002 double dx, dy, j, k, x, y;
\r
4004 if( d_x == s_x ) {
\r
4005 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4007 arrow[0].x = s_x + A_WIDTH;
\r
4010 arrow[1].x = s_x + A_WIDTH;
\r
4011 arrow[1].y = d_y - h;
\r
4013 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4014 arrow[2].y = d_y - h;
\r
4019 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4020 arrow[4].y = d_y - h;
\r
4022 arrow[5].x = s_x - A_WIDTH;
\r
4023 arrow[5].y = d_y - h;
\r
4025 arrow[6].x = s_x - A_WIDTH;
\r
4028 else if( d_y == s_y ) {
\r
4029 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4032 arrow[0].y = s_y + A_WIDTH;
\r
4034 arrow[1].x = d_x - w;
\r
4035 arrow[1].y = s_y + A_WIDTH;
\r
4037 arrow[2].x = d_x - w;
\r
4038 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4043 arrow[4].x = d_x - w;
\r
4044 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4046 arrow[5].x = d_x - w;
\r
4047 arrow[5].y = s_y - A_WIDTH;
\r
4050 arrow[6].y = s_y - A_WIDTH;
\r
4053 /* [AS] Needed a lot of paper for this! :-) */
\r
4054 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4055 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4057 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4059 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4064 arrow[0].x = Round(x - j);
\r
4065 arrow[0].y = Round(y + j*dx);
\r
4067 arrow[1].x = Round(x + j);
\r
4068 arrow[1].y = Round(y - j*dx);
\r
4071 x = (double) d_x - k;
\r
4072 y = (double) d_y - k*dy;
\r
4075 x = (double) d_x + k;
\r
4076 y = (double) d_y + k*dy;
\r
4079 arrow[2].x = Round(x + j);
\r
4080 arrow[2].y = Round(y - j*dx);
\r
4082 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4083 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4088 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4089 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4091 arrow[6].x = Round(x - j);
\r
4092 arrow[6].y = Round(y + j*dx);
\r
4095 Polygon( hdc, arrow, 7 );
\r
4098 /* [AS] Draw an arrow between two squares */
\r
4099 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4101 int s_x, s_y, d_x, d_y;
\r
4108 if( s_col == d_col && s_row == d_row ) {
\r
4112 /* Get source and destination points */
\r
4113 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4114 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4117 d_y += squareSize / 4;
\r
4119 else if( d_y < s_y ) {
\r
4120 d_y += 3 * squareSize / 4;
\r
4123 d_y += squareSize / 2;
\r
4127 d_x += squareSize / 4;
\r
4129 else if( d_x < s_x ) {
\r
4130 d_x += 3 * squareSize / 4;
\r
4133 d_x += squareSize / 2;
\r
4136 s_x += squareSize / 2;
\r
4137 s_y += squareSize / 2;
\r
4139 /* Adjust width */
\r
4140 A_WIDTH = squareSize / 14;
\r
4143 stLB.lbStyle = BS_SOLID;
\r
4144 stLB.lbColor = appData.highlightArrowColor;
\r
4147 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4148 holdpen = SelectObject( hdc, hpen );
\r
4149 hbrush = CreateBrushIndirect( &stLB );
\r
4150 holdbrush = SelectObject( hdc, hbrush );
\r
4152 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4154 SelectObject( hdc, holdpen );
\r
4155 SelectObject( hdc, holdbrush );
\r
4156 DeleteObject( hpen );
\r
4157 DeleteObject( hbrush );
\r
4160 BOOL HasHighlightInfo()
\r
4162 BOOL result = FALSE;
\r
4164 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4165 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4173 BOOL IsDrawArrowEnabled()
\r
4175 BOOL result = FALSE;
\r
4177 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4184 VOID DrawArrowHighlight( HDC hdc )
\r
4186 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4187 DrawArrowBetweenSquares( hdc,
\r
4188 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4189 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4193 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4195 HRGN result = NULL;
\r
4197 if( HasHighlightInfo() ) {
\r
4198 int x1, y1, x2, y2;
\r
4199 int sx, sy, dx, dy;
\r
4201 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4202 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4204 sx = MIN( x1, x2 );
\r
4205 sy = MIN( y1, y2 );
\r
4206 dx = MAX( x1, x2 ) + squareSize;
\r
4207 dy = MAX( y1, y2 ) + squareSize;
\r
4209 result = CreateRectRgn( sx, sy, dx, dy );
\r
4216 Warning: this function modifies the behavior of several other functions.
\r
4218 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4219 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4220 repaint is scattered all over the place, which is not good for features such as
\r
4221 "arrow highlighting" that require a full repaint of the board.
\r
4223 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4224 user interaction, when speed is not so important) but especially to avoid errors
\r
4225 in the displayed graphics.
\r
4227 In such patched places, I always try refer to this function so there is a single
\r
4228 place to maintain knowledge.
\r
4230 To restore the original behavior, just return FALSE unconditionally.
\r
4232 BOOL IsFullRepaintPreferrable()
\r
4234 BOOL result = FALSE;
\r
4236 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4237 /* Arrow may appear on the board */
\r
4245 This function is called by DrawPosition to know whether a full repaint must
\r
4248 Only DrawPosition may directly call this function, which makes use of
\r
4249 some state information. Other function should call DrawPosition specifying
\r
4250 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4252 BOOL DrawPositionNeedsFullRepaint()
\r
4254 BOOL result = FALSE;
\r
4257 Probably a slightly better policy would be to trigger a full repaint
\r
4258 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4259 but animation is fast enough that it's difficult to notice.
\r
4261 if( animInfo.piece == EmptySquare ) {
\r
4262 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4271 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4273 int row, column, x, y, square_color, piece_color;
\r
4274 ChessSquare piece;
\r
4276 HDC texture_hdc = NULL;
\r
4278 /* [AS] Initialize background textures if needed */
\r
4279 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4280 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4281 if( backTextureSquareSize != squareSize
\r
4282 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4283 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4284 backTextureSquareSize = squareSize;
\r
4285 RebuildTextureSquareInfo();
\r
4288 texture_hdc = CreateCompatibleDC( hdc );
\r
4291 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4292 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4294 SquareToPos(row, column, &x, &y);
\r
4296 piece = board[row][column];
\r
4298 square_color = ((column + row) % 2) == 1;
\r
4299 if( gameInfo.variant == VariantXiangqi ) {
\r
4300 square_color = !InPalace(row, column);
\r
4301 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4302 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4304 piece_color = (int) piece < (int) BlackPawn;
\r
4307 /* [HGM] holdings file: light square or black */
\r
4308 if(column == BOARD_LEFT-2) {
\r
4309 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4312 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4316 if(column == BOARD_RGHT + 1 ) {
\r
4317 if( row < gameInfo.holdingsSize )
\r
4320 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4324 if(column == BOARD_LEFT-1 ) /* left align */
\r
4325 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4326 else if( column == BOARD_RGHT) /* right align */
\r
4327 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4329 if (appData.monoMode) {
\r
4330 if (piece == EmptySquare) {
\r
4331 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4332 square_color ? WHITENESS : BLACKNESS);
\r
4334 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4337 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4338 /* [AS] Draw the square using a texture bitmap */
\r
4339 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4340 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4341 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4344 squareSize, squareSize,
\r
4347 backTextureSquareInfo[r][c].mode,
\r
4348 backTextureSquareInfo[r][c].x,
\r
4349 backTextureSquareInfo[r][c].y );
\r
4351 SelectObject( texture_hdc, hbm );
\r
4353 if (piece != EmptySquare) {
\r
4354 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4358 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4360 oldBrush = SelectObject(hdc, brush );
\r
4361 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4362 SelectObject(hdc, oldBrush);
\r
4363 if (piece != EmptySquare)
\r
4364 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4369 if( texture_hdc != NULL ) {
\r
4370 DeleteDC( texture_hdc );
\r
4374 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4375 void fputDW(FILE *f, int x)
\r
4377 fputc(x & 255, f);
\r
4378 fputc(x>>8 & 255, f);
\r
4379 fputc(x>>16 & 255, f);
\r
4380 fputc(x>>24 & 255, f);
\r
4383 #define MAX_CLIPS 200 /* more than enough */
\r
4386 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4388 // HBITMAP bufferBitmap;
\r
4393 int w = 100, h = 50;
\r
4395 if(logo == NULL) return;
\r
4396 // GetClientRect(hwndMain, &Rect);
\r
4397 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4398 // Rect.bottom-Rect.top+1);
\r
4399 tmphdc = CreateCompatibleDC(hdc);
\r
4400 hbm = SelectObject(tmphdc, logo);
\r
4401 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4405 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4406 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4407 SelectObject(tmphdc, hbm);
\r
4412 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4414 static Board lastReq, lastDrawn;
\r
4415 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4416 static int lastDrawnFlipView = 0;
\r
4417 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4418 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4421 HBITMAP bufferBitmap;
\r
4422 HBITMAP oldBitmap;
\r
4424 HRGN clips[MAX_CLIPS];
\r
4425 ChessSquare dragged_piece = EmptySquare;
\r
4427 /* I'm undecided on this - this function figures out whether a full
\r
4428 * repaint is necessary on its own, so there's no real reason to have the
\r
4429 * caller tell it that. I think this can safely be set to FALSE - but
\r
4430 * if we trust the callers not to request full repaints unnessesarily, then
\r
4431 * we could skip some clipping work. In other words, only request a full
\r
4432 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4433 * gamestart and similar) --Hawk
\r
4435 Boolean fullrepaint = repaint;
\r
4437 if( DrawPositionNeedsFullRepaint() ) {
\r
4438 fullrepaint = TRUE;
\r
4442 if( fullrepaint ) {
\r
4443 static int repaint_count = 0;
\r
4447 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4448 OutputDebugString( buf );
\r
4452 if (board == NULL) {
\r
4453 if (!lastReqValid) {
\r
4458 CopyBoard(lastReq, board);
\r
4462 if (doingSizing) {
\r
4466 if (IsIconic(hwndMain)) {
\r
4470 if (hdc == NULL) {
\r
4471 hdc = GetDC(hwndMain);
\r
4472 if (!appData.monoMode) {
\r
4473 SelectPalette(hdc, hPal, FALSE);
\r
4474 RealizePalette(hdc);
\r
4478 releaseDC = FALSE;
\r
4482 fprintf(debugFP, "*******************************\n"
\r
4484 "dragInfo.from (%d,%d)\n"
\r
4485 "dragInfo.start (%d,%d)\n"
\r
4486 "dragInfo.pos (%d,%d)\n"
\r
4487 "dragInfo.lastpos (%d,%d)\n",
\r
4488 repaint ? "TRUE" : "FALSE",
\r
4489 dragInfo.from.x, dragInfo.from.y,
\r
4490 dragInfo.start.x, dragInfo.start.y,
\r
4491 dragInfo.pos.x, dragInfo.pos.y,
\r
4492 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4493 fprintf(debugFP, "prev: ");
\r
4494 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4495 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4496 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4499 fprintf(debugFP, "\n");
\r
4500 fprintf(debugFP, "board: ");
\r
4501 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4502 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4503 fprintf(debugFP, "%d ", board[row][column]);
\r
4506 fprintf(debugFP, "\n");
\r
4510 /* Create some work-DCs */
\r
4511 hdcmem = CreateCompatibleDC(hdc);
\r
4512 tmphdc = CreateCompatibleDC(hdc);
\r
4514 /* If dragging is in progress, we temporarely remove the piece */
\r
4515 /* [HGM] or temporarily decrease count if stacked */
\r
4516 /* !! Moved to before board compare !! */
\r
4517 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4518 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4519 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4520 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4521 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4523 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4524 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4525 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4527 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4530 /* Figure out which squares need updating by comparing the
\r
4531 * newest board with the last drawn board and checking if
\r
4532 * flipping has changed.
\r
4534 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4535 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4536 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4537 if (lastDrawn[row][column] != board[row][column]) {
\r
4538 SquareToPos(row, column, &x, &y);
\r
4539 clips[num_clips++] =
\r
4540 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4544 for (i=0; i<2; i++) {
\r
4545 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4546 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4547 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4548 lastDrawnHighlight.sq[i].y >= 0) {
\r
4549 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4550 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4551 clips[num_clips++] =
\r
4552 CreateRectRgn(x - lineGap, y - lineGap,
\r
4553 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4555 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4556 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4557 clips[num_clips++] =
\r
4558 CreateRectRgn(x - lineGap, y - lineGap,
\r
4559 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4563 for (i=0; i<2; i++) {
\r
4564 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4565 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4566 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4567 lastDrawnPremove.sq[i].y >= 0) {
\r
4568 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4569 lastDrawnPremove.sq[i].x, &x, &y);
\r
4570 clips[num_clips++] =
\r
4571 CreateRectRgn(x - lineGap, y - lineGap,
\r
4572 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4574 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4575 premoveHighlightInfo.sq[i].y >= 0) {
\r
4576 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4577 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4578 clips[num_clips++] =
\r
4579 CreateRectRgn(x - lineGap, y - lineGap,
\r
4580 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4585 fullrepaint = TRUE;
\r
4588 /* Create a buffer bitmap - this is the actual bitmap
\r
4589 * being written to. When all the work is done, we can
\r
4590 * copy it to the real DC (the screen). This avoids
\r
4591 * the problems with flickering.
\r
4593 GetClientRect(hwndMain, &Rect);
\r
4594 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4595 Rect.bottom-Rect.top+1);
\r
4596 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4597 if (!appData.monoMode) {
\r
4598 SelectPalette(hdcmem, hPal, FALSE);
\r
4601 /* Create clips for dragging */
\r
4602 if (!fullrepaint) {
\r
4603 if (dragInfo.from.x >= 0) {
\r
4604 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4605 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4607 if (dragInfo.start.x >= 0) {
\r
4608 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4609 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4611 if (dragInfo.pos.x >= 0) {
\r
4612 x = dragInfo.pos.x - squareSize / 2;
\r
4613 y = dragInfo.pos.y - squareSize / 2;
\r
4614 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4616 if (dragInfo.lastpos.x >= 0) {
\r
4617 x = dragInfo.lastpos.x - squareSize / 2;
\r
4618 y = dragInfo.lastpos.y - squareSize / 2;
\r
4619 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4623 /* Are we animating a move?
\r
4625 * - remove the piece from the board (temporarely)
\r
4626 * - calculate the clipping region
\r
4628 if (!fullrepaint) {
\r
4629 if (animInfo.piece != EmptySquare) {
\r
4630 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4631 x = boardRect.left + animInfo.lastpos.x;
\r
4632 y = boardRect.top + animInfo.lastpos.y;
\r
4633 x2 = boardRect.left + animInfo.pos.x;
\r
4634 y2 = boardRect.top + animInfo.pos.y;
\r
4635 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4636 /* Slight kludge. The real problem is that after AnimateMove is
\r
4637 done, the position on the screen does not match lastDrawn.
\r
4638 This currently causes trouble only on e.p. captures in
\r
4639 atomic, where the piece moves to an empty square and then
\r
4640 explodes. The old and new positions both had an empty square
\r
4641 at the destination, but animation has drawn a piece there and
\r
4642 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4643 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4647 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4648 if (num_clips == 0)
\r
4649 fullrepaint = TRUE;
\r
4651 /* Set clipping on the memory DC */
\r
4652 if (!fullrepaint) {
\r
4653 SelectClipRgn(hdcmem, clips[0]);
\r
4654 for (x = 1; x < num_clips; x++) {
\r
4655 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4656 abort(); // this should never ever happen!
\r
4660 /* Do all the drawing to the memory DC */
\r
4661 if(explodeInfo.radius) { // [HGM] atomic
\r
4663 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4664 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4665 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4666 x += squareSize/2;
\r
4667 y += squareSize/2;
\r
4668 if(!fullrepaint) {
\r
4669 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4670 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4672 DrawGridOnDC(hdcmem);
\r
4673 DrawHighlightsOnDC(hdcmem);
\r
4674 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4675 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4676 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4677 SelectObject(hdcmem, oldBrush);
\r
4679 DrawGridOnDC(hdcmem);
\r
4680 DrawHighlightsOnDC(hdcmem);
\r
4681 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4684 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4685 if(appData.autoLogo) {
\r
4687 switch(gameMode) { // pick logos based on game mode
\r
4688 case IcsObserving:
\r
4689 whiteLogo = second.programLogo; // ICS logo
\r
4690 blackLogo = second.programLogo;
\r
4693 case IcsPlayingWhite:
\r
4694 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4695 blackLogo = second.programLogo; // ICS logo
\r
4697 case IcsPlayingBlack:
\r
4698 whiteLogo = second.programLogo; // ICS logo
\r
4699 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4701 case TwoMachinesPlay:
\r
4702 if(first.twoMachinesColor[0] == 'b') {
\r
4703 whiteLogo = second.programLogo;
\r
4704 blackLogo = first.programLogo;
\r
4707 case MachinePlaysWhite:
\r
4708 blackLogo = userLogo;
\r
4710 case MachinePlaysBlack:
\r
4711 whiteLogo = userLogo;
\r
4712 blackLogo = first.programLogo;
\r
4715 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4716 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4719 if( appData.highlightMoveWithArrow ) {
\r
4720 DrawArrowHighlight(hdcmem);
\r
4723 DrawCoordsOnDC(hdcmem);
\r
4725 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4726 /* to make sure lastDrawn contains what is actually drawn */
\r
4728 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4729 if (dragged_piece != EmptySquare) {
\r
4730 /* [HGM] or restack */
\r
4731 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4732 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4734 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4735 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4736 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4737 x = dragInfo.pos.x - squareSize / 2;
\r
4738 y = dragInfo.pos.y - squareSize / 2;
\r
4739 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4740 ((int) dragged_piece < (int) BlackPawn),
\r
4741 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4744 /* Put the animated piece back into place and draw it */
\r
4745 if (animInfo.piece != EmptySquare) {
\r
4746 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4747 x = boardRect.left + animInfo.pos.x;
\r
4748 y = boardRect.top + animInfo.pos.y;
\r
4749 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4750 ((int) animInfo.piece < (int) BlackPawn),
\r
4751 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4754 /* Release the bufferBitmap by selecting in the old bitmap
\r
4755 * and delete the memory DC
\r
4757 SelectObject(hdcmem, oldBitmap);
\r
4760 /* Set clipping on the target DC */
\r
4761 if (!fullrepaint) {
\r
4762 SelectClipRgn(hdc, clips[0]);
\r
4763 for (x = 1; x < num_clips; x++) {
\r
4764 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4765 abort(); // this should never ever happen!
\r
4769 /* Copy the new bitmap onto the screen in one go.
\r
4770 * This way we avoid any flickering
\r
4772 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4773 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4774 boardRect.right - boardRect.left,
\r
4775 boardRect.bottom - boardRect.top,
\r
4776 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4777 if(saveDiagFlag) {
\r
4778 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4779 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4781 GetObject(bufferBitmap, sizeof(b), &b);
\r
4782 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4783 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4784 bih.biWidth = b.bmWidth;
\r
4785 bih.biHeight = b.bmHeight;
\r
4787 bih.biBitCount = b.bmBitsPixel;
\r
4788 bih.biCompression = 0;
\r
4789 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4790 bih.biXPelsPerMeter = 0;
\r
4791 bih.biYPelsPerMeter = 0;
\r
4792 bih.biClrUsed = 0;
\r
4793 bih.biClrImportant = 0;
\r
4794 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4795 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4796 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4797 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4800 wb = b.bmWidthBytes;
\r
4802 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4803 int k = ((int*) pData)[i];
\r
4804 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4805 if(j >= 16) break;
\r
4807 if(j >= nrColors) nrColors = j+1;
\r
4809 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4811 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4812 for(w=0; w<(wb>>2); w+=2) {
\r
4813 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4814 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4815 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4816 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4817 pData[p++] = m | j<<4;
\r
4819 while(p&3) pData[p++] = 0;
\r
4822 wb = ((wb+31)>>5)<<2;
\r
4824 // write BITMAPFILEHEADER
\r
4825 fprintf(diagFile, "BM");
\r
4826 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4827 fputDW(diagFile, 0);
\r
4828 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4829 // write BITMAPINFOHEADER
\r
4830 fputDW(diagFile, 40);
\r
4831 fputDW(diagFile, b.bmWidth);
\r
4832 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4833 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4834 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4835 fputDW(diagFile, 0);
\r
4836 fputDW(diagFile, 0);
\r
4837 fputDW(diagFile, 0);
\r
4838 fputDW(diagFile, 0);
\r
4839 fputDW(diagFile, 0);
\r
4840 fputDW(diagFile, 0);
\r
4841 // write color table
\r
4843 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4844 // write bitmap data
\r
4845 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4846 fputc(pData[i], diagFile);
\r
4851 SelectObject(tmphdc, oldBitmap);
\r
4853 /* Massive cleanup */
\r
4854 for (x = 0; x < num_clips; x++)
\r
4855 DeleteObject(clips[x]);
\r
4858 DeleteObject(bufferBitmap);
\r
4861 ReleaseDC(hwndMain, hdc);
\r
4863 if (lastDrawnFlipView != flipView) {
\r
4865 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4867 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4870 /* CopyBoard(lastDrawn, board);*/
\r
4871 lastDrawnHighlight = highlightInfo;
\r
4872 lastDrawnPremove = premoveHighlightInfo;
\r
4873 lastDrawnFlipView = flipView;
\r
4874 lastDrawnValid = 1;
\r
4877 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4882 saveDiagFlag = 1; diagFile = f;
\r
4883 HDCDrawPosition(NULL, TRUE, NULL);
\r
4887 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4894 /*---------------------------------------------------------------------------*\
\r
4895 | CLIENT PAINT PROCEDURE
\r
4896 | This is the main event-handler for the WM_PAINT message.
\r
4898 \*---------------------------------------------------------------------------*/
\r
4900 PaintProc(HWND hwnd)
\r
4906 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4907 if (IsIconic(hwnd)) {
\r
4908 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4910 if (!appData.monoMode) {
\r
4911 SelectPalette(hdc, hPal, FALSE);
\r
4912 RealizePalette(hdc);
\r
4914 HDCDrawPosition(hdc, 1, NULL);
\r
4916 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4917 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4918 ETO_CLIPPED|ETO_OPAQUE,
\r
4919 &messageRect, messageText, strlen(messageText), NULL);
\r
4920 SelectObject(hdc, oldFont);
\r
4921 DisplayBothClocks();
\r
4923 EndPaint(hwnd,&ps);
\r
4931 * If the user selects on a border boundary, return -1; if off the board,
\r
4932 * return -2. Otherwise map the event coordinate to the square.
\r
4933 * The offset boardRect.left or boardRect.top must already have been
\r
4934 * subtracted from x.
\r
4937 EventToSquare(int x)
\r
4944 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4946 x /= (squareSize + lineGap);
\r
4947 if (x >= BOARD_SIZE)
\r
4958 DropEnable dropEnables[] = {
\r
4959 { 'P', DP_Pawn, "Pawn" },
\r
4960 { 'N', DP_Knight, "Knight" },
\r
4961 { 'B', DP_Bishop, "Bishop" },
\r
4962 { 'R', DP_Rook, "Rook" },
\r
4963 { 'Q', DP_Queen, "Queen" },
\r
4967 SetupDropMenu(HMENU hmenu)
\r
4969 int i, count, enable;
\r
4971 extern char white_holding[], black_holding[];
\r
4972 char item[MSG_SIZ];
\r
4974 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4975 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4976 dropEnables[i].piece);
\r
4978 while (p && *p++ == dropEnables[i].piece) count++;
\r
4979 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4980 enable = count > 0 || !appData.testLegality
\r
4981 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4982 && !appData.icsActive);
\r
4983 ModifyMenu(hmenu, dropEnables[i].command,
\r
4984 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4985 dropEnables[i].command, item);
\r
4989 /* Event handler for mouse messages */
\r
4991 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4995 static int recursive = 0;
\r
4997 // BOOLEAN needsRedraw = FALSE;
\r
4998 BOOLEAN saveAnimate;
\r
4999 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
5000 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
5001 ChessMove moveType;
\r
5004 if (message == WM_MBUTTONUP) {
\r
5005 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5006 to the middle button: we simulate pressing the left button too!
\r
5008 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5009 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5015 pt.x = LOWORD(lParam);
\r
5016 pt.y = HIWORD(lParam);
\r
5017 x = EventToSquare(pt.x - boardRect.left);
\r
5018 y = EventToSquare(pt.y - boardRect.top);
\r
5019 if (!flipView && y >= 0) {
\r
5020 y = BOARD_HEIGHT - 1 - y;
\r
5022 if (flipView && x >= 0) {
\r
5023 x = BOARD_WIDTH - 1 - x;
\r
5026 switch (message) {
\r
5027 case WM_LBUTTONDOWN:
\r
5028 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5029 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5030 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5031 if(gameInfo.holdingsWidth &&
\r
5032 (WhiteOnMove(currentMove)
\r
5033 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5034 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5035 // click in right holdings, for determining promotion piece
\r
5036 ChessSquare p = boards[currentMove][y][x];
\r
5037 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5038 if(p != EmptySquare) {
\r
5039 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5040 fromX = fromY = -1;
\r
5044 DrawPosition(FALSE, boards[currentMove]);
\r
5048 sameAgain = FALSE;
\r
5050 /* Downclick vertically off board; check if on clock */
\r
5051 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5052 if (gameMode == EditPosition) {
\r
5053 SetWhiteToPlayEvent();
\r
5054 } else if (gameMode == IcsPlayingBlack ||
\r
5055 gameMode == MachinePlaysWhite) {
\r
5057 } else if (gameMode == EditGame) {
\r
5058 AdjustClock(flipClock, -1);
\r
5060 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5061 if (gameMode == EditPosition) {
\r
5062 SetBlackToPlayEvent();
\r
5063 } else if (gameMode == IcsPlayingWhite ||
\r
5064 gameMode == MachinePlaysBlack) {
\r
5066 } else if (gameMode == EditGame) {
\r
5067 AdjustClock(!flipClock, -1);
\r
5070 if (!appData.highlightLastMove) {
\r
5071 ClearHighlights();
\r
5072 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5074 fromX = fromY = -1;
\r
5075 dragInfo.start.x = dragInfo.start.y = -1;
\r
5076 dragInfo.from = dragInfo.start;
\r
5078 } else if (x < 0 || y < 0
\r
5079 /* [HGM] block clicks between board and holdings */
\r
5080 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5081 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5082 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5083 /* EditPosition, empty square, or different color piece;
\r
5084 click-click move is possible */
\r
5087 } else if (fromX == x && fromY == y) {
\r
5088 /* Downclick on same square again */
\r
5089 ClearHighlights();
\r
5090 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5091 sameAgain = TRUE;
\r
5092 } else if (fromX != -1 &&
\r
5093 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5095 /* Downclick on different square. */
\r
5096 /* [HGM] if on holdings file, should count as new first click ! */
\r
5097 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5100 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5101 to make sure move is legal before showing promotion popup */
\r
5102 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5103 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5104 fromX = fromY = -1;
\r
5105 ClearHighlights();
\r
5106 DrawPosition(FALSE, boards[currentMove]);
\r
5109 if(moveType != ImpossibleMove) {
\r
5110 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5111 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5112 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5113 appData.alwaysPromoteToQueen)) {
\r
5114 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5115 if (!appData.highlightLastMove) {
\r
5116 ClearHighlights();
\r
5117 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5120 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5121 SetHighlights(fromX, fromY, toX, toY);
\r
5122 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5123 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5124 If promotion to Q is legal, all are legal! */
\r
5125 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5126 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5127 // kludge to temporarily execute move on display, wthout promotng yet
\r
5128 promotionChoice = TRUE;
\r
5129 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5130 boards[currentMove][toY][toX] = p;
\r
5131 DrawPosition(FALSE, boards[currentMove]);
\r
5132 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5133 boards[currentMove][toY][toX] = q;
\r
5135 PromotionPopup(hwnd);
\r
5136 } else { /* not a promotion */
\r
5137 if (appData.animate || appData.highlightLastMove) {
\r
5138 SetHighlights(fromX, fromY, toX, toY);
\r
5140 ClearHighlights();
\r
5142 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5143 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_Engine1Options:
\r
6131 EngineOptionsPopup(hwnd, &first);
\r
6134 case IDM_Engine2Options:
\r
6135 EngineOptionsPopup(hwnd, &second);
\r
6138 case IDM_OptionsUCI:
\r
6139 UciOptionsPopup(hwnd);
\r
6142 case IDM_IcsOptions:
\r
6143 IcsOptionsPopup(hwnd);
\r
6147 FontsOptionsPopup(hwnd);
\r
6151 SoundOptionsPopup(hwnd);
\r
6154 case IDM_CommPort:
\r
6155 CommPortOptionsPopup(hwnd);
\r
6158 case IDM_LoadOptions:
\r
6159 LoadOptionsPopup(hwnd);
\r
6162 case IDM_SaveOptions:
\r
6163 SaveOptionsPopup(hwnd);
\r
6166 case IDM_TimeControl:
\r
6167 TimeControlOptionsPopup(hwnd);
\r
6170 case IDM_SaveSettings:
\r
6171 SaveSettings(settingsFileName);
\r
6174 case IDM_SaveSettingsOnExit:
\r
6175 saveSettingsOnExit = !saveSettingsOnExit;
\r
6176 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6177 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6178 MF_CHECKED : MF_UNCHECKED));
\r
6189 case IDM_AboutGame:
\r
6194 appData.debugMode = !appData.debugMode;
\r
6195 if (appData.debugMode) {
\r
6196 char dir[MSG_SIZ];
\r
6197 GetCurrentDirectory(MSG_SIZ, dir);
\r
6198 SetCurrentDirectory(installDir);
\r
6199 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6200 SetCurrentDirectory(dir);
\r
6201 setbuf(debugFP, NULL);
\r
6208 case IDM_HELPCONTENTS:
\r
6209 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6210 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6211 MessageBox (GetFocus(),
\r
6212 "Unable to activate help",
\r
6213 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6217 case IDM_HELPSEARCH:
\r
6218 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6219 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6220 MessageBox (GetFocus(),
\r
6221 "Unable to activate help",
\r
6222 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6226 case IDM_HELPHELP:
\r
6227 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6228 MessageBox (GetFocus(),
\r
6229 "Unable to activate help",
\r
6230 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6235 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6237 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6238 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6239 FreeProcInstance(lpProc);
\r
6242 case IDM_DirectCommand1:
\r
6243 AskQuestionEvent("Direct Command",
\r
6244 "Send to chess program:", "", "1");
\r
6246 case IDM_DirectCommand2:
\r
6247 AskQuestionEvent("Direct Command",
\r
6248 "Send to second chess program:", "", "2");
\r
6251 case EP_WhitePawn:
\r
6252 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6253 fromX = fromY = -1;
\r
6256 case EP_WhiteKnight:
\r
6257 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6258 fromX = fromY = -1;
\r
6261 case EP_WhiteBishop:
\r
6262 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6263 fromX = fromY = -1;
\r
6266 case EP_WhiteRook:
\r
6267 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6268 fromX = fromY = -1;
\r
6271 case EP_WhiteQueen:
\r
6272 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6273 fromX = fromY = -1;
\r
6276 case EP_WhiteFerz:
\r
6277 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6278 fromX = fromY = -1;
\r
6281 case EP_WhiteWazir:
\r
6282 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6283 fromX = fromY = -1;
\r
6286 case EP_WhiteAlfil:
\r
6287 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6288 fromX = fromY = -1;
\r
6291 case EP_WhiteCannon:
\r
6292 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6293 fromX = fromY = -1;
\r
6296 case EP_WhiteCardinal:
\r
6297 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6298 fromX = fromY = -1;
\r
6301 case EP_WhiteMarshall:
\r
6302 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6303 fromX = fromY = -1;
\r
6306 case EP_WhiteKing:
\r
6307 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6308 fromX = fromY = -1;
\r
6311 case EP_BlackPawn:
\r
6312 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6313 fromX = fromY = -1;
\r
6316 case EP_BlackKnight:
\r
6317 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6318 fromX = fromY = -1;
\r
6321 case EP_BlackBishop:
\r
6322 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6323 fromX = fromY = -1;
\r
6326 case EP_BlackRook:
\r
6327 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6328 fromX = fromY = -1;
\r
6331 case EP_BlackQueen:
\r
6332 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6333 fromX = fromY = -1;
\r
6336 case EP_BlackFerz:
\r
6337 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6338 fromX = fromY = -1;
\r
6341 case EP_BlackWazir:
\r
6342 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6343 fromX = fromY = -1;
\r
6346 case EP_BlackAlfil:
\r
6347 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6348 fromX = fromY = -1;
\r
6351 case EP_BlackCannon:
\r
6352 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6353 fromX = fromY = -1;
\r
6356 case EP_BlackCardinal:
\r
6357 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6358 fromX = fromY = -1;
\r
6361 case EP_BlackMarshall:
\r
6362 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6363 fromX = fromY = -1;
\r
6366 case EP_BlackKing:
\r
6367 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6368 fromX = fromY = -1;
\r
6371 case EP_EmptySquare:
\r
6372 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6373 fromX = fromY = -1;
\r
6376 case EP_ClearBoard:
\r
6377 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6378 fromX = fromY = -1;
\r
6382 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6383 fromX = fromY = -1;
\r
6387 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6388 fromX = fromY = -1;
\r
6392 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6393 fromX = fromY = -1;
\r
6397 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6398 fromX = fromY = -1;
\r
6402 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6403 fromX = fromY = -1;
\r
6407 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6408 fromX = fromY = -1;
\r
6412 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6413 fromX = fromY = -1;
\r
6417 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6418 fromX = fromY = -1;
\r
6422 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6423 fromX = fromY = -1;
\r
6427 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6433 case CLOCK_TIMER_ID:
\r
6434 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6435 clockTimerEvent = 0;
\r
6436 DecrementClocks(); /* call into back end */
\r
6438 case LOAD_GAME_TIMER_ID:
\r
6439 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6440 loadGameTimerEvent = 0;
\r
6441 AutoPlayGameLoop(); /* call into back end */
\r
6443 case ANALYSIS_TIMER_ID:
\r
6444 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6445 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6446 AnalysisPeriodicEvent(0);
\r
6448 KillTimer(hwnd, analysisTimerEvent);
\r
6449 analysisTimerEvent = 0;
\r
6452 case DELAYED_TIMER_ID:
\r
6453 KillTimer(hwnd, delayedTimerEvent);
\r
6454 delayedTimerEvent = 0;
\r
6455 delayedTimerCallback();
\r
6460 case WM_USER_Input:
\r
6461 InputEvent(hwnd, message, wParam, lParam);
\r
6464 /* [AS] Also move "attached" child windows */
\r
6465 case WM_WINDOWPOSCHANGING:
\r
6467 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6468 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6470 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6471 /* Window is moving */
\r
6474 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6475 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6476 rcMain.right = boardX + winWidth;
\r
6477 rcMain.top = boardY;
\r
6478 rcMain.bottom = boardY + winHeight;
\r
6480 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6481 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6482 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6483 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6484 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6491 /* [AS] Snapping */
\r
6492 case WM_ENTERSIZEMOVE:
\r
6493 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6494 if (hwnd == hwndMain) {
\r
6495 doingSizing = TRUE;
\r
6498 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6502 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6503 if (hwnd == hwndMain) {
\r
6504 lastSizing = wParam;
\r
6509 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6510 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6512 case WM_EXITSIZEMOVE:
\r
6513 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6514 if (hwnd == hwndMain) {
\r
6516 doingSizing = FALSE;
\r
6517 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6518 GetClientRect(hwnd, &client);
\r
6519 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6521 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6523 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6526 case WM_DESTROY: /* message: window being destroyed */
\r
6527 PostQuitMessage(0);
\r
6531 if (hwnd == hwndMain) {
\r
6536 default: /* Passes it on if unprocessed */
\r
6537 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6542 /*---------------------------------------------------------------------------*\
\r
6544 * Misc utility routines
\r
6546 \*---------------------------------------------------------------------------*/
\r
6549 * Decent random number generator, at least not as bad as Windows
\r
6550 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6552 unsigned int randstate;
\r
6557 randstate = randstate * 1664525 + 1013904223;
\r
6558 return (int) randstate & 0x7fffffff;
\r
6562 mysrandom(unsigned int seed)
\r
6569 * returns TRUE if user selects a different color, FALSE otherwise
\r
6573 ChangeColor(HWND hwnd, COLORREF *which)
\r
6575 static BOOL firstTime = TRUE;
\r
6576 static DWORD customColors[16];
\r
6578 COLORREF newcolor;
\r
6583 /* Make initial colors in use available as custom colors */
\r
6584 /* Should we put the compiled-in defaults here instead? */
\r
6586 customColors[i++] = lightSquareColor & 0xffffff;
\r
6587 customColors[i++] = darkSquareColor & 0xffffff;
\r
6588 customColors[i++] = whitePieceColor & 0xffffff;
\r
6589 customColors[i++] = blackPieceColor & 0xffffff;
\r
6590 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6591 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6593 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6594 customColors[i++] = textAttribs[ccl].color;
\r
6596 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6597 firstTime = FALSE;
\r
6600 cc.lStructSize = sizeof(cc);
\r
6601 cc.hwndOwner = hwnd;
\r
6602 cc.hInstance = NULL;
\r
6603 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6604 cc.lpCustColors = (LPDWORD) customColors;
\r
6605 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6607 if (!ChooseColor(&cc)) return FALSE;
\r
6609 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6610 if (newcolor == *which) return FALSE;
\r
6611 *which = newcolor;
\r
6615 InitDrawingColors();
\r
6616 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6621 MyLoadSound(MySound *ms)
\r
6627 if (ms->data) free(ms->data);
\r
6630 switch (ms->name[0]) {
\r
6636 /* System sound from Control Panel. Don't preload here. */
\r
6640 if (ms->name[1] == NULLCHAR) {
\r
6641 /* "!" alone = silence */
\r
6644 /* Builtin wave resource. Error if not found. */
\r
6645 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6646 if (h == NULL) break;
\r
6647 ms->data = (void *)LoadResource(hInst, h);
\r
6648 if (h == NULL) break;
\r
6653 /* .wav file. Error if not found. */
\r
6654 f = fopen(ms->name, "rb");
\r
6655 if (f == NULL) break;
\r
6656 if (fstat(fileno(f), &st) < 0) break;
\r
6657 ms->data = malloc(st.st_size);
\r
6658 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6664 char buf[MSG_SIZ];
\r
6665 sprintf(buf, "Error loading sound %s", ms->name);
\r
6666 DisplayError(buf, GetLastError());
\r
6672 MyPlaySound(MySound *ms)
\r
6674 BOOLEAN ok = FALSE;
\r
6676 switch (ms->name[0]) {
\r
6678 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6683 /* System sound from Control Panel (deprecated feature).
\r
6684 "$" alone or an unset sound name gets default beep (still in use). */
\r
6685 if (ms->name[1]) {
\r
6686 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6688 if (!ok) ok = MessageBeep(MB_OK);
\r
6691 /* Builtin wave resource, or "!" alone for silence */
\r
6692 if (ms->name[1]) {
\r
6693 if (ms->data == NULL) return FALSE;
\r
6694 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6700 /* .wav file. Error if not found. */
\r
6701 if (ms->data == NULL) return FALSE;
\r
6702 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6705 /* Don't print an error: this can happen innocently if the sound driver
\r
6706 is busy; for instance, if another instance of WinBoard is playing
\r
6707 a sound at about the same time. */
\r
6710 char buf[MSG_SIZ];
\r
6711 sprintf(buf, "Error playing sound %s", ms->name);
\r
6712 DisplayError(buf, GetLastError());
\r
6720 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6723 OPENFILENAME *ofn;
\r
6724 static UINT *number; /* gross that this is static */
\r
6726 switch (message) {
\r
6727 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6728 /* Center the dialog over the application window */
\r
6729 ofn = (OPENFILENAME *) lParam;
\r
6730 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6731 number = (UINT *) ofn->lCustData;
\r
6732 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6736 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6737 return FALSE; /* Allow for further processing */
\r
6740 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6741 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6743 return FALSE; /* Allow for further processing */
\r
6749 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6751 static UINT *number;
\r
6752 OPENFILENAME *ofname;
\r
6755 case WM_INITDIALOG:
\r
6756 ofname = (OPENFILENAME *)lParam;
\r
6757 number = (UINT *)(ofname->lCustData);
\r
6760 ofnot = (OFNOTIFY *)lParam;
\r
6761 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6762 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6771 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6772 char *nameFilt, char *dlgTitle, UINT *number,
\r
6773 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6775 OPENFILENAME openFileName;
\r
6776 char buf1[MSG_SIZ];
\r
6779 if (fileName == NULL) fileName = buf1;
\r
6780 if (defName == NULL) {
\r
6781 strcpy(fileName, "*.");
\r
6782 strcat(fileName, defExt);
\r
6784 strcpy(fileName, defName);
\r
6786 if (fileTitle) strcpy(fileTitle, "");
\r
6787 if (number) *number = 0;
\r
6789 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6790 openFileName.hwndOwner = hwnd;
\r
6791 openFileName.hInstance = (HANDLE) hInst;
\r
6792 openFileName.lpstrFilter = nameFilt;
\r
6793 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6794 openFileName.nMaxCustFilter = 0L;
\r
6795 openFileName.nFilterIndex = 1L;
\r
6796 openFileName.lpstrFile = fileName;
\r
6797 openFileName.nMaxFile = MSG_SIZ;
\r
6798 openFileName.lpstrFileTitle = fileTitle;
\r
6799 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6800 openFileName.lpstrInitialDir = NULL;
\r
6801 openFileName.lpstrTitle = dlgTitle;
\r
6802 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6803 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6804 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6805 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6806 openFileName.nFileOffset = 0;
\r
6807 openFileName.nFileExtension = 0;
\r
6808 openFileName.lpstrDefExt = defExt;
\r
6809 openFileName.lCustData = (LONG) number;
\r
6810 openFileName.lpfnHook = oldDialog ?
\r
6811 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6812 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6814 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6815 GetOpenFileName(&openFileName)) {
\r
6816 /* open the file */
\r
6817 f = fopen(openFileName.lpstrFile, write);
\r
6819 MessageBox(hwnd, "File open failed", NULL,
\r
6820 MB_OK|MB_ICONEXCLAMATION);
\r
6824 int err = CommDlgExtendedError();
\r
6825 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6834 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6836 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6839 * Get the first pop-up menu in the menu template. This is the
\r
6840 * menu that TrackPopupMenu displays.
\r
6842 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6844 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6847 * TrackPopup uses screen coordinates, so convert the
\r
6848 * coordinates of the mouse click to screen coordinates.
\r
6850 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6852 /* Draw and track the floating pop-up menu. */
\r
6853 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6854 pt.x, pt.y, 0, hwnd, NULL);
\r
6856 /* Destroy the menu.*/
\r
6857 DestroyMenu(hmenu);
\r
6862 int sizeX, sizeY, newSizeX, newSizeY;
\r
6864 } ResizeEditPlusButtonsClosure;
\r
6867 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6869 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6873 if (hChild == cl->hText) return TRUE;
\r
6874 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6875 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6876 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6877 ScreenToClient(cl->hDlg, &pt);
\r
6878 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6879 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6883 /* Resize a dialog that has a (rich) edit field filling most of
\r
6884 the top, with a row of buttons below */
\r
6886 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6889 int newTextHeight, newTextWidth;
\r
6890 ResizeEditPlusButtonsClosure cl;
\r
6892 /*if (IsIconic(hDlg)) return;*/
\r
6893 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6895 cl.hdwp = BeginDeferWindowPos(8);
\r
6897 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6898 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6899 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6900 if (newTextHeight < 0) {
\r
6901 newSizeY += -newTextHeight;
\r
6902 newTextHeight = 0;
\r
6904 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6905 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6911 cl.newSizeX = newSizeX;
\r
6912 cl.newSizeY = newSizeY;
\r
6913 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6915 EndDeferWindowPos(cl.hdwp);
\r
6918 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6920 RECT rChild, rParent;
\r
6921 int wChild, hChild, wParent, hParent;
\r
6922 int wScreen, hScreen, xNew, yNew;
\r
6925 /* Get the Height and Width of the child window */
\r
6926 GetWindowRect (hwndChild, &rChild);
\r
6927 wChild = rChild.right - rChild.left;
\r
6928 hChild = rChild.bottom - rChild.top;
\r
6930 /* Get the Height and Width of the parent window */
\r
6931 GetWindowRect (hwndParent, &rParent);
\r
6932 wParent = rParent.right - rParent.left;
\r
6933 hParent = rParent.bottom - rParent.top;
\r
6935 /* Get the display limits */
\r
6936 hdc = GetDC (hwndChild);
\r
6937 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6938 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6939 ReleaseDC(hwndChild, hdc);
\r
6941 /* Calculate new X position, then adjust for screen */
\r
6942 xNew = rParent.left + ((wParent - wChild) /2);
\r
6945 } else if ((xNew+wChild) > wScreen) {
\r
6946 xNew = wScreen - wChild;
\r
6949 /* Calculate new Y position, then adjust for screen */
\r
6951 yNew = rParent.top + ((hParent - hChild) /2);
\r
6954 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6959 } else if ((yNew+hChild) > hScreen) {
\r
6960 yNew = hScreen - hChild;
\r
6963 /* Set it, and return */
\r
6964 return SetWindowPos (hwndChild, NULL,
\r
6965 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6968 /* Center one window over another */
\r
6969 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6971 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6974 /*---------------------------------------------------------------------------*\
\r
6976 * Startup Dialog functions
\r
6978 \*---------------------------------------------------------------------------*/
\r
6980 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6982 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6984 while (*cd != NULL) {
\r
6985 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6991 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6993 char buf1[ARG_MAX];
\r
6996 if (str[0] == '@') {
\r
6997 FILE* f = fopen(str + 1, "r");
\r
6999 DisplayFatalError(str + 1, errno, 2);
\r
7002 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
7004 buf1[len] = NULLCHAR;
\r
7008 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7011 char buf[MSG_SIZ];
\r
7012 char *end = strchr(str, '\n');
\r
7013 if (end == NULL) return;
\r
7014 memcpy(buf, str, end - str);
\r
7015 buf[end - str] = NULLCHAR;
\r
7016 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7022 SetStartupDialogEnables(HWND hDlg)
\r
7024 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7025 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7026 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7027 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7028 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7029 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7030 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7031 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7032 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7033 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7034 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7035 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7036 IsDlgButtonChecked(hDlg, OPT_View));
\r
7040 QuoteForFilename(char *filename)
\r
7042 int dquote, space;
\r
7043 dquote = strchr(filename, '"') != NULL;
\r
7044 space = strchr(filename, ' ') != NULL;
\r
7045 if (dquote || space) {
\r
7057 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7059 char buf[MSG_SIZ];
\r
7062 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7063 q = QuoteForFilename(nthcp);
\r
7064 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7065 if (*nthdir != NULLCHAR) {
\r
7066 q = QuoteForFilename(nthdir);
\r
7067 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7069 if (*nthcp == NULLCHAR) {
\r
7070 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7071 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7072 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7073 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7078 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7080 char buf[MSG_SIZ];
\r
7084 switch (message) {
\r
7085 case WM_INITDIALOG:
\r
7086 /* Center the dialog */
\r
7087 CenterWindow (hDlg, GetDesktopWindow());
\r
7088 /* Initialize the dialog items */
\r
7089 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7090 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7091 firstChessProgramNames);
\r
7092 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7093 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7094 secondChessProgramNames);
\r
7095 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7096 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7097 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7098 if (*appData.icsHelper != NULLCHAR) {
\r
7099 char *q = QuoteForFilename(appData.icsHelper);
\r
7100 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7102 if (*appData.icsHost == NULLCHAR) {
\r
7103 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7104 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7105 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7106 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7107 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7110 if (appData.icsActive) {
\r
7111 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7113 else if (appData.noChessProgram) {
\r
7114 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7117 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7120 SetStartupDialogEnables(hDlg);
\r
7124 switch (LOWORD(wParam)) {
\r
7126 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7127 strcpy(buf, "/fcp=");
\r
7128 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7130 ParseArgs(StringGet, &p);
\r
7131 strcpy(buf, "/scp=");
\r
7132 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7134 ParseArgs(StringGet, &p);
\r
7135 appData.noChessProgram = FALSE;
\r
7136 appData.icsActive = FALSE;
\r
7137 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7138 strcpy(buf, "/ics /icshost=");
\r
7139 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7141 ParseArgs(StringGet, &p);
\r
7142 if (appData.zippyPlay) {
\r
7143 strcpy(buf, "/fcp=");
\r
7144 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7146 ParseArgs(StringGet, &p);
\r
7148 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7149 appData.noChessProgram = TRUE;
\r
7150 appData.icsActive = FALSE;
\r
7152 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7153 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7156 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7157 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7159 ParseArgs(StringGet, &p);
\r
7161 EndDialog(hDlg, TRUE);
\r
7168 case IDM_HELPCONTENTS:
\r
7169 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7170 MessageBox (GetFocus(),
\r
7171 "Unable to activate help",
\r
7172 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7177 SetStartupDialogEnables(hDlg);
\r
7185 /*---------------------------------------------------------------------------*\
\r
7187 * About box dialog functions
\r
7189 \*---------------------------------------------------------------------------*/
\r
7191 /* Process messages for "About" dialog box */
\r
7193 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7195 switch (message) {
\r
7196 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7197 /* Center the dialog over the application window */
\r
7198 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7199 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7203 case WM_COMMAND: /* message: received a command */
\r
7204 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7205 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7206 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7214 /*---------------------------------------------------------------------------*\
\r
7216 * Comment Dialog functions
\r
7218 \*---------------------------------------------------------------------------*/
\r
7221 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7223 static HANDLE hwndText = NULL;
\r
7224 int len, newSizeX, newSizeY, flags;
\r
7225 static int sizeX, sizeY;
\r
7230 switch (message) {
\r
7231 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7232 /* Initialize the dialog items */
\r
7233 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7234 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7235 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7236 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7237 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7238 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7239 SetWindowText(hDlg, commentTitle);
\r
7240 if (editComment) {
\r
7241 SetFocus(hwndText);
\r
7243 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7245 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7246 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7247 MAKELPARAM(FALSE, 0));
\r
7248 /* Size and position the dialog */
\r
7249 if (!commentDialog) {
\r
7250 commentDialog = hDlg;
\r
7251 flags = SWP_NOZORDER;
\r
7252 GetClientRect(hDlg, &rect);
\r
7253 sizeX = rect.right;
\r
7254 sizeY = rect.bottom;
\r
7255 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7256 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7257 WINDOWPLACEMENT wp;
\r
7258 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7259 wp.length = sizeof(WINDOWPLACEMENT);
\r
7261 wp.showCmd = SW_SHOW;
\r
7262 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7263 wp.rcNormalPosition.left = commentX;
\r
7264 wp.rcNormalPosition.right = commentX + commentW;
\r
7265 wp.rcNormalPosition.top = commentY;
\r
7266 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7267 SetWindowPlacement(hDlg, &wp);
\r
7269 GetClientRect(hDlg, &rect);
\r
7270 newSizeX = rect.right;
\r
7271 newSizeY = rect.bottom;
\r
7272 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7273 newSizeX, newSizeY);
\r
7280 case WM_COMMAND: /* message: received a command */
\r
7281 switch (LOWORD(wParam)) {
\r
7283 if (editComment) {
\r
7285 /* Read changed options from the dialog box */
\r
7286 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7287 len = GetWindowTextLength(hwndText);
\r
7288 str = (char *) malloc(len + 1);
\r
7289 GetWindowText(hwndText, str, len + 1);
\r
7298 ReplaceComment(commentIndex, str);
\r
7305 case OPT_CancelComment:
\r
7309 case OPT_ClearComment:
\r
7310 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7313 case OPT_EditComment:
\r
7314 EditCommentEvent();
\r
7323 newSizeX = LOWORD(lParam);
\r
7324 newSizeY = HIWORD(lParam);
\r
7325 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7330 case WM_GETMINMAXINFO:
\r
7331 /* Prevent resizing window too small */
\r
7332 mmi = (MINMAXINFO *) lParam;
\r
7333 mmi->ptMinTrackSize.x = 100;
\r
7334 mmi->ptMinTrackSize.y = 100;
\r
7341 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7346 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7348 if (str == NULL) str = "";
\r
7349 p = (char *) malloc(2 * strlen(str) + 2);
\r
7352 if (*str == '\n') *q++ = '\r';
\r
7356 if (commentText != NULL) free(commentText);
\r
7358 commentIndex = index;
\r
7359 commentTitle = title;
\r
7361 editComment = edit;
\r
7363 if (commentDialog) {
\r
7364 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7365 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7367 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7368 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7369 hwndMain, (DLGPROC)lpProc);
\r
7370 FreeProcInstance(lpProc);
\r
7372 commentDialogUp = TRUE;
\r
7376 /*---------------------------------------------------------------------------*\
\r
7378 * Type-in move dialog functions
\r
7380 \*---------------------------------------------------------------------------*/
\r
7383 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7385 char move[MSG_SIZ];
\r
7387 ChessMove moveType;
\r
7388 int fromX, fromY, toX, toY;
\r
7391 switch (message) {
\r
7392 case WM_INITDIALOG:
\r
7393 move[0] = (char) lParam;
\r
7394 move[1] = NULLCHAR;
\r
7395 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7396 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7397 SetWindowText(hInput, move);
\r
7399 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7403 switch (LOWORD(wParam)) {
\r
7405 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7406 { int n; Board board;
\r
7408 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7409 EditPositionPasteFEN(move);
\r
7410 EndDialog(hDlg, TRUE);
\r
7413 // [HGM] movenum: allow move number to be typed in any mode
\r
7414 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7415 currentMove = 2*n-1;
\r
7416 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7417 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7418 EndDialog(hDlg, TRUE);
\r
7419 DrawPosition(TRUE, boards[currentMove]);
\r
7420 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7421 else DisplayMessage("", "");
\r
7425 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7426 gameMode != Training) {
\r
7427 DisplayMoveError("Displayed move is not current");
\r
7429 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7430 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7431 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7432 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7433 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7434 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7435 if (gameMode != Training)
\r
7436 forwardMostMove = currentMove;
\r
7437 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7439 DisplayMoveError("Could not parse move");
\r
7442 EndDialog(hDlg, TRUE);
\r
7445 EndDialog(hDlg, FALSE);
\r
7456 PopUpMoveDialog(char firstchar)
\r
7460 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7461 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7462 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7463 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7464 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7465 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7466 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7467 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7468 gameMode == Training) {
\r
7469 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7470 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7471 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7472 FreeProcInstance(lpProc);
\r
7476 /*---------------------------------------------------------------------------*\
\r
7478 * Type-in name dialog functions
\r
7480 \*---------------------------------------------------------------------------*/
\r
7483 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7485 char move[MSG_SIZ];
\r
7488 switch (message) {
\r
7489 case WM_INITDIALOG:
\r
7490 move[0] = (char) lParam;
\r
7491 move[1] = NULLCHAR;
\r
7492 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7493 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7494 SetWindowText(hInput, move);
\r
7496 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7500 switch (LOWORD(wParam)) {
\r
7502 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7503 appData.userName = strdup(move);
\r
7506 EndDialog(hDlg, TRUE);
\r
7509 EndDialog(hDlg, FALSE);
\r
7520 PopUpNameDialog(char firstchar)
\r
7524 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7525 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7526 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7527 FreeProcInstance(lpProc);
\r
7530 /*---------------------------------------------------------------------------*\
\r
7534 \*---------------------------------------------------------------------------*/
\r
7536 /* Nonmodal error box */
\r
7537 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7538 WPARAM wParam, LPARAM lParam);
\r
7541 ErrorPopUp(char *title, char *content)
\r
7545 BOOLEAN modal = hwndMain == NULL;
\r
7563 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7564 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7567 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7569 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7570 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7571 hwndMain, (DLGPROC)lpProc);
\r
7572 FreeProcInstance(lpProc);
\r
7579 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7580 if (errorDialog == NULL) return;
\r
7581 DestroyWindow(errorDialog);
\r
7582 errorDialog = NULL;
\r
7586 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7591 switch (message) {
\r
7592 case WM_INITDIALOG:
\r
7593 GetWindowRect(hDlg, &rChild);
\r
7596 SetWindowPos(hDlg, NULL, rChild.left,
\r
7597 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7598 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7602 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7603 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7604 and it doesn't work when you resize the dialog.
\r
7605 For now, just give it a default position.
\r
7607 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7609 errorDialog = hDlg;
\r
7610 SetWindowText(hDlg, errorTitle);
\r
7611 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7612 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7616 switch (LOWORD(wParam)) {
\r
7619 if (errorDialog == hDlg) errorDialog = NULL;
\r
7620 DestroyWindow(hDlg);
\r
7632 HWND gothicDialog = NULL;
\r
7635 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7639 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7641 switch (message) {
\r
7642 case WM_INITDIALOG:
\r
7643 GetWindowRect(hDlg, &rChild);
\r
7645 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7649 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7650 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7651 and it doesn't work when you resize the dialog.
\r
7652 For now, just give it a default position.
\r
7654 gothicDialog = hDlg;
\r
7655 SetWindowText(hDlg, errorTitle);
\r
7656 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7657 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7661 switch (LOWORD(wParam)) {
\r
7664 if (errorDialog == hDlg) errorDialog = NULL;
\r
7665 DestroyWindow(hDlg);
\r
7677 GothicPopUp(char *title, VariantClass variant)
\r
7680 static char *lastTitle;
\r
7682 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7683 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7685 if(lastTitle != title && gothicDialog != NULL) {
\r
7686 DestroyWindow(gothicDialog);
\r
7687 gothicDialog = NULL;
\r
7689 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7690 title = lastTitle;
\r
7691 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7692 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7693 hwndMain, (DLGPROC)lpProc);
\r
7694 FreeProcInstance(lpProc);
\r
7699 /*---------------------------------------------------------------------------*\
\r
7701 * Ics Interaction console functions
\r
7703 \*---------------------------------------------------------------------------*/
\r
7705 #define HISTORY_SIZE 64
\r
7706 static char *history[HISTORY_SIZE];
\r
7707 int histIn = 0, histP = 0;
\r
7710 SaveInHistory(char *cmd)
\r
7712 if (history[histIn] != NULL) {
\r
7713 free(history[histIn]);
\r
7714 history[histIn] = NULL;
\r
7716 if (*cmd == NULLCHAR) return;
\r
7717 history[histIn] = StrSave(cmd);
\r
7718 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7719 if (history[histIn] != NULL) {
\r
7720 free(history[histIn]);
\r
7721 history[histIn] = NULL;
\r
7727 PrevInHistory(char *cmd)
\r
7730 if (histP == histIn) {
\r
7731 if (history[histIn] != NULL) free(history[histIn]);
\r
7732 history[histIn] = StrSave(cmd);
\r
7734 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7735 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7737 return history[histP];
\r
7743 if (histP == histIn) return NULL;
\r
7744 histP = (histP + 1) % HISTORY_SIZE;
\r
7745 return history[histP];
\r
7752 BOOLEAN immediate;
\r
7753 } IcsTextMenuEntry;
\r
7754 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7755 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7758 ParseIcsTextMenu(char *icsTextMenuString)
\r
7761 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7762 char *p = icsTextMenuString;
\r
7763 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7766 if (e->command != NULL) {
\r
7768 e->command = NULL;
\r
7772 e = icsTextMenuEntry;
\r
7773 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7774 if (*p == ';' || *p == '\n') {
\r
7775 e->item = strdup("-");
\r
7776 e->command = NULL;
\r
7778 } else if (*p == '-') {
\r
7779 e->item = strdup("-");
\r
7780 e->command = NULL;
\r
7784 char *q, *r, *s, *t;
\r
7786 q = strchr(p, ',');
\r
7787 if (q == NULL) break;
\r
7789 r = strchr(q + 1, ',');
\r
7790 if (r == NULL) break;
\r
7792 s = strchr(r + 1, ',');
\r
7793 if (s == NULL) break;
\r
7796 t = strchr(s + 1, c);
\r
7799 t = strchr(s + 1, c);
\r
7801 if (t != NULL) *t = NULLCHAR;
\r
7802 e->item = strdup(p);
\r
7803 e->command = strdup(q + 1);
\r
7804 e->getname = *(r + 1) != '0';
\r
7805 e->immediate = *(s + 1) != '0';
\r
7809 if (t == NULL) break;
\r
7818 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7822 hmenu = LoadMenu(hInst, "TextMenu");
\r
7823 h = GetSubMenu(hmenu, 0);
\r
7825 if (strcmp(e->item, "-") == 0) {
\r
7826 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7828 if (e->item[0] == '|') {
\r
7829 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7830 IDM_CommandX + i, &e->item[1]);
\r
7832 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7841 WNDPROC consoleTextWindowProc;
\r
7844 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7846 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7847 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7851 SetWindowText(hInput, command);
\r
7853 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7855 sel.cpMin = 999999;
\r
7856 sel.cpMax = 999999;
\r
7857 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7862 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7863 if (sel.cpMin == sel.cpMax) {
\r
7864 /* Expand to surrounding word */
\r
7867 tr.chrg.cpMax = sel.cpMin;
\r
7868 tr.chrg.cpMin = --sel.cpMin;
\r
7869 if (sel.cpMin < 0) break;
\r
7870 tr.lpstrText = name;
\r
7871 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7872 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7876 tr.chrg.cpMin = sel.cpMax;
\r
7877 tr.chrg.cpMax = ++sel.cpMax;
\r
7878 tr.lpstrText = name;
\r
7879 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7880 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7883 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7884 MessageBeep(MB_ICONEXCLAMATION);
\r
7888 tr.lpstrText = name;
\r
7889 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7891 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7892 MessageBeep(MB_ICONEXCLAMATION);
\r
7895 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7898 sprintf(buf, "%s %s", command, name);
\r
7899 SetWindowText(hInput, buf);
\r
7900 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7902 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7903 SetWindowText(hInput, buf);
\r
7904 sel.cpMin = 999999;
\r
7905 sel.cpMax = 999999;
\r
7906 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7912 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7917 switch (message) {
\r
7919 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7922 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7925 sel.cpMin = 999999;
\r
7926 sel.cpMax = 999999;
\r
7927 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7928 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7933 if(wParam != '\022') {
\r
7934 if (wParam == '\t') {
\r
7935 if (GetKeyState(VK_SHIFT) < 0) {
\r
7937 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7938 if (buttonDesc[0].hwnd) {
\r
7939 SetFocus(buttonDesc[0].hwnd);
\r
7941 SetFocus(hwndMain);
\r
7945 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7948 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7949 JAWS_DELETE( SetFocus(hInput); )
\r
7950 SendMessage(hInput, message, wParam, lParam);
\r
7953 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7954 case WM_RBUTTONUP:
\r
7955 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7956 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7957 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7960 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7961 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7962 if (sel.cpMin == sel.cpMax) {
\r
7963 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7964 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7966 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7967 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7969 pt.x = LOWORD(lParam);
\r
7970 pt.y = HIWORD(lParam);
\r
7971 MenuPopup(hwnd, pt, hmenu, -1);
\r
7975 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7977 return SendMessage(hInput, message, wParam, lParam);
\r
7978 case WM_MBUTTONDOWN:
\r
7979 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7980 case WM_RBUTTONDOWN:
\r
7981 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7982 /* Move selection here if it was empty */
\r
7984 pt.x = LOWORD(lParam);
\r
7985 pt.y = HIWORD(lParam);
\r
7986 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7987 if (sel.cpMin == sel.cpMax) {
\r
7988 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7989 sel.cpMax = sel.cpMin;
\r
7990 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7992 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7996 switch (LOWORD(wParam)) {
\r
7997 case IDM_QuickPaste:
\r
7999 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8000 if (sel.cpMin == sel.cpMax) {
\r
8001 MessageBeep(MB_ICONEXCLAMATION);
\r
8004 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8005 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8006 SendMessage(hInput, WM_PASTE, 0, 0);
\r
8011 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8014 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8017 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8021 int i = LOWORD(wParam) - IDM_CommandX;
\r
8022 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8023 icsTextMenuEntry[i].command != NULL) {
\r
8024 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8025 icsTextMenuEntry[i].getname,
\r
8026 icsTextMenuEntry[i].immediate);
\r
8034 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8037 WNDPROC consoleInputWindowProc;
\r
8040 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8042 char buf[MSG_SIZ];
\r
8044 static BOOL sendNextChar = FALSE;
\r
8045 static BOOL quoteNextChar = FALSE;
\r
8046 InputSource *is = consoleInputSource;
\r
8050 switch (message) {
\r
8052 if (!appData.localLineEditing || sendNextChar) {
\r
8053 is->buf[0] = (CHAR) wParam;
\r
8055 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8056 sendNextChar = FALSE;
\r
8059 if (quoteNextChar) {
\r
8060 buf[0] = (char) wParam;
\r
8061 buf[1] = NULLCHAR;
\r
8062 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8063 quoteNextChar = FALSE;
\r
8067 case '\r': /* Enter key */
\r
8068 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8069 if (consoleEcho) SaveInHistory(is->buf);
\r
8070 is->buf[is->count++] = '\n';
\r
8071 is->buf[is->count] = NULLCHAR;
\r
8072 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8073 if (consoleEcho) {
\r
8074 ConsoleOutput(is->buf, is->count, TRUE);
\r
8075 } else if (appData.localLineEditing) {
\r
8076 ConsoleOutput("\n", 1, TRUE);
\r
8079 case '\033': /* Escape key */
\r
8080 SetWindowText(hwnd, "");
\r
8081 cf.cbSize = sizeof(CHARFORMAT);
\r
8082 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8083 if (consoleEcho) {
\r
8084 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8086 cf.crTextColor = COLOR_ECHOOFF;
\r
8088 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8089 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8091 case '\t': /* Tab key */
\r
8092 if (GetKeyState(VK_SHIFT) < 0) {
\r
8094 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8097 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8098 if (buttonDesc[0].hwnd) {
\r
8099 SetFocus(buttonDesc[0].hwnd);
\r
8101 SetFocus(hwndMain);
\r
8105 case '\023': /* Ctrl+S */
\r
8106 sendNextChar = TRUE;
\r
8108 case '\021': /* Ctrl+Q */
\r
8109 quoteNextChar = TRUE;
\r
8119 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8120 p = PrevInHistory(buf);
\r
8122 SetWindowText(hwnd, p);
\r
8123 sel.cpMin = 999999;
\r
8124 sel.cpMax = 999999;
\r
8125 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8130 p = NextInHistory();
\r
8132 SetWindowText(hwnd, p);
\r
8133 sel.cpMin = 999999;
\r
8134 sel.cpMax = 999999;
\r
8135 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8141 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8145 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8149 case WM_MBUTTONDOWN:
\r
8150 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8151 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8153 case WM_RBUTTONUP:
\r
8154 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8155 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8156 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8160 hmenu = LoadMenu(hInst, "InputMenu");
\r
8161 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8162 if (sel.cpMin == sel.cpMax) {
\r
8163 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8164 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8166 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8167 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8169 pt.x = LOWORD(lParam);
\r
8170 pt.y = HIWORD(lParam);
\r
8171 MenuPopup(hwnd, pt, hmenu, -1);
\r
8175 switch (LOWORD(wParam)) {
\r
8177 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8179 case IDM_SelectAll:
\r
8181 sel.cpMax = -1; /*999999?*/
\r
8182 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8185 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8188 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8191 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8196 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8199 #define CO_MAX 100000
\r
8200 #define CO_TRIM 1000
\r
8203 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8205 static SnapData sd;
\r
8206 static HWND hText, hInput /*, hFocus*/;
\r
8207 // InputSource *is = consoleInputSource;
\r
8209 static int sizeX, sizeY;
\r
8210 int newSizeX, newSizeY;
\r
8213 switch (message) {
\r
8214 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8215 hwndConsole = hDlg;
\r
8216 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8217 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8219 consoleTextWindowProc = (WNDPROC)
\r
8220 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8221 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8222 consoleInputWindowProc = (WNDPROC)
\r
8223 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8224 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8225 Colorize(ColorNormal, TRUE);
\r
8226 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8227 ChangedConsoleFont();
\r
8228 GetClientRect(hDlg, &rect);
\r
8229 sizeX = rect.right;
\r
8230 sizeY = rect.bottom;
\r
8231 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8232 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8233 WINDOWPLACEMENT wp;
\r
8234 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8235 wp.length = sizeof(WINDOWPLACEMENT);
\r
8237 wp.showCmd = SW_SHOW;
\r
8238 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8239 wp.rcNormalPosition.left = wpConsole.x;
\r
8240 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8241 wp.rcNormalPosition.top = wpConsole.y;
\r
8242 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8243 SetWindowPlacement(hDlg, &wp);
\r
8246 // [HGM] Chessknight's change 2004-07-13
\r
8247 else { /* Determine Defaults */
\r
8248 WINDOWPLACEMENT wp;
\r
8249 wpConsole.x = winWidth + 1;
\r
8250 wpConsole.y = boardY;
\r
8251 wpConsole.width = screenWidth - winWidth;
\r
8252 wpConsole.height = winHeight;
\r
8253 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8254 wp.length = sizeof(WINDOWPLACEMENT);
\r
8256 wp.showCmd = SW_SHOW;
\r
8257 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8258 wp.rcNormalPosition.left = wpConsole.x;
\r
8259 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8260 wp.rcNormalPosition.top = wpConsole.y;
\r
8261 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8262 SetWindowPlacement(hDlg, &wp);
\r
8277 if (IsIconic(hDlg)) break;
\r
8278 newSizeX = LOWORD(lParam);
\r
8279 newSizeY = HIWORD(lParam);
\r
8280 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8281 RECT rectText, rectInput;
\r
8283 int newTextHeight, newTextWidth;
\r
8284 GetWindowRect(hText, &rectText);
\r
8285 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8286 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8287 if (newTextHeight < 0) {
\r
8288 newSizeY += -newTextHeight;
\r
8289 newTextHeight = 0;
\r
8291 SetWindowPos(hText, NULL, 0, 0,
\r
8292 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8293 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8294 pt.x = rectInput.left;
\r
8295 pt.y = rectInput.top + newSizeY - sizeY;
\r
8296 ScreenToClient(hDlg, &pt);
\r
8297 SetWindowPos(hInput, NULL,
\r
8298 pt.x, pt.y, /* needs client coords */
\r
8299 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8300 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8306 case WM_GETMINMAXINFO:
\r
8307 /* Prevent resizing window too small */
\r
8308 mmi = (MINMAXINFO *) lParam;
\r
8309 mmi->ptMinTrackSize.x = 100;
\r
8310 mmi->ptMinTrackSize.y = 100;
\r
8313 /* [AS] Snapping */
\r
8314 case WM_ENTERSIZEMOVE:
\r
8315 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8318 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8321 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8323 case WM_EXITSIZEMOVE:
\r
8324 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8327 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8335 if (hwndConsole) return;
\r
8336 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8337 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8342 ConsoleOutput(char* data, int length, int forceVisible)
\r
8347 char buf[CO_MAX+1];
\r
8350 static int delayLF = 0;
\r
8351 CHARRANGE savesel, sel;
\r
8353 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8361 while (length--) {
\r
8369 } else if (*p == '\007') {
\r
8370 MyPlaySound(&sounds[(int)SoundBell]);
\r
8377 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8378 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8379 /* Save current selection */
\r
8380 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8381 exlen = GetWindowTextLength(hText);
\r
8382 /* Find out whether current end of text is visible */
\r
8383 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8384 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8385 /* Trim existing text if it's too long */
\r
8386 if (exlen + (q - buf) > CO_MAX) {
\r
8387 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8390 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8391 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8393 savesel.cpMin -= trim;
\r
8394 savesel.cpMax -= trim;
\r
8395 if (exlen < 0) exlen = 0;
\r
8396 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8397 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8399 /* Append the new text */
\r
8400 sel.cpMin = exlen;
\r
8401 sel.cpMax = exlen;
\r
8402 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8403 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8404 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8405 if (forceVisible || exlen == 0 ||
\r
8406 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8407 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8408 /* Scroll to make new end of text visible if old end of text
\r
8409 was visible or new text is an echo of user typein */
\r
8410 sel.cpMin = 9999999;
\r
8411 sel.cpMax = 9999999;
\r
8412 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8413 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8414 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8415 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8417 if (savesel.cpMax == exlen || forceVisible) {
\r
8418 /* Move insert point to new end of text if it was at the old
\r
8419 end of text or if the new text is an echo of user typein */
\r
8420 sel.cpMin = 9999999;
\r
8421 sel.cpMax = 9999999;
\r
8422 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8424 /* Restore previous selection */
\r
8425 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8427 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8434 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8438 COLORREF oldFg, oldBg;
\r
8442 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8444 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8445 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8446 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8449 rect.right = x + squareSize;
\r
8451 rect.bottom = y + squareSize;
\r
8454 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8455 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8456 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8457 &rect, str, strlen(str), NULL);
\r
8459 (void) SetTextColor(hdc, oldFg);
\r
8460 (void) SetBkColor(hdc, oldBg);
\r
8461 (void) SelectObject(hdc, oldFont);
\r
8465 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8466 RECT *rect, char *color, char *flagFell)
\r
8470 COLORREF oldFg, oldBg;
\r
8473 if (appData.clockMode) {
\r
8475 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8477 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8484 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8485 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8487 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8488 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8490 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8494 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8495 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8496 rect, str, strlen(str), NULL);
\r
8497 if(logoHeight > 0 && appData.clockMode) {
\r
8499 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8500 r.top = rect->top + logoHeight/2;
\r
8501 r.left = rect->left;
\r
8502 r.right = rect->right;
\r
8503 r.bottom = rect->bottom;
\r
8504 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8505 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8506 &r, str, strlen(str), NULL);
\r
8508 (void) SetTextColor(hdc, oldFg);
\r
8509 (void) SetBkColor(hdc, oldBg);
\r
8510 (void) SelectObject(hdc, oldFont);
\r
8515 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8521 if( count <= 0 ) {
\r
8522 if (appData.debugMode) {
\r
8523 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8526 return ERROR_INVALID_USER_BUFFER;
\r
8529 ResetEvent(ovl->hEvent);
\r
8530 ovl->Offset = ovl->OffsetHigh = 0;
\r
8531 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8535 err = GetLastError();
\r
8536 if (err == ERROR_IO_PENDING) {
\r
8537 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8541 err = GetLastError();
\r
8548 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8553 ResetEvent(ovl->hEvent);
\r
8554 ovl->Offset = ovl->OffsetHigh = 0;
\r
8555 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8559 err = GetLastError();
\r
8560 if (err == ERROR_IO_PENDING) {
\r
8561 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8565 err = GetLastError();
\r
8571 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8572 void CheckForInputBufferFull( InputSource * is )
\r
8574 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8575 /* Look for end of line */
\r
8576 char * p = is->buf;
\r
8578 while( p < is->next && *p != '\n' ) {
\r
8582 if( p >= is->next ) {
\r
8583 if (appData.debugMode) {
\r
8584 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8587 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8588 is->count = (DWORD) -1;
\r
8589 is->next = is->buf;
\r
8595 InputThread(LPVOID arg)
\r
8600 is = (InputSource *) arg;
\r
8601 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8602 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8603 while (is->hThread != NULL) {
\r
8604 is->error = DoReadFile(is->hFile, is->next,
\r
8605 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8606 &is->count, &ovl);
\r
8607 if (is->error == NO_ERROR) {
\r
8608 is->next += is->count;
\r
8610 if (is->error == ERROR_BROKEN_PIPE) {
\r
8611 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8614 is->count = (DWORD) -1;
\r
8615 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8620 CheckForInputBufferFull( is );
\r
8622 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8624 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8626 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8629 CloseHandle(ovl.hEvent);
\r
8630 CloseHandle(is->hFile);
\r
8632 if (appData.debugMode) {
\r
8633 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8640 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8642 NonOvlInputThread(LPVOID arg)
\r
8649 is = (InputSource *) arg;
\r
8650 while (is->hThread != NULL) {
\r
8651 is->error = ReadFile(is->hFile, is->next,
\r
8652 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8653 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8654 if (is->error == NO_ERROR) {
\r
8655 /* Change CRLF to LF */
\r
8656 if (is->next > is->buf) {
\r
8658 i = is->count + 1;
\r
8666 if (prev == '\r' && *p == '\n') {
\r
8678 if (is->error == ERROR_BROKEN_PIPE) {
\r
8679 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8682 is->count = (DWORD) -1;
\r
8686 CheckForInputBufferFull( is );
\r
8688 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8690 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8692 if (is->count < 0) break; /* Quit on error */
\r
8694 CloseHandle(is->hFile);
\r
8699 SocketInputThread(LPVOID arg)
\r
8703 is = (InputSource *) arg;
\r
8704 while (is->hThread != NULL) {
\r
8705 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8706 if ((int)is->count == SOCKET_ERROR) {
\r
8707 is->count = (DWORD) -1;
\r
8708 is->error = WSAGetLastError();
\r
8710 is->error = NO_ERROR;
\r
8711 is->next += is->count;
\r
8712 if (is->count == 0 && is->second == is) {
\r
8713 /* End of file on stderr; quit with no message */
\r
8717 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8719 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8721 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8727 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8731 is = (InputSource *) lParam;
\r
8732 if (is->lineByLine) {
\r
8733 /* Feed in lines one by one */
\r
8734 char *p = is->buf;
\r
8736 while (q < is->next) {
\r
8737 if (*q++ == '\n') {
\r
8738 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8743 /* Move any partial line to the start of the buffer */
\r
8745 while (p < is->next) {
\r
8750 if (is->error != NO_ERROR || is->count == 0) {
\r
8751 /* Notify backend of the error. Note: If there was a partial
\r
8752 line at the end, it is not flushed through. */
\r
8753 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8756 /* Feed in the whole chunk of input at once */
\r
8757 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8758 is->next = is->buf;
\r
8762 /*---------------------------------------------------------------------------*\
\r
8764 * Menu enables. Used when setting various modes.
\r
8766 \*---------------------------------------------------------------------------*/
\r
8774 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8776 while (enab->item > 0) {
\r
8777 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8782 Enables gnuEnables[] = {
\r
8783 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8784 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8785 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8786 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8787 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8788 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8789 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8790 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8791 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8792 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8796 Enables icsEnables[] = {
\r
8797 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8798 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8799 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8800 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8801 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8802 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8803 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8804 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8805 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8806 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8807 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8808 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8813 Enables zippyEnables[] = {
\r
8814 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8815 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8816 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8821 Enables ncpEnables[] = {
\r
8822 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8823 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8824 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8825 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8826 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8827 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8828 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8829 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8830 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8831 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8832 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8833 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8834 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8835 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8836 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8840 Enables trainingOnEnables[] = {
\r
8841 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8842 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8843 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8844 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8845 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8846 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8847 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8848 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8852 Enables trainingOffEnables[] = {
\r
8853 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8854 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8855 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8856 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8857 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8858 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8859 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8860 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8864 /* These modify either ncpEnables or gnuEnables */
\r
8865 Enables cmailEnables[] = {
\r
8866 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8867 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8868 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8869 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8870 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8871 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8872 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8876 Enables machineThinkingEnables[] = {
\r
8877 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8878 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8879 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8880 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8881 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8882 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8883 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8884 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8885 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8886 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8887 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8888 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8889 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8890 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8891 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8895 Enables userThinkingEnables[] = {
\r
8896 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8897 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8898 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8899 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8900 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8901 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8902 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8903 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8904 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8905 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8906 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8907 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8908 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8909 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8910 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8914 /*---------------------------------------------------------------------------*\
\r
8916 * Front-end interface functions exported by XBoard.
\r
8917 * Functions appear in same order as prototypes in frontend.h.
\r
8919 \*---------------------------------------------------------------------------*/
\r
8923 static UINT prevChecked = 0;
\r
8924 static int prevPausing = 0;
\r
8927 if (pausing != prevPausing) {
\r
8928 prevPausing = pausing;
\r
8929 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8930 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8931 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8934 switch (gameMode) {
\r
8935 case BeginningOfGame:
\r
8936 if (appData.icsActive)
\r
8937 nowChecked = IDM_IcsClient;
\r
8938 else if (appData.noChessProgram)
\r
8939 nowChecked = IDM_EditGame;
\r
8941 nowChecked = IDM_MachineBlack;
\r
8943 case MachinePlaysBlack:
\r
8944 nowChecked = IDM_MachineBlack;
\r
8946 case MachinePlaysWhite:
\r
8947 nowChecked = IDM_MachineWhite;
\r
8949 case TwoMachinesPlay:
\r
8950 nowChecked = IDM_TwoMachines;
\r
8953 nowChecked = IDM_AnalysisMode;
\r
8956 nowChecked = IDM_AnalyzeFile;
\r
8959 nowChecked = IDM_EditGame;
\r
8961 case PlayFromGameFile:
\r
8962 nowChecked = IDM_LoadGame;
\r
8964 case EditPosition:
\r
8965 nowChecked = IDM_EditPosition;
\r
8968 nowChecked = IDM_Training;
\r
8970 case IcsPlayingWhite:
\r
8971 case IcsPlayingBlack:
\r
8972 case IcsObserving:
\r
8974 nowChecked = IDM_IcsClient;
\r
8981 if (prevChecked != 0)
\r
8982 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8983 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8984 if (nowChecked != 0)
\r
8985 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8986 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8988 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8989 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8990 MF_BYCOMMAND|MF_ENABLED);
\r
8992 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8993 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8996 prevChecked = nowChecked;
\r
8998 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8999 if (appData.icsActive) {
\r
9000 if (appData.icsEngineAnalyze) {
\r
9001 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9002 MF_BYCOMMAND|MF_CHECKED);
\r
9004 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9005 MF_BYCOMMAND|MF_UNCHECKED);
\r
9013 HMENU hmenu = GetMenu(hwndMain);
\r
9014 SetMenuEnables(hmenu, icsEnables);
\r
9015 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9016 MF_BYPOSITION|MF_ENABLED);
\r
9018 if (appData.zippyPlay) {
\r
9019 SetMenuEnables(hmenu, zippyEnables);
\r
9020 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9021 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9022 MF_BYCOMMAND|MF_ENABLED);
\r
9030 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9036 HMENU hmenu = GetMenu(hwndMain);
\r
9037 SetMenuEnables(hmenu, ncpEnables);
\r
9038 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9039 MF_BYPOSITION|MF_GRAYED);
\r
9040 DrawMenuBar(hwndMain);
\r
9046 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9050 SetTrainingModeOn()
\r
9053 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9054 for (i = 0; i < N_BUTTONS; i++) {
\r
9055 if (buttonDesc[i].hwnd != NULL)
\r
9056 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9061 VOID SetTrainingModeOff()
\r
9064 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9065 for (i = 0; i < N_BUTTONS; i++) {
\r
9066 if (buttonDesc[i].hwnd != NULL)
\r
9067 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9073 SetUserThinkingEnables()
\r
9075 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9079 SetMachineThinkingEnables()
\r
9081 HMENU hMenu = GetMenu(hwndMain);
\r
9082 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9084 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9086 if (gameMode == MachinePlaysBlack) {
\r
9087 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9088 } else if (gameMode == MachinePlaysWhite) {
\r
9089 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9090 } else if (gameMode == TwoMachinesPlay) {
\r
9091 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9097 DisplayTitle(char *str)
\r
9099 char title[MSG_SIZ], *host;
\r
9100 if (str[0] != NULLCHAR) {
\r
9101 strcpy(title, str);
\r
9102 } else if (appData.icsActive) {
\r
9103 if (appData.icsCommPort[0] != NULLCHAR)
\r
9106 host = appData.icsHost;
\r
9107 sprintf(title, "%s: %s", szTitle, host);
\r
9108 } else if (appData.noChessProgram) {
\r
9109 strcpy(title, szTitle);
\r
9111 strcpy(title, szTitle);
\r
9112 strcat(title, ": ");
\r
9113 strcat(title, first.tidy);
\r
9115 SetWindowText(hwndMain, title);
\r
9120 DisplayMessage(char *str1, char *str2)
\r
9124 int remain = MESSAGE_TEXT_MAX - 1;
\r
9127 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9128 messageText[0] = NULLCHAR;
\r
9130 len = strlen(str1);
\r
9131 if (len > remain) len = remain;
\r
9132 strncpy(messageText, str1, len);
\r
9133 messageText[len] = NULLCHAR;
\r
9136 if (*str2 && remain >= 2) {
\r
9138 strcat(messageText, " ");
\r
9141 len = strlen(str2);
\r
9142 if (len > remain) len = remain;
\r
9143 strncat(messageText, str2, len);
\r
9145 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9147 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9151 hdc = GetDC(hwndMain);
\r
9152 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9153 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9154 &messageRect, messageText, strlen(messageText), NULL);
\r
9155 (void) SelectObject(hdc, oldFont);
\r
9156 (void) ReleaseDC(hwndMain, hdc);
\r
9160 DisplayError(char *str, int error)
\r
9162 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9168 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9169 NULL, error, LANG_NEUTRAL,
\r
9170 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9172 sprintf(buf, "%s:\n%s", str, buf2);
\r
9174 ErrorMap *em = errmap;
\r
9175 while (em->err != 0 && em->err != error) em++;
\r
9176 if (em->err != 0) {
\r
9177 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9179 sprintf(buf, "%s:\nError code %d", str, error);
\r
9184 ErrorPopUp("Error", buf);
\r
9189 DisplayMoveError(char *str)
\r
9191 fromX = fromY = -1;
\r
9192 ClearHighlights();
\r
9193 DrawPosition(FALSE, NULL);
\r
9194 if (appData.popupMoveErrors) {
\r
9195 ErrorPopUp("Error", str);
\r
9197 DisplayMessage(str, "");
\r
9198 moveErrorMessageUp = TRUE;
\r
9203 DisplayFatalError(char *str, int error, int exitStatus)
\r
9205 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9207 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9210 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9211 NULL, error, LANG_NEUTRAL,
\r
9212 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9214 sprintf(buf, "%s:\n%s", str, buf2);
\r
9216 ErrorMap *em = errmap;
\r
9217 while (em->err != 0 && em->err != error) em++;
\r
9218 if (em->err != 0) {
\r
9219 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9221 sprintf(buf, "%s:\nError code %d", str, error);
\r
9226 if (appData.debugMode) {
\r
9227 fprintf(debugFP, "%s: %s\n", label, str);
\r
9229 if (appData.popupExitMessage) {
\r
9230 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9231 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9233 ExitEvent(exitStatus);
\r
9238 DisplayInformation(char *str)
\r
9240 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9245 DisplayNote(char *str)
\r
9247 ErrorPopUp("Note", str);
\r
9252 char *title, *question, *replyPrefix;
\r
9257 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9259 static QuestionParams *qp;
\r
9260 char reply[MSG_SIZ];
\r
9263 switch (message) {
\r
9264 case WM_INITDIALOG:
\r
9265 qp = (QuestionParams *) lParam;
\r
9266 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9267 SetWindowText(hDlg, qp->title);
\r
9268 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9269 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9273 switch (LOWORD(wParam)) {
\r
9275 strcpy(reply, qp->replyPrefix);
\r
9276 if (*reply) strcat(reply, " ");
\r
9277 len = strlen(reply);
\r
9278 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9279 strcat(reply, "\n");
\r
9280 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9281 EndDialog(hDlg, TRUE);
\r
9282 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9285 EndDialog(hDlg, FALSE);
\r
9296 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9298 QuestionParams qp;
\r
9302 qp.question = question;
\r
9303 qp.replyPrefix = replyPrefix;
\r
9305 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9306 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9307 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9308 FreeProcInstance(lpProc);
\r
9311 /* [AS] Pick FRC position */
\r
9312 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9314 static int * lpIndexFRC;
\r
9320 case WM_INITDIALOG:
\r
9321 lpIndexFRC = (int *) lParam;
\r
9323 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9325 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9326 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9327 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9328 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9333 switch( LOWORD(wParam) ) {
\r
9335 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9336 EndDialog( hDlg, 0 );
\r
9337 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9340 EndDialog( hDlg, 1 );
\r
9342 case IDC_NFG_Edit:
\r
9343 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9344 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9346 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9349 case IDC_NFG_Random:
\r
9350 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9351 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9364 int index = appData.defaultFrcPosition;
\r
9365 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9367 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9369 if( result == 0 ) {
\r
9370 appData.defaultFrcPosition = index;
\r
9376 /* [AS] Game list options */
\r
9382 static GLT_Item GLT_ItemInfo[] = {
\r
9383 { GLT_EVENT, "Event" },
\r
9384 { GLT_SITE, "Site" },
\r
9385 { GLT_DATE, "Date" },
\r
9386 { GLT_ROUND, "Round" },
\r
9387 { GLT_PLAYERS, "Players" },
\r
9388 { GLT_RESULT, "Result" },
\r
9389 { GLT_WHITE_ELO, "White Rating" },
\r
9390 { GLT_BLACK_ELO, "Black Rating" },
\r
9391 { GLT_TIME_CONTROL,"Time Control" },
\r
9392 { GLT_VARIANT, "Variant" },
\r
9393 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9397 const char * GLT_FindItem( char id )
\r
9399 const char * result = 0;
\r
9401 GLT_Item * list = GLT_ItemInfo;
\r
9403 while( list->id != 0 ) {
\r
9404 if( list->id == id ) {
\r
9405 result = list->name;
\r
9415 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9417 const char * name = GLT_FindItem( id );
\r
9420 if( index >= 0 ) {
\r
9421 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9424 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9429 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9433 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9436 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9440 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9442 pc = GLT_ALL_TAGS;
\r
9445 if( strchr( tags, *pc ) == 0 ) {
\r
9446 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9451 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9454 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9456 char result = '\0';
\r
9459 GLT_Item * list = GLT_ItemInfo;
\r
9461 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9462 while( list->id != 0 ) {
\r
9463 if( strcmp( list->name, name ) == 0 ) {
\r
9464 result = list->id;
\r
9475 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9477 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9478 int idx2 = idx1 + delta;
\r
9479 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9481 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9484 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9485 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9486 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9487 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9491 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9493 static char glt[64];
\r
9494 static char * lpUserGLT;
\r
9498 case WM_INITDIALOG:
\r
9499 lpUserGLT = (char *) lParam;
\r
9501 strcpy( glt, lpUserGLT );
\r
9503 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9505 /* Initialize list */
\r
9506 GLT_TagsToList( hDlg, glt );
\r
9508 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9513 switch( LOWORD(wParam) ) {
\r
9516 char * pc = lpUserGLT;
\r
9518 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9522 id = GLT_ListItemToTag( hDlg, idx );
\r
9526 } while( id != '\0' );
\r
9528 EndDialog( hDlg, 0 );
\r
9531 EndDialog( hDlg, 1 );
\r
9534 case IDC_GLT_Default:
\r
9535 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9536 GLT_TagsToList( hDlg, glt );
\r
9539 case IDC_GLT_Restore:
\r
9540 strcpy( glt, lpUserGLT );
\r
9541 GLT_TagsToList( hDlg, glt );
\r
9545 GLT_MoveSelection( hDlg, -1 );
\r
9548 case IDC_GLT_Down:
\r
9549 GLT_MoveSelection( hDlg, +1 );
\r
9559 int GameListOptions()
\r
9563 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9565 strcpy( glt, appData.gameListTags );
\r
9567 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9569 if( result == 0 ) {
\r
9570 /* [AS] Memory leak here! */
\r
9571 appData.gameListTags = strdup( glt );
\r
9579 DisplayIcsInteractionTitle(char *str)
\r
9581 char consoleTitle[MSG_SIZ];
\r
9583 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9584 SetWindowText(hwndConsole, consoleTitle);
\r
9588 DrawPosition(int fullRedraw, Board board)
\r
9590 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9597 fromX = fromY = -1;
\r
9598 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9599 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9600 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9601 dragInfo.lastpos = dragInfo.pos;
\r
9602 dragInfo.start.x = dragInfo.start.y = -1;
\r
9603 dragInfo.from = dragInfo.start;
\r
9605 DrawPosition(TRUE, NULL);
\r
9611 CommentPopUp(char *title, char *str)
\r
9613 HWND hwnd = GetActiveWindow();
\r
9614 EitherCommentPopUp(0, title, str, FALSE);
\r
9615 SetActiveWindow(hwnd);
\r
9619 CommentPopDown(void)
\r
9621 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9622 if (commentDialog) {
\r
9623 ShowWindow(commentDialog, SW_HIDE);
\r
9625 commentDialogUp = FALSE;
\r
9629 EditCommentPopUp(int index, char *title, char *str)
\r
9631 EitherCommentPopUp(index, title, str, TRUE);
\r
9638 MyPlaySound(&sounds[(int)SoundMove]);
\r
9641 VOID PlayIcsWinSound()
\r
9643 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9646 VOID PlayIcsLossSound()
\r
9648 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9651 VOID PlayIcsDrawSound()
\r
9653 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9656 VOID PlayIcsUnfinishedSound()
\r
9658 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9664 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9672 consoleEcho = TRUE;
\r
9673 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9674 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9675 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9684 consoleEcho = FALSE;
\r
9685 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9686 /* This works OK: set text and background both to the same color */
\r
9688 cf.crTextColor = COLOR_ECHOOFF;
\r
9689 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9690 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9693 /* No Raw()...? */
\r
9695 void Colorize(ColorClass cc, int continuation)
\r
9697 currentColorClass = cc;
\r
9698 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9699 consoleCF.crTextColor = textAttribs[cc].color;
\r
9700 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9701 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9707 static char buf[MSG_SIZ];
\r
9708 DWORD bufsiz = MSG_SIZ;
\r
9710 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9711 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9713 if (!GetUserName(buf, &bufsiz)) {
\r
9714 /*DisplayError("Error getting user name", GetLastError());*/
\r
9715 strcpy(buf, "User");
\r
9723 static char buf[MSG_SIZ];
\r
9724 DWORD bufsiz = MSG_SIZ;
\r
9726 if (!GetComputerName(buf, &bufsiz)) {
\r
9727 /*DisplayError("Error getting host name", GetLastError());*/
\r
9728 strcpy(buf, "Unknown");
\r
9735 ClockTimerRunning()
\r
9737 return clockTimerEvent != 0;
\r
9743 if (clockTimerEvent == 0) return FALSE;
\r
9744 KillTimer(hwndMain, clockTimerEvent);
\r
9745 clockTimerEvent = 0;
\r
9750 StartClockTimer(long millisec)
\r
9752 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9753 (UINT) millisec, NULL);
\r
9757 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9760 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9762 if(appData.noGUI) return;
\r
9763 hdc = GetDC(hwndMain);
\r
9764 if (!IsIconic(hwndMain)) {
\r
9765 DisplayAClock(hdc, timeRemaining, highlight,
\r
9766 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9768 if (highlight && iconCurrent == iconBlack) {
\r
9769 iconCurrent = iconWhite;
\r
9770 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9771 if (IsIconic(hwndMain)) {
\r
9772 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9775 (void) ReleaseDC(hwndMain, hdc);
\r
9777 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9781 DisplayBlackClock(long timeRemaining, int highlight)
\r
9784 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9786 if(appData.noGUI) return;
\r
9787 hdc = GetDC(hwndMain);
\r
9788 if (!IsIconic(hwndMain)) {
\r
9789 DisplayAClock(hdc, timeRemaining, highlight,
\r
9790 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9792 if (highlight && iconCurrent == iconWhite) {
\r
9793 iconCurrent = iconBlack;
\r
9794 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9795 if (IsIconic(hwndMain)) {
\r
9796 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9799 (void) ReleaseDC(hwndMain, hdc);
\r
9801 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9806 LoadGameTimerRunning()
\r
9808 return loadGameTimerEvent != 0;
\r
9812 StopLoadGameTimer()
\r
9814 if (loadGameTimerEvent == 0) return FALSE;
\r
9815 KillTimer(hwndMain, loadGameTimerEvent);
\r
9816 loadGameTimerEvent = 0;
\r
9821 StartLoadGameTimer(long millisec)
\r
9823 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9824 (UINT) millisec, NULL);
\r
9832 char fileTitle[MSG_SIZ];
\r
9834 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9835 f = OpenFileDialog(hwndMain, "a", defName,
\r
9836 appData.oldSaveStyle ? "gam" : "pgn",
\r
9838 "Save Game to File", NULL, fileTitle, NULL);
\r
9840 SaveGame(f, 0, "");
\r
9847 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9849 if (delayedTimerEvent != 0) {
\r
9850 if (appData.debugMode) {
\r
9851 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9853 KillTimer(hwndMain, delayedTimerEvent);
\r
9854 delayedTimerEvent = 0;
\r
9855 delayedTimerCallback();
\r
9857 delayedTimerCallback = cb;
\r
9858 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9859 (UINT) millisec, NULL);
\r
9862 DelayedEventCallback
\r
9865 if (delayedTimerEvent) {
\r
9866 return delayedTimerCallback;
\r
9873 CancelDelayedEvent()
\r
9875 if (delayedTimerEvent) {
\r
9876 KillTimer(hwndMain, delayedTimerEvent);
\r
9877 delayedTimerEvent = 0;
\r
9881 DWORD GetWin32Priority(int nice)
\r
9882 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9884 REALTIME_PRIORITY_CLASS 0x00000100
\r
9885 HIGH_PRIORITY_CLASS 0x00000080
\r
9886 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9887 NORMAL_PRIORITY_CLASS 0x00000020
\r
9888 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9889 IDLE_PRIORITY_CLASS 0x00000040
\r
9891 if (nice < -15) return 0x00000080;
\r
9892 if (nice < 0) return 0x00008000;
\r
9893 if (nice == 0) return 0x00000020;
\r
9894 if (nice < 15) return 0x00004000;
\r
9895 return 0x00000040;
\r
9898 /* Start a child process running the given program.
\r
9899 The process's standard output can be read from "from", and its
\r
9900 standard input can be written to "to".
\r
9901 Exit with fatal error if anything goes wrong.
\r
9902 Returns an opaque pointer that can be used to destroy the process
\r
9906 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9908 #define BUFSIZE 4096
\r
9910 HANDLE hChildStdinRd, hChildStdinWr,
\r
9911 hChildStdoutRd, hChildStdoutWr;
\r
9912 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9913 SECURITY_ATTRIBUTES saAttr;
\r
9915 PROCESS_INFORMATION piProcInfo;
\r
9916 STARTUPINFO siStartInfo;
\r
9918 char buf[MSG_SIZ];
\r
9921 if (appData.debugMode) {
\r
9922 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9927 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9928 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9929 saAttr.bInheritHandle = TRUE;
\r
9930 saAttr.lpSecurityDescriptor = NULL;
\r
9933 * The steps for redirecting child's STDOUT:
\r
9934 * 1. Create anonymous pipe to be STDOUT for child.
\r
9935 * 2. Create a noninheritable duplicate of read handle,
\r
9936 * and close the inheritable read handle.
\r
9939 /* Create a pipe for the child's STDOUT. */
\r
9940 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9941 return GetLastError();
\r
9944 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9945 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9946 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9947 FALSE, /* not inherited */
\r
9948 DUPLICATE_SAME_ACCESS);
\r
9950 return GetLastError();
\r
9952 CloseHandle(hChildStdoutRd);
\r
9955 * The steps for redirecting child's STDIN:
\r
9956 * 1. Create anonymous pipe to be STDIN for child.
\r
9957 * 2. Create a noninheritable duplicate of write handle,
\r
9958 * and close the inheritable write handle.
\r
9961 /* Create a pipe for the child's STDIN. */
\r
9962 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9963 return GetLastError();
\r
9966 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9967 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9968 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9969 FALSE, /* not inherited */
\r
9970 DUPLICATE_SAME_ACCESS);
\r
9972 return GetLastError();
\r
9974 CloseHandle(hChildStdinWr);
\r
9976 /* Arrange to (1) look in dir for the child .exe file, and
\r
9977 * (2) have dir be the child's working directory. Interpret
\r
9978 * dir relative to the directory WinBoard loaded from. */
\r
9979 GetCurrentDirectory(MSG_SIZ, buf);
\r
9980 SetCurrentDirectory(installDir);
\r
9981 SetCurrentDirectory(dir);
\r
9983 /* Now create the child process. */
\r
9985 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9986 siStartInfo.lpReserved = NULL;
\r
9987 siStartInfo.lpDesktop = NULL;
\r
9988 siStartInfo.lpTitle = NULL;
\r
9989 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9990 siStartInfo.cbReserved2 = 0;
\r
9991 siStartInfo.lpReserved2 = NULL;
\r
9992 siStartInfo.hStdInput = hChildStdinRd;
\r
9993 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9994 siStartInfo.hStdError = hChildStdoutWr;
\r
9996 fSuccess = CreateProcess(NULL,
\r
9997 cmdLine, /* command line */
\r
9998 NULL, /* process security attributes */
\r
9999 NULL, /* primary thread security attrs */
\r
10000 TRUE, /* handles are inherited */
\r
10001 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
10002 NULL, /* use parent's environment */
\r
10004 &siStartInfo, /* STARTUPINFO pointer */
\r
10005 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
10007 err = GetLastError();
\r
10008 SetCurrentDirectory(buf); /* return to prev directory */
\r
10009 if (! fSuccess) {
\r
10013 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10014 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10015 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10018 /* Close the handles we don't need in the parent */
\r
10019 CloseHandle(piProcInfo.hThread);
\r
10020 CloseHandle(hChildStdinRd);
\r
10021 CloseHandle(hChildStdoutWr);
\r
10023 /* Prepare return value */
\r
10024 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10025 cp->kind = CPReal;
\r
10026 cp->hProcess = piProcInfo.hProcess;
\r
10027 cp->pid = piProcInfo.dwProcessId;
\r
10028 cp->hFrom = hChildStdoutRdDup;
\r
10029 cp->hTo = hChildStdinWrDup;
\r
10031 *pr = (void *) cp;
\r
10033 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10034 2000 where engines sometimes don't see the initial command(s)
\r
10035 from WinBoard and hang. I don't understand how that can happen,
\r
10036 but the Sleep is harmless, so I've put it in. Others have also
\r
10037 reported what may be the same problem, so hopefully this will fix
\r
10038 it for them too. */
\r
10046 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10048 ChildProc *cp; int result;
\r
10050 cp = (ChildProc *) pr;
\r
10051 if (cp == NULL) return;
\r
10053 switch (cp->kind) {
\r
10055 /* TerminateProcess is considered harmful, so... */
\r
10056 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10057 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10058 /* The following doesn't work because the chess program
\r
10059 doesn't "have the same console" as WinBoard. Maybe
\r
10060 we could arrange for this even though neither WinBoard
\r
10061 nor the chess program uses a console for stdio? */
\r
10062 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10064 /* [AS] Special termination modes for misbehaving programs... */
\r
10065 if( signal == 9 ) {
\r
10066 result = TerminateProcess( cp->hProcess, 0 );
\r
10068 if ( appData.debugMode) {
\r
10069 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10072 else if( signal == 10 ) {
\r
10073 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10075 if( dw != WAIT_OBJECT_0 ) {
\r
10076 result = TerminateProcess( cp->hProcess, 0 );
\r
10078 if ( appData.debugMode) {
\r
10079 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10085 CloseHandle(cp->hProcess);
\r
10089 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10093 closesocket(cp->sock);
\r
10098 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10099 closesocket(cp->sock);
\r
10100 closesocket(cp->sock2);
\r
10108 InterruptChildProcess(ProcRef pr)
\r
10112 cp = (ChildProc *) pr;
\r
10113 if (cp == NULL) return;
\r
10114 switch (cp->kind) {
\r
10116 /* The following doesn't work because the chess program
\r
10117 doesn't "have the same console" as WinBoard. Maybe
\r
10118 we could arrange for this even though neither WinBoard
\r
10119 nor the chess program uses a console for stdio */
\r
10120 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10125 /* Can't interrupt */
\r
10129 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10136 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10138 char cmdLine[MSG_SIZ];
\r
10140 if (port[0] == NULLCHAR) {
\r
10141 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10143 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10145 return StartChildProcess(cmdLine, "", pr);
\r
10149 /* Code to open TCP sockets */
\r
10152 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10157 struct sockaddr_in sa, mysa;
\r
10158 struct hostent FAR *hp;
\r
10159 unsigned short uport;
\r
10160 WORD wVersionRequested;
\r
10163 /* Initialize socket DLL */
\r
10164 wVersionRequested = MAKEWORD(1, 1);
\r
10165 err = WSAStartup(wVersionRequested, &wsaData);
\r
10166 if (err != 0) return err;
\r
10168 /* Make socket */
\r
10169 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10170 err = WSAGetLastError();
\r
10175 /* Bind local address using (mostly) don't-care values.
\r
10177 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10178 mysa.sin_family = AF_INET;
\r
10179 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10180 uport = (unsigned short) 0;
\r
10181 mysa.sin_port = htons(uport);
\r
10182 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10183 == SOCKET_ERROR) {
\r
10184 err = WSAGetLastError();
\r
10189 /* Resolve remote host name */
\r
10190 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10191 if (!(hp = gethostbyname(host))) {
\r
10192 unsigned int b0, b1, b2, b3;
\r
10194 err = WSAGetLastError();
\r
10196 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10197 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10198 hp->h_addrtype = AF_INET;
\r
10199 hp->h_length = 4;
\r
10200 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10201 hp->h_addr_list[0] = (char *) malloc(4);
\r
10202 hp->h_addr_list[0][0] = (char) b0;
\r
10203 hp->h_addr_list[0][1] = (char) b1;
\r
10204 hp->h_addr_list[0][2] = (char) b2;
\r
10205 hp->h_addr_list[0][3] = (char) b3;
\r
10211 sa.sin_family = hp->h_addrtype;
\r
10212 uport = (unsigned short) atoi(port);
\r
10213 sa.sin_port = htons(uport);
\r
10214 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10216 /* Make connection */
\r
10217 if (connect(s, (struct sockaddr *) &sa,
\r
10218 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10219 err = WSAGetLastError();
\r
10224 /* Prepare return value */
\r
10225 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10226 cp->kind = CPSock;
\r
10228 *pr = (ProcRef *) cp;
\r
10234 OpenCommPort(char *name, ProcRef *pr)
\r
10239 char fullname[MSG_SIZ];
\r
10241 if (*name != '\\')
\r
10242 sprintf(fullname, "\\\\.\\%s", name);
\r
10244 strcpy(fullname, name);
\r
10246 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10247 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10248 if (h == (HANDLE) -1) {
\r
10249 return GetLastError();
\r
10253 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10255 /* Accumulate characters until a 100ms pause, then parse */
\r
10256 ct.ReadIntervalTimeout = 100;
\r
10257 ct.ReadTotalTimeoutMultiplier = 0;
\r
10258 ct.ReadTotalTimeoutConstant = 0;
\r
10259 ct.WriteTotalTimeoutMultiplier = 0;
\r
10260 ct.WriteTotalTimeoutConstant = 0;
\r
10261 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10263 /* Prepare return value */
\r
10264 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10265 cp->kind = CPComm;
\r
10268 *pr = (ProcRef *) cp;
\r
10274 OpenLoopback(ProcRef *pr)
\r
10276 DisplayFatalError("Not implemented", 0, 1);
\r
10282 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10286 SOCKET s, s2, s3;
\r
10287 struct sockaddr_in sa, mysa;
\r
10288 struct hostent FAR *hp;
\r
10289 unsigned short uport;
\r
10290 WORD wVersionRequested;
\r
10293 char stderrPortStr[MSG_SIZ];
\r
10295 /* Initialize socket DLL */
\r
10296 wVersionRequested = MAKEWORD(1, 1);
\r
10297 err = WSAStartup(wVersionRequested, &wsaData);
\r
10298 if (err != 0) return err;
\r
10300 /* Resolve remote host name */
\r
10301 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10302 if (!(hp = gethostbyname(host))) {
\r
10303 unsigned int b0, b1, b2, b3;
\r
10305 err = WSAGetLastError();
\r
10307 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10308 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10309 hp->h_addrtype = AF_INET;
\r
10310 hp->h_length = 4;
\r
10311 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10312 hp->h_addr_list[0] = (char *) malloc(4);
\r
10313 hp->h_addr_list[0][0] = (char) b0;
\r
10314 hp->h_addr_list[0][1] = (char) b1;
\r
10315 hp->h_addr_list[0][2] = (char) b2;
\r
10316 hp->h_addr_list[0][3] = (char) b3;
\r
10322 sa.sin_family = hp->h_addrtype;
\r
10323 uport = (unsigned short) 514;
\r
10324 sa.sin_port = htons(uport);
\r
10325 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10327 /* Bind local socket to unused "privileged" port address
\r
10329 s = INVALID_SOCKET;
\r
10330 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10331 mysa.sin_family = AF_INET;
\r
10332 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10333 for (fromPort = 1023;; fromPort--) {
\r
10334 if (fromPort < 0) {
\r
10336 return WSAEADDRINUSE;
\r
10338 if (s == INVALID_SOCKET) {
\r
10339 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10340 err = WSAGetLastError();
\r
10345 uport = (unsigned short) fromPort;
\r
10346 mysa.sin_port = htons(uport);
\r
10347 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10348 == SOCKET_ERROR) {
\r
10349 err = WSAGetLastError();
\r
10350 if (err == WSAEADDRINUSE) continue;
\r
10354 if (connect(s, (struct sockaddr *) &sa,
\r
10355 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10356 err = WSAGetLastError();
\r
10357 if (err == WSAEADDRINUSE) {
\r
10368 /* Bind stderr local socket to unused "privileged" port address
\r
10370 s2 = INVALID_SOCKET;
\r
10371 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10372 mysa.sin_family = AF_INET;
\r
10373 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10374 for (fromPort = 1023;; fromPort--) {
\r
10375 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10376 if (fromPort < 0) {
\r
10377 (void) closesocket(s);
\r
10379 return WSAEADDRINUSE;
\r
10381 if (s2 == INVALID_SOCKET) {
\r
10382 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10383 err = WSAGetLastError();
\r
10389 uport = (unsigned short) fromPort;
\r
10390 mysa.sin_port = htons(uport);
\r
10391 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10392 == SOCKET_ERROR) {
\r
10393 err = WSAGetLastError();
\r
10394 if (err == WSAEADDRINUSE) continue;
\r
10395 (void) closesocket(s);
\r
10399 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10400 err = WSAGetLastError();
\r
10401 if (err == WSAEADDRINUSE) {
\r
10403 s2 = INVALID_SOCKET;
\r
10406 (void) closesocket(s);
\r
10407 (void) closesocket(s2);
\r
10413 prevStderrPort = fromPort; // remember port used
\r
10414 sprintf(stderrPortStr, "%d", fromPort);
\r
10416 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10417 err = WSAGetLastError();
\r
10418 (void) closesocket(s);
\r
10419 (void) closesocket(s2);
\r
10424 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10425 err = WSAGetLastError();
\r
10426 (void) closesocket(s);
\r
10427 (void) closesocket(s2);
\r
10431 if (*user == NULLCHAR) user = UserName();
\r
10432 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10433 err = WSAGetLastError();
\r
10434 (void) closesocket(s);
\r
10435 (void) closesocket(s2);
\r
10439 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10440 err = WSAGetLastError();
\r
10441 (void) closesocket(s);
\r
10442 (void) closesocket(s2);
\r
10447 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10448 err = WSAGetLastError();
\r
10449 (void) closesocket(s);
\r
10450 (void) closesocket(s2);
\r
10454 (void) closesocket(s2); /* Stop listening */
\r
10456 /* Prepare return value */
\r
10457 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10458 cp->kind = CPRcmd;
\r
10461 *pr = (ProcRef *) cp;
\r
10468 AddInputSource(ProcRef pr, int lineByLine,
\r
10469 InputCallback func, VOIDSTAR closure)
\r
10471 InputSource *is, *is2 = NULL;
\r
10472 ChildProc *cp = (ChildProc *) pr;
\r
10474 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10475 is->lineByLine = lineByLine;
\r
10477 is->closure = closure;
\r
10478 is->second = NULL;
\r
10479 is->next = is->buf;
\r
10480 if (pr == NoProc) {
\r
10481 is->kind = CPReal;
\r
10482 consoleInputSource = is;
\r
10484 is->kind = cp->kind;
\r
10486 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10487 we create all threads suspended so that the is->hThread variable can be
\r
10488 safely assigned, then let the threads start with ResumeThread.
\r
10490 switch (cp->kind) {
\r
10492 is->hFile = cp->hFrom;
\r
10493 cp->hFrom = NULL; /* now owned by InputThread */
\r
10495 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10496 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10500 is->hFile = cp->hFrom;
\r
10501 cp->hFrom = NULL; /* now owned by InputThread */
\r
10503 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10504 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10508 is->sock = cp->sock;
\r
10510 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10511 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10515 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10517 is->sock = cp->sock;
\r
10518 is->second = is2;
\r
10519 is2->sock = cp->sock2;
\r
10520 is2->second = is2;
\r
10522 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10523 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10525 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10526 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10530 if( is->hThread != NULL ) {
\r
10531 ResumeThread( is->hThread );
\r
10534 if( is2 != NULL && is2->hThread != NULL ) {
\r
10535 ResumeThread( is2->hThread );
\r
10539 return (InputSourceRef) is;
\r
10543 RemoveInputSource(InputSourceRef isr)
\r
10547 is = (InputSource *) isr;
\r
10548 is->hThread = NULL; /* tell thread to stop */
\r
10549 CloseHandle(is->hThread);
\r
10550 if (is->second != NULL) {
\r
10551 is->second->hThread = NULL;
\r
10552 CloseHandle(is->second->hThread);
\r
10558 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10561 int outCount = SOCKET_ERROR;
\r
10562 ChildProc *cp = (ChildProc *) pr;
\r
10563 static OVERLAPPED ovl;
\r
10565 if (pr == NoProc) {
\r
10566 ConsoleOutput(message, count, FALSE);
\r
10570 if (ovl.hEvent == NULL) {
\r
10571 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10573 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10575 switch (cp->kind) {
\r
10578 outCount = send(cp->sock, message, count, 0);
\r
10579 if (outCount == SOCKET_ERROR) {
\r
10580 *outError = WSAGetLastError();
\r
10582 *outError = NO_ERROR;
\r
10587 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10588 &dOutCount, NULL)) {
\r
10589 *outError = NO_ERROR;
\r
10590 outCount = (int) dOutCount;
\r
10592 *outError = GetLastError();
\r
10597 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10598 &dOutCount, &ovl);
\r
10599 if (*outError == NO_ERROR) {
\r
10600 outCount = (int) dOutCount;
\r
10608 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10611 /* Ignore delay, not implemented for WinBoard */
\r
10612 return OutputToProcess(pr, message, count, outError);
\r
10617 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10618 char *buf, int count, int error)
\r
10620 DisplayFatalError("Not implemented", 0, 1);
\r
10623 /* see wgamelist.c for Game List functions */
\r
10624 /* see wedittags.c for Edit Tags functions */
\r
10631 char buf[MSG_SIZ];
\r
10634 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10635 f = fopen(buf, "r");
\r
10637 ProcessICSInitScript(f);
\r
10645 StartAnalysisClock()
\r
10647 if (analysisTimerEvent) return;
\r
10648 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10649 (UINT) 2000, NULL);
\r
10653 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10655 static HANDLE hwndText;
\r
10657 static int sizeX, sizeY;
\r
10658 int newSizeX, newSizeY, flags;
\r
10661 switch (message) {
\r
10662 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10663 /* Initialize the dialog items */
\r
10664 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10665 SetWindowText(hDlg, analysisTitle);
\r
10666 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10667 /* Size and position the dialog */
\r
10668 if (!analysisDialog) {
\r
10669 analysisDialog = hDlg;
\r
10670 flags = SWP_NOZORDER;
\r
10671 GetClientRect(hDlg, &rect);
\r
10672 sizeX = rect.right;
\r
10673 sizeY = rect.bottom;
\r
10674 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10675 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10676 WINDOWPLACEMENT wp;
\r
10677 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10678 wp.length = sizeof(WINDOWPLACEMENT);
\r
10680 wp.showCmd = SW_SHOW;
\r
10681 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10682 wp.rcNormalPosition.left = analysisX;
\r
10683 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10684 wp.rcNormalPosition.top = analysisY;
\r
10685 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10686 SetWindowPlacement(hDlg, &wp);
\r
10688 GetClientRect(hDlg, &rect);
\r
10689 newSizeX = rect.right;
\r
10690 newSizeY = rect.bottom;
\r
10691 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10692 newSizeX, newSizeY);
\r
10693 sizeX = newSizeX;
\r
10694 sizeY = newSizeY;
\r
10699 case WM_COMMAND: /* message: received a command */
\r
10700 switch (LOWORD(wParam)) {
\r
10702 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10703 ExitAnalyzeMode();
\r
10715 newSizeX = LOWORD(lParam);
\r
10716 newSizeY = HIWORD(lParam);
\r
10717 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10718 sizeX = newSizeX;
\r
10719 sizeY = newSizeY;
\r
10722 case WM_GETMINMAXINFO:
\r
10723 /* Prevent resizing window too small */
\r
10724 mmi = (MINMAXINFO *) lParam;
\r
10725 mmi->ptMinTrackSize.x = 100;
\r
10726 mmi->ptMinTrackSize.y = 100;
\r
10733 AnalysisPopUp(char* title, char* str)
\r
10739 EngineOutputPopUp();
\r
10742 if (str == NULL) str = "";
\r
10743 p = (char *) malloc(2 * strlen(str) + 2);
\r
10746 if (*str == '\n') *q++ = '\r';
\r
10750 if (analysisText != NULL) free(analysisText);
\r
10751 analysisText = p;
\r
10753 if (analysisDialog) {
\r
10754 SetWindowText(analysisDialog, title);
\r
10755 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10756 ShowWindow(analysisDialog, SW_SHOW);
\r
10758 analysisTitle = title;
\r
10759 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10760 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10761 hwndMain, (DLGPROC)lpProc);
\r
10762 FreeProcInstance(lpProc);
\r
10764 analysisDialogUp = TRUE;
\r
10768 AnalysisPopDown()
\r
10770 if (analysisDialog) {
\r
10771 ShowWindow(analysisDialog, SW_HIDE);
\r
10773 analysisDialogUp = FALSE;
\r
10778 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10780 highlightInfo.sq[0].x = fromX;
\r
10781 highlightInfo.sq[0].y = fromY;
\r
10782 highlightInfo.sq[1].x = toX;
\r
10783 highlightInfo.sq[1].y = toY;
\r
10787 ClearHighlights()
\r
10789 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10790 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10794 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10796 premoveHighlightInfo.sq[0].x = fromX;
\r
10797 premoveHighlightInfo.sq[0].y = fromY;
\r
10798 premoveHighlightInfo.sq[1].x = toX;
\r
10799 premoveHighlightInfo.sq[1].y = toY;
\r
10803 ClearPremoveHighlights()
\r
10805 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10806 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10810 ShutDownFrontEnd()
\r
10812 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10813 DeleteClipboardTempFiles();
\r
10819 if (IsIconic(hwndMain))
\r
10820 ShowWindow(hwndMain, SW_RESTORE);
\r
10822 SetActiveWindow(hwndMain);
\r
10826 * Prototypes for animation support routines
\r
10828 static void ScreenSquare(int column, int row, POINT * pt);
\r
10829 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10830 POINT frames[], int * nFrames);
\r
10834 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10835 { // [HGM] atomic: animate blast wave
\r
10837 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10838 explodeInfo.fromX = fromX;
\r
10839 explodeInfo.fromY = fromY;
\r
10840 explodeInfo.toX = toX;
\r
10841 explodeInfo.toY = toY;
\r
10842 for(i=1; i<nFrames; i++) {
\r
10843 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10844 DrawPosition(FALSE, NULL);
\r
10845 Sleep(appData.animSpeed);
\r
10847 explodeInfo.radius = 0;
\r
10848 DrawPosition(TRUE, NULL);
\r
10851 #define kFactor 4
\r
10854 AnimateMove(board, fromX, fromY, toX, toY)
\r
10861 ChessSquare piece;
\r
10862 POINT start, finish, mid;
\r
10863 POINT frames[kFactor * 2 + 1];
\r
10866 if (!appData.animate) return;
\r
10867 if (doingSizing) return;
\r
10868 if (fromY < 0 || fromX < 0) return;
\r
10869 piece = board[fromY][fromX];
\r
10870 if (piece >= EmptySquare) return;
\r
10872 ScreenSquare(fromX, fromY, &start);
\r
10873 ScreenSquare(toX, toY, &finish);
\r
10875 /* All pieces except knights move in straight line */
\r
10876 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10877 mid.x = start.x + (finish.x - start.x) / 2;
\r
10878 mid.y = start.y + (finish.y - start.y) / 2;
\r
10880 /* Knight: make diagonal movement then straight */
\r
10881 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10882 mid.x = start.x + (finish.x - start.x) / 2;
\r
10883 mid.y = finish.y;
\r
10885 mid.x = finish.x;
\r
10886 mid.y = start.y + (finish.y - start.y) / 2;
\r
10890 /* Don't use as many frames for very short moves */
\r
10891 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10892 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10894 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10896 animInfo.from.x = fromX;
\r
10897 animInfo.from.y = fromY;
\r
10898 animInfo.to.x = toX;
\r
10899 animInfo.to.y = toY;
\r
10900 animInfo.lastpos = start;
\r
10901 animInfo.piece = piece;
\r
10902 for (n = 0; n < nFrames; n++) {
\r
10903 animInfo.pos = frames[n];
\r
10904 DrawPosition(FALSE, NULL);
\r
10905 animInfo.lastpos = animInfo.pos;
\r
10906 Sleep(appData.animSpeed);
\r
10908 animInfo.pos = finish;
\r
10909 DrawPosition(FALSE, NULL);
\r
10910 animInfo.piece = EmptySquare;
\r
10911 if(gameInfo.variant == VariantAtomic &&
\r
10912 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10913 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10916 /* Convert board position to corner of screen rect and color */
\r
10919 ScreenSquare(column, row, pt)
\r
10920 int column; int row; POINT * pt;
\r
10923 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10924 pt->y = lineGap + row * (squareSize + lineGap);
\r
10926 pt->x = lineGap + column * (squareSize + lineGap);
\r
10927 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10931 /* Generate a series of frame coords from start->mid->finish.
\r
10932 The movement rate doubles until the half way point is
\r
10933 reached, then halves back down to the final destination,
\r
10934 which gives a nice slow in/out effect. The algorithmn
\r
10935 may seem to generate too many intermediates for short
\r
10936 moves, but remember that the purpose is to attract the
\r
10937 viewers attention to the piece about to be moved and
\r
10938 then to where it ends up. Too few frames would be less
\r
10942 Tween(start, mid, finish, factor, frames, nFrames)
\r
10943 POINT * start; POINT * mid;
\r
10944 POINT * finish; int factor;
\r
10945 POINT frames[]; int * nFrames;
\r
10947 int n, fraction = 1, count = 0;
\r
10949 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10950 for (n = 0; n < factor; n++)
\r
10952 for (n = 0; n < factor; n++) {
\r
10953 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10954 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10956 fraction = fraction / 2;
\r
10960 frames[count] = *mid;
\r
10963 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10965 for (n = 0; n < factor; n++) {
\r
10966 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10967 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10969 fraction = fraction * 2;
\r
10971 *nFrames = count;
\r
10975 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10980 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10981 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10983 OutputDebugString( buf );
\r
10986 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10988 EvalGraphSet( first, last, current, pvInfoList );
\r
10991 void SetProgramStats( FrontEndProgramStats * stats )
\r
10996 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10997 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10999 OutputDebugString( buf );
\r
11002 EngineOutputUpdate( stats );
\r