2 * WinBoard.c -- Windows NT front end to XBoard
\r
3 * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
\r
5 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
6 * Massachusetts. Enhancements Copyright
\r
7 * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software
\r
10 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
11 * which was written and is copyrighted by Wayne Christopher.
\r
13 * The following terms apply to Digital Equipment Corporation's copyright
\r
14 * interest in XBoard:
\r
15 * ------------------------------------------------------------------------
\r
16 * All Rights Reserved
\r
18 * Permission to use, copy, modify, and distribute this software and its
\r
19 * documentation for any purpose and without fee is hereby granted,
\r
20 * provided that the above copyright notice appear in all copies and that
\r
21 * both that copyright notice and this permission notice appear in
\r
22 * supporting documentation, and that the name of Digital not be
\r
23 * used in advertising or publicity pertaining to distribution of the
\r
24 * software without specific, written prior permission.
\r
26 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
27 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
28 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
29 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
30 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
31 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
33 * ------------------------------------------------------------------------
\r
35 * The following terms apply to the enhanced version of XBoard
\r
36 * distributed by the Free Software Foundation:
\r
37 * ------------------------------------------------------------------------
\r
39 * GNU XBoard is free software: you can redistribute it and/or modify
\r
40 * it under the terms of the GNU General Public License as published by
\r
41 * the Free Software Foundation, either version 3 of the License, or (at
\r
42 * your option) any later version.
\r
44 * GNU XBoard is distributed in the hope that it will be useful, but
\r
45 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
46 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
47 * General Public License for more details.
\r
49 * You should have received a copy of the GNU General Public License
\r
50 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
52 *------------------------------------------------------------------------
\r
53 ** See the file ChangeLog for a revision history. */
\r
57 #include <windows.h>
\r
58 #include <winuser.h>
\r
59 #include <winsock.h>
\r
60 #include <commctrl.h>
\r
66 #include <sys/stat.h>
\r
69 #include <commdlg.h>
\r
71 #include <richedit.h>
\r
72 #include <mmsystem.h>
\r
81 #include "winboard.h"
\r
82 #include "frontend.h"
\r
83 #include "backend.h"
\r
85 #include "wclipbrd.h"
\r
86 #include "wgamelist.h"
\r
87 #include "wedittags.h"
\r
88 #include "woptions.h"
\r
89 #include "wsockerr.h"
\r
90 #include "defaults.h"
\r
94 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
97 void mysrandom(unsigned int seed);
\r
99 extern int whiteFlag, blackFlag;
\r
100 Boolean flipClock = FALSE;
\r
102 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
103 VOID NewVariantPopup(HWND hwnd);
\r
104 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
105 /*char*/int promoChar));
\r
106 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
107 void DisplayMove P((int moveNumber));
\r
108 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
109 HWND WINAPI HtmlHelp( HWND hwnd, LPCSTR helpFile, UINT action, DWORD_PTR data );
\r
112 ChessSquare piece;
\r
113 POINT pos; /* window coordinates of current pos */
\r
114 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
115 POINT from; /* board coordinates of the piece's orig pos */
\r
116 POINT to; /* board coordinates of the piece's new pos */
\r
119 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
122 POINT start; /* window coordinates of start pos */
\r
123 POINT pos; /* window coordinates of current pos */
\r
124 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
125 POINT from; /* board coordinates of the piece's orig pos */
\r
128 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
131 POINT sq[2]; /* board coordinates of from, to squares */
\r
134 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
135 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
137 typedef struct { // [HGM] atomic
\r
138 int fromX, fromY, toX, toY, radius;
\r
141 static ExplodeInfo explodeInfo;
\r
143 /* Window class names */
\r
144 char szAppName[] = "WinBoard";
\r
145 char szConsoleName[] = "WBConsole";
\r
147 /* Title bar text */
\r
148 char szTitle[] = "WinBoard";
\r
149 char szConsoleTitle[] = "I C S Interaction";
\r
152 char *settingsFileName;
\r
153 BOOLEAN saveSettingsOnExit;
\r
154 char installDir[MSG_SIZ];
\r
156 BoardSize boardSize;
\r
157 BOOLEAN chessProgram;
\r
158 static int boardX, boardY;
\r
159 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
160 static int squareSize, lineGap, minorSize;
\r
161 static int winWidth, winHeight, winW, winH;
\r
162 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
163 static int logoHeight = 0;
\r
164 static char messageText[MESSAGE_TEXT_MAX];
\r
165 static int clockTimerEvent = 0;
\r
166 static int loadGameTimerEvent = 0;
\r
167 static int analysisTimerEvent = 0;
\r
168 static DelayedEventCallback delayedTimerCallback;
\r
169 static int delayedTimerEvent = 0;
\r
170 static int buttonCount = 2;
\r
171 char *icsTextMenuString;
\r
173 char *firstChessProgramNames;
\r
174 char *secondChessProgramNames;
\r
176 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
178 #define PALETTESIZE 256
\r
180 HINSTANCE hInst; /* current instance */
\r
181 HWND hwndMain = NULL; /* root window*/
\r
182 HWND hwndConsole = NULL;
\r
183 BOOLEAN alwaysOnTop = FALSE;
\r
185 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
186 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
188 ColorClass currentColorClass;
\r
190 HWND hCommPort = NULL; /* currently open comm port */
\r
191 static HWND hwndPause; /* pause button */
\r
192 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
193 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
194 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
195 explodeBrush, /* [HGM] atomic */
\r
196 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
197 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
198 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
199 static HPEN gridPen = NULL;
\r
200 static HPEN highlightPen = NULL;
\r
201 static HPEN premovePen = NULL;
\r
202 static NPLOGPALETTE pLogPal;
\r
203 static BOOL paletteChanged = FALSE;
\r
204 static HICON iconWhite, iconBlack, iconCurrent;
\r
205 static int doingSizing = FALSE;
\r
206 static int lastSizing = 0;
\r
207 static int prevStderrPort;
\r
208 static HBITMAP userLogo;
\r
210 /* [AS] Support for background textures */
\r
211 #define BACK_TEXTURE_MODE_DISABLED 0
\r
212 #define BACK_TEXTURE_MODE_PLAIN 1
\r
213 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
215 static HBITMAP liteBackTexture = NULL;
\r
216 static HBITMAP darkBackTexture = NULL;
\r
217 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
218 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
219 static int backTextureSquareSize = 0;
\r
220 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
222 #if __GNUC__ && !defined(_winmajor)
\r
223 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
225 #define oldDialog (_winmajor < 4)
\r
228 char *defaultTextAttribs[] =
\r
230 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
231 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
241 int cliWidth, cliHeight;
\r
244 SizeInfo sizeInfo[] =
\r
246 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
247 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
248 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
249 { "petite", 33, 1, 1, 1, 0, 0 },
\r
250 { "slim", 37, 2, 1, 0, 0, 0 },
\r
251 { "small", 40, 2, 1, 0, 0, 0 },
\r
252 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
253 { "middling", 49, 2, 0, 0, 0, 0 },
\r
254 { "average", 54, 2, 0, 0, 0, 0 },
\r
255 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
256 { "medium", 64, 3, 0, 0, 0, 0 },
\r
257 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
258 { "large", 80, 3, 0, 0, 0, 0 },
\r
259 { "big", 87, 3, 0, 0, 0, 0 },
\r
260 { "huge", 95, 3, 0, 0, 0, 0 },
\r
261 { "giant", 108, 3, 0, 0, 0, 0 },
\r
262 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
263 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
264 { NULL, 0, 0, 0, 0, 0, 0 }
\r
267 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
268 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
270 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
271 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
272 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
273 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
274 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
275 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
276 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
277 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
278 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
279 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
280 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
281 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
282 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
283 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
284 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
285 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
286 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
287 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
290 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
299 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
300 #define N_BUTTONS 5
\r
302 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
304 {"<<", IDM_ToStart, NULL, NULL},
\r
305 {"<", IDM_Backward, NULL, NULL},
\r
306 {"P", IDM_Pause, NULL, NULL},
\r
307 {">", IDM_Forward, NULL, NULL},
\r
308 {">>", IDM_ToEnd, NULL, NULL},
\r
311 int tinyLayout = 0, smallLayout = 0;
\r
312 #define MENU_BAR_ITEMS 6
\r
313 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
314 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
315 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
319 MySound sounds[(int)NSoundClasses];
\r
320 MyTextAttribs textAttribs[(int)NColorClasses];
\r
322 MyColorizeAttribs colorizeAttribs[] = {
\r
323 { (COLORREF)0, 0, "Shout Text" },
\r
324 { (COLORREF)0, 0, "SShout/CShout" },
\r
325 { (COLORREF)0, 0, "Channel 1 Text" },
\r
326 { (COLORREF)0, 0, "Channel Text" },
\r
327 { (COLORREF)0, 0, "Kibitz Text" },
\r
328 { (COLORREF)0, 0, "Tell Text" },
\r
329 { (COLORREF)0, 0, "Challenge Text" },
\r
330 { (COLORREF)0, 0, "Request Text" },
\r
331 { (COLORREF)0, 0, "Seek Text" },
\r
332 { (COLORREF)0, 0, "Normal Text" },
\r
333 { (COLORREF)0, 0, "None" }
\r
338 static char *commentTitle;
\r
339 static char *commentText;
\r
340 static int commentIndex;
\r
341 static Boolean editComment = FALSE;
\r
342 HWND commentDialog = NULL;
\r
343 BOOLEAN commentDialogUp = FALSE;
\r
344 static int commentX, commentY, commentH, commentW;
\r
346 static char *analysisTitle;
\r
347 static char *analysisText;
\r
348 HWND analysisDialog = NULL;
\r
349 BOOLEAN analysisDialogUp = FALSE;
\r
350 static int analysisX, analysisY, analysisH, analysisW;
\r
352 char errorTitle[MSG_SIZ];
\r
353 char errorMessage[2*MSG_SIZ];
\r
354 HWND errorDialog = NULL;
\r
355 BOOLEAN moveErrorMessageUp = FALSE;
\r
356 BOOLEAN consoleEcho = TRUE;
\r
357 CHARFORMAT consoleCF;
\r
358 COLORREF consoleBackgroundColor;
\r
360 char *programVersion;
\r
366 typedef int CPKind;
\r
375 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
378 #define INPUT_SOURCE_BUF_SIZE 4096
\r
380 typedef struct _InputSource {
\r
387 char buf[INPUT_SOURCE_BUF_SIZE];
\r
391 InputCallback func;
\r
392 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
396 InputSource *consoleInputSource;
\r
401 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
402 VOID ConsoleCreate();
\r
404 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
405 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
406 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
407 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
409 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
410 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
411 void ParseIcsTextMenu(char *icsTextMenuString);
\r
412 VOID PopUpMoveDialog(char firstchar);
\r
413 VOID PopUpNameDialog(char firstchar);
\r
414 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
418 int GameListOptions();
\r
420 HWND moveHistoryDialog = NULL;
\r
421 BOOLEAN moveHistoryDialogUp = FALSE;
\r
423 WindowPlacement wpMoveHistory;
\r
425 HWND evalGraphDialog = NULL;
\r
426 BOOLEAN evalGraphDialogUp = FALSE;
\r
428 WindowPlacement wpEvalGraph;
\r
430 HWND engineOutputDialog = NULL;
\r
431 BOOLEAN engineOutputDialogUp = FALSE;
\r
433 WindowPlacement wpEngineOutput;
\r
434 WindowPlacement wpGameList;
\r
435 WindowPlacement wpConsole;
\r
437 VOID MoveHistoryPopUp();
\r
438 VOID MoveHistoryPopDown();
\r
439 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
440 BOOL MoveHistoryIsUp();
\r
442 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
443 VOID EvalGraphPopUp();
\r
444 VOID EvalGraphPopDown();
\r
445 BOOL EvalGraphIsUp();
\r
447 VOID EngineOutputPopUp();
\r
448 VOID EngineOutputPopDown();
\r
449 BOOL EngineOutputIsUp();
\r
450 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
452 VOID GothicPopUp(char *title, VariantClass variant);
\r
454 * Setting "frozen" should disable all user input other than deleting
\r
455 * the window. We do this while engines are initializing themselves.
\r
457 static int frozen = 0;
\r
458 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
464 if (frozen) return;
\r
466 hmenu = GetMenu(hwndMain);
\r
467 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
468 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
470 DrawMenuBar(hwndMain);
\r
473 /* Undo a FreezeUI */
\r
479 if (!frozen) return;
\r
481 hmenu = GetMenu(hwndMain);
\r
482 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
483 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
485 DrawMenuBar(hwndMain);
\r
488 static int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
490 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
495 #define JAWS_ALT_INTERCEPT
\r
496 #define JAWS_KB_NAVIGATION
\r
497 #define JAWS_MENU_ITEMS
\r
498 #define JAWS_SILENCE
\r
499 #define JAWS_REPLAY
\r
500 #define JAWS_DELETE(X) X
\r
501 #define SAYMACHINEMOVE()
\r
505 /*---------------------------------------------------------------------------*\
\r
509 \*---------------------------------------------------------------------------*/
\r
512 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
513 LPSTR lpCmdLine, int nCmdShow)
\r
516 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
517 // INITCOMMONCONTROLSEX ex;
\r
521 LoadLibrary("RICHED32.DLL");
\r
522 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
524 if (!InitApplication(hInstance)) {
\r
527 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
533 // InitCommonControlsEx(&ex);
\r
534 InitCommonControls();
\r
536 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
537 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
538 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
540 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
542 while (GetMessage(&msg, /* message structure */
\r
543 NULL, /* handle of window receiving the message */
\r
544 0, /* lowest message to examine */
\r
545 0)) /* highest message to examine */
\r
548 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
549 // [HGM] navigate: switch between all windows with tab
\r
550 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
551 int i, currentElement = 0;
\r
553 // first determine what element of the chain we come from (if any)
\r
554 if(appData.icsActive) {
\r
555 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
556 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
558 if(engineOutputDialog && EngineOutputIsUp()) {
\r
559 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
560 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
562 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
563 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
565 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
566 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
567 if(msg.hwnd == e1) currentElement = 2; else
\r
568 if(msg.hwnd == e2) currentElement = 3; else
\r
569 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
570 if(msg.hwnd == mh) currentElement = 4; else
\r
571 if(msg.hwnd == evalGraphDialog) currentElement = 7; else
\r
572 if(msg.hwnd == hText) currentElement = 5; else
\r
573 if(msg.hwnd == hInput) currentElement = 6; else
\r
574 for (i = 0; i < N_BUTTONS; i++) {
\r
575 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
578 // determine where to go to
\r
579 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
581 currentElement = (currentElement + direction) % 7;
\r
582 switch(currentElement) {
\r
584 h = hwndMain; break; // passing this case always makes the loop exit
\r
586 h = buttonDesc[0].hwnd; break; // could be NULL
\r
588 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
591 if(!EngineOutputIsUp()) continue;
\r
594 if(!MoveHistoryIsUp()) continue;
\r
596 // case 5: // input to eval graph does not seem to get here!
\r
597 // if(!EvalGraphIsUp()) continue;
\r
598 // h = evalGraphDialog; break;
\r
600 if(!appData.icsActive) continue;
\r
604 if(!appData.icsActive) continue;
\r
610 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
611 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
614 continue; // this message now has been processed
\r
618 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
619 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
620 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
621 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
622 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
623 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
624 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
625 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
626 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
627 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
628 TranslateMessage(&msg); /* Translates virtual key codes */
\r
629 DispatchMessage(&msg); /* Dispatches message to window */
\r
634 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
637 /*---------------------------------------------------------------------------*\
\r
639 * Initialization functions
\r
641 \*---------------------------------------------------------------------------*/
\r
645 { // update user logo if necessary
\r
646 static char oldUserName[MSG_SIZ], *curName;
\r
648 if(appData.autoLogo) {
\r
649 curName = UserName();
\r
650 if(strcmp(curName, oldUserName)) {
\r
651 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
652 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
653 strcpy(oldUserName, curName);
\r
659 InitApplication(HINSTANCE hInstance)
\r
663 /* Fill in window class structure with parameters that describe the */
\r
666 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
667 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
668 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
669 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
670 wc.hInstance = hInstance; /* Owner of this class */
\r
671 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
672 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
673 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
674 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
675 wc.lpszClassName = szAppName; /* Name to register as */
\r
677 /* Register the window class and return success/failure code. */
\r
678 if (!RegisterClass(&wc)) return FALSE;
\r
680 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
681 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
683 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
684 wc.hInstance = hInstance;
\r
685 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
686 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
687 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
688 wc.lpszMenuName = NULL;
\r
689 wc.lpszClassName = szConsoleName;
\r
691 if (!RegisterClass(&wc)) return FALSE;
\r
696 /* Set by InitInstance, used by EnsureOnScreen */
\r
697 int screenHeight, screenWidth;
\r
700 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
702 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
703 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
704 if (*x > screenWidth - 32) *x = 0;
\r
705 if (*y > screenHeight - 32) *y = 0;
\r
706 if (*x < minX) *x = minX;
\r
707 if (*y < minY) *y = minY;
\r
711 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
713 HWND hwnd; /* Main window handle. */
\r
715 WINDOWPLACEMENT wp;
\r
718 hInst = hInstance; /* Store instance handle in our global variable */
\r
720 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
721 *filepart = NULLCHAR;
\r
723 GetCurrentDirectory(MSG_SIZ, installDir);
\r
725 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
726 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
727 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
728 if (appData.debugMode) {
\r
729 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
730 setbuf(debugFP, NULL);
\r
735 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
736 // InitEngineUCI( installDir, &second );
\r
738 /* Create a main window for this application instance. */
\r
739 hwnd = CreateWindow(szAppName, szTitle,
\r
740 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
741 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
742 NULL, NULL, hInstance, NULL);
\r
745 /* If window could not be created, return "failure" */
\r
750 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
751 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
752 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
754 if (first.programLogo == NULL && appData.debugMode) {
\r
755 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
757 } else if(appData.autoLogo) {
\r
758 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
760 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
761 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
765 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
766 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
768 if (second.programLogo == NULL && appData.debugMode) {
\r
769 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
771 } else if(appData.autoLogo) {
\r
773 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
774 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
775 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
777 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
778 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
779 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
785 iconWhite = LoadIcon(hInstance, "icon_white");
\r
786 iconBlack = LoadIcon(hInstance, "icon_black");
\r
787 iconCurrent = iconWhite;
\r
788 InitDrawingColors();
\r
789 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
790 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
791 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
792 /* Compute window size for each board size, and use the largest
\r
793 size that fits on this screen as the default. */
\r
794 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
795 if (boardSize == (BoardSize)-1 &&
\r
796 winH <= screenHeight
\r
797 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
798 && winW <= screenWidth) {
\r
799 boardSize = (BoardSize)ibs;
\r
803 InitDrawingSizes(boardSize, 0);
\r
805 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
807 /* [AS] Load textures if specified */
\r
808 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
810 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
811 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
812 liteBackTextureMode = appData.liteBackTextureMode;
\r
814 if (liteBackTexture == NULL && appData.debugMode) {
\r
815 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
819 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
820 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
821 darkBackTextureMode = appData.darkBackTextureMode;
\r
823 if (darkBackTexture == NULL && appData.debugMode) {
\r
824 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
828 mysrandom( (unsigned) time(NULL) );
\r
830 /* [AS] Restore layout */
\r
831 if( wpMoveHistory.visible ) {
\r
832 MoveHistoryPopUp();
\r
835 if( wpEvalGraph.visible ) {
\r
839 if( wpEngineOutput.visible ) {
\r
840 EngineOutputPopUp();
\r
845 /* Make the window visible; update its client area; and return "success" */
\r
846 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
847 wp.length = sizeof(WINDOWPLACEMENT);
\r
849 wp.showCmd = nCmdShow;
\r
850 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
851 wp.rcNormalPosition.left = boardX;
\r
852 wp.rcNormalPosition.right = boardX + winWidth;
\r
853 wp.rcNormalPosition.top = boardY;
\r
854 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
855 SetWindowPlacement(hwndMain, &wp);
\r
857 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
858 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
862 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
863 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
865 ShowWindow(hwndConsole, nCmdShow);
\r
867 UpdateWindow(hwnd);
\r
875 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
876 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
877 ArgSettingsFilename,
\r
878 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
886 String *pString; // ArgString
\r
887 int *pInt; // ArgInt
\r
888 float *pFloat; // ArgFloat
\r
889 Boolean *pBoolean; // ArgBoolean
\r
890 COLORREF *pColor; // ArgColor
\r
891 ColorClass cc; // ArgAttribs
\r
892 String *pFilename; // ArgFilename
\r
893 BoardSize *pBoardSize; // ArgBoardSize
\r
894 int whichFont; // ArgFont
\r
895 DCB *pDCB; // ArgCommSettings
\r
896 String *pFilename; // ArgSettingsFilename
\r
904 ArgDescriptor argDescriptors[] = {
\r
905 /* positional arguments */
\r
906 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
907 { "", ArgNone, NULL },
\r
908 /* keyword arguments */
\r
909 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
910 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
911 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
912 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
913 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
914 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
915 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
916 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
917 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
918 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
919 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
920 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
921 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
922 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
923 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
924 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
925 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
926 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
928 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
930 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
932 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
933 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
935 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
936 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
937 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
938 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
939 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
940 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
941 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
942 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
943 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
944 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
945 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
946 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
947 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
948 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
949 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
950 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
951 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
952 /*!!bitmapDirectory?*/
\r
953 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
954 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
955 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
956 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
957 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
958 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
959 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
960 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
961 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
962 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
963 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
964 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
965 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
966 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
967 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
968 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
969 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
970 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
971 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
972 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
973 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
974 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
975 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
976 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
977 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
978 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
979 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
980 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
981 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
982 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
983 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
984 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
985 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
986 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
987 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
988 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
989 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
990 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
991 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
992 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
993 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
994 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
995 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
996 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
997 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
998 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
999 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1000 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1001 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1002 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1003 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1004 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1005 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1006 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1007 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1008 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1009 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1010 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1011 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1012 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1013 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1014 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1015 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1016 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1017 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1018 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1019 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1020 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1021 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1022 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1023 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1024 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1025 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1026 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1027 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1028 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1029 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1030 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1031 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1032 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1033 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1034 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1035 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1036 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1037 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1038 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1039 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1040 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1041 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1042 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1043 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1044 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1045 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1046 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1047 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1048 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1049 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1050 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1051 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1052 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1053 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1054 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1055 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1056 TRUE }, /* must come after all fonts */
\r
1057 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1058 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1059 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1060 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1061 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1062 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1063 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1064 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1065 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1066 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1067 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1068 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1069 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1070 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1071 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1072 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1073 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1074 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1075 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1076 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1077 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1078 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1079 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1080 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1081 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1082 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1083 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1084 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1085 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1086 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1087 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1089 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1090 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1092 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1093 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1094 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1095 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1096 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1097 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1098 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1099 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1100 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1101 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1102 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1103 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1104 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1105 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1106 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1107 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1108 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1109 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1110 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1111 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1112 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1113 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1114 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1115 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1116 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1117 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1118 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1119 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1120 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1121 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1122 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1123 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1124 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1125 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1126 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1127 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1128 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1129 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1130 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1131 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1132 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1133 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1134 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1135 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1136 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1137 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1138 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1139 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1140 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1141 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1142 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1143 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1144 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1145 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1146 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1147 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1148 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1149 { "highlightLastMove", ArgBoolean,
\r
1150 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1151 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1152 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1153 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1154 { "highlightDragging", ArgBoolean,
\r
1155 (LPVOID) &appData.highlightDragging, TRUE },
\r
1156 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1157 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1158 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1159 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1160 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1161 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1162 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1163 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1164 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1165 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1166 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1167 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1168 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1169 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1170 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1171 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1172 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1173 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1174 { "soundShout", ArgFilename,
\r
1175 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1176 { "soundSShout", ArgFilename,
\r
1177 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1178 { "soundChannel1", ArgFilename,
\r
1179 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1180 { "soundChannel", ArgFilename,
\r
1181 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1182 { "soundKibitz", ArgFilename,
\r
1183 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1184 { "soundTell", ArgFilename,
\r
1185 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1186 { "soundChallenge", ArgFilename,
\r
1187 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1188 { "soundRequest", ArgFilename,
\r
1189 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1190 { "soundSeek", ArgFilename,
\r
1191 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1192 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1193 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1194 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1195 { "soundIcsLoss", ArgFilename,
\r
1196 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1197 { "soundIcsDraw", ArgFilename,
\r
1198 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1199 { "soundIcsUnfinished", ArgFilename,
\r
1200 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1201 { "soundIcsAlarm", ArgFilename,
\r
1202 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1203 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1204 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1205 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1206 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1207 { "reuseChessPrograms", ArgBoolean,
\r
1208 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1209 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1210 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1211 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1212 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1213 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1214 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1215 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1216 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1217 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1218 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1219 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1220 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1221 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1222 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1223 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1225 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1227 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1228 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1229 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1230 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1231 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1232 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1233 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1234 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1235 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1236 /* [AS] New features */
\r
1237 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1238 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1239 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1240 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1241 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1242 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1243 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1244 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1245 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1246 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1247 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1248 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1249 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1250 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1251 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1252 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1253 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1254 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1255 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1256 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1257 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1258 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1259 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1260 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1261 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1262 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1263 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1264 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1265 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1266 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1267 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1268 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1269 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1270 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1271 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1272 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1273 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1274 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1275 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1276 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1277 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1278 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1279 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1280 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1281 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1282 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1283 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1284 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1285 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1286 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1288 /* [HGM] board-size, adjudication and misc. options */
\r
1289 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1290 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1291 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1292 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1293 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1294 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1295 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1296 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1297 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1298 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1299 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1300 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1301 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1302 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1303 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1304 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1305 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1306 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1307 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1308 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1309 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1310 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1311 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1312 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1313 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1314 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1315 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1316 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1317 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1318 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1319 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1322 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1323 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1324 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1325 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1326 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1327 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1328 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1329 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1330 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1331 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1332 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1333 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1334 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1336 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1337 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1338 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1339 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1340 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1341 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1342 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1344 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1345 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1346 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1347 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1348 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1349 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1350 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1351 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1352 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1353 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1354 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1355 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1356 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1357 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1358 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1359 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1360 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1361 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1362 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1364 /* [HGM] options for broadcasting and time odds */
\r
1365 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1366 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1367 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1368 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1369 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1370 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1371 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1372 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1373 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1374 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1375 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1377 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1378 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1379 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1380 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1381 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1382 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1383 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1384 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1385 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1386 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1387 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1388 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1389 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1390 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1391 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1392 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1393 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1394 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1395 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1396 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1397 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1398 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1399 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1400 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1401 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1402 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1403 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1404 /* [AS] Layout stuff */
\r
1405 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1406 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1407 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1408 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1409 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1411 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1412 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1413 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1414 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1415 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1417 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1418 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1419 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1420 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1421 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1423 { NULL, ArgNone, NULL, FALSE }
\r
1427 /* Kludge for indirection files on command line */
\r
1428 char* lastIndirectionFilename;
\r
1429 ArgDescriptor argDescriptorIndirection =
\r
1430 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1434 ExitArgError(char *msg, char *badArg)
\r
1436 char buf[MSG_SIZ];
\r
1438 sprintf(buf, "%s %s", msg, badArg);
\r
1439 DisplayFatalError(buf, 0, 2);
\r
1443 /* Command line font name parser. NULL name means do nothing.
\r
1444 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1445 For backward compatibility, syntax without the colon is also
\r
1446 accepted, but font names with digits in them won't work in that case.
\r
1449 ParseFontName(char *name, MyFontParams *mfp)
\r
1452 if (name == NULL) return;
\r
1454 q = strchr(p, ':');
\r
1456 if (q - p >= sizeof(mfp->faceName))
\r
1457 ExitArgError("Font name too long:", name);
\r
1458 memcpy(mfp->faceName, p, q - p);
\r
1459 mfp->faceName[q - p] = NULLCHAR;
\r
1462 q = mfp->faceName;
\r
1463 while (*p && !isdigit(*p)) {
\r
1465 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1466 ExitArgError("Font name too long:", name);
\r
1468 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1471 if (!*p) ExitArgError("Font point size missing:", name);
\r
1472 mfp->pointSize = (float) atof(p);
\r
1473 mfp->bold = (strchr(p, 'b') != NULL);
\r
1474 mfp->italic = (strchr(p, 'i') != NULL);
\r
1475 mfp->underline = (strchr(p, 'u') != NULL);
\r
1476 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1479 /* Color name parser.
\r
1480 X version accepts X color names, but this one
\r
1481 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1483 ParseColorName(char *name)
\r
1485 int red, green, blue, count;
\r
1486 char buf[MSG_SIZ];
\r
1488 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1490 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1491 &red, &green, &blue);
\r
1494 sprintf(buf, "Can't parse color name %s", name);
\r
1495 DisplayError(buf, 0);
\r
1496 return RGB(0, 0, 0);
\r
1498 return PALETTERGB(red, green, blue);
\r
1502 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1504 char *e = argValue;
\r
1508 if (*e == 'b') eff |= CFE_BOLD;
\r
1509 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1510 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1511 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1512 else if (*e == '#' || isdigit(*e)) break;
\r
1516 *color = ParseColorName(e);
\r
1521 ParseBoardSize(char *name)
\r
1523 BoardSize bs = SizeTiny;
\r
1524 while (sizeInfo[bs].name != NULL) {
\r
1525 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1528 ExitArgError("Unrecognized board size value", name);
\r
1529 return bs; /* not reached */
\r
1534 StringGet(void *getClosure)
\r
1536 char **p = (char **) getClosure;
\r
1541 FileGet(void *getClosure)
\r
1544 FILE* f = (FILE*) getClosure;
\r
1547 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1554 /* Parse settings file named "name". If file found, return the
\r
1555 full name in fullname and return TRUE; else return FALSE */
\r
1557 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1561 int ok; char buf[MSG_SIZ];
\r
1563 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1564 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1565 sprintf(buf, "%s.ini", name);
\r
1566 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1569 f = fopen(fullname, "r");
\r
1571 ParseArgs(FileGet, f);
\r
1580 ParseArgs(GetFunc get, void *cl)
\r
1582 char argName[ARG_MAX];
\r
1583 char argValue[ARG_MAX];
\r
1584 ArgDescriptor *ad;
\r
1593 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1594 if (ch == NULLCHAR) break;
\r
1596 /* Comment to end of line */
\r
1598 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1600 } else if (ch == '/' || ch == '-') {
\r
1603 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1604 ch != '\n' && ch != '\t') {
\r
1610 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1611 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1613 if (ad->argName == NULL)
\r
1614 ExitArgError("Unrecognized argument", argName);
\r
1616 } else if (ch == '@') {
\r
1617 /* Indirection file */
\r
1618 ad = &argDescriptorIndirection;
\r
1621 /* Positional argument */
\r
1622 ad = &argDescriptors[posarg++];
\r
1623 strcpy(argName, ad->argName);
\r
1626 if (ad->argType == ArgTrue) {
\r
1627 *(Boolean *) ad->argLoc = TRUE;
\r
1630 if (ad->argType == ArgFalse) {
\r
1631 *(Boolean *) ad->argLoc = FALSE;
\r
1635 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1636 if (ch == NULLCHAR || ch == '\n') {
\r
1637 ExitArgError("No value provided for argument", argName);
\r
1641 // Quoting with { }. No characters have to (or can) be escaped.
\r
1642 // Thus the string cannot contain a '}' character.
\r
1662 } else if (ch == '\'' || ch == '"') {
\r
1663 // Quoting with ' ' or " ", with \ as escape character.
\r
1664 // Inconvenient for long strings that may contain Windows filenames.
\r
1681 if (ch == start) {
\r
1690 if (ad->argType == ArgFilename
\r
1691 || ad->argType == ArgSettingsFilename) {
\r
1697 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1721 for (i = 0; i < 3; i++) {
\r
1722 if (ch >= '0' && ch <= '7') {
\r
1723 octval = octval*8 + (ch - '0');
\r
1730 *q++ = (char) octval;
\r
1741 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1748 switch (ad->argType) {
\r
1750 *(int *) ad->argLoc = atoi(argValue);
\r
1754 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1758 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1762 *(int *) ad->argLoc = atoi(argValue);
\r
1763 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1767 *(float *) ad->argLoc = (float) atof(argValue);
\r
1772 *(char **) ad->argLoc = strdup(argValue);
\r
1775 case ArgSettingsFilename:
\r
1777 char fullname[MSG_SIZ];
\r
1778 if (ParseSettingsFile(argValue, fullname)) {
\r
1779 if (ad->argLoc != NULL) {
\r
1780 *(char **) ad->argLoc = strdup(fullname);
\r
1783 if (ad->argLoc != NULL) {
\r
1785 ExitArgError("Failed to open indirection file", argValue);
\r
1792 switch (argValue[0]) {
\r
1795 *(Boolean *) ad->argLoc = TRUE;
\r
1799 *(Boolean *) ad->argLoc = FALSE;
\r
1802 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1808 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1811 case ArgAttribs: {
\r
1812 ColorClass cc = (ColorClass)ad->argLoc;
\r
1813 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1817 case ArgBoardSize:
\r
1818 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1822 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1825 case ArgCommSettings:
\r
1826 ParseCommSettings(argValue, &dcb);
\r
1830 ExitArgError("Unrecognized argument", argValue);
\r
1839 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1841 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1842 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1845 lf->lfEscapement = 0;
\r
1846 lf->lfOrientation = 0;
\r
1847 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1848 lf->lfItalic = mfp->italic;
\r
1849 lf->lfUnderline = mfp->underline;
\r
1850 lf->lfStrikeOut = mfp->strikeout;
\r
1851 lf->lfCharSet = DEFAULT_CHARSET;
\r
1852 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1853 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1854 lf->lfQuality = DEFAULT_QUALITY;
\r
1855 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1856 strcpy(lf->lfFaceName, mfp->faceName);
\r
1860 CreateFontInMF(MyFont *mf)
\r
1862 LFfromMFP(&mf->lf, &mf->mfp);
\r
1863 if (mf->hf) DeleteObject(mf->hf);
\r
1864 mf->hf = CreateFontIndirect(&mf->lf);
\r
1868 SetDefaultTextAttribs()
\r
1871 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1872 ParseAttribs(&textAttribs[cc].color,
\r
1873 &textAttribs[cc].effects,
\r
1874 defaultTextAttribs[cc]);
\r
1879 SetDefaultSounds()
\r
1883 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1884 textAttribs[cc].sound.name = strdup("");
\r
1885 textAttribs[cc].sound.data = NULL;
\r
1887 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1888 sounds[sc].name = strdup("");
\r
1889 sounds[sc].data = NULL;
\r
1891 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1899 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1900 MyLoadSound(&textAttribs[cc].sound);
\r
1902 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1903 MyLoadSound(&sounds[sc]);
\r
1908 InitAppData(LPSTR lpCmdLine)
\r
1911 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1914 programName = szAppName;
\r
1916 /* Initialize to defaults */
\r
1917 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1918 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1919 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1920 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1921 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1922 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1923 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1924 SetDefaultTextAttribs();
\r
1925 SetDefaultSounds();
\r
1926 appData.movesPerSession = MOVES_PER_SESSION;
\r
1927 appData.initString = INIT_STRING;
\r
1928 appData.secondInitString = INIT_STRING;
\r
1929 appData.firstComputerString = COMPUTER_STRING;
\r
1930 appData.secondComputerString = COMPUTER_STRING;
\r
1931 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1932 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1933 appData.firstPlaysBlack = FALSE;
\r
1934 appData.noChessProgram = FALSE;
\r
1935 chessProgram = FALSE;
\r
1936 appData.firstHost = FIRST_HOST;
\r
1937 appData.secondHost = SECOND_HOST;
\r
1938 appData.firstDirectory = FIRST_DIRECTORY;
\r
1939 appData.secondDirectory = SECOND_DIRECTORY;
\r
1940 appData.bitmapDirectory = "";
\r
1941 appData.remoteShell = REMOTE_SHELL;
\r
1942 appData.remoteUser = "";
\r
1943 appData.timeDelay = TIME_DELAY;
\r
1944 appData.timeControl = TIME_CONTROL;
\r
1945 appData.timeIncrement = TIME_INCREMENT;
\r
1946 appData.icsActive = FALSE;
\r
1947 appData.icsHost = "";
\r
1948 appData.icsPort = ICS_PORT;
\r
1949 appData.icsCommPort = ICS_COMM_PORT;
\r
1950 appData.icsLogon = ICS_LOGON;
\r
1951 appData.icsHelper = "";
\r
1952 appData.useTelnet = FALSE;
\r
1953 appData.telnetProgram = TELNET_PROGRAM;
\r
1954 appData.gateway = "";
\r
1955 appData.loadGameFile = "";
\r
1956 appData.loadGameIndex = 0;
\r
1957 appData.saveGameFile = "";
\r
1958 appData.autoSaveGames = FALSE;
\r
1959 appData.loadPositionFile = "";
\r
1960 appData.loadPositionIndex = 1;
\r
1961 appData.savePositionFile = "";
\r
1962 appData.matchMode = FALSE;
\r
1963 appData.matchGames = 0;
\r
1964 appData.monoMode = FALSE;
\r
1965 appData.debugMode = FALSE;
\r
1966 appData.clockMode = TRUE;
\r
1967 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1968 appData.Iconic = FALSE; /*unused*/
\r
1969 appData.searchTime = "";
\r
1970 appData.searchDepth = 0;
\r
1971 appData.showCoords = FALSE;
\r
1972 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1973 appData.autoCallFlag = FALSE;
\r
1974 appData.flipView = FALSE;
\r
1975 appData.autoFlipView = TRUE;
\r
1976 appData.cmailGameName = "";
\r
1977 appData.alwaysPromoteToQueen = FALSE;
\r
1978 appData.oldSaveStyle = FALSE;
\r
1979 appData.quietPlay = FALSE;
\r
1980 appData.showThinking = FALSE;
\r
1981 appData.ponderNextMove = TRUE;
\r
1982 appData.periodicUpdates = TRUE;
\r
1983 appData.popupExitMessage = TRUE;
\r
1984 appData.popupMoveErrors = FALSE;
\r
1985 appData.autoObserve = FALSE;
\r
1986 appData.autoComment = FALSE;
\r
1987 appData.animate = TRUE;
\r
1988 appData.animSpeed = 10;
\r
1989 appData.animateDragging = TRUE;
\r
1990 appData.highlightLastMove = TRUE;
\r
1991 appData.getMoveList = TRUE;
\r
1992 appData.testLegality = TRUE;
\r
1993 appData.premove = TRUE;
\r
1994 appData.premoveWhite = FALSE;
\r
1995 appData.premoveWhiteText = "";
\r
1996 appData.premoveBlack = FALSE;
\r
1997 appData.premoveBlackText = "";
\r
1998 appData.icsAlarm = TRUE;
\r
1999 appData.icsAlarmTime = 5000;
\r
2000 appData.autoRaiseBoard = TRUE;
\r
2001 appData.localLineEditing = TRUE;
\r
2002 appData.colorize = TRUE;
\r
2003 appData.reuseFirst = TRUE;
\r
2004 appData.reuseSecond = TRUE;
\r
2005 appData.blindfold = FALSE;
\r
2006 appData.icsEngineAnalyze = FALSE;
\r
2007 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2008 dcb.DCBlength = sizeof(DCB);
\r
2009 dcb.BaudRate = 9600;
\r
2010 dcb.fBinary = TRUE;
\r
2011 dcb.fParity = FALSE;
\r
2012 dcb.fOutxCtsFlow = FALSE;
\r
2013 dcb.fOutxDsrFlow = FALSE;
\r
2014 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2015 dcb.fDsrSensitivity = FALSE;
\r
2016 dcb.fTXContinueOnXoff = TRUE;
\r
2017 dcb.fOutX = FALSE;
\r
2019 dcb.fNull = FALSE;
\r
2020 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2021 dcb.fAbortOnError = FALSE;
\r
2023 dcb.Parity = SPACEPARITY;
\r
2024 dcb.StopBits = ONESTOPBIT;
\r
2025 settingsFileName = SETTINGS_FILE;
\r
2026 saveSettingsOnExit = TRUE;
\r
2027 boardX = CW_USEDEFAULT;
\r
2028 boardY = CW_USEDEFAULT;
\r
2029 analysisX = CW_USEDEFAULT;
\r
2030 analysisY = CW_USEDEFAULT;
\r
2031 analysisW = CW_USEDEFAULT;
\r
2032 analysisH = CW_USEDEFAULT;
\r
2033 commentX = CW_USEDEFAULT;
\r
2034 commentY = CW_USEDEFAULT;
\r
2035 commentW = CW_USEDEFAULT;
\r
2036 commentH = CW_USEDEFAULT;
\r
2037 editTagsX = CW_USEDEFAULT;
\r
2038 editTagsY = CW_USEDEFAULT;
\r
2039 editTagsW = CW_USEDEFAULT;
\r
2040 editTagsH = CW_USEDEFAULT;
\r
2041 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2042 icsNames = ICS_NAMES;
\r
2043 firstChessProgramNames = FCP_NAMES;
\r
2044 secondChessProgramNames = SCP_NAMES;
\r
2045 appData.initialMode = "";
\r
2046 appData.variant = "normal";
\r
2047 appData.firstProtocolVersion = PROTOVER;
\r
2048 appData.secondProtocolVersion = PROTOVER;
\r
2049 appData.showButtonBar = TRUE;
\r
2051 /* [AS] New properties (see comments in header file) */
\r
2052 appData.firstScoreIsAbsolute = FALSE;
\r
2053 appData.secondScoreIsAbsolute = FALSE;
\r
2054 appData.saveExtendedInfoInPGN = FALSE;
\r
2055 appData.hideThinkingFromHuman = FALSE;
\r
2056 appData.liteBackTextureFile = "";
\r
2057 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2058 appData.darkBackTextureFile = "";
\r
2059 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2060 appData.renderPiecesWithFont = "";
\r
2061 appData.fontToPieceTable = "";
\r
2062 appData.fontBackColorWhite = 0;
\r
2063 appData.fontForeColorWhite = 0;
\r
2064 appData.fontBackColorBlack = 0;
\r
2065 appData.fontForeColorBlack = 0;
\r
2066 appData.fontPieceSize = 80;
\r
2067 appData.overrideLineGap = 1;
\r
2068 appData.adjudicateLossThreshold = 0;
\r
2069 appData.delayBeforeQuit = 0;
\r
2070 appData.delayAfterQuit = 0;
\r
2071 appData.nameOfDebugFile = "winboard.debug";
\r
2072 appData.pgnEventHeader = "Computer Chess Game";
\r
2073 appData.defaultFrcPosition = -1;
\r
2074 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2075 appData.saveOutOfBookInfo = TRUE;
\r
2076 appData.showEvalInMoveHistory = TRUE;
\r
2077 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2078 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2079 appData.highlightMoveWithArrow = FALSE;
\r
2080 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2081 appData.useStickyWindows = TRUE;
\r
2082 appData.adjudicateDrawMoves = 0;
\r
2083 appData.autoDisplayComment = TRUE;
\r
2084 appData.autoDisplayTags = TRUE;
\r
2085 appData.firstIsUCI = FALSE;
\r
2086 appData.secondIsUCI = FALSE;
\r
2087 appData.firstHasOwnBookUCI = TRUE;
\r
2088 appData.secondHasOwnBookUCI = TRUE;
\r
2089 appData.polyglotDir = "";
\r
2090 appData.usePolyglotBook = FALSE;
\r
2091 appData.polyglotBook = "";
\r
2092 appData.defaultHashSize = 64;
\r
2093 appData.defaultCacheSizeEGTB = 4;
\r
2094 appData.defaultPathEGTB = "c:\\egtb";
\r
2095 appData.firstOptions = "";
\r
2096 appData.secondOptions = "";
\r
2098 InitWindowPlacement( &wpGameList );
\r
2099 InitWindowPlacement( &wpMoveHistory );
\r
2100 InitWindowPlacement( &wpEvalGraph );
\r
2101 InitWindowPlacement( &wpEngineOutput );
\r
2102 InitWindowPlacement( &wpConsole );
\r
2104 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2105 appData.NrFiles = -1;
\r
2106 appData.NrRanks = -1;
\r
2107 appData.holdingsSize = -1;
\r
2108 appData.testClaims = FALSE;
\r
2109 appData.checkMates = FALSE;
\r
2110 appData.materialDraws= FALSE;
\r
2111 appData.trivialDraws = FALSE;
\r
2112 appData.ruleMoves = 51;
\r
2113 appData.drawRepeats = 6;
\r
2114 appData.matchPause = 10000;
\r
2115 appData.alphaRank = FALSE;
\r
2116 appData.allWhite = FALSE;
\r
2117 appData.upsideDown = FALSE;
\r
2118 appData.serverPause = 15;
\r
2119 appData.serverMovesName = NULL;
\r
2120 appData.suppressLoadMoves = FALSE;
\r
2121 appData.firstTimeOdds = 1;
\r
2122 appData.secondTimeOdds = 1;
\r
2123 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2124 appData.secondAccumulateTC = 1;
\r
2125 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2126 appData.secondNPS = -1;
\r
2127 appData.engineComments = 1;
\r
2128 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2129 appData.egtFormats = "";
\r
2132 appData.zippyTalk = ZIPPY_TALK;
\r
2133 appData.zippyPlay = ZIPPY_PLAY;
\r
2134 appData.zippyLines = ZIPPY_LINES;
\r
2135 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2136 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2137 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2138 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2139 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2140 appData.zippyUseI = ZIPPY_USE_I;
\r
2141 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2142 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2143 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2144 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2145 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2146 appData.zippyAbort = ZIPPY_ABORT;
\r
2147 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2148 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2149 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2152 /* Point font array elements to structures and
\r
2153 parse default font names */
\r
2154 for (i=0; i<NUM_FONTS; i++) {
\r
2155 for (j=0; j<NUM_SIZES; j++) {
\r
2156 font[j][i] = &fontRec[j][i];
\r
2157 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2161 /* Parse default settings file if any */
\r
2162 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2163 settingsFileName = strdup(buf);
\r
2166 /* Parse command line */
\r
2167 ParseArgs(StringGet, &lpCmdLine);
\r
2169 /* [HGM] make sure board size is acceptable */
\r
2170 if(appData.NrFiles > BOARD_SIZE ||
\r
2171 appData.NrRanks > BOARD_SIZE )
\r
2172 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2174 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2175 * with options from the command line, we now make an even higher priority
\r
2176 * overrule by WB options attached to the engine command line. This so that
\r
2177 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2180 if(appData.firstChessProgram != NULL) {
\r
2181 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2182 static char *f = "first";
\r
2183 char buf[MSG_SIZ], *q = buf;
\r
2184 if(p != NULL) { // engine command line contains WinBoard options
\r
2185 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2186 ParseArgs(StringGet, &q);
\r
2187 p[-1] = 0; // cut them offengine command line
\r
2190 // now do same for second chess program
\r
2191 if(appData.secondChessProgram != NULL) {
\r
2192 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2193 static char *s = "second";
\r
2194 char buf[MSG_SIZ], *q = buf;
\r
2195 if(p != NULL) { // engine command line contains WinBoard options
\r
2196 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2197 ParseArgs(StringGet, &q);
\r
2198 p[-1] = 0; // cut them offengine command line
\r
2203 /* Propagate options that affect others */
\r
2204 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2205 if (appData.icsActive || appData.noChessProgram) {
\r
2206 chessProgram = FALSE; /* not local chess program mode */
\r
2209 /* Open startup dialog if needed */
\r
2210 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2211 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2212 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2213 *appData.secondChessProgram == NULLCHAR))) {
\r
2216 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2217 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2218 FreeProcInstance(lpProc);
\r
2221 /* Make sure save files land in the right (?) directory */
\r
2222 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2223 appData.saveGameFile = strdup(buf);
\r
2225 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2226 appData.savePositionFile = strdup(buf);
\r
2229 /* Finish initialization for fonts and sounds */
\r
2230 for (i=0; i<NUM_FONTS; i++) {
\r
2231 for (j=0; j<NUM_SIZES; j++) {
\r
2232 CreateFontInMF(font[j][i]);
\r
2235 /* xboard, and older WinBoards, controlled the move sound with the
\r
2236 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2237 always turn the option on (so that the backend will call us),
\r
2238 then let the user turn the sound off by setting it to silence if
\r
2239 desired. To accommodate old winboard.ini files saved by old
\r
2240 versions of WinBoard, we also turn off the sound if the option
\r
2241 was initially set to false. */
\r
2242 if (!appData.ringBellAfterMoves) {
\r
2243 sounds[(int)SoundMove].name = strdup("");
\r
2244 appData.ringBellAfterMoves = TRUE;
\r
2246 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2247 SetCurrentDirectory(installDir);
\r
2249 SetCurrentDirectory(currDir);
\r
2251 p = icsTextMenuString;
\r
2252 if (p[0] == '@') {
\r
2253 FILE* f = fopen(p + 1, "r");
\r
2255 DisplayFatalError(p + 1, errno, 2);
\r
2258 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2260 buf[i] = NULLCHAR;
\r
2263 ParseIcsTextMenu(strdup(p));
\r
2270 HMENU hmenu = GetMenu(hwndMain);
\r
2272 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2273 MF_BYCOMMAND|((appData.icsActive &&
\r
2274 *appData.icsCommPort != NULLCHAR) ?
\r
2275 MF_ENABLED : MF_GRAYED));
\r
2276 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2277 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2278 MF_CHECKED : MF_UNCHECKED));
\r
2283 SaveSettings(char* name)
\r
2286 ArgDescriptor *ad;
\r
2287 WINDOWPLACEMENT wp;
\r
2288 char dir[MSG_SIZ];
\r
2290 if (!hwndMain) return;
\r
2292 GetCurrentDirectory(MSG_SIZ, dir);
\r
2293 SetCurrentDirectory(installDir);
\r
2294 f = fopen(name, "w");
\r
2295 SetCurrentDirectory(dir);
\r
2297 DisplayError(name, errno);
\r
2300 fprintf(f, ";\n");
\r
2301 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2302 fprintf(f, ";\n");
\r
2303 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2304 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2305 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2306 fprintf(f, ";\n");
\r
2308 wp.length = sizeof(WINDOWPLACEMENT);
\r
2309 GetWindowPlacement(hwndMain, &wp);
\r
2310 boardX = wp.rcNormalPosition.left;
\r
2311 boardY = wp.rcNormalPosition.top;
\r
2313 if (hwndConsole) {
\r
2314 GetWindowPlacement(hwndConsole, &wp);
\r
2315 wpConsole.x = wp.rcNormalPosition.left;
\r
2316 wpConsole.y = wp.rcNormalPosition.top;
\r
2317 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2318 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2321 if (analysisDialog) {
\r
2322 GetWindowPlacement(analysisDialog, &wp);
\r
2323 analysisX = wp.rcNormalPosition.left;
\r
2324 analysisY = wp.rcNormalPosition.top;
\r
2325 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2326 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2329 if (commentDialog) {
\r
2330 GetWindowPlacement(commentDialog, &wp);
\r
2331 commentX = wp.rcNormalPosition.left;
\r
2332 commentY = wp.rcNormalPosition.top;
\r
2333 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2334 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2337 if (editTagsDialog) {
\r
2338 GetWindowPlacement(editTagsDialog, &wp);
\r
2339 editTagsX = wp.rcNormalPosition.left;
\r
2340 editTagsY = wp.rcNormalPosition.top;
\r
2341 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2342 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2345 if (gameListDialog) {
\r
2346 GetWindowPlacement(gameListDialog, &wp);
\r
2347 wpGameList.x = wp.rcNormalPosition.left;
\r
2348 wpGameList.y = wp.rcNormalPosition.top;
\r
2349 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2350 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2353 /* [AS] Move history */
\r
2354 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2356 if( moveHistoryDialog ) {
\r
2357 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2358 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2359 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2360 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2361 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2364 /* [AS] Eval graph */
\r
2365 wpEvalGraph.visible = EvalGraphIsUp();
\r
2367 if( evalGraphDialog ) {
\r
2368 GetWindowPlacement(evalGraphDialog, &wp);
\r
2369 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2370 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2371 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2372 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2375 /* [AS] Engine output */
\r
2376 wpEngineOutput.visible = EngineOutputIsUp();
\r
2378 if( engineOutputDialog ) {
\r
2379 GetWindowPlacement(engineOutputDialog, &wp);
\r
2380 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2381 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2382 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2383 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2386 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2387 if (!ad->save) continue;
\r
2388 switch (ad->argType) {
\r
2391 char *p = *(char **)ad->argLoc;
\r
2392 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2393 /* Quote multiline values or \-containing values
\r
2394 with { } if possible */
\r
2395 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2397 /* Else quote with " " */
\r
2398 fprintf(f, "/%s=\"", ad->argName);
\r
2400 if (*p == '\n') fprintf(f, "\n");
\r
2401 else if (*p == '\r') fprintf(f, "\\r");
\r
2402 else if (*p == '\t') fprintf(f, "\\t");
\r
2403 else if (*p == '\b') fprintf(f, "\\b");
\r
2404 else if (*p == '\f') fprintf(f, "\\f");
\r
2405 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2406 else if (*p == '\"') fprintf(f, "\\\"");
\r
2407 else if (*p == '\\') fprintf(f, "\\\\");
\r
2411 fprintf(f, "\"\n");
\r
2417 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2420 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2423 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2426 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2429 fprintf(f, "/%s=%s\n", ad->argName,
\r
2430 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2433 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2436 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2440 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2441 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2442 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2447 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2448 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2449 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2450 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2451 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2452 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2453 (ta->effects) ? " " : "",
\r
2454 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2458 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2459 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2461 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2464 case ArgBoardSize:
\r
2465 fprintf(f, "/%s=%s\n", ad->argName,
\r
2466 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2471 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2472 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2473 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2474 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2475 ad->argName, mfp->faceName, mfp->pointSize,
\r
2476 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2477 mfp->bold ? "b" : "",
\r
2478 mfp->italic ? "i" : "",
\r
2479 mfp->underline ? "u" : "",
\r
2480 mfp->strikeout ? "s" : "");
\r
2484 case ArgCommSettings:
\r
2485 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2487 case ArgSettingsFilename: ;
\r
2495 /*---------------------------------------------------------------------------*\
\r
2497 * GDI board drawing routines
\r
2499 \*---------------------------------------------------------------------------*/
\r
2501 /* [AS] Draw square using background texture */
\r
2502 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2507 return; /* Should never happen! */
\r
2510 SetGraphicsMode( dst, GM_ADVANCED );
\r
2517 /* X reflection */
\r
2522 x.eDx = (FLOAT) dw + dx - 1;
\r
2525 SetWorldTransform( dst, &x );
\r
2528 /* Y reflection */
\r
2534 x.eDy = (FLOAT) dh + dy - 1;
\r
2536 SetWorldTransform( dst, &x );
\r
2544 x.eDx = (FLOAT) dx;
\r
2545 x.eDy = (FLOAT) dy;
\r
2548 SetWorldTransform( dst, &x );
\r
2552 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2560 SetWorldTransform( dst, &x );
\r
2562 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2565 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2567 PM_WP = (int) WhitePawn,
\r
2568 PM_WN = (int) WhiteKnight,
\r
2569 PM_WB = (int) WhiteBishop,
\r
2570 PM_WR = (int) WhiteRook,
\r
2571 PM_WQ = (int) WhiteQueen,
\r
2572 PM_WF = (int) WhiteFerz,
\r
2573 PM_WW = (int) WhiteWazir,
\r
2574 PM_WE = (int) WhiteAlfil,
\r
2575 PM_WM = (int) WhiteMan,
\r
2576 PM_WO = (int) WhiteCannon,
\r
2577 PM_WU = (int) WhiteUnicorn,
\r
2578 PM_WH = (int) WhiteNightrider,
\r
2579 PM_WA = (int) WhiteAngel,
\r
2580 PM_WC = (int) WhiteMarshall,
\r
2581 PM_WAB = (int) WhiteCardinal,
\r
2582 PM_WD = (int) WhiteDragon,
\r
2583 PM_WL = (int) WhiteLance,
\r
2584 PM_WS = (int) WhiteCobra,
\r
2585 PM_WV = (int) WhiteFalcon,
\r
2586 PM_WSG = (int) WhiteSilver,
\r
2587 PM_WG = (int) WhiteGrasshopper,
\r
2588 PM_WK = (int) WhiteKing,
\r
2589 PM_BP = (int) BlackPawn,
\r
2590 PM_BN = (int) BlackKnight,
\r
2591 PM_BB = (int) BlackBishop,
\r
2592 PM_BR = (int) BlackRook,
\r
2593 PM_BQ = (int) BlackQueen,
\r
2594 PM_BF = (int) BlackFerz,
\r
2595 PM_BW = (int) BlackWazir,
\r
2596 PM_BE = (int) BlackAlfil,
\r
2597 PM_BM = (int) BlackMan,
\r
2598 PM_BO = (int) BlackCannon,
\r
2599 PM_BU = (int) BlackUnicorn,
\r
2600 PM_BH = (int) BlackNightrider,
\r
2601 PM_BA = (int) BlackAngel,
\r
2602 PM_BC = (int) BlackMarshall,
\r
2603 PM_BG = (int) BlackGrasshopper,
\r
2604 PM_BAB = (int) BlackCardinal,
\r
2605 PM_BD = (int) BlackDragon,
\r
2606 PM_BL = (int) BlackLance,
\r
2607 PM_BS = (int) BlackCobra,
\r
2608 PM_BV = (int) BlackFalcon,
\r
2609 PM_BSG = (int) BlackSilver,
\r
2610 PM_BK = (int) BlackKing
\r
2613 static HFONT hPieceFont = NULL;
\r
2614 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2615 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2616 static int fontBitmapSquareSize = 0;
\r
2617 static char pieceToFontChar[(int) EmptySquare] =
\r
2618 { 'p', 'n', 'b', 'r', 'q',
\r
2619 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2620 'k', 'o', 'm', 'v', 't', 'w',
\r
2621 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2624 extern BOOL SetCharTable( char *table, const char * map );
\r
2625 /* [HGM] moved to backend.c */
\r
2627 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2630 BYTE r1 = GetRValue( color );
\r
2631 BYTE g1 = GetGValue( color );
\r
2632 BYTE b1 = GetBValue( color );
\r
2638 /* Create a uniform background first */
\r
2639 hbrush = CreateSolidBrush( color );
\r
2640 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2641 FillRect( hdc, &rc, hbrush );
\r
2642 DeleteObject( hbrush );
\r
2645 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2646 int steps = squareSize / 2;
\r
2649 for( i=0; i<steps; i++ ) {
\r
2650 BYTE r = r1 - (r1-r2) * i / steps;
\r
2651 BYTE g = g1 - (g1-g2) * i / steps;
\r
2652 BYTE b = b1 - (b1-b2) * i / steps;
\r
2654 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2655 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2656 FillRect( hdc, &rc, hbrush );
\r
2657 DeleteObject(hbrush);
\r
2660 else if( mode == 2 ) {
\r
2661 /* Diagonal gradient, good more or less for every piece */
\r
2662 POINT triangle[3];
\r
2663 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2664 HBRUSH hbrush_old;
\r
2665 int steps = squareSize;
\r
2668 triangle[0].x = squareSize - steps;
\r
2669 triangle[0].y = squareSize;
\r
2670 triangle[1].x = squareSize;
\r
2671 triangle[1].y = squareSize;
\r
2672 triangle[2].x = squareSize;
\r
2673 triangle[2].y = squareSize - steps;
\r
2675 for( i=0; i<steps; i++ ) {
\r
2676 BYTE r = r1 - (r1-r2) * i / steps;
\r
2677 BYTE g = g1 - (g1-g2) * i / steps;
\r
2678 BYTE b = b1 - (b1-b2) * i / steps;
\r
2680 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2681 hbrush_old = SelectObject( hdc, hbrush );
\r
2682 Polygon( hdc, triangle, 3 );
\r
2683 SelectObject( hdc, hbrush_old );
\r
2684 DeleteObject(hbrush);
\r
2689 SelectObject( hdc, hpen );
\r
2694 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2695 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2696 piece: follow the steps as explained below.
\r
2698 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2702 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2706 int backColor = whitePieceColor;
\r
2707 int foreColor = blackPieceColor;
\r
2709 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2710 backColor = appData.fontBackColorWhite;
\r
2711 foreColor = appData.fontForeColorWhite;
\r
2713 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2714 backColor = appData.fontBackColorBlack;
\r
2715 foreColor = appData.fontForeColorBlack;
\r
2719 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2721 hbm_old = SelectObject( hdc, hbm );
\r
2725 rc.right = squareSize;
\r
2726 rc.bottom = squareSize;
\r
2728 /* Step 1: background is now black */
\r
2729 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2731 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2733 pt.x = (squareSize - sz.cx) / 2;
\r
2734 pt.y = (squareSize - sz.cy) / 2;
\r
2736 SetBkMode( hdc, TRANSPARENT );
\r
2737 SetTextColor( hdc, chroma );
\r
2738 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2739 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2741 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2742 /* Step 3: the area outside the piece is filled with white */
\r
2743 // FloodFill( hdc, 0, 0, chroma );
\r
2744 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2745 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2746 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2747 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2748 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2750 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2751 but if the start point is not inside the piece we're lost!
\r
2752 There should be a better way to do this... if we could create a region or path
\r
2753 from the fill operation we would be fine for example.
\r
2755 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2756 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2758 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2759 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2760 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2762 SelectObject( dc2, bm2 );
\r
2763 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2764 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2765 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2766 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2767 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2770 DeleteObject( bm2 );
\r
2773 SetTextColor( hdc, 0 );
\r
2775 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2776 draw the piece again in black for safety.
\r
2778 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2780 SelectObject( hdc, hbm_old );
\r
2782 if( hPieceMask[index] != NULL ) {
\r
2783 DeleteObject( hPieceMask[index] );
\r
2786 hPieceMask[index] = hbm;
\r
2789 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2791 SelectObject( hdc, hbm );
\r
2794 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2795 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2796 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2798 SelectObject( dc1, hPieceMask[index] );
\r
2799 SelectObject( dc2, bm2 );
\r
2800 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2801 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2804 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2805 the piece background and deletes (makes transparent) the rest.
\r
2806 Thanks to that mask, we are free to paint the background with the greates
\r
2807 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2808 We use this, to make gradients and give the pieces a "roundish" look.
\r
2810 SetPieceBackground( hdc, backColor, 2 );
\r
2811 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2815 DeleteObject( bm2 );
\r
2818 SetTextColor( hdc, foreColor );
\r
2819 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2821 SelectObject( hdc, hbm_old );
\r
2823 if( hPieceFace[index] != NULL ) {
\r
2824 DeleteObject( hPieceFace[index] );
\r
2827 hPieceFace[index] = hbm;
\r
2830 static int TranslatePieceToFontPiece( int piece )
\r
2860 case BlackMarshall:
\r
2864 case BlackNightrider:
\r
2870 case BlackUnicorn:
\r
2874 case BlackGrasshopper:
\r
2886 case BlackCardinal:
\r
2893 case WhiteMarshall:
\r
2897 case WhiteNightrider:
\r
2903 case WhiteUnicorn:
\r
2907 case WhiteGrasshopper:
\r
2919 case WhiteCardinal:
\r
2928 void CreatePiecesFromFont()
\r
2931 HDC hdc_window = NULL;
\r
2937 if( fontBitmapSquareSize < 0 ) {
\r
2938 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2942 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2943 fontBitmapSquareSize = -1;
\r
2947 if( fontBitmapSquareSize != squareSize ) {
\r
2948 hdc_window = GetDC( hwndMain );
\r
2949 hdc = CreateCompatibleDC( hdc_window );
\r
2951 if( hPieceFont != NULL ) {
\r
2952 DeleteObject( hPieceFont );
\r
2955 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2956 hPieceMask[i] = NULL;
\r
2957 hPieceFace[i] = NULL;
\r
2963 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2964 fontHeight = appData.fontPieceSize;
\r
2967 fontHeight = (fontHeight * squareSize) / 100;
\r
2969 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2971 lf.lfEscapement = 0;
\r
2972 lf.lfOrientation = 0;
\r
2973 lf.lfWeight = FW_NORMAL;
\r
2975 lf.lfUnderline = 0;
\r
2976 lf.lfStrikeOut = 0;
\r
2977 lf.lfCharSet = DEFAULT_CHARSET;
\r
2978 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2979 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2980 lf.lfQuality = PROOF_QUALITY;
\r
2981 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2982 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2983 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2985 hPieceFont = CreateFontIndirect( &lf );
\r
2987 if( hPieceFont == NULL ) {
\r
2988 fontBitmapSquareSize = -2;
\r
2991 /* Setup font-to-piece character table */
\r
2992 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2993 /* No (or wrong) global settings, try to detect the font */
\r
2994 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2996 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2998 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2999 /* DiagramTT* family */
\r
3000 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3002 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3003 /* Fairy symbols */
\r
3004 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3006 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3007 /* Good Companion (Some characters get warped as literal :-( */
\r
3008 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3009 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3010 SetCharTable(pieceToFontChar, s);
\r
3013 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3014 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3018 /* Create bitmaps */
\r
3019 hfont_old = SelectObject( hdc, hPieceFont );
\r
3021 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3022 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3023 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3024 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3025 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3026 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3027 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3028 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3029 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3030 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3031 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3032 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3034 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3035 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3036 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3037 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3038 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3039 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3040 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3042 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3043 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3048 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3050 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3051 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3055 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3056 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3063 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3064 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3065 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3067 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3068 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3069 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3071 SelectObject( hdc, hfont_old );
\r
3073 fontBitmapSquareSize = squareSize;
\r
3077 if( hdc != NULL ) {
\r
3081 if( hdc_window != NULL ) {
\r
3082 ReleaseDC( hwndMain, hdc_window );
\r
3087 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3091 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3092 if (gameInfo.event &&
\r
3093 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3094 strcmp(name, "k80s") == 0) {
\r
3095 strcpy(name, "tim");
\r
3097 return LoadBitmap(hinst, name);
\r
3101 /* Insert a color into the program's logical palette
\r
3102 structure. This code assumes the given color is
\r
3103 the result of the RGB or PALETTERGB macro, and it
\r
3104 knows how those macros work (which is documented).
\r
3107 InsertInPalette(COLORREF color)
\r
3109 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3111 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3112 DisplayFatalError("Too many colors", 0, 1);
\r
3113 pLogPal->palNumEntries--;
\r
3117 pe->peFlags = (char) 0;
\r
3118 pe->peRed = (char) (0xFF & color);
\r
3119 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3120 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3126 InitDrawingColors()
\r
3128 if (pLogPal == NULL) {
\r
3129 /* Allocate enough memory for a logical palette with
\r
3130 * PALETTESIZE entries and set the size and version fields
\r
3131 * of the logical palette structure.
\r
3133 pLogPal = (NPLOGPALETTE)
\r
3134 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3135 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3136 pLogPal->palVersion = 0x300;
\r
3138 pLogPal->palNumEntries = 0;
\r
3140 InsertInPalette(lightSquareColor);
\r
3141 InsertInPalette(darkSquareColor);
\r
3142 InsertInPalette(whitePieceColor);
\r
3143 InsertInPalette(blackPieceColor);
\r
3144 InsertInPalette(highlightSquareColor);
\r
3145 InsertInPalette(premoveHighlightColor);
\r
3147 /* create a logical color palette according the information
\r
3148 * in the LOGPALETTE structure.
\r
3150 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3152 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3153 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3154 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3155 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3156 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3157 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3158 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3159 /* [AS] Force rendering of the font-based pieces */
\r
3160 if( fontBitmapSquareSize > 0 ) {
\r
3161 fontBitmapSquareSize = 0;
\r
3167 BoardWidth(int boardSize, int n)
\r
3168 { /* [HGM] argument n added to allow different width and height */
\r
3169 int lineGap = sizeInfo[boardSize].lineGap;
\r
3171 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3172 lineGap = appData.overrideLineGap;
\r
3175 return (n + 1) * lineGap +
\r
3176 n * sizeInfo[boardSize].squareSize;
\r
3179 /* Respond to board resize by dragging edge */
\r
3181 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3183 BoardSize newSize = NUM_SIZES - 1;
\r
3184 static int recurse = 0;
\r
3185 if (IsIconic(hwndMain)) return;
\r
3186 if (recurse > 0) return;
\r
3188 while (newSize > 0) {
\r
3189 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3190 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3191 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3194 boardSize = newSize;
\r
3195 InitDrawingSizes(boardSize, flags);
\r
3202 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3204 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3205 ChessSquare piece;
\r
3206 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3208 SIZE clockSize, messageSize;
\r
3210 char buf[MSG_SIZ];
\r
3212 HMENU hmenu = GetMenu(hwndMain);
\r
3213 RECT crect, wrect, oldRect;
\r
3215 LOGBRUSH logbrush;
\r
3217 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3218 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3220 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3221 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3223 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3224 oldRect.top = boardY;
\r
3225 oldRect.right = boardX + winWidth;
\r
3226 oldRect.bottom = boardY + winHeight;
\r
3228 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3229 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3230 squareSize = sizeInfo[boardSize].squareSize;
\r
3231 lineGap = sizeInfo[boardSize].lineGap;
\r
3232 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3234 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3235 lineGap = appData.overrideLineGap;
\r
3238 if (tinyLayout != oldTinyLayout) {
\r
3239 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3241 style &= ~WS_SYSMENU;
\r
3242 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3243 "&Minimize\tCtrl+F4");
\r
3245 style |= WS_SYSMENU;
\r
3246 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3248 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3250 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3251 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3252 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3254 DrawMenuBar(hwndMain);
\r
3257 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3258 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3260 /* Get text area sizes */
\r
3261 hdc = GetDC(hwndMain);
\r
3262 if (appData.clockMode) {
\r
3263 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3265 sprintf(buf, "White");
\r
3267 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3268 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3269 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3270 str = "We only care about the height here";
\r
3271 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3272 SelectObject(hdc, oldFont);
\r
3273 ReleaseDC(hwndMain, hdc);
\r
3275 /* Compute where everything goes */
\r
3276 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3277 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3278 logoHeight = 2*clockSize.cy;
\r
3279 leftLogoRect.left = OUTER_MARGIN;
\r
3280 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3281 leftLogoRect.top = OUTER_MARGIN;
\r
3282 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3284 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3285 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3286 rightLogoRect.top = OUTER_MARGIN;
\r
3287 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3290 whiteRect.left = leftLogoRect.right;
\r
3291 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3292 whiteRect.top = OUTER_MARGIN;
\r
3293 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3295 blackRect.right = rightLogoRect.left;
\r
3296 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3297 blackRect.top = whiteRect.top;
\r
3298 blackRect.bottom = whiteRect.bottom;
\r
3300 whiteRect.left = OUTER_MARGIN;
\r
3301 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3302 whiteRect.top = OUTER_MARGIN;
\r
3303 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3305 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3306 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3307 blackRect.top = whiteRect.top;
\r
3308 blackRect.bottom = whiteRect.bottom;
\r
3311 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3312 if (appData.showButtonBar) {
\r
3313 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3314 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3316 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3318 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3319 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3321 boardRect.left = OUTER_MARGIN;
\r
3322 boardRect.right = boardRect.left + boardWidth;
\r
3323 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3324 boardRect.bottom = boardRect.top + boardHeight;
\r
3326 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3327 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3328 oldBoardSize = boardSize;
\r
3329 oldTinyLayout = tinyLayout;
\r
3330 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3331 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3332 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3333 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3334 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3335 winHeight = winH; // without disturbing window attachments
\r
3336 GetWindowRect(hwndMain, &wrect);
\r
3337 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3338 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3340 // [HGM] placement: let attached windows follow size change.
\r
3341 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3342 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3343 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3344 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3345 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3347 /* compensate if menu bar wrapped */
\r
3348 GetClientRect(hwndMain, &crect);
\r
3349 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3350 winHeight += offby;
\r
3352 case WMSZ_TOPLEFT:
\r
3353 SetWindowPos(hwndMain, NULL,
\r
3354 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3355 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3358 case WMSZ_TOPRIGHT:
\r
3360 SetWindowPos(hwndMain, NULL,
\r
3361 wrect.left, wrect.bottom - winHeight,
\r
3362 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3365 case WMSZ_BOTTOMLEFT:
\r
3367 SetWindowPos(hwndMain, NULL,
\r
3368 wrect.right - winWidth, wrect.top,
\r
3369 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3372 case WMSZ_BOTTOMRIGHT:
\r
3376 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3377 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3382 for (i = 0; i < N_BUTTONS; i++) {
\r
3383 if (buttonDesc[i].hwnd != NULL) {
\r
3384 DestroyWindow(buttonDesc[i].hwnd);
\r
3385 buttonDesc[i].hwnd = NULL;
\r
3387 if (appData.showButtonBar) {
\r
3388 buttonDesc[i].hwnd =
\r
3389 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3390 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3391 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3392 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3393 (HMENU) buttonDesc[i].id,
\r
3394 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3396 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3397 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3398 MAKELPARAM(FALSE, 0));
\r
3400 if (buttonDesc[i].id == IDM_Pause)
\r
3401 hwndPause = buttonDesc[i].hwnd;
\r
3402 buttonDesc[i].wndproc = (WNDPROC)
\r
3403 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3406 if (gridPen != NULL) DeleteObject(gridPen);
\r
3407 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3408 if (premovePen != NULL) DeleteObject(premovePen);
\r
3409 if (lineGap != 0) {
\r
3410 logbrush.lbStyle = BS_SOLID;
\r
3411 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3413 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3414 lineGap, &logbrush, 0, NULL);
\r
3415 logbrush.lbColor = highlightSquareColor;
\r
3417 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3418 lineGap, &logbrush, 0, NULL);
\r
3420 logbrush.lbColor = premoveHighlightColor;
\r
3422 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3423 lineGap, &logbrush, 0, NULL);
\r
3425 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3426 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3427 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3428 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3429 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3430 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3431 BOARD_WIDTH * (squareSize + lineGap);
\r
3432 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3434 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3435 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3436 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3437 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3438 lineGap / 2 + (i * (squareSize + lineGap));
\r
3439 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3440 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3441 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3445 /* [HGM] Licensing requirement */
\r
3447 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3450 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3452 GothicPopUp( "", VariantNormal);
\r
3455 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3457 /* Load piece bitmaps for this board size */
\r
3458 for (i=0; i<=2; i++) {
\r
3459 for (piece = WhitePawn;
\r
3460 (int) piece < (int) BlackPawn;
\r
3461 piece = (ChessSquare) ((int) piece + 1)) {
\r
3462 if (pieceBitmap[i][piece] != NULL)
\r
3463 DeleteObject(pieceBitmap[i][piece]);
\r
3467 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3468 // Orthodox Chess pieces
\r
3469 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3470 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3471 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3472 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3473 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3474 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3475 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3476 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3477 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3478 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3479 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3480 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3481 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3482 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3483 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3484 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3485 // in Shogi, Hijack the unused Queen for Lance
\r
3486 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3487 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3488 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3490 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3491 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3492 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3495 if(squareSize <= 72 && squareSize >= 33) {
\r
3496 /* A & C are available in most sizes now */
\r
3497 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3498 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3499 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3500 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3501 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3502 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3503 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3504 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3505 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3506 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3507 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3508 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3509 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3510 } else { // Smirf-like
\r
3511 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3512 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3513 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3515 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3516 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3517 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3518 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3519 } else { // WinBoard standard
\r
3520 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3521 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3522 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3527 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3528 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3529 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3530 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3531 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3532 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3533 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3534 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3535 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3536 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3537 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3538 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3539 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3540 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3541 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3542 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3543 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3544 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3545 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3546 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3547 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3548 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3549 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3550 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3551 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3552 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3553 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3554 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3555 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3556 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3557 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3559 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3560 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3561 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3562 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3563 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3564 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3565 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3566 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3567 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3568 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3569 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3570 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3571 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3573 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3574 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3575 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3576 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3577 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3578 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3579 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3580 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3581 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3582 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3583 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3584 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3587 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3588 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3589 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3590 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3591 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3592 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3593 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3594 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3595 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3596 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3597 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3598 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3599 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3600 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3601 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3605 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3606 /* special Shogi support in this size */
\r
3607 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3608 for (piece = WhitePawn;
\r
3609 (int) piece < (int) BlackPawn;
\r
3610 piece = (ChessSquare) ((int) piece + 1)) {
\r
3611 if (pieceBitmap[i][piece] != NULL)
\r
3612 DeleteObject(pieceBitmap[i][piece]);
\r
3615 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3616 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3617 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3618 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3619 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3620 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3621 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3622 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3623 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3624 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3625 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3626 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3627 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3628 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3629 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3630 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3631 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3632 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3633 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3634 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3635 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3636 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3637 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3638 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3639 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3640 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3641 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3642 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3643 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3644 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3645 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3646 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3647 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3648 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3649 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3650 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3651 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3652 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3653 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3654 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3655 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3656 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3662 PieceBitmap(ChessSquare p, int kind)
\r
3664 if ((int) p >= (int) BlackPawn)
\r
3665 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3667 return pieceBitmap[kind][(int) p];
\r
3670 /***************************************************************/
\r
3672 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3673 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3675 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3676 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3680 SquareToPos(int row, int column, int * x, int * y)
\r
3683 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3684 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3686 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3687 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3692 DrawCoordsOnDC(HDC hdc)
\r
3694 static char files[24] = {'0', '1','2','3','4','5','6','7','8','9','0','1','1','0','9','8','7','6','5','4','3','2','1','0'};
\r
3695 static char ranks[24] = {'l', 'k','j','i','h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h','i','j','k','l'};
\r
3696 char str[2] = { NULLCHAR, NULLCHAR };
\r
3697 int oldMode, oldAlign, x, y, start, i;
\r
3701 if (!appData.showCoords)
\r
3704 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3706 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3707 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3708 oldAlign = GetTextAlign(hdc);
\r
3709 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3711 y = boardRect.top + lineGap;
\r
3712 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3714 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3715 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3716 str[0] = files[start + i];
\r
3717 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3718 y += squareSize + lineGap;
\r
3721 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3723 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3724 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3725 str[0] = ranks[start + i];
\r
3726 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3727 x += squareSize + lineGap;
\r
3730 SelectObject(hdc, oldBrush);
\r
3731 SetBkMode(hdc, oldMode);
\r
3732 SetTextAlign(hdc, oldAlign);
\r
3733 SelectObject(hdc, oldFont);
\r
3737 DrawGridOnDC(HDC hdc)
\r
3741 if (lineGap != 0) {
\r
3742 oldPen = SelectObject(hdc, gridPen);
\r
3743 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3744 SelectObject(hdc, oldPen);
\r
3748 #define HIGHLIGHT_PEN 0
\r
3749 #define PREMOVE_PEN 1
\r
3752 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3755 HPEN oldPen, hPen;
\r
3756 if (lineGap == 0) return;
\r
3758 x1 = boardRect.left +
\r
3759 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3760 y1 = boardRect.top +
\r
3761 lineGap/2 + y * (squareSize + lineGap);
\r
3763 x1 = boardRect.left +
\r
3764 lineGap/2 + x * (squareSize + lineGap);
\r
3765 y1 = boardRect.top +
\r
3766 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3768 hPen = pen ? premovePen : highlightPen;
\r
3769 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3770 MoveToEx(hdc, x1, y1, NULL);
\r
3771 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3772 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3773 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3774 LineTo(hdc, x1, y1);
\r
3775 SelectObject(hdc, oldPen);
\r
3779 DrawHighlightsOnDC(HDC hdc)
\r
3782 for (i=0; i<2; i++) {
\r
3783 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3784 DrawHighlightOnDC(hdc, TRUE,
\r
3785 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3788 for (i=0; i<2; i++) {
\r
3789 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3790 premoveHighlightInfo.sq[i].y >= 0) {
\r
3791 DrawHighlightOnDC(hdc, TRUE,
\r
3792 premoveHighlightInfo.sq[i].x,
\r
3793 premoveHighlightInfo.sq[i].y,
\r
3799 /* Note: sqcolor is used only in monoMode */
\r
3800 /* Note that this code is largely duplicated in woptions.c,
\r
3801 function DrawSampleSquare, so that needs to be updated too */
\r
3803 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3805 HBITMAP oldBitmap;
\r
3809 if (appData.blindfold) return;
\r
3811 /* [AS] Use font-based pieces if needed */
\r
3812 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3813 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3814 CreatePiecesFromFont();
\r
3816 if( fontBitmapSquareSize == squareSize ) {
\r
3817 int index = TranslatePieceToFontPiece(piece);
\r
3819 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3823 squareSize, squareSize,
\r
3828 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3832 squareSize, squareSize,
\r
3841 if (appData.monoMode) {
\r
3842 SelectObject(tmphdc, PieceBitmap(piece,
\r
3843 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3844 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3845 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3847 tmpSize = squareSize;
\r
3849 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3850 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3851 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3852 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3853 x += (squareSize - minorSize)>>1;
\r
3854 y += squareSize - minorSize - 2;
\r
3855 tmpSize = minorSize;
\r
3857 if (color || appData.allWhite ) {
\r
3858 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3860 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3861 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3862 if(appData.upsideDown && color==flipView)
\r
3863 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3865 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3867 /* Use black piece color for outline of white pieces */
\r
3868 /* Not sure this looks really good (though xboard does it).
\r
3869 Maybe better to have another selectable color, default black */
\r
3870 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3871 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3872 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3874 /* Use black for outline of white pieces */
\r
3875 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3876 if(appData.upsideDown && color==flipView)
\r
3877 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3879 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3883 /* Use white piece color for details of black pieces */
\r
3884 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3885 WHITE_PIECE ones aren't always the right shape. */
\r
3886 /* Not sure this looks really good (though xboard does it).
\r
3887 Maybe better to have another selectable color, default medium gray? */
\r
3888 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3889 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3890 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3891 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3892 SelectObject(hdc, blackPieceBrush);
\r
3893 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3895 /* Use square color for details of black pieces */
\r
3896 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3897 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3898 if(appData.upsideDown && !flipView)
\r
3899 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3901 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3904 SelectObject(hdc, oldBrush);
\r
3905 SelectObject(tmphdc, oldBitmap);
\r
3909 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3910 int GetBackTextureMode( int algo )
\r
3912 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3916 case BACK_TEXTURE_MODE_PLAIN:
\r
3917 result = 1; /* Always use identity map */
\r
3919 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3920 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3928 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3929 to handle redraws cleanly (as random numbers would always be different).
\r
3931 VOID RebuildTextureSquareInfo()
\r
3941 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3943 if( liteBackTexture != NULL ) {
\r
3944 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3945 lite_w = bi.bmWidth;
\r
3946 lite_h = bi.bmHeight;
\r
3950 if( darkBackTexture != NULL ) {
\r
3951 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3952 dark_w = bi.bmWidth;
\r
3953 dark_h = bi.bmHeight;
\r
3957 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3958 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3959 if( (col + row) & 1 ) {
\r
3961 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3962 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3963 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3964 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3969 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3970 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3971 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3972 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3979 /* [AS] Arrow highlighting support */
\r
3981 static int A_WIDTH = 5; /* Width of arrow body */
\r
3983 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3984 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3986 static double Sqr( double x )
\r
3991 static int Round( double x )
\r
3993 return (int) (x + 0.5);
\r
3996 /* Draw an arrow between two points using current settings */
\r
3997 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
4000 double dx, dy, j, k, x, y;
\r
4002 if( d_x == s_x ) {
\r
4003 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4005 arrow[0].x = s_x + A_WIDTH;
\r
4008 arrow[1].x = s_x + A_WIDTH;
\r
4009 arrow[1].y = d_y - h;
\r
4011 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4012 arrow[2].y = d_y - h;
\r
4017 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4018 arrow[4].y = d_y - h;
\r
4020 arrow[5].x = s_x - A_WIDTH;
\r
4021 arrow[5].y = d_y - h;
\r
4023 arrow[6].x = s_x - A_WIDTH;
\r
4026 else if( d_y == s_y ) {
\r
4027 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4030 arrow[0].y = s_y + A_WIDTH;
\r
4032 arrow[1].x = d_x - w;
\r
4033 arrow[1].y = s_y + A_WIDTH;
\r
4035 arrow[2].x = d_x - w;
\r
4036 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4041 arrow[4].x = d_x - w;
\r
4042 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4044 arrow[5].x = d_x - w;
\r
4045 arrow[5].y = s_y - A_WIDTH;
\r
4048 arrow[6].y = s_y - A_WIDTH;
\r
4051 /* [AS] Needed a lot of paper for this! :-) */
\r
4052 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4053 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4055 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4057 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4062 arrow[0].x = Round(x - j);
\r
4063 arrow[0].y = Round(y + j*dx);
\r
4065 arrow[1].x = Round(x + j);
\r
4066 arrow[1].y = Round(y - j*dx);
\r
4069 x = (double) d_x - k;
\r
4070 y = (double) d_y - k*dy;
\r
4073 x = (double) d_x + k;
\r
4074 y = (double) d_y + k*dy;
\r
4077 arrow[2].x = Round(x + j);
\r
4078 arrow[2].y = Round(y - j*dx);
\r
4080 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4081 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4086 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4087 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4089 arrow[6].x = Round(x - j);
\r
4090 arrow[6].y = Round(y + j*dx);
\r
4093 Polygon( hdc, arrow, 7 );
\r
4096 /* [AS] Draw an arrow between two squares */
\r
4097 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4099 int s_x, s_y, d_x, d_y;
\r
4106 if( s_col == d_col && s_row == d_row ) {
\r
4110 /* Get source and destination points */
\r
4111 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4112 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4115 d_y += squareSize / 4;
\r
4117 else if( d_y < s_y ) {
\r
4118 d_y += 3 * squareSize / 4;
\r
4121 d_y += squareSize / 2;
\r
4125 d_x += squareSize / 4;
\r
4127 else if( d_x < s_x ) {
\r
4128 d_x += 3 * squareSize / 4;
\r
4131 d_x += squareSize / 2;
\r
4134 s_x += squareSize / 2;
\r
4135 s_y += squareSize / 2;
\r
4137 /* Adjust width */
\r
4138 A_WIDTH = squareSize / 14;
\r
4141 stLB.lbStyle = BS_SOLID;
\r
4142 stLB.lbColor = appData.highlightArrowColor;
\r
4145 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4146 holdpen = SelectObject( hdc, hpen );
\r
4147 hbrush = CreateBrushIndirect( &stLB );
\r
4148 holdbrush = SelectObject( hdc, hbrush );
\r
4150 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4152 SelectObject( hdc, holdpen );
\r
4153 SelectObject( hdc, holdbrush );
\r
4154 DeleteObject( hpen );
\r
4155 DeleteObject( hbrush );
\r
4158 BOOL HasHighlightInfo()
\r
4160 BOOL result = FALSE;
\r
4162 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4163 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4171 BOOL IsDrawArrowEnabled()
\r
4173 BOOL result = FALSE;
\r
4175 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4182 VOID DrawArrowHighlight( HDC hdc )
\r
4184 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4185 DrawArrowBetweenSquares( hdc,
\r
4186 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4187 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4191 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4193 HRGN result = NULL;
\r
4195 if( HasHighlightInfo() ) {
\r
4196 int x1, y1, x2, y2;
\r
4197 int sx, sy, dx, dy;
\r
4199 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4200 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4202 sx = MIN( x1, x2 );
\r
4203 sy = MIN( y1, y2 );
\r
4204 dx = MAX( x1, x2 ) + squareSize;
\r
4205 dy = MAX( y1, y2 ) + squareSize;
\r
4207 result = CreateRectRgn( sx, sy, dx, dy );
\r
4214 Warning: this function modifies the behavior of several other functions.
\r
4216 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4217 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4218 repaint is scattered all over the place, which is not good for features such as
\r
4219 "arrow highlighting" that require a full repaint of the board.
\r
4221 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4222 user interaction, when speed is not so important) but especially to avoid errors
\r
4223 in the displayed graphics.
\r
4225 In such patched places, I always try refer to this function so there is a single
\r
4226 place to maintain knowledge.
\r
4228 To restore the original behavior, just return FALSE unconditionally.
\r
4230 BOOL IsFullRepaintPreferrable()
\r
4232 BOOL result = FALSE;
\r
4234 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4235 /* Arrow may appear on the board */
\r
4243 This function is called by DrawPosition to know whether a full repaint must
\r
4246 Only DrawPosition may directly call this function, which makes use of
\r
4247 some state information. Other function should call DrawPosition specifying
\r
4248 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4250 BOOL DrawPositionNeedsFullRepaint()
\r
4252 BOOL result = FALSE;
\r
4255 Probably a slightly better policy would be to trigger a full repaint
\r
4256 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4257 but animation is fast enough that it's difficult to notice.
\r
4259 if( animInfo.piece == EmptySquare ) {
\r
4260 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4269 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4271 int row, column, x, y, square_color, piece_color;
\r
4272 ChessSquare piece;
\r
4274 HDC texture_hdc = NULL;
\r
4276 /* [AS] Initialize background textures if needed */
\r
4277 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4278 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4279 if( backTextureSquareSize != squareSize
\r
4280 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4281 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4282 backTextureSquareSize = squareSize;
\r
4283 RebuildTextureSquareInfo();
\r
4286 texture_hdc = CreateCompatibleDC( hdc );
\r
4289 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4290 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4292 SquareToPos(row, column, &x, &y);
\r
4294 piece = board[row][column];
\r
4296 square_color = ((column + row) % 2) == 1;
\r
4297 if( gameInfo.variant == VariantXiangqi ) {
\r
4298 square_color = !InPalace(row, column);
\r
4299 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4300 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4302 piece_color = (int) piece < (int) BlackPawn;
\r
4305 /* [HGM] holdings file: light square or black */
\r
4306 if(column == BOARD_LEFT-2) {
\r
4307 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4310 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4314 if(column == BOARD_RGHT + 1 ) {
\r
4315 if( row < gameInfo.holdingsSize )
\r
4318 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4322 if(column == BOARD_LEFT-1 ) /* left align */
\r
4323 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4324 else if( column == BOARD_RGHT) /* right align */
\r
4325 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4327 if (appData.monoMode) {
\r
4328 if (piece == EmptySquare) {
\r
4329 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4330 square_color ? WHITENESS : BLACKNESS);
\r
4332 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4335 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4336 /* [AS] Draw the square using a texture bitmap */
\r
4337 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4338 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4339 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4342 squareSize, squareSize,
\r
4345 backTextureSquareInfo[r][c].mode,
\r
4346 backTextureSquareInfo[r][c].x,
\r
4347 backTextureSquareInfo[r][c].y );
\r
4349 SelectObject( texture_hdc, hbm );
\r
4351 if (piece != EmptySquare) {
\r
4352 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4356 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4358 oldBrush = SelectObject(hdc, brush );
\r
4359 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4360 SelectObject(hdc, oldBrush);
\r
4361 if (piece != EmptySquare)
\r
4362 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4367 if( texture_hdc != NULL ) {
\r
4368 DeleteDC( texture_hdc );
\r
4372 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4373 void fputDW(FILE *f, int x)
\r
4375 fputc(x & 255, f);
\r
4376 fputc(x>>8 & 255, f);
\r
4377 fputc(x>>16 & 255, f);
\r
4378 fputc(x>>24 & 255, f);
\r
4381 #define MAX_CLIPS 200 /* more than enough */
\r
4384 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4386 // HBITMAP bufferBitmap;
\r
4391 int w = 100, h = 50;
\r
4393 if(logo == NULL) return;
\r
4394 // GetClientRect(hwndMain, &Rect);
\r
4395 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4396 // Rect.bottom-Rect.top+1);
\r
4397 tmphdc = CreateCompatibleDC(hdc);
\r
4398 hbm = SelectObject(tmphdc, logo);
\r
4399 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4403 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4404 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4405 SelectObject(tmphdc, hbm);
\r
4410 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4412 static Board lastReq, lastDrawn;
\r
4413 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4414 static int lastDrawnFlipView = 0;
\r
4415 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4416 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4419 HBITMAP bufferBitmap;
\r
4420 HBITMAP oldBitmap;
\r
4422 HRGN clips[MAX_CLIPS];
\r
4423 ChessSquare dragged_piece = EmptySquare;
\r
4425 /* I'm undecided on this - this function figures out whether a full
\r
4426 * repaint is necessary on its own, so there's no real reason to have the
\r
4427 * caller tell it that. I think this can safely be set to FALSE - but
\r
4428 * if we trust the callers not to request full repaints unnessesarily, then
\r
4429 * we could skip some clipping work. In other words, only request a full
\r
4430 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4431 * gamestart and similar) --Hawk
\r
4433 Boolean fullrepaint = repaint;
\r
4435 if( DrawPositionNeedsFullRepaint() ) {
\r
4436 fullrepaint = TRUE;
\r
4440 if( fullrepaint ) {
\r
4441 static int repaint_count = 0;
\r
4445 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4446 OutputDebugString( buf );
\r
4450 if (board == NULL) {
\r
4451 if (!lastReqValid) {
\r
4456 CopyBoard(lastReq, board);
\r
4460 if (doingSizing) {
\r
4464 if (IsIconic(hwndMain)) {
\r
4468 if (hdc == NULL) {
\r
4469 hdc = GetDC(hwndMain);
\r
4470 if (!appData.monoMode) {
\r
4471 SelectPalette(hdc, hPal, FALSE);
\r
4472 RealizePalette(hdc);
\r
4476 releaseDC = FALSE;
\r
4480 fprintf(debugFP, "*******************************\n"
\r
4482 "dragInfo.from (%d,%d)\n"
\r
4483 "dragInfo.start (%d,%d)\n"
\r
4484 "dragInfo.pos (%d,%d)\n"
\r
4485 "dragInfo.lastpos (%d,%d)\n",
\r
4486 repaint ? "TRUE" : "FALSE",
\r
4487 dragInfo.from.x, dragInfo.from.y,
\r
4488 dragInfo.start.x, dragInfo.start.y,
\r
4489 dragInfo.pos.x, dragInfo.pos.y,
\r
4490 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4491 fprintf(debugFP, "prev: ");
\r
4492 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4493 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4494 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4497 fprintf(debugFP, "\n");
\r
4498 fprintf(debugFP, "board: ");
\r
4499 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4500 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4501 fprintf(debugFP, "%d ", board[row][column]);
\r
4504 fprintf(debugFP, "\n");
\r
4508 /* Create some work-DCs */
\r
4509 hdcmem = CreateCompatibleDC(hdc);
\r
4510 tmphdc = CreateCompatibleDC(hdc);
\r
4512 /* If dragging is in progress, we temporarely remove the piece */
\r
4513 /* [HGM] or temporarily decrease count if stacked */
\r
4514 /* !! Moved to before board compare !! */
\r
4515 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4516 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4517 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4518 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4519 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4521 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4522 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4523 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4525 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4528 /* Figure out which squares need updating by comparing the
\r
4529 * newest board with the last drawn board and checking if
\r
4530 * flipping has changed.
\r
4532 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4533 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4534 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4535 if (lastDrawn[row][column] != board[row][column]) {
\r
4536 SquareToPos(row, column, &x, &y);
\r
4537 clips[num_clips++] =
\r
4538 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4542 for (i=0; i<2; i++) {
\r
4543 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4544 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4545 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4546 lastDrawnHighlight.sq[i].y >= 0) {
\r
4547 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4548 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4549 clips[num_clips++] =
\r
4550 CreateRectRgn(x - lineGap, y - lineGap,
\r
4551 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4553 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4554 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4555 clips[num_clips++] =
\r
4556 CreateRectRgn(x - lineGap, y - lineGap,
\r
4557 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4561 for (i=0; i<2; i++) {
\r
4562 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4563 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4564 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4565 lastDrawnPremove.sq[i].y >= 0) {
\r
4566 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4567 lastDrawnPremove.sq[i].x, &x, &y);
\r
4568 clips[num_clips++] =
\r
4569 CreateRectRgn(x - lineGap, y - lineGap,
\r
4570 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4572 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4573 premoveHighlightInfo.sq[i].y >= 0) {
\r
4574 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4575 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4576 clips[num_clips++] =
\r
4577 CreateRectRgn(x - lineGap, y - lineGap,
\r
4578 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4583 fullrepaint = TRUE;
\r
4586 /* Create a buffer bitmap - this is the actual bitmap
\r
4587 * being written to. When all the work is done, we can
\r
4588 * copy it to the real DC (the screen). This avoids
\r
4589 * the problems with flickering.
\r
4591 GetClientRect(hwndMain, &Rect);
\r
4592 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4593 Rect.bottom-Rect.top+1);
\r
4594 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4595 if (!appData.monoMode) {
\r
4596 SelectPalette(hdcmem, hPal, FALSE);
\r
4599 /* Create clips for dragging */
\r
4600 if (!fullrepaint) {
\r
4601 if (dragInfo.from.x >= 0) {
\r
4602 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4603 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4605 if (dragInfo.start.x >= 0) {
\r
4606 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4607 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4609 if (dragInfo.pos.x >= 0) {
\r
4610 x = dragInfo.pos.x - squareSize / 2;
\r
4611 y = dragInfo.pos.y - squareSize / 2;
\r
4612 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4614 if (dragInfo.lastpos.x >= 0) {
\r
4615 x = dragInfo.lastpos.x - squareSize / 2;
\r
4616 y = dragInfo.lastpos.y - squareSize / 2;
\r
4617 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4621 /* Are we animating a move?
\r
4623 * - remove the piece from the board (temporarely)
\r
4624 * - calculate the clipping region
\r
4626 if (!fullrepaint) {
\r
4627 if (animInfo.piece != EmptySquare) {
\r
4628 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4629 x = boardRect.left + animInfo.lastpos.x;
\r
4630 y = boardRect.top + animInfo.lastpos.y;
\r
4631 x2 = boardRect.left + animInfo.pos.x;
\r
4632 y2 = boardRect.top + animInfo.pos.y;
\r
4633 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4634 /* Slight kludge. The real problem is that after AnimateMove is
\r
4635 done, the position on the screen does not match lastDrawn.
\r
4636 This currently causes trouble only on e.p. captures in
\r
4637 atomic, where the piece moves to an empty square and then
\r
4638 explodes. The old and new positions both had an empty square
\r
4639 at the destination, but animation has drawn a piece there and
\r
4640 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4641 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4645 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4646 if (num_clips == 0)
\r
4647 fullrepaint = TRUE;
\r
4649 /* Set clipping on the memory DC */
\r
4650 if (!fullrepaint) {
\r
4651 SelectClipRgn(hdcmem, clips[0]);
\r
4652 for (x = 1; x < num_clips; x++) {
\r
4653 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4654 abort(); // this should never ever happen!
\r
4658 /* Do all the drawing to the memory DC */
\r
4659 if(explodeInfo.radius) { // [HGM] atomic
\r
4661 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4662 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4663 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4664 x += squareSize/2;
\r
4665 y += squareSize/2;
\r
4666 if(!fullrepaint) {
\r
4667 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4668 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4670 DrawGridOnDC(hdcmem);
\r
4671 DrawHighlightsOnDC(hdcmem);
\r
4672 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4673 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4674 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4675 SelectObject(hdcmem, oldBrush);
\r
4677 DrawGridOnDC(hdcmem);
\r
4678 DrawHighlightsOnDC(hdcmem);
\r
4679 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4682 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4683 if(appData.autoLogo) {
\r
4685 switch(gameMode) { // pick logos based on game mode
\r
4686 case IcsObserving:
\r
4687 whiteLogo = second.programLogo; // ICS logo
\r
4688 blackLogo = second.programLogo;
\r
4691 case IcsPlayingWhite:
\r
4692 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4693 blackLogo = second.programLogo; // ICS logo
\r
4695 case IcsPlayingBlack:
\r
4696 whiteLogo = second.programLogo; // ICS logo
\r
4697 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4699 case TwoMachinesPlay:
\r
4700 if(first.twoMachinesColor[0] == 'b') {
\r
4701 whiteLogo = second.programLogo;
\r
4702 blackLogo = first.programLogo;
\r
4705 case MachinePlaysWhite:
\r
4706 blackLogo = userLogo;
\r
4708 case MachinePlaysBlack:
\r
4709 whiteLogo = userLogo;
\r
4710 blackLogo = first.programLogo;
\r
4713 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4714 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4717 if( appData.highlightMoveWithArrow ) {
\r
4718 DrawArrowHighlight(hdcmem);
\r
4721 DrawCoordsOnDC(hdcmem);
\r
4723 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4724 /* to make sure lastDrawn contains what is actually drawn */
\r
4726 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4727 if (dragged_piece != EmptySquare) {
\r
4728 /* [HGM] or restack */
\r
4729 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4730 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4732 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4733 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4734 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4735 x = dragInfo.pos.x - squareSize / 2;
\r
4736 y = dragInfo.pos.y - squareSize / 2;
\r
4737 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4738 ((int) dragged_piece < (int) BlackPawn),
\r
4739 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4742 /* Put the animated piece back into place and draw it */
\r
4743 if (animInfo.piece != EmptySquare) {
\r
4744 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4745 x = boardRect.left + animInfo.pos.x;
\r
4746 y = boardRect.top + animInfo.pos.y;
\r
4747 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4748 ((int) animInfo.piece < (int) BlackPawn),
\r
4749 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4752 /* Release the bufferBitmap by selecting in the old bitmap
\r
4753 * and delete the memory DC
\r
4755 SelectObject(hdcmem, oldBitmap);
\r
4758 /* Set clipping on the target DC */
\r
4759 if (!fullrepaint) {
\r
4760 SelectClipRgn(hdc, clips[0]);
\r
4761 for (x = 1; x < num_clips; x++) {
\r
4762 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4763 abort(); // this should never ever happen!
\r
4767 /* Copy the new bitmap onto the screen in one go.
\r
4768 * This way we avoid any flickering
\r
4770 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4771 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4772 boardRect.right - boardRect.left,
\r
4773 boardRect.bottom - boardRect.top,
\r
4774 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4775 if(saveDiagFlag) {
\r
4776 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4777 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4779 GetObject(bufferBitmap, sizeof(b), &b);
\r
4780 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4781 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4782 bih.biWidth = b.bmWidth;
\r
4783 bih.biHeight = b.bmHeight;
\r
4785 bih.biBitCount = b.bmBitsPixel;
\r
4786 bih.biCompression = 0;
\r
4787 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4788 bih.biXPelsPerMeter = 0;
\r
4789 bih.biYPelsPerMeter = 0;
\r
4790 bih.biClrUsed = 0;
\r
4791 bih.biClrImportant = 0;
\r
4792 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4793 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4794 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4795 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4798 wb = b.bmWidthBytes;
\r
4800 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4801 int k = ((int*) pData)[i];
\r
4802 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4803 if(j >= 16) break;
\r
4805 if(j >= nrColors) nrColors = j+1;
\r
4807 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4809 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4810 for(w=0; w<(wb>>2); w+=2) {
\r
4811 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4812 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4813 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4814 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4815 pData[p++] = m | j<<4;
\r
4817 while(p&3) pData[p++] = 0;
\r
4820 wb = ((wb+31)>>5)<<2;
\r
4822 // write BITMAPFILEHEADER
\r
4823 fprintf(diagFile, "BM");
\r
4824 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4825 fputDW(diagFile, 0);
\r
4826 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4827 // write BITMAPINFOHEADER
\r
4828 fputDW(diagFile, 40);
\r
4829 fputDW(diagFile, b.bmWidth);
\r
4830 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4831 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4832 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4833 fputDW(diagFile, 0);
\r
4834 fputDW(diagFile, 0);
\r
4835 fputDW(diagFile, 0);
\r
4836 fputDW(diagFile, 0);
\r
4837 fputDW(diagFile, 0);
\r
4838 fputDW(diagFile, 0);
\r
4839 // write color table
\r
4841 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4842 // write bitmap data
\r
4843 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4844 fputc(pData[i], diagFile);
\r
4849 SelectObject(tmphdc, oldBitmap);
\r
4851 /* Massive cleanup */
\r
4852 for (x = 0; x < num_clips; x++)
\r
4853 DeleteObject(clips[x]);
\r
4856 DeleteObject(bufferBitmap);
\r
4859 ReleaseDC(hwndMain, hdc);
\r
4861 if (lastDrawnFlipView != flipView) {
\r
4863 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4865 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4868 /* CopyBoard(lastDrawn, board);*/
\r
4869 lastDrawnHighlight = highlightInfo;
\r
4870 lastDrawnPremove = premoveHighlightInfo;
\r
4871 lastDrawnFlipView = flipView;
\r
4872 lastDrawnValid = 1;
\r
4875 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4880 saveDiagFlag = 1; diagFile = f;
\r
4881 HDCDrawPosition(NULL, TRUE, NULL);
\r
4885 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4892 /*---------------------------------------------------------------------------*\
\r
4893 | CLIENT PAINT PROCEDURE
\r
4894 | This is the main event-handler for the WM_PAINT message.
\r
4896 \*---------------------------------------------------------------------------*/
\r
4898 PaintProc(HWND hwnd)
\r
4904 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4905 if (IsIconic(hwnd)) {
\r
4906 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4908 if (!appData.monoMode) {
\r
4909 SelectPalette(hdc, hPal, FALSE);
\r
4910 RealizePalette(hdc);
\r
4912 HDCDrawPosition(hdc, 1, NULL);
\r
4914 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4915 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4916 ETO_CLIPPED|ETO_OPAQUE,
\r
4917 &messageRect, messageText, strlen(messageText), NULL);
\r
4918 SelectObject(hdc, oldFont);
\r
4919 DisplayBothClocks();
\r
4921 EndPaint(hwnd,&ps);
\r
4929 * If the user selects on a border boundary, return -1; if off the board,
\r
4930 * return -2. Otherwise map the event coordinate to the square.
\r
4931 * The offset boardRect.left or boardRect.top must already have been
\r
4932 * subtracted from x.
\r
4935 EventToSquare(int x)
\r
4942 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4944 x /= (squareSize + lineGap);
\r
4945 if (x >= BOARD_SIZE)
\r
4956 DropEnable dropEnables[] = {
\r
4957 { 'P', DP_Pawn, "Pawn" },
\r
4958 { 'N', DP_Knight, "Knight" },
\r
4959 { 'B', DP_Bishop, "Bishop" },
\r
4960 { 'R', DP_Rook, "Rook" },
\r
4961 { 'Q', DP_Queen, "Queen" },
\r
4965 SetupDropMenu(HMENU hmenu)
\r
4967 int i, count, enable;
\r
4969 extern char white_holding[], black_holding[];
\r
4970 char item[MSG_SIZ];
\r
4972 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4973 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4974 dropEnables[i].piece);
\r
4976 while (p && *p++ == dropEnables[i].piece) count++;
\r
4977 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4978 enable = count > 0 || !appData.testLegality
\r
4979 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4980 && !appData.icsActive);
\r
4981 ModifyMenu(hmenu, dropEnables[i].command,
\r
4982 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4983 dropEnables[i].command, item);
\r
4987 /* Event handler for mouse messages */
\r
4989 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4993 static int recursive = 0;
\r
4995 // BOOLEAN needsRedraw = FALSE;
\r
4996 BOOLEAN saveAnimate;
\r
4997 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4998 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4999 ChessMove moveType;
\r
5002 if (message == WM_MBUTTONUP) {
\r
5003 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5004 to the middle button: we simulate pressing the left button too!
\r
5006 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5007 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5013 pt.x = LOWORD(lParam);
\r
5014 pt.y = HIWORD(lParam);
\r
5015 x = EventToSquare(pt.x - boardRect.left);
\r
5016 y = EventToSquare(pt.y - boardRect.top);
\r
5017 if (!flipView && y >= 0) {
\r
5018 y = BOARD_HEIGHT - 1 - y;
\r
5020 if (flipView && x >= 0) {
\r
5021 x = BOARD_WIDTH - 1 - x;
\r
5024 switch (message) {
\r
5025 case WM_LBUTTONDOWN:
\r
5026 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5027 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5028 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5029 if(gameInfo.holdingsWidth &&
\r
5030 (WhiteOnMove(currentMove)
\r
5031 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5032 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5033 // click in right holdings, for determining promotion piece
\r
5034 ChessSquare p = boards[currentMove][y][x];
\r
5035 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5036 if(p != EmptySquare) {
\r
5037 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5038 fromX = fromY = -1;
\r
5042 DrawPosition(FALSE, boards[currentMove]);
\r
5046 sameAgain = FALSE;
\r
5048 /* Downclick vertically off board; check if on clock */
\r
5049 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5050 if (gameMode == EditPosition) {
\r
5051 SetWhiteToPlayEvent();
\r
5052 } else if (gameMode == IcsPlayingBlack ||
\r
5053 gameMode == MachinePlaysWhite) {
\r
5055 } else if (gameMode == EditGame) {
\r
5056 AdjustClock(flipClock, -1);
\r
5058 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5059 if (gameMode == EditPosition) {
\r
5060 SetBlackToPlayEvent();
\r
5061 } else if (gameMode == IcsPlayingWhite ||
\r
5062 gameMode == MachinePlaysBlack) {
\r
5064 } else if (gameMode == EditGame) {
\r
5065 AdjustClock(!flipClock, -1);
\r
5068 if (!appData.highlightLastMove) {
\r
5069 ClearHighlights();
\r
5070 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5072 fromX = fromY = -1;
\r
5073 dragInfo.start.x = dragInfo.start.y = -1;
\r
5074 dragInfo.from = dragInfo.start;
\r
5076 } else if (x < 0 || y < 0
\r
5077 /* [HGM] block clicks between board and holdings */
\r
5078 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5079 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5080 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5081 /* EditPosition, empty square, or different color piece;
\r
5082 click-click move is possible */
\r
5085 } else if (fromX == x && fromY == y) {
\r
5086 /* Downclick on same square again */
\r
5087 ClearHighlights();
\r
5088 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5089 sameAgain = TRUE;
\r
5090 } else if (fromX != -1 &&
\r
5091 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5093 /* Downclick on different square. */
\r
5094 /* [HGM] if on holdings file, should count as new first click ! */
\r
5095 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5098 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5099 to make sure move is legal before showing promotion popup */
\r
5100 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5101 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5102 fromX = fromY = -1;
\r
5103 ClearHighlights();
\r
5104 DrawPosition(FALSE, boards[currentMove]);
\r
5107 if(moveType != ImpossibleMove) {
\r
5108 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5109 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5110 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5111 appData.alwaysPromoteToQueen)) {
\r
5112 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5113 if (!appData.highlightLastMove) {
\r
5114 ClearHighlights();
\r
5115 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5118 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5119 SetHighlights(fromX, fromY, toX, toY);
\r
5120 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5121 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5122 If promotion to Q is legal, all are legal! */
\r
5123 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5124 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5125 // kludge to temporarily execute move on display, wthout promotng yet
\r
5126 promotionChoice = TRUE;
\r
5127 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5128 boards[currentMove][toY][toX] = p;
\r
5129 DrawPosition(FALSE, boards[currentMove]);
\r
5130 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5131 boards[currentMove][toY][toX] = q;
\r
5133 PromotionPopup(hwnd);
\r
5134 } else { /* not a promotion */
\r
5135 if (appData.animate || appData.highlightLastMove) {
\r
5136 SetHighlights(fromX, fromY, toX, toY);
\r
5138 ClearHighlights();
\r
5140 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5141 fromX = fromY = -1;
\r
5142 if (appData.animate && !appData.highlightLastMove) {
\r
5143 ClearHighlights();
\r
5144 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5150 /* [HGM] it seemed that braces were missing here */
\r
5151 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5152 fromX = fromY = -1;
\r
5156 ClearHighlights();
\r
5157 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5159 /* First downclick, or restart on a square with same color piece */
\r
5160 if (!frozen && OKToStartUserMove(x, y)) {
\r
5163 dragInfo.lastpos = pt;
\r
5164 dragInfo.from.x = fromX;
\r
5165 dragInfo.from.y = fromY;
\r
5166 dragInfo.start = dragInfo.from;
\r
5167 SetCapture(hwndMain);
\r
5169 fromX = fromY = -1;
\r
5170 dragInfo.start.x = dragInfo.start.y = -1;
\r
5171 dragInfo.from = dragInfo.start;
\r
5172 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5176 case WM_LBUTTONUP:
\r
5178 if (fromX == -1) break;
\r
5179 if (x == fromX && y == fromY) {
\r
5180 dragInfo.from.x = dragInfo.from.y = -1;
\r
5181 /* Upclick on same square */
\r
5183 /* Clicked same square twice: abort click-click move */
\r
5184 fromX = fromY = -1;
\r
5186 ClearPremoveHighlights();
\r
5188 /* First square clicked: start click-click move */
\r
5189 SetHighlights(fromX, fromY, -1, -1);
\r
5191 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5192 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5193 /* Errant click; ignore */
\r
5196 /* Finish drag move. */
\r
5197 if (appData.debugMode) {
\r
5198 fprintf(debugFP, "release\n");
\r
5200 dragInfo.from.x = dragInfo.from.y = -1;
\r
5203 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5204 appData.animate = appData.animate && !appData.animateDragging;
\r
5205 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5206 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5207 fromX = fromY = -1;
\r
5208 ClearHighlights();
\r
5209 DrawPosition(FALSE, boards[currentMove]);
\r
5210 appData.animate = saveAnimate;
\r
5213 if(moveType != ImpossibleMove) {
\r
5214 /* [HGM] use move type to determine if move is promotion.
\r
5215 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5216 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5217 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5218 appData.alwaysPromoteToQueen))
\r
5219 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5221 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5222 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5223 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5224 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5225 // kludge to temporarily execute move on display, wthout promotng yet
\r
5226 promotionChoice = TRUE;
\r
5227 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5228 boards[currentMove][toY][toX] = p;
\r
5229 DrawPosition(FALSE, boards[currentMove]);
\r
5230 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5231 boards[currentMove][toY][toX] = q;
\r
5232 appData.animate = saveAnimate;
\r
5235 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5237 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5238 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5239 moveType == WhiteCapturesEnPassant ||
\r
5240 moveType == BlackCapturesEnPassant ) )
\r
5241 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5242 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5245 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5246 appData.animate = saveAnimate;
\r
5247 fromX = fromY = -1;
\r
5248 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5249 ClearHighlights();
\r
5251 if (appData.animate || appData.animateDragging ||
\r
5252 appData.highlightDragging || gotPremove) {
\r
5253 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5256 dragInfo.start.x = dragInfo.start.y = -1;
\r
5257 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5260 case WM_MOUSEMOVE:
\r
5261 if ((appData.animateDragging || appData.highlightDragging)
\r
5262 && (wParam & MK_LBUTTON)
\r
5263 && dragInfo.from.x >= 0)
\r
5265 BOOL full_repaint = FALSE;
\r
5267 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5268 if (appData.animateDragging) {
\r
5269 dragInfo.pos = pt;
\r
5271 if (appData.highlightDragging) {
\r
5272 SetHighlights(fromX, fromY, x, y);
\r
5273 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5274 full_repaint = TRUE;
\r
5278 DrawPosition( full_repaint, NULL);
\r
5280 dragInfo.lastpos = dragInfo.pos;
\r
5284 case WM_MOUSEWHEEL: // [DM]
\r
5285 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5286 /* Mouse Wheel is being rolled forward
\r
5287 * Play moves forward
\r
5289 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5290 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5291 /* Mouse Wheel is being rolled backward
\r
5292 * Play moves backward
\r
5294 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5295 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5299 case WM_MBUTTONDOWN:
\r
5300 case WM_RBUTTONDOWN:
\r
5303 fromX = fromY = -1;
\r
5304 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5305 dragInfo.start.x = dragInfo.start.y = -1;
\r
5306 dragInfo.from = dragInfo.start;
\r
5307 dragInfo.lastpos = dragInfo.pos;
\r
5308 if (appData.highlightDragging) {
\r
5309 ClearHighlights();
\r
5312 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5313 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5314 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5315 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5316 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5319 DrawPosition(TRUE, NULL);
\r
5321 switch (gameMode) {
\r
5322 case EditPosition:
\r
5323 case IcsExamining:
\r
5324 if (x < 0 || y < 0) break;
\r
5327 if (message == WM_MBUTTONDOWN) {
\r
5328 buttonCount = 3; /* even if system didn't think so */
\r
5329 if (wParam & MK_SHIFT)
\r
5330 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5332 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5333 } else { /* message == WM_RBUTTONDOWN */
\r
5335 if (buttonCount == 3) {
\r
5336 if (wParam & MK_SHIFT)
\r
5337 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5339 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5341 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5344 /* Just have one menu, on the right button. Windows users don't
\r
5345 think to try the middle one, and sometimes other software steals
\r
5346 it, or it doesn't really exist. */
\r
5347 if(gameInfo.variant != VariantShogi)
\r
5348 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5350 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5354 case IcsPlayingWhite:
\r
5355 case IcsPlayingBlack:
\r
5357 case MachinePlaysWhite:
\r
5358 case MachinePlaysBlack:
\r
5359 if (appData.testLegality &&
\r
5360 gameInfo.variant != VariantBughouse &&
\r
5361 gameInfo.variant != VariantCrazyhouse) break;
\r
5362 if (x < 0 || y < 0) break;
\r
5365 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5366 SetupDropMenu(hmenu);
\r
5367 MenuPopup(hwnd, pt, hmenu, -1);
\r
5378 /* Preprocess messages for buttons in main window */
\r
5380 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5382 int id = GetWindowLong(hwnd, GWL_ID);
\r
5385 for (i=0; i<N_BUTTONS; i++) {
\r
5386 if (buttonDesc[i].id == id) break;
\r
5388 if (i == N_BUTTONS) return 0;
\r
5389 switch (message) {
\r
5394 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5395 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5402 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5405 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5406 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5407 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5408 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5410 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5412 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5413 PopUpMoveDialog((char)wParam);
\r
5419 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5422 /* Process messages for Promotion dialog box */
\r
5424 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5428 switch (message) {
\r
5429 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5430 /* Center the dialog over the application window */
\r
5431 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5432 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5433 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5434 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5435 SW_SHOW : SW_HIDE);
\r
5436 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5437 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5438 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5439 PieceToChar(WhiteAngel) != '~') ||
\r
5440 (PieceToChar(BlackAngel) >= 'A' &&
\r
5441 PieceToChar(BlackAngel) != '~') ) ?
\r
5442 SW_SHOW : SW_HIDE);
\r
5443 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5444 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5445 PieceToChar(WhiteMarshall) != '~') ||
\r
5446 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5447 PieceToChar(BlackMarshall) != '~') ) ?
\r
5448 SW_SHOW : SW_HIDE);
\r
5449 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5450 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5451 gameInfo.variant != VariantShogi ?
\r
5452 SW_SHOW : SW_HIDE);
\r
5453 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5454 gameInfo.variant != VariantShogi ?
\r
5455 SW_SHOW : SW_HIDE);
\r
5456 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5457 gameInfo.variant == VariantShogi ?
\r
5458 SW_SHOW : SW_HIDE);
\r
5459 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5460 gameInfo.variant == VariantShogi ?
\r
5461 SW_SHOW : SW_HIDE);
\r
5462 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5463 gameInfo.variant == VariantSuper ?
\r
5464 SW_SHOW : SW_HIDE);
\r
5467 case WM_COMMAND: /* message: received a command */
\r
5468 switch (LOWORD(wParam)) {
\r
5470 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5471 ClearHighlights();
\r
5472 DrawPosition(FALSE, NULL);
\r
5475 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5478 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5481 promoChar = PieceToChar(BlackRook);
\r
5484 promoChar = PieceToChar(BlackBishop);
\r
5486 case PB_Chancellor:
\r
5487 promoChar = PieceToChar(BlackMarshall);
\r
5489 case PB_Archbishop:
\r
5490 promoChar = PieceToChar(BlackAngel);
\r
5493 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5498 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5499 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5500 only show the popup when we are already sure the move is valid or
\r
5501 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5502 will figure out it is a promotion from the promoChar. */
\r
5503 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5504 if (!appData.highlightLastMove) {
\r
5505 ClearHighlights();
\r
5506 DrawPosition(FALSE, NULL);
\r
5513 /* Pop up promotion dialog */
\r
5515 PromotionPopup(HWND hwnd)
\r
5519 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5520 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5521 hwnd, (DLGPROC)lpProc);
\r
5522 FreeProcInstance(lpProc);
\r
5525 /* Toggle ShowThinking */
\r
5527 ToggleShowThinking()
\r
5529 appData.showThinking = !appData.showThinking;
\r
5530 ShowThinkingEvent();
\r
5534 LoadGameDialog(HWND hwnd, char* title)
\r
5538 char fileTitle[MSG_SIZ];
\r
5539 f = OpenFileDialog(hwnd, "rb", "",
\r
5540 appData.oldSaveStyle ? "gam" : "pgn",
\r
5542 title, &number, fileTitle, NULL);
\r
5544 cmailMsgLoaded = FALSE;
\r
5545 if (number == 0) {
\r
5546 int error = GameListBuild(f);
\r
5548 DisplayError("Cannot build game list", error);
\r
5549 } else if (!ListEmpty(&gameList) &&
\r
5550 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5551 GameListPopUp(f, fileTitle);
\r
5554 GameListDestroy();
\r
5557 LoadGame(f, number, fileTitle, FALSE);
\r
5562 ChangedConsoleFont()
\r
5565 CHARRANGE tmpsel, sel;
\r
5566 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5567 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5568 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5571 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5572 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5573 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5574 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5575 * size. This was undocumented in the version of MSVC++ that I had
\r
5576 * when I wrote the code, but is apparently documented now.
\r
5578 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5579 cfmt.bCharSet = f->lf.lfCharSet;
\r
5580 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5581 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5582 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5583 /* Why are the following seemingly needed too? */
\r
5584 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5585 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5586 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5588 tmpsel.cpMax = -1; /*999999?*/
\r
5589 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5590 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5591 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5592 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5594 paraf.cbSize = sizeof(paraf);
\r
5595 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5596 paraf.dxStartIndent = 0;
\r
5597 paraf.dxOffset = WRAP_INDENT;
\r
5598 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5599 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5602 /*---------------------------------------------------------------------------*\
\r
5604 * Window Proc for main window
\r
5606 \*---------------------------------------------------------------------------*/
\r
5608 /* Process messages for main window, etc. */
\r
5610 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5613 int wmId, wmEvent;
\r
5617 char fileTitle[MSG_SIZ];
\r
5618 char buf[MSG_SIZ];
\r
5619 static SnapData sd;
\r
5621 switch (message) {
\r
5623 case WM_PAINT: /* message: repaint portion of window */
\r
5627 case WM_ERASEBKGND:
\r
5628 if (IsIconic(hwnd)) {
\r
5629 /* Cheat; change the message */
\r
5630 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5632 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5636 case WM_LBUTTONDOWN:
\r
5637 case WM_MBUTTONDOWN:
\r
5638 case WM_RBUTTONDOWN:
\r
5639 case WM_LBUTTONUP:
\r
5640 case WM_MBUTTONUP:
\r
5641 case WM_RBUTTONUP:
\r
5642 case WM_MOUSEMOVE:
\r
5643 case WM_MOUSEWHEEL:
\r
5644 MouseEvent(hwnd, message, wParam, lParam);
\r
5647 JAWS_KB_NAVIGATION
\r
5651 JAWS_ALT_INTERCEPT
\r
5653 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5654 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5655 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5656 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5658 SendMessage(h, message, wParam, lParam);
\r
5659 } else if(lParam != KF_REPEAT) {
\r
5660 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5661 PopUpMoveDialog((char)wParam);
\r
5667 case WM_PALETTECHANGED:
\r
5668 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5670 HDC hdc = GetDC(hwndMain);
\r
5671 SelectPalette(hdc, hPal, TRUE);
\r
5672 nnew = RealizePalette(hdc);
\r
5674 paletteChanged = TRUE;
\r
5676 UpdateColors(hdc);
\r
5678 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5681 ReleaseDC(hwnd, hdc);
\r
5685 case WM_QUERYNEWPALETTE:
\r
5686 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5688 HDC hdc = GetDC(hwndMain);
\r
5689 paletteChanged = FALSE;
\r
5690 SelectPalette(hdc, hPal, FALSE);
\r
5691 nnew = RealizePalette(hdc);
\r
5693 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5695 ReleaseDC(hwnd, hdc);
\r
5700 case WM_COMMAND: /* message: command from application menu */
\r
5701 wmId = LOWORD(wParam);
\r
5702 wmEvent = HIWORD(wParam);
\r
5707 AnalysisPopDown();
\r
5708 SAY("new game enter a move to play against the computer with white");
\r
5711 case IDM_NewGameFRC:
\r
5712 if( NewGameFRC() == 0 ) {
\r
5714 AnalysisPopDown();
\r
5718 case IDM_NewVariant:
\r
5719 NewVariantPopup(hwnd);
\r
5722 case IDM_LoadGame:
\r
5723 LoadGameDialog(hwnd, "Load Game from File");
\r
5726 case IDM_LoadNextGame:
\r
5730 case IDM_LoadPrevGame:
\r
5734 case IDM_ReloadGame:
\r
5738 case IDM_LoadPosition:
\r
5739 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5740 Reset(FALSE, TRUE);
\r
5743 f = OpenFileDialog(hwnd, "rb", "",
\r
5744 appData.oldSaveStyle ? "pos" : "fen",
\r
5746 "Load Position from File", &number, fileTitle, NULL);
\r
5748 LoadPosition(f, number, fileTitle);
\r
5752 case IDM_LoadNextPosition:
\r
5753 ReloadPosition(1);
\r
5756 case IDM_LoadPrevPosition:
\r
5757 ReloadPosition(-1);
\r
5760 case IDM_ReloadPosition:
\r
5761 ReloadPosition(0);
\r
5764 case IDM_SaveGame:
\r
5765 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5766 f = OpenFileDialog(hwnd, "a", defName,
\r
5767 appData.oldSaveStyle ? "gam" : "pgn",
\r
5769 "Save Game to File", NULL, fileTitle, NULL);
\r
5771 SaveGame(f, 0, "");
\r
5775 case IDM_SavePosition:
\r
5776 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5777 f = OpenFileDialog(hwnd, "a", defName,
\r
5778 appData.oldSaveStyle ? "pos" : "fen",
\r
5780 "Save Position to File", NULL, fileTitle, NULL);
\r
5782 SavePosition(f, 0, "");
\r
5786 case IDM_SaveDiagram:
\r
5787 defName = "diagram";
\r
5788 f = OpenFileDialog(hwnd, "wb", defName,
\r
5791 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5797 case IDM_CopyGame:
\r
5798 CopyGameToClipboard();
\r
5801 case IDM_PasteGame:
\r
5802 PasteGameFromClipboard();
\r
5805 case IDM_CopyGameListToClipboard:
\r
5806 CopyGameListToClipboard();
\r
5809 /* [AS] Autodetect FEN or PGN data */
\r
5810 case IDM_PasteAny:
\r
5811 PasteGameOrFENFromClipboard();
\r
5814 /* [AS] Move history */
\r
5815 case IDM_ShowMoveHistory:
\r
5816 if( MoveHistoryIsUp() ) {
\r
5817 MoveHistoryPopDown();
\r
5820 MoveHistoryPopUp();
\r
5824 /* [AS] Eval graph */
\r
5825 case IDM_ShowEvalGraph:
\r
5826 if( EvalGraphIsUp() ) {
\r
5827 EvalGraphPopDown();
\r
5831 SetFocus(hwndMain);
\r
5835 /* [AS] Engine output */
\r
5836 case IDM_ShowEngineOutput:
\r
5837 if( EngineOutputIsUp() ) {
\r
5838 EngineOutputPopDown();
\r
5841 EngineOutputPopUp();
\r
5845 /* [AS] User adjudication */
\r
5846 case IDM_UserAdjudication_White:
\r
5847 UserAdjudicationEvent( +1 );
\r
5850 case IDM_UserAdjudication_Black:
\r
5851 UserAdjudicationEvent( -1 );
\r
5854 case IDM_UserAdjudication_Draw:
\r
5855 UserAdjudicationEvent( 0 );
\r
5858 /* [AS] Game list options dialog */
\r
5859 case IDM_GameListOptions:
\r
5860 GameListOptions();
\r
5863 case IDM_CopyPosition:
\r
5864 CopyFENToClipboard();
\r
5867 case IDM_PastePosition:
\r
5868 PasteFENFromClipboard();
\r
5871 case IDM_MailMove:
\r
5875 case IDM_ReloadCMailMsg:
\r
5876 Reset(TRUE, TRUE);
\r
5877 ReloadCmailMsgEvent(FALSE);
\r
5880 case IDM_Minimize:
\r
5881 ShowWindow(hwnd, SW_MINIMIZE);
\r
5888 case IDM_MachineWhite:
\r
5889 MachineWhiteEvent();
\r
5891 * refresh the tags dialog only if it's visible
\r
5893 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5895 tags = PGNTags(&gameInfo);
\r
5896 TagsPopUp(tags, CmailMsg());
\r
5899 SAY("computer starts playing white");
\r
5902 case IDM_MachineBlack:
\r
5903 MachineBlackEvent();
\r
5905 * refresh the tags dialog only if it's visible
\r
5907 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5909 tags = PGNTags(&gameInfo);
\r
5910 TagsPopUp(tags, CmailMsg());
\r
5913 SAY("computer starts playing black");
\r
5916 case IDM_TwoMachines:
\r
5917 TwoMachinesEvent();
\r
5919 * refresh the tags dialog only if it's visible
\r
5921 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5923 tags = PGNTags(&gameInfo);
\r
5924 TagsPopUp(tags, CmailMsg());
\r
5927 SAY("programs start playing each other");
\r
5930 case IDM_AnalysisMode:
\r
5931 if (!first.analysisSupport) {
\r
5932 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5933 DisplayError(buf, 0);
\r
5935 SAY("analyzing current position");
\r
5936 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5937 if (appData.icsActive) {
\r
5938 if (gameMode != IcsObserving) {
\r
5939 sprintf(buf, "You are not observing a game");
\r
5940 DisplayError(buf, 0);
\r
5941 /* secure check */
\r
5942 if (appData.icsEngineAnalyze) {
\r
5943 if (appData.debugMode)
\r
5944 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5945 ExitAnalyzeMode();
\r
5951 /* if enable, user want disable icsEngineAnalyze */
\r
5952 if (appData.icsEngineAnalyze) {
\r
5953 ExitAnalyzeMode();
\r
5957 appData.icsEngineAnalyze = TRUE;
\r
5958 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5961 if (!appData.showThinking) ToggleShowThinking();
\r
5962 AnalyzeModeEvent();
\r
5966 case IDM_AnalyzeFile:
\r
5967 if (!first.analysisSupport) {
\r
5968 char buf[MSG_SIZ];
\r
5969 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5970 DisplayError(buf, 0);
\r
5972 if (!appData.showThinking) ToggleShowThinking();
\r
5973 AnalyzeFileEvent();
\r
5974 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5975 AnalysisPeriodicEvent(1);
\r
5979 case IDM_IcsClient:
\r
5983 case IDM_EditGame:
\r
5988 case IDM_EditPosition:
\r
5989 EditPositionEvent();
\r
5990 SAY("to set up a position type a FEN");
\r
5993 case IDM_Training:
\r
5997 case IDM_ShowGameList:
\r
5998 ShowGameListProc();
\r
6001 case IDM_EditTags:
\r
6005 case IDM_EditComment:
\r
6006 if (commentDialogUp && editComment) {
\r
6009 EditCommentEvent();
\r
6029 case IDM_CallFlag:
\r
6049 case IDM_StopObserving:
\r
6050 StopObservingEvent();
\r
6053 case IDM_StopExamining:
\r
6054 StopExaminingEvent();
\r
6057 case IDM_TypeInMove:
\r
6058 PopUpMoveDialog('\000');
\r
6061 case IDM_TypeInName:
\r
6062 PopUpNameDialog('\000');
\r
6065 case IDM_Backward:
\r
6067 SetFocus(hwndMain);
\r
6074 SetFocus(hwndMain);
\r
6079 SetFocus(hwndMain);
\r
6084 SetFocus(hwndMain);
\r
6091 case IDM_TruncateGame:
\r
6092 TruncateGameEvent();
\r
6099 case IDM_RetractMove:
\r
6100 RetractMoveEvent();
\r
6103 case IDM_FlipView:
\r
6104 flipView = !flipView;
\r
6105 DrawPosition(FALSE, NULL);
\r
6108 case IDM_FlipClock:
\r
6109 flipClock = !flipClock;
\r
6110 DisplayBothClocks();
\r
6111 DrawPosition(FALSE, NULL);
\r
6114 case IDM_GeneralOptions:
\r
6115 GeneralOptionsPopup(hwnd);
\r
6116 DrawPosition(TRUE, NULL);
\r
6119 case IDM_BoardOptions:
\r
6120 BoardOptionsPopup(hwnd);
\r
6123 case IDM_EnginePlayOptions:
\r
6124 EnginePlayOptionsPopup(hwnd);
\r
6127 case IDM_OptionsUCI:
\r
6128 UciOptionsPopup(hwnd);
\r
6131 case IDM_IcsOptions:
\r
6132 IcsOptionsPopup(hwnd);
\r
6136 FontsOptionsPopup(hwnd);
\r
6140 SoundOptionsPopup(hwnd);
\r
6143 case IDM_CommPort:
\r
6144 CommPortOptionsPopup(hwnd);
\r
6147 case IDM_LoadOptions:
\r
6148 LoadOptionsPopup(hwnd);
\r
6151 case IDM_SaveOptions:
\r
6152 SaveOptionsPopup(hwnd);
\r
6155 case IDM_TimeControl:
\r
6156 TimeControlOptionsPopup(hwnd);
\r
6159 case IDM_SaveSettings:
\r
6160 SaveSettings(settingsFileName);
\r
6163 case IDM_SaveSettingsOnExit:
\r
6164 saveSettingsOnExit = !saveSettingsOnExit;
\r
6165 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6166 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6167 MF_CHECKED : MF_UNCHECKED));
\r
6178 case IDM_AboutGame:
\r
6183 appData.debugMode = !appData.debugMode;
\r
6184 if (appData.debugMode) {
\r
6185 char dir[MSG_SIZ];
\r
6186 GetCurrentDirectory(MSG_SIZ, dir);
\r
6187 SetCurrentDirectory(installDir);
\r
6188 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6189 SetCurrentDirectory(dir);
\r
6190 setbuf(debugFP, NULL);
\r
6197 case IDM_HELPCONTENTS:
\r
6198 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6199 !HtmlHelp(hwnd, "winboard.chm", 0, NULL) ) {
\r
6200 MessageBox (GetFocus(),
\r
6201 "Unable to activate help",
\r
6202 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6206 case IDM_HELPSEARCH:
\r
6207 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6208 !HtmlHelp(hwnd, "winboard.chm", 0, NULL) ) {
\r
6209 MessageBox (GetFocus(),
\r
6210 "Unable to activate help",
\r
6211 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6215 case IDM_HELPHELP:
\r
6216 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6217 MessageBox (GetFocus(),
\r
6218 "Unable to activate help",
\r
6219 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6224 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6226 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6227 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6228 FreeProcInstance(lpProc);
\r
6231 case IDM_DirectCommand1:
\r
6232 AskQuestionEvent("Direct Command",
\r
6233 "Send to chess program:", "", "1");
\r
6235 case IDM_DirectCommand2:
\r
6236 AskQuestionEvent("Direct Command",
\r
6237 "Send to second chess program:", "", "2");
\r
6240 case EP_WhitePawn:
\r
6241 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6242 fromX = fromY = -1;
\r
6245 case EP_WhiteKnight:
\r
6246 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6247 fromX = fromY = -1;
\r
6250 case EP_WhiteBishop:
\r
6251 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6252 fromX = fromY = -1;
\r
6255 case EP_WhiteRook:
\r
6256 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6257 fromX = fromY = -1;
\r
6260 case EP_WhiteQueen:
\r
6261 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6262 fromX = fromY = -1;
\r
6265 case EP_WhiteFerz:
\r
6266 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6267 fromX = fromY = -1;
\r
6270 case EP_WhiteWazir:
\r
6271 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6272 fromX = fromY = -1;
\r
6275 case EP_WhiteAlfil:
\r
6276 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6277 fromX = fromY = -1;
\r
6280 case EP_WhiteCannon:
\r
6281 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6282 fromX = fromY = -1;
\r
6285 case EP_WhiteCardinal:
\r
6286 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6287 fromX = fromY = -1;
\r
6290 case EP_WhiteMarshall:
\r
6291 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6292 fromX = fromY = -1;
\r
6295 case EP_WhiteKing:
\r
6296 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6297 fromX = fromY = -1;
\r
6300 case EP_BlackPawn:
\r
6301 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6302 fromX = fromY = -1;
\r
6305 case EP_BlackKnight:
\r
6306 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6307 fromX = fromY = -1;
\r
6310 case EP_BlackBishop:
\r
6311 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6312 fromX = fromY = -1;
\r
6315 case EP_BlackRook:
\r
6316 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6317 fromX = fromY = -1;
\r
6320 case EP_BlackQueen:
\r
6321 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6322 fromX = fromY = -1;
\r
6325 case EP_BlackFerz:
\r
6326 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6327 fromX = fromY = -1;
\r
6330 case EP_BlackWazir:
\r
6331 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6332 fromX = fromY = -1;
\r
6335 case EP_BlackAlfil:
\r
6336 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6337 fromX = fromY = -1;
\r
6340 case EP_BlackCannon:
\r
6341 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6342 fromX = fromY = -1;
\r
6345 case EP_BlackCardinal:
\r
6346 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6347 fromX = fromY = -1;
\r
6350 case EP_BlackMarshall:
\r
6351 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6352 fromX = fromY = -1;
\r
6355 case EP_BlackKing:
\r
6356 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6357 fromX = fromY = -1;
\r
6360 case EP_EmptySquare:
\r
6361 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6362 fromX = fromY = -1;
\r
6365 case EP_ClearBoard:
\r
6366 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6367 fromX = fromY = -1;
\r
6371 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6372 fromX = fromY = -1;
\r
6376 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6377 fromX = fromY = -1;
\r
6381 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6382 fromX = fromY = -1;
\r
6386 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6387 fromX = fromY = -1;
\r
6391 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6392 fromX = fromY = -1;
\r
6396 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6397 fromX = fromY = -1;
\r
6401 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6402 fromX = fromY = -1;
\r
6406 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6407 fromX = fromY = -1;
\r
6411 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6412 fromX = fromY = -1;
\r
6416 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6422 case CLOCK_TIMER_ID:
\r
6423 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6424 clockTimerEvent = 0;
\r
6425 DecrementClocks(); /* call into back end */
\r
6427 case LOAD_GAME_TIMER_ID:
\r
6428 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6429 loadGameTimerEvent = 0;
\r
6430 AutoPlayGameLoop(); /* call into back end */
\r
6432 case ANALYSIS_TIMER_ID:
\r
6433 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6434 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6435 AnalysisPeriodicEvent(0);
\r
6437 KillTimer(hwnd, analysisTimerEvent);
\r
6438 analysisTimerEvent = 0;
\r
6441 case DELAYED_TIMER_ID:
\r
6442 KillTimer(hwnd, delayedTimerEvent);
\r
6443 delayedTimerEvent = 0;
\r
6444 delayedTimerCallback();
\r
6449 case WM_USER_Input:
\r
6450 InputEvent(hwnd, message, wParam, lParam);
\r
6453 /* [AS] Also move "attached" child windows */
\r
6454 case WM_WINDOWPOSCHANGING:
\r
6456 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6457 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6459 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6460 /* Window is moving */
\r
6463 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6464 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6465 rcMain.right = boardX + winWidth;
\r
6466 rcMain.top = boardY;
\r
6467 rcMain.bottom = boardY + winHeight;
\r
6469 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6470 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6471 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6472 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6473 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6480 /* [AS] Snapping */
\r
6481 case WM_ENTERSIZEMOVE:
\r
6482 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6483 if (hwnd == hwndMain) {
\r
6484 doingSizing = TRUE;
\r
6487 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6491 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6492 if (hwnd == hwndMain) {
\r
6493 lastSizing = wParam;
\r
6498 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6499 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6501 case WM_EXITSIZEMOVE:
\r
6502 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6503 if (hwnd == hwndMain) {
\r
6505 doingSizing = FALSE;
\r
6506 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6507 GetClientRect(hwnd, &client);
\r
6508 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6510 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6512 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6515 case WM_DESTROY: /* message: window being destroyed */
\r
6516 PostQuitMessage(0);
\r
6520 if (hwnd == hwndMain) {
\r
6525 default: /* Passes it on if unprocessed */
\r
6526 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6531 /*---------------------------------------------------------------------------*\
\r
6533 * Misc utility routines
\r
6535 \*---------------------------------------------------------------------------*/
\r
6538 * Decent random number generator, at least not as bad as Windows
\r
6539 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6541 unsigned int randstate;
\r
6546 randstate = randstate * 1664525 + 1013904223;
\r
6547 return (int) randstate & 0x7fffffff;
\r
6551 mysrandom(unsigned int seed)
\r
6558 * returns TRUE if user selects a different color, FALSE otherwise
\r
6562 ChangeColor(HWND hwnd, COLORREF *which)
\r
6564 static BOOL firstTime = TRUE;
\r
6565 static DWORD customColors[16];
\r
6567 COLORREF newcolor;
\r
6572 /* Make initial colors in use available as custom colors */
\r
6573 /* Should we put the compiled-in defaults here instead? */
\r
6575 customColors[i++] = lightSquareColor & 0xffffff;
\r
6576 customColors[i++] = darkSquareColor & 0xffffff;
\r
6577 customColors[i++] = whitePieceColor & 0xffffff;
\r
6578 customColors[i++] = blackPieceColor & 0xffffff;
\r
6579 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6580 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6582 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6583 customColors[i++] = textAttribs[ccl].color;
\r
6585 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6586 firstTime = FALSE;
\r
6589 cc.lStructSize = sizeof(cc);
\r
6590 cc.hwndOwner = hwnd;
\r
6591 cc.hInstance = NULL;
\r
6592 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6593 cc.lpCustColors = (LPDWORD) customColors;
\r
6594 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6596 if (!ChooseColor(&cc)) return FALSE;
\r
6598 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6599 if (newcolor == *which) return FALSE;
\r
6600 *which = newcolor;
\r
6604 InitDrawingColors();
\r
6605 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6610 MyLoadSound(MySound *ms)
\r
6616 if (ms->data) free(ms->data);
\r
6619 switch (ms->name[0]) {
\r
6625 /* System sound from Control Panel. Don't preload here. */
\r
6629 if (ms->name[1] == NULLCHAR) {
\r
6630 /* "!" alone = silence */
\r
6633 /* Builtin wave resource. Error if not found. */
\r
6634 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6635 if (h == NULL) break;
\r
6636 ms->data = (void *)LoadResource(hInst, h);
\r
6637 if (h == NULL) break;
\r
6642 /* .wav file. Error if not found. */
\r
6643 f = fopen(ms->name, "rb");
\r
6644 if (f == NULL) break;
\r
6645 if (fstat(fileno(f), &st) < 0) break;
\r
6646 ms->data = malloc(st.st_size);
\r
6647 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6653 char buf[MSG_SIZ];
\r
6654 sprintf(buf, "Error loading sound %s", ms->name);
\r
6655 DisplayError(buf, GetLastError());
\r
6661 MyPlaySound(MySound *ms)
\r
6663 BOOLEAN ok = FALSE;
\r
6664 if(appData.debugMode) fprintf(debugFP, "make sound %s %x %d\n", ms->name, ms, ms->name[0]);
\r
6665 switch (ms->name[0]) {
\r
6667 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6672 /* System sound from Control Panel (deprecated feature).
\r
6673 "$" alone or an unset sound name gets default beep (still in use). */
\r
6674 if (ms->name[1]) {
\r
6675 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6677 if (!ok) ok = MessageBeep(MB_OK);
\r
6680 /* Builtin wave resource, or "!" alone for silence */
\r
6681 if (ms->name[1]) {
\r
6682 if (ms->data == NULL) return FALSE;
\r
6683 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6689 /* .wav file. Error if not found. */
\r
6690 if (ms->data == NULL) return FALSE;
\r
6691 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6694 /* Don't print an error: this can happen innocently if the sound driver
\r
6695 is busy; for instance, if another instance of WinBoard is playing
\r
6696 a sound at about the same time. */
\r
6699 char buf[MSG_SIZ];
\r
6700 sprintf(buf, "Error playing sound %s", ms->name);
\r
6701 DisplayError(buf, GetLastError());
\r
6709 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6712 OPENFILENAME *ofn;
\r
6713 static UINT *number; /* gross that this is static */
\r
6715 switch (message) {
\r
6716 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6717 /* Center the dialog over the application window */
\r
6718 ofn = (OPENFILENAME *) lParam;
\r
6719 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6720 number = (UINT *) ofn->lCustData;
\r
6721 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6725 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6726 return FALSE; /* Allow for further processing */
\r
6729 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6730 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6732 return FALSE; /* Allow for further processing */
\r
6738 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6740 static UINT *number;
\r
6741 OPENFILENAME *ofname;
\r
6744 case WM_INITDIALOG:
\r
6745 ofname = (OPENFILENAME *)lParam;
\r
6746 number = (UINT *)(ofname->lCustData);
\r
6749 ofnot = (OFNOTIFY *)lParam;
\r
6750 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6751 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6760 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6761 char *nameFilt, char *dlgTitle, UINT *number,
\r
6762 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6764 OPENFILENAME openFileName;
\r
6765 char buf1[MSG_SIZ];
\r
6768 if (fileName == NULL) fileName = buf1;
\r
6769 if (defName == NULL) {
\r
6770 strcpy(fileName, "*.");
\r
6771 strcat(fileName, defExt);
\r
6773 strcpy(fileName, defName);
\r
6775 if (fileTitle) strcpy(fileTitle, "");
\r
6776 if (number) *number = 0;
\r
6778 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6779 openFileName.hwndOwner = hwnd;
\r
6780 openFileName.hInstance = (HANDLE) hInst;
\r
6781 openFileName.lpstrFilter = nameFilt;
\r
6782 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6783 openFileName.nMaxCustFilter = 0L;
\r
6784 openFileName.nFilterIndex = 1L;
\r
6785 openFileName.lpstrFile = fileName;
\r
6786 openFileName.nMaxFile = MSG_SIZ;
\r
6787 openFileName.lpstrFileTitle = fileTitle;
\r
6788 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6789 openFileName.lpstrInitialDir = NULL;
\r
6790 openFileName.lpstrTitle = dlgTitle;
\r
6791 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6792 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6793 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6794 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6795 openFileName.nFileOffset = 0;
\r
6796 openFileName.nFileExtension = 0;
\r
6797 openFileName.lpstrDefExt = defExt;
\r
6798 openFileName.lCustData = (LONG) number;
\r
6799 openFileName.lpfnHook = oldDialog ?
\r
6800 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6801 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6803 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6804 GetOpenFileName(&openFileName)) {
\r
6805 /* open the file */
\r
6806 f = fopen(openFileName.lpstrFile, write);
\r
6808 MessageBox(hwnd, "File open failed", NULL,
\r
6809 MB_OK|MB_ICONEXCLAMATION);
\r
6813 int err = CommDlgExtendedError();
\r
6814 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6823 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6825 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6828 * Get the first pop-up menu in the menu template. This is the
\r
6829 * menu that TrackPopupMenu displays.
\r
6831 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6833 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6836 * TrackPopup uses screen coordinates, so convert the
\r
6837 * coordinates of the mouse click to screen coordinates.
\r
6839 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6841 /* Draw and track the floating pop-up menu. */
\r
6842 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6843 pt.x, pt.y, 0, hwnd, NULL);
\r
6845 /* Destroy the menu.*/
\r
6846 DestroyMenu(hmenu);
\r
6851 int sizeX, sizeY, newSizeX, newSizeY;
\r
6853 } ResizeEditPlusButtonsClosure;
\r
6856 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6858 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6862 if (hChild == cl->hText) return TRUE;
\r
6863 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6864 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6865 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6866 ScreenToClient(cl->hDlg, &pt);
\r
6867 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6868 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6872 /* Resize a dialog that has a (rich) edit field filling most of
\r
6873 the top, with a row of buttons below */
\r
6875 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6878 int newTextHeight, newTextWidth;
\r
6879 ResizeEditPlusButtonsClosure cl;
\r
6881 /*if (IsIconic(hDlg)) return;*/
\r
6882 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6884 cl.hdwp = BeginDeferWindowPos(8);
\r
6886 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6887 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6888 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6889 if (newTextHeight < 0) {
\r
6890 newSizeY += -newTextHeight;
\r
6891 newTextHeight = 0;
\r
6893 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6894 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6900 cl.newSizeX = newSizeX;
\r
6901 cl.newSizeY = newSizeY;
\r
6902 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6904 EndDeferWindowPos(cl.hdwp);
\r
6907 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6909 RECT rChild, rParent;
\r
6910 int wChild, hChild, wParent, hParent;
\r
6911 int wScreen, hScreen, xNew, yNew;
\r
6914 /* Get the Height and Width of the child window */
\r
6915 GetWindowRect (hwndChild, &rChild);
\r
6916 wChild = rChild.right - rChild.left;
\r
6917 hChild = rChild.bottom - rChild.top;
\r
6919 /* Get the Height and Width of the parent window */
\r
6920 GetWindowRect (hwndParent, &rParent);
\r
6921 wParent = rParent.right - rParent.left;
\r
6922 hParent = rParent.bottom - rParent.top;
\r
6924 /* Get the display limits */
\r
6925 hdc = GetDC (hwndChild);
\r
6926 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6927 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6928 ReleaseDC(hwndChild, hdc);
\r
6930 /* Calculate new X position, then adjust for screen */
\r
6931 xNew = rParent.left + ((wParent - wChild) /2);
\r
6934 } else if ((xNew+wChild) > wScreen) {
\r
6935 xNew = wScreen - wChild;
\r
6938 /* Calculate new Y position, then adjust for screen */
\r
6940 yNew = rParent.top + ((hParent - hChild) /2);
\r
6943 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6948 } else if ((yNew+hChild) > hScreen) {
\r
6949 yNew = hScreen - hChild;
\r
6952 /* Set it, and return */
\r
6953 return SetWindowPos (hwndChild, NULL,
\r
6954 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6957 /* Center one window over another */
\r
6958 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6960 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6963 /*---------------------------------------------------------------------------*\
\r
6965 * Startup Dialog functions
\r
6967 \*---------------------------------------------------------------------------*/
\r
6969 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6971 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6973 while (*cd != NULL) {
\r
6974 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6980 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6982 char buf1[ARG_MAX];
\r
6985 if (str[0] == '@') {
\r
6986 FILE* f = fopen(str + 1, "r");
\r
6988 DisplayFatalError(str + 1, errno, 2);
\r
6991 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6993 buf1[len] = NULLCHAR;
\r
6997 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7000 char buf[MSG_SIZ];
\r
7001 char *end = strchr(str, '\n');
\r
7002 if (end == NULL) return;
\r
7003 memcpy(buf, str, end - str);
\r
7004 buf[end - str] = NULLCHAR;
\r
7005 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7011 SetStartupDialogEnables(HWND hDlg)
\r
7013 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7014 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7015 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7016 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7017 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7018 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7019 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7020 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7021 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7022 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7023 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7024 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7025 IsDlgButtonChecked(hDlg, OPT_View));
\r
7029 QuoteForFilename(char *filename)
\r
7031 int dquote, space;
\r
7032 dquote = strchr(filename, '"') != NULL;
\r
7033 space = strchr(filename, ' ') != NULL;
\r
7034 if (dquote || space) {
\r
7046 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7048 char buf[MSG_SIZ];
\r
7051 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7052 q = QuoteForFilename(nthcp);
\r
7053 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7054 if (*nthdir != NULLCHAR) {
\r
7055 q = QuoteForFilename(nthdir);
\r
7056 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7058 if (*nthcp == NULLCHAR) {
\r
7059 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7060 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7061 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7062 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7067 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7069 char buf[MSG_SIZ];
\r
7073 switch (message) {
\r
7074 case WM_INITDIALOG:
\r
7075 /* Center the dialog */
\r
7076 CenterWindow (hDlg, GetDesktopWindow());
\r
7077 /* Initialize the dialog items */
\r
7078 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7079 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7080 firstChessProgramNames);
\r
7081 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7082 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7083 secondChessProgramNames);
\r
7084 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7085 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7086 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7087 if (*appData.icsHelper != NULLCHAR) {
\r
7088 char *q = QuoteForFilename(appData.icsHelper);
\r
7089 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7091 if (*appData.icsHost == NULLCHAR) {
\r
7092 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7093 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7094 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7095 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7096 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7099 if (appData.icsActive) {
\r
7100 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7102 else if (appData.noChessProgram) {
\r
7103 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7106 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7109 SetStartupDialogEnables(hDlg);
\r
7113 switch (LOWORD(wParam)) {
\r
7115 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7116 strcpy(buf, "/fcp=");
\r
7117 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7119 ParseArgs(StringGet, &p);
\r
7120 strcpy(buf, "/scp=");
\r
7121 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7123 ParseArgs(StringGet, &p);
\r
7124 appData.noChessProgram = FALSE;
\r
7125 appData.icsActive = FALSE;
\r
7126 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7127 strcpy(buf, "/ics /icshost=");
\r
7128 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7130 ParseArgs(StringGet, &p);
\r
7131 if (appData.zippyPlay) {
\r
7132 strcpy(buf, "/fcp=");
\r
7133 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7135 ParseArgs(StringGet, &p);
\r
7137 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7138 appData.noChessProgram = TRUE;
\r
7139 appData.icsActive = FALSE;
\r
7141 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7142 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7145 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7146 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7148 ParseArgs(StringGet, &p);
\r
7150 EndDialog(hDlg, TRUE);
\r
7157 case IDM_HELPCONTENTS:
\r
7158 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7159 MessageBox (GetFocus(),
\r
7160 "Unable to activate help",
\r
7161 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7166 SetStartupDialogEnables(hDlg);
\r
7174 /*---------------------------------------------------------------------------*\
\r
7176 * About box dialog functions
\r
7178 \*---------------------------------------------------------------------------*/
\r
7180 /* Process messages for "About" dialog box */
\r
7182 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7184 switch (message) {
\r
7185 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7186 /* Center the dialog over the application window */
\r
7187 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7188 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7191 case WM_COMMAND: /* message: received a command */
\r
7192 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7193 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7194 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7202 /*---------------------------------------------------------------------------*\
\r
7204 * Comment Dialog functions
\r
7206 \*---------------------------------------------------------------------------*/
\r
7209 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7211 static HANDLE hwndText = NULL;
\r
7212 int len, newSizeX, newSizeY, flags;
\r
7213 static int sizeX, sizeY;
\r
7218 switch (message) {
\r
7219 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7220 /* Initialize the dialog items */
\r
7221 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7222 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7223 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7224 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7225 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7226 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7227 SetWindowText(hDlg, commentTitle);
\r
7228 if (editComment) {
\r
7229 SetFocus(hwndText);
\r
7231 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7233 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7234 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7235 MAKELPARAM(FALSE, 0));
\r
7236 /* Size and position the dialog */
\r
7237 if (!commentDialog) {
\r
7238 commentDialog = hDlg;
\r
7239 flags = SWP_NOZORDER;
\r
7240 GetClientRect(hDlg, &rect);
\r
7241 sizeX = rect.right;
\r
7242 sizeY = rect.bottom;
\r
7243 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7244 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7245 WINDOWPLACEMENT wp;
\r
7246 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7247 wp.length = sizeof(WINDOWPLACEMENT);
\r
7249 wp.showCmd = SW_SHOW;
\r
7250 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7251 wp.rcNormalPosition.left = commentX;
\r
7252 wp.rcNormalPosition.right = commentX + commentW;
\r
7253 wp.rcNormalPosition.top = commentY;
\r
7254 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7255 SetWindowPlacement(hDlg, &wp);
\r
7257 GetClientRect(hDlg, &rect);
\r
7258 newSizeX = rect.right;
\r
7259 newSizeY = rect.bottom;
\r
7260 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7261 newSizeX, newSizeY);
\r
7268 case WM_COMMAND: /* message: received a command */
\r
7269 switch (LOWORD(wParam)) {
\r
7271 if (editComment) {
\r
7273 /* Read changed options from the dialog box */
\r
7274 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7275 len = GetWindowTextLength(hwndText);
\r
7276 str = (char *) malloc(len + 1);
\r
7277 GetWindowText(hwndText, str, len + 1);
\r
7286 ReplaceComment(commentIndex, str);
\r
7293 case OPT_CancelComment:
\r
7297 case OPT_ClearComment:
\r
7298 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7301 case OPT_EditComment:
\r
7302 EditCommentEvent();
\r
7311 newSizeX = LOWORD(lParam);
\r
7312 newSizeY = HIWORD(lParam);
\r
7313 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7318 case WM_GETMINMAXINFO:
\r
7319 /* Prevent resizing window too small */
\r
7320 mmi = (MINMAXINFO *) lParam;
\r
7321 mmi->ptMinTrackSize.x = 100;
\r
7322 mmi->ptMinTrackSize.y = 100;
\r
7329 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7334 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7336 if (str == NULL) str = "";
\r
7337 p = (char *) malloc(2 * strlen(str) + 2);
\r
7340 if (*str == '\n') *q++ = '\r';
\r
7344 if (commentText != NULL) free(commentText);
\r
7346 commentIndex = index;
\r
7347 commentTitle = title;
\r
7349 editComment = edit;
\r
7351 if (commentDialog) {
\r
7352 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7353 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7355 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7356 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7357 hwndMain, (DLGPROC)lpProc);
\r
7358 FreeProcInstance(lpProc);
\r
7360 commentDialogUp = TRUE;
\r
7364 /*---------------------------------------------------------------------------*\
\r
7366 * Type-in move dialog functions
\r
7368 \*---------------------------------------------------------------------------*/
\r
7371 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7373 char move[MSG_SIZ];
\r
7375 ChessMove moveType;
\r
7376 int fromX, fromY, toX, toY;
\r
7379 switch (message) {
\r
7380 case WM_INITDIALOG:
\r
7381 move[0] = (char) lParam;
\r
7382 move[1] = NULLCHAR;
\r
7383 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7384 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7385 SetWindowText(hInput, move);
\r
7387 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7391 switch (LOWORD(wParam)) {
\r
7393 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7394 { int n; Board board;
\r
7396 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7397 EditPositionPasteFEN(move);
\r
7398 EndDialog(hDlg, TRUE);
\r
7401 // [HGM] movenum: allow move number to be typed in any mode
\r
7402 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7403 currentMove = 2*n-1;
\r
7404 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7405 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7406 EndDialog(hDlg, TRUE);
\r
7407 DrawPosition(TRUE, boards[currentMove]);
\r
7408 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7409 else DisplayMessage("", "");
\r
7413 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7414 gameMode != Training) {
\r
7415 DisplayMoveError("Displayed move is not current");
\r
7417 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7418 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7419 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7420 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7421 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7422 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7423 if (gameMode != Training)
\r
7424 forwardMostMove = currentMove;
\r
7425 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7427 DisplayMoveError("Could not parse move");
\r
7430 EndDialog(hDlg, TRUE);
\r
7433 EndDialog(hDlg, FALSE);
\r
7444 PopUpMoveDialog(char firstchar)
\r
7448 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7449 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7450 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7451 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7452 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7453 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7454 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7455 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7456 gameMode == Training) {
\r
7457 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7458 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7459 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7460 FreeProcInstance(lpProc);
\r
7464 /*---------------------------------------------------------------------------*\
\r
7466 * Type-in name dialog functions
\r
7468 \*---------------------------------------------------------------------------*/
\r
7471 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7473 char move[MSG_SIZ];
\r
7476 switch (message) {
\r
7477 case WM_INITDIALOG:
\r
7478 move[0] = (char) lParam;
\r
7479 move[1] = NULLCHAR;
\r
7480 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7481 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7482 SetWindowText(hInput, move);
\r
7484 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7488 switch (LOWORD(wParam)) {
\r
7490 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7491 appData.userName = strdup(move);
\r
7494 EndDialog(hDlg, TRUE);
\r
7497 EndDialog(hDlg, FALSE);
\r
7508 PopUpNameDialog(char firstchar)
\r
7512 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7513 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7514 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7515 FreeProcInstance(lpProc);
\r
7518 /*---------------------------------------------------------------------------*\
\r
7522 \*---------------------------------------------------------------------------*/
\r
7524 /* Nonmodal error box */
\r
7525 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7526 WPARAM wParam, LPARAM lParam);
\r
7529 ErrorPopUp(char *title, char *content)
\r
7533 BOOLEAN modal = hwndMain == NULL;
\r
7551 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7552 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7555 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7557 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7558 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7559 hwndMain, (DLGPROC)lpProc);
\r
7560 FreeProcInstance(lpProc);
\r
7567 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7568 if (errorDialog == NULL) return;
\r
7569 DestroyWindow(errorDialog);
\r
7570 errorDialog = NULL;
\r
7574 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7579 switch (message) {
\r
7580 case WM_INITDIALOG:
\r
7581 GetWindowRect(hDlg, &rChild);
\r
7584 SetWindowPos(hDlg, NULL, rChild.left,
\r
7585 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7586 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7590 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7591 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7592 and it doesn't work when you resize the dialog.
\r
7593 For now, just give it a default position.
\r
7595 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7597 errorDialog = hDlg;
\r
7598 SetWindowText(hDlg, errorTitle);
\r
7599 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7600 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7604 switch (LOWORD(wParam)) {
\r
7607 if (errorDialog == hDlg) errorDialog = NULL;
\r
7608 DestroyWindow(hDlg);
\r
7620 HWND gothicDialog = NULL;
\r
7623 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7627 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7629 switch (message) {
\r
7630 case WM_INITDIALOG:
\r
7631 GetWindowRect(hDlg, &rChild);
\r
7633 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7637 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7638 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7639 and it doesn't work when you resize the dialog.
\r
7640 For now, just give it a default position.
\r
7642 gothicDialog = hDlg;
\r
7643 SetWindowText(hDlg, errorTitle);
\r
7644 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7645 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7649 switch (LOWORD(wParam)) {
\r
7652 if (errorDialog == hDlg) errorDialog = NULL;
\r
7653 DestroyWindow(hDlg);
\r
7665 GothicPopUp(char *title, VariantClass variant)
\r
7668 static char *lastTitle;
\r
7670 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7671 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7673 if(lastTitle != title && gothicDialog != NULL) {
\r
7674 DestroyWindow(gothicDialog);
\r
7675 gothicDialog = NULL;
\r
7677 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7678 title = lastTitle;
\r
7679 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7680 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7681 hwndMain, (DLGPROC)lpProc);
\r
7682 FreeProcInstance(lpProc);
\r
7687 /*---------------------------------------------------------------------------*\
\r
7689 * Ics Interaction console functions
\r
7691 \*---------------------------------------------------------------------------*/
\r
7693 #define HISTORY_SIZE 64
\r
7694 static char *history[HISTORY_SIZE];
\r
7695 int histIn = 0, histP = 0;
\r
7698 SaveInHistory(char *cmd)
\r
7700 if (history[histIn] != NULL) {
\r
7701 free(history[histIn]);
\r
7702 history[histIn] = NULL;
\r
7704 if (*cmd == NULLCHAR) return;
\r
7705 history[histIn] = StrSave(cmd);
\r
7706 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7707 if (history[histIn] != NULL) {
\r
7708 free(history[histIn]);
\r
7709 history[histIn] = NULL;
\r
7715 PrevInHistory(char *cmd)
\r
7718 if (histP == histIn) {
\r
7719 if (history[histIn] != NULL) free(history[histIn]);
\r
7720 history[histIn] = StrSave(cmd);
\r
7722 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7723 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7725 return history[histP];
\r
7731 if (histP == histIn) return NULL;
\r
7732 histP = (histP + 1) % HISTORY_SIZE;
\r
7733 return history[histP];
\r
7740 BOOLEAN immediate;
\r
7741 } IcsTextMenuEntry;
\r
7742 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7743 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7746 ParseIcsTextMenu(char *icsTextMenuString)
\r
7749 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7750 char *p = icsTextMenuString;
\r
7751 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7754 if (e->command != NULL) {
\r
7756 e->command = NULL;
\r
7760 e = icsTextMenuEntry;
\r
7761 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7762 if (*p == ';' || *p == '\n') {
\r
7763 e->item = strdup("-");
\r
7764 e->command = NULL;
\r
7766 } else if (*p == '-') {
\r
7767 e->item = strdup("-");
\r
7768 e->command = NULL;
\r
7772 char *q, *r, *s, *t;
\r
7774 q = strchr(p, ',');
\r
7775 if (q == NULL) break;
\r
7777 r = strchr(q + 1, ',');
\r
7778 if (r == NULL) break;
\r
7780 s = strchr(r + 1, ',');
\r
7781 if (s == NULL) break;
\r
7784 t = strchr(s + 1, c);
\r
7787 t = strchr(s + 1, c);
\r
7789 if (t != NULL) *t = NULLCHAR;
\r
7790 e->item = strdup(p);
\r
7791 e->command = strdup(q + 1);
\r
7792 e->getname = *(r + 1) != '0';
\r
7793 e->immediate = *(s + 1) != '0';
\r
7797 if (t == NULL) break;
\r
7806 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7810 hmenu = LoadMenu(hInst, "TextMenu");
\r
7811 h = GetSubMenu(hmenu, 0);
\r
7813 if (strcmp(e->item, "-") == 0) {
\r
7814 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7816 if (e->item[0] == '|') {
\r
7817 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7818 IDM_CommandX + i, &e->item[1]);
\r
7820 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7829 WNDPROC consoleTextWindowProc;
\r
7832 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7834 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7835 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7839 SetWindowText(hInput, command);
\r
7841 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7843 sel.cpMin = 999999;
\r
7844 sel.cpMax = 999999;
\r
7845 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7850 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7851 if (sel.cpMin == sel.cpMax) {
\r
7852 /* Expand to surrounding word */
\r
7855 tr.chrg.cpMax = sel.cpMin;
\r
7856 tr.chrg.cpMin = --sel.cpMin;
\r
7857 if (sel.cpMin < 0) break;
\r
7858 tr.lpstrText = name;
\r
7859 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7860 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7864 tr.chrg.cpMin = sel.cpMax;
\r
7865 tr.chrg.cpMax = ++sel.cpMax;
\r
7866 tr.lpstrText = name;
\r
7867 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7868 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7871 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7872 MessageBeep(MB_ICONEXCLAMATION);
\r
7876 tr.lpstrText = name;
\r
7877 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7879 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7880 MessageBeep(MB_ICONEXCLAMATION);
\r
7883 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7886 sprintf(buf, "%s %s", command, name);
\r
7887 SetWindowText(hInput, buf);
\r
7888 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7890 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7891 SetWindowText(hInput, buf);
\r
7892 sel.cpMin = 999999;
\r
7893 sel.cpMax = 999999;
\r
7894 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7900 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7905 switch (message) {
\r
7907 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7910 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7913 sel.cpMin = 999999;
\r
7914 sel.cpMax = 999999;
\r
7915 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7916 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7921 if(wParam != '\022') {
\r
7922 if (wParam == '\t') {
\r
7923 if (GetKeyState(VK_SHIFT) < 0) {
\r
7925 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7926 if (buttonDesc[0].hwnd) {
\r
7927 SetFocus(buttonDesc[0].hwnd);
\r
7929 SetFocus(hwndMain);
\r
7933 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7936 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7937 JAWS_DELETE( SetFocus(hInput); )
\r
7938 SendMessage(hInput, message, wParam, lParam);
\r
7941 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7942 case WM_RBUTTONUP:
\r
7943 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7944 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7945 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7948 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7949 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7950 if (sel.cpMin == sel.cpMax) {
\r
7951 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7952 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7954 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7955 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7957 pt.x = LOWORD(lParam);
\r
7958 pt.y = HIWORD(lParam);
\r
7959 MenuPopup(hwnd, pt, hmenu, -1);
\r
7963 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7965 return SendMessage(hInput, message, wParam, lParam);
\r
7966 case WM_MBUTTONDOWN:
\r
7967 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7968 case WM_RBUTTONDOWN:
\r
7969 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7970 /* Move selection here if it was empty */
\r
7972 pt.x = LOWORD(lParam);
\r
7973 pt.y = HIWORD(lParam);
\r
7974 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7975 if (sel.cpMin == sel.cpMax) {
\r
7976 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7977 sel.cpMax = sel.cpMin;
\r
7978 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7980 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7984 switch (LOWORD(wParam)) {
\r
7985 case IDM_QuickPaste:
\r
7987 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7988 if (sel.cpMin == sel.cpMax) {
\r
7989 MessageBeep(MB_ICONEXCLAMATION);
\r
7992 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7993 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7994 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7999 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8002 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8005 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8009 int i = LOWORD(wParam) - IDM_CommandX;
\r
8010 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8011 icsTextMenuEntry[i].command != NULL) {
\r
8012 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8013 icsTextMenuEntry[i].getname,
\r
8014 icsTextMenuEntry[i].immediate);
\r
8022 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8025 WNDPROC consoleInputWindowProc;
\r
8028 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8030 char buf[MSG_SIZ];
\r
8032 static BOOL sendNextChar = FALSE;
\r
8033 static BOOL quoteNextChar = FALSE;
\r
8034 InputSource *is = consoleInputSource;
\r
8038 switch (message) {
\r
8040 if (!appData.localLineEditing || sendNextChar) {
\r
8041 is->buf[0] = (CHAR) wParam;
\r
8043 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8044 sendNextChar = FALSE;
\r
8047 if (quoteNextChar) {
\r
8048 buf[0] = (char) wParam;
\r
8049 buf[1] = NULLCHAR;
\r
8050 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8051 quoteNextChar = FALSE;
\r
8055 case '\r': /* Enter key */
\r
8056 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8057 if (consoleEcho) SaveInHistory(is->buf);
\r
8058 is->buf[is->count++] = '\n';
\r
8059 is->buf[is->count] = NULLCHAR;
\r
8060 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8061 if (consoleEcho) {
\r
8062 ConsoleOutput(is->buf, is->count, TRUE);
\r
8063 } else if (appData.localLineEditing) {
\r
8064 ConsoleOutput("\n", 1, TRUE);
\r
8067 case '\033': /* Escape key */
\r
8068 SetWindowText(hwnd, "");
\r
8069 cf.cbSize = sizeof(CHARFORMAT);
\r
8070 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8071 if (consoleEcho) {
\r
8072 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8074 cf.crTextColor = COLOR_ECHOOFF;
\r
8076 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8077 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8079 case '\t': /* Tab key */
\r
8080 if (GetKeyState(VK_SHIFT) < 0) {
\r
8082 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8085 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8086 if (buttonDesc[0].hwnd) {
\r
8087 SetFocus(buttonDesc[0].hwnd);
\r
8089 SetFocus(hwndMain);
\r
8093 case '\023': /* Ctrl+S */
\r
8094 sendNextChar = TRUE;
\r
8096 case '\021': /* Ctrl+Q */
\r
8097 quoteNextChar = TRUE;
\r
8107 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8108 p = PrevInHistory(buf);
\r
8110 SetWindowText(hwnd, p);
\r
8111 sel.cpMin = 999999;
\r
8112 sel.cpMax = 999999;
\r
8113 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8118 p = NextInHistory();
\r
8120 SetWindowText(hwnd, p);
\r
8121 sel.cpMin = 999999;
\r
8122 sel.cpMax = 999999;
\r
8123 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8129 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8133 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8137 case WM_MBUTTONDOWN:
\r
8138 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8139 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8141 case WM_RBUTTONUP:
\r
8142 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8143 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8144 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8148 hmenu = LoadMenu(hInst, "InputMenu");
\r
8149 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8150 if (sel.cpMin == sel.cpMax) {
\r
8151 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8152 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8154 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8155 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8157 pt.x = LOWORD(lParam);
\r
8158 pt.y = HIWORD(lParam);
\r
8159 MenuPopup(hwnd, pt, hmenu, -1);
\r
8163 switch (LOWORD(wParam)) {
\r
8165 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8167 case IDM_SelectAll:
\r
8169 sel.cpMax = -1; /*999999?*/
\r
8170 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8173 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8176 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8179 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8184 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8187 #define CO_MAX 100000
\r
8188 #define CO_TRIM 1000
\r
8191 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8193 static SnapData sd;
\r
8194 static HWND hText, hInput /*, hFocus*/;
\r
8195 // InputSource *is = consoleInputSource;
\r
8197 static int sizeX, sizeY;
\r
8198 int newSizeX, newSizeY;
\r
8201 switch (message) {
\r
8202 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8203 hwndConsole = hDlg;
\r
8204 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8205 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8207 consoleTextWindowProc = (WNDPROC)
\r
8208 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8209 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8210 consoleInputWindowProc = (WNDPROC)
\r
8211 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8212 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8213 Colorize(ColorNormal, TRUE);
\r
8214 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8215 ChangedConsoleFont();
\r
8216 GetClientRect(hDlg, &rect);
\r
8217 sizeX = rect.right;
\r
8218 sizeY = rect.bottom;
\r
8219 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8220 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8221 WINDOWPLACEMENT wp;
\r
8222 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8223 wp.length = sizeof(WINDOWPLACEMENT);
\r
8225 wp.showCmd = SW_SHOW;
\r
8226 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8227 wp.rcNormalPosition.left = wpConsole.x;
\r
8228 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8229 wp.rcNormalPosition.top = wpConsole.y;
\r
8230 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8231 SetWindowPlacement(hDlg, &wp);
\r
8234 // [HGM] Chessknight's change 2004-07-13
\r
8235 else { /* Determine Defaults */
\r
8236 WINDOWPLACEMENT wp;
\r
8237 wpConsole.x = winWidth + 1;
\r
8238 wpConsole.y = boardY;
\r
8239 wpConsole.width = screenWidth - winWidth;
\r
8240 wpConsole.height = winHeight;
\r
8241 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8242 wp.length = sizeof(WINDOWPLACEMENT);
\r
8244 wp.showCmd = SW_SHOW;
\r
8245 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8246 wp.rcNormalPosition.left = wpConsole.x;
\r
8247 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8248 wp.rcNormalPosition.top = wpConsole.y;
\r
8249 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8250 SetWindowPlacement(hDlg, &wp);
\r
8265 if (IsIconic(hDlg)) break;
\r
8266 newSizeX = LOWORD(lParam);
\r
8267 newSizeY = HIWORD(lParam);
\r
8268 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8269 RECT rectText, rectInput;
\r
8271 int newTextHeight, newTextWidth;
\r
8272 GetWindowRect(hText, &rectText);
\r
8273 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8274 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8275 if (newTextHeight < 0) {
\r
8276 newSizeY += -newTextHeight;
\r
8277 newTextHeight = 0;
\r
8279 SetWindowPos(hText, NULL, 0, 0,
\r
8280 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8281 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8282 pt.x = rectInput.left;
\r
8283 pt.y = rectInput.top + newSizeY - sizeY;
\r
8284 ScreenToClient(hDlg, &pt);
\r
8285 SetWindowPos(hInput, NULL,
\r
8286 pt.x, pt.y, /* needs client coords */
\r
8287 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8288 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8294 case WM_GETMINMAXINFO:
\r
8295 /* Prevent resizing window too small */
\r
8296 mmi = (MINMAXINFO *) lParam;
\r
8297 mmi->ptMinTrackSize.x = 100;
\r
8298 mmi->ptMinTrackSize.y = 100;
\r
8301 /* [AS] Snapping */
\r
8302 case WM_ENTERSIZEMOVE:
\r
8303 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8306 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8309 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8311 case WM_EXITSIZEMOVE:
\r
8312 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8315 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8323 if (hwndConsole) return;
\r
8324 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8325 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8330 ConsoleOutput(char* data, int length, int forceVisible)
\r
8335 char buf[CO_MAX+1];
\r
8338 static int delayLF = 0;
\r
8339 CHARRANGE savesel, sel;
\r
8341 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8349 while (length--) {
\r
8357 } else if (*p == '\007') {
\r
8358 MyPlaySound(&sounds[(int)SoundBell]);
\r
8365 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8366 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8367 /* Save current selection */
\r
8368 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8369 exlen = GetWindowTextLength(hText);
\r
8370 /* Find out whether current end of text is visible */
\r
8371 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8372 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8373 /* Trim existing text if it's too long */
\r
8374 if (exlen + (q - buf) > CO_MAX) {
\r
8375 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8378 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8379 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8381 savesel.cpMin -= trim;
\r
8382 savesel.cpMax -= trim;
\r
8383 if (exlen < 0) exlen = 0;
\r
8384 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8385 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8387 /* Append the new text */
\r
8388 sel.cpMin = exlen;
\r
8389 sel.cpMax = exlen;
\r
8390 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8391 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8392 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8393 if (forceVisible || exlen == 0 ||
\r
8394 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8395 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8396 /* Scroll to make new end of text visible if old end of text
\r
8397 was visible or new text is an echo of user typein */
\r
8398 sel.cpMin = 9999999;
\r
8399 sel.cpMax = 9999999;
\r
8400 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8401 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8402 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8403 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8405 if (savesel.cpMax == exlen || forceVisible) {
\r
8406 /* Move insert point to new end of text if it was at the old
\r
8407 end of text or if the new text is an echo of user typein */
\r
8408 sel.cpMin = 9999999;
\r
8409 sel.cpMax = 9999999;
\r
8410 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8412 /* Restore previous selection */
\r
8413 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8415 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8422 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8426 COLORREF oldFg, oldBg;
\r
8430 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8432 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8433 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8434 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8437 rect.right = x + squareSize;
\r
8439 rect.bottom = y + squareSize;
\r
8442 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8443 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8444 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8445 &rect, str, strlen(str), NULL);
\r
8447 (void) SetTextColor(hdc, oldFg);
\r
8448 (void) SetBkColor(hdc, oldBg);
\r
8449 (void) SelectObject(hdc, oldFont);
\r
8453 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8454 RECT *rect, char *color, char *flagFell)
\r
8458 COLORREF oldFg, oldBg;
\r
8461 if (appData.clockMode) {
\r
8463 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8465 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8472 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8473 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8475 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8476 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8478 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8482 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8483 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8484 rect, str, strlen(str), NULL);
\r
8485 if(logoHeight > 0 && appData.clockMode) {
\r
8487 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8488 r.top = rect->top + logoHeight/2;
\r
8489 r.left = rect->left;
\r
8490 r.right = rect->right;
\r
8491 r.bottom = rect->bottom;
\r
8492 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8493 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8494 &r, str, strlen(str), NULL);
\r
8496 (void) SetTextColor(hdc, oldFg);
\r
8497 (void) SetBkColor(hdc, oldBg);
\r
8498 (void) SelectObject(hdc, oldFont);
\r
8503 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8509 if( count <= 0 ) {
\r
8510 if (appData.debugMode) {
\r
8511 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8514 return ERROR_INVALID_USER_BUFFER;
\r
8517 ResetEvent(ovl->hEvent);
\r
8518 ovl->Offset = ovl->OffsetHigh = 0;
\r
8519 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8523 err = GetLastError();
\r
8524 if (err == ERROR_IO_PENDING) {
\r
8525 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8529 err = GetLastError();
\r
8536 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8541 ResetEvent(ovl->hEvent);
\r
8542 ovl->Offset = ovl->OffsetHigh = 0;
\r
8543 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8547 err = GetLastError();
\r
8548 if (err == ERROR_IO_PENDING) {
\r
8549 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8553 err = GetLastError();
\r
8559 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8560 void CheckForInputBufferFull( InputSource * is )
\r
8562 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8563 /* Look for end of line */
\r
8564 char * p = is->buf;
\r
8566 while( p < is->next && *p != '\n' ) {
\r
8570 if( p >= is->next ) {
\r
8571 if (appData.debugMode) {
\r
8572 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8575 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8576 is->count = (DWORD) -1;
\r
8577 is->next = is->buf;
\r
8583 InputThread(LPVOID arg)
\r
8588 is = (InputSource *) arg;
\r
8589 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8590 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8591 while (is->hThread != NULL) {
\r
8592 is->error = DoReadFile(is->hFile, is->next,
\r
8593 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8594 &is->count, &ovl);
\r
8595 if (is->error == NO_ERROR) {
\r
8596 is->next += is->count;
\r
8598 if (is->error == ERROR_BROKEN_PIPE) {
\r
8599 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8602 is->count = (DWORD) -1;
\r
8603 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8608 CheckForInputBufferFull( is );
\r
8610 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8612 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8614 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8617 CloseHandle(ovl.hEvent);
\r
8618 CloseHandle(is->hFile);
\r
8620 if (appData.debugMode) {
\r
8621 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8628 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8630 NonOvlInputThread(LPVOID arg)
\r
8637 is = (InputSource *) arg;
\r
8638 while (is->hThread != NULL) {
\r
8639 is->error = ReadFile(is->hFile, is->next,
\r
8640 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8641 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8642 if (is->error == NO_ERROR) {
\r
8643 /* Change CRLF to LF */
\r
8644 if (is->next > is->buf) {
\r
8646 i = is->count + 1;
\r
8654 if (prev == '\r' && *p == '\n') {
\r
8666 if (is->error == ERROR_BROKEN_PIPE) {
\r
8667 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8670 is->count = (DWORD) -1;
\r
8674 CheckForInputBufferFull( is );
\r
8676 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8678 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8680 if (is->count < 0) break; /* Quit on error */
\r
8682 CloseHandle(is->hFile);
\r
8687 SocketInputThread(LPVOID arg)
\r
8691 is = (InputSource *) arg;
\r
8692 while (is->hThread != NULL) {
\r
8693 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8694 if ((int)is->count == SOCKET_ERROR) {
\r
8695 is->count = (DWORD) -1;
\r
8696 is->error = WSAGetLastError();
\r
8698 is->error = NO_ERROR;
\r
8699 is->next += is->count;
\r
8700 if (is->count == 0 && is->second == is) {
\r
8701 /* End of file on stderr; quit with no message */
\r
8705 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8707 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8709 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8715 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8719 is = (InputSource *) lParam;
\r
8720 if (is->lineByLine) {
\r
8721 /* Feed in lines one by one */
\r
8722 char *p = is->buf;
\r
8724 while (q < is->next) {
\r
8725 if (*q++ == '\n') {
\r
8726 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8731 /* Move any partial line to the start of the buffer */
\r
8733 while (p < is->next) {
\r
8738 if (is->error != NO_ERROR || is->count == 0) {
\r
8739 /* Notify backend of the error. Note: If there was a partial
\r
8740 line at the end, it is not flushed through. */
\r
8741 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8744 /* Feed in the whole chunk of input at once */
\r
8745 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8746 is->next = is->buf;
\r
8750 /*---------------------------------------------------------------------------*\
\r
8752 * Menu enables. Used when setting various modes.
\r
8754 \*---------------------------------------------------------------------------*/
\r
8762 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8764 while (enab->item > 0) {
\r
8765 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8770 Enables gnuEnables[] = {
\r
8771 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8772 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8773 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8774 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8775 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8776 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8777 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8778 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8779 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8780 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8784 Enables icsEnables[] = {
\r
8785 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8786 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8787 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8788 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8789 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8790 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8791 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8792 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8793 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8794 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8795 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8796 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8801 Enables zippyEnables[] = {
\r
8802 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8803 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8804 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8809 Enables ncpEnables[] = {
\r
8810 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8811 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8812 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8813 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8814 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8815 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8816 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8817 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8818 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8819 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8820 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8822 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8823 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8824 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8828 Enables trainingOnEnables[] = {
\r
8829 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8830 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8831 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8832 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8833 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8834 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8835 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8836 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8840 Enables trainingOffEnables[] = {
\r
8841 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8842 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8843 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8844 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8845 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8846 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8847 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8848 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8852 /* These modify either ncpEnables or gnuEnables */
\r
8853 Enables cmailEnables[] = {
\r
8854 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8855 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8856 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8857 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8858 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8859 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8860 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8864 Enables machineThinkingEnables[] = {
\r
8865 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8866 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8867 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8868 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8869 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8870 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8871 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8872 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8873 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8874 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8875 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8876 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8877 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8878 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8879 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8883 Enables userThinkingEnables[] = {
\r
8884 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8885 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8886 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8887 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8888 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8889 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8890 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8891 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8892 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8893 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8894 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8895 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8896 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8897 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8898 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8902 /*---------------------------------------------------------------------------*\
\r
8904 * Front-end interface functions exported by XBoard.
\r
8905 * Functions appear in same order as prototypes in frontend.h.
\r
8907 \*---------------------------------------------------------------------------*/
\r
8911 static UINT prevChecked = 0;
\r
8912 static int prevPausing = 0;
\r
8915 if (pausing != prevPausing) {
\r
8916 prevPausing = pausing;
\r
8917 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8918 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8919 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8922 switch (gameMode) {
\r
8923 case BeginningOfGame:
\r
8924 if (appData.icsActive)
\r
8925 nowChecked = IDM_IcsClient;
\r
8926 else if (appData.noChessProgram)
\r
8927 nowChecked = IDM_EditGame;
\r
8929 nowChecked = IDM_MachineBlack;
\r
8931 case MachinePlaysBlack:
\r
8932 nowChecked = IDM_MachineBlack;
\r
8934 case MachinePlaysWhite:
\r
8935 nowChecked = IDM_MachineWhite;
\r
8937 case TwoMachinesPlay:
\r
8938 nowChecked = IDM_TwoMachines;
\r
8941 nowChecked = IDM_AnalysisMode;
\r
8944 nowChecked = IDM_AnalyzeFile;
\r
8947 nowChecked = IDM_EditGame;
\r
8949 case PlayFromGameFile:
\r
8950 nowChecked = IDM_LoadGame;
\r
8952 case EditPosition:
\r
8953 nowChecked = IDM_EditPosition;
\r
8956 nowChecked = IDM_Training;
\r
8958 case IcsPlayingWhite:
\r
8959 case IcsPlayingBlack:
\r
8960 case IcsObserving:
\r
8962 nowChecked = IDM_IcsClient;
\r
8969 if (prevChecked != 0)
\r
8970 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8971 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8972 if (nowChecked != 0)
\r
8973 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8974 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8976 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8977 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8978 MF_BYCOMMAND|MF_ENABLED);
\r
8980 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8981 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8984 prevChecked = nowChecked;
\r
8986 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8987 if (appData.icsActive) {
\r
8988 if (appData.icsEngineAnalyze) {
\r
8989 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8990 MF_BYCOMMAND|MF_CHECKED);
\r
8992 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8993 MF_BYCOMMAND|MF_UNCHECKED);
\r
9001 HMENU hmenu = GetMenu(hwndMain);
\r
9002 SetMenuEnables(hmenu, icsEnables);
\r
9003 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9004 MF_BYPOSITION|MF_ENABLED);
\r
9006 if (appData.zippyPlay) {
\r
9007 SetMenuEnables(hmenu, zippyEnables);
\r
9008 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9009 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9010 MF_BYCOMMAND|MF_ENABLED);
\r
9018 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9024 HMENU hmenu = GetMenu(hwndMain);
\r
9025 SetMenuEnables(hmenu, ncpEnables);
\r
9026 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9027 MF_BYPOSITION|MF_GRAYED);
\r
9028 DrawMenuBar(hwndMain);
\r
9034 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9038 SetTrainingModeOn()
\r
9041 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9042 for (i = 0; i < N_BUTTONS; i++) {
\r
9043 if (buttonDesc[i].hwnd != NULL)
\r
9044 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9049 VOID SetTrainingModeOff()
\r
9052 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9053 for (i = 0; i < N_BUTTONS; i++) {
\r
9054 if (buttonDesc[i].hwnd != NULL)
\r
9055 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9061 SetUserThinkingEnables()
\r
9063 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9067 SetMachineThinkingEnables()
\r
9069 HMENU hMenu = GetMenu(hwndMain);
\r
9070 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9072 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9074 if (gameMode == MachinePlaysBlack) {
\r
9075 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9076 } else if (gameMode == MachinePlaysWhite) {
\r
9077 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9078 } else if (gameMode == TwoMachinesPlay) {
\r
9079 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9085 DisplayTitle(char *str)
\r
9087 char title[MSG_SIZ], *host;
\r
9088 if (str[0] != NULLCHAR) {
\r
9089 strcpy(title, str);
\r
9090 } else if (appData.icsActive) {
\r
9091 if (appData.icsCommPort[0] != NULLCHAR)
\r
9094 host = appData.icsHost;
\r
9095 sprintf(title, "%s: %s", szTitle, host);
\r
9096 } else if (appData.noChessProgram) {
\r
9097 strcpy(title, szTitle);
\r
9099 strcpy(title, szTitle);
\r
9100 strcat(title, ": ");
\r
9101 strcat(title, first.tidy);
\r
9103 SetWindowText(hwndMain, title);
\r
9108 DisplayMessage(char *str1, char *str2)
\r
9112 int remain = MESSAGE_TEXT_MAX - 1;
\r
9115 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9116 messageText[0] = NULLCHAR;
\r
9118 len = strlen(str1);
\r
9119 if (len > remain) len = remain;
\r
9120 strncpy(messageText, str1, len);
\r
9121 messageText[len] = NULLCHAR;
\r
9124 if (*str2 && remain >= 2) {
\r
9126 strcat(messageText, " ");
\r
9129 len = strlen(str2);
\r
9130 if (len > remain) len = remain;
\r
9131 strncat(messageText, str2, len);
\r
9133 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9135 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9139 hdc = GetDC(hwndMain);
\r
9140 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9141 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9142 &messageRect, messageText, strlen(messageText), NULL);
\r
9143 (void) SelectObject(hdc, oldFont);
\r
9144 (void) ReleaseDC(hwndMain, hdc);
\r
9148 DisplayError(char *str, int error)
\r
9150 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9156 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9157 NULL, error, LANG_NEUTRAL,
\r
9158 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9160 sprintf(buf, "%s:\n%s", str, buf2);
\r
9162 ErrorMap *em = errmap;
\r
9163 while (em->err != 0 && em->err != error) em++;
\r
9164 if (em->err != 0) {
\r
9165 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9167 sprintf(buf, "%s:\nError code %d", str, error);
\r
9172 ErrorPopUp("Error", buf);
\r
9177 DisplayMoveError(char *str)
\r
9179 fromX = fromY = -1;
\r
9180 ClearHighlights();
\r
9181 DrawPosition(FALSE, NULL);
\r
9182 if (appData.popupMoveErrors) {
\r
9183 ErrorPopUp("Error", str);
\r
9185 DisplayMessage(str, "");
\r
9186 moveErrorMessageUp = TRUE;
\r
9191 DisplayFatalError(char *str, int error, int exitStatus)
\r
9193 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9195 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9198 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9199 NULL, error, LANG_NEUTRAL,
\r
9200 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9202 sprintf(buf, "%s:\n%s", str, buf2);
\r
9204 ErrorMap *em = errmap;
\r
9205 while (em->err != 0 && em->err != error) em++;
\r
9206 if (em->err != 0) {
\r
9207 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9209 sprintf(buf, "%s:\nError code %d", str, error);
\r
9214 if (appData.debugMode) {
\r
9215 fprintf(debugFP, "%s: %s\n", label, str);
\r
9217 if (appData.popupExitMessage) {
\r
9218 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9219 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9221 ExitEvent(exitStatus);
\r
9226 DisplayInformation(char *str)
\r
9228 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9233 DisplayNote(char *str)
\r
9235 ErrorPopUp("Note", str);
\r
9240 char *title, *question, *replyPrefix;
\r
9245 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9247 static QuestionParams *qp;
\r
9248 char reply[MSG_SIZ];
\r
9251 switch (message) {
\r
9252 case WM_INITDIALOG:
\r
9253 qp = (QuestionParams *) lParam;
\r
9254 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9255 SetWindowText(hDlg, qp->title);
\r
9256 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9257 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9261 switch (LOWORD(wParam)) {
\r
9263 strcpy(reply, qp->replyPrefix);
\r
9264 if (*reply) strcat(reply, " ");
\r
9265 len = strlen(reply);
\r
9266 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9267 strcat(reply, "\n");
\r
9268 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9269 EndDialog(hDlg, TRUE);
\r
9270 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9273 EndDialog(hDlg, FALSE);
\r
9284 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9286 QuestionParams qp;
\r
9290 qp.question = question;
\r
9291 qp.replyPrefix = replyPrefix;
\r
9293 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9294 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9295 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9296 FreeProcInstance(lpProc);
\r
9299 /* [AS] Pick FRC position */
\r
9300 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9302 static int * lpIndexFRC;
\r
9308 case WM_INITDIALOG:
\r
9309 lpIndexFRC = (int *) lParam;
\r
9311 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9313 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9314 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9315 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9316 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9321 switch( LOWORD(wParam) ) {
\r
9323 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9324 EndDialog( hDlg, 0 );
\r
9325 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9328 EndDialog( hDlg, 1 );
\r
9330 case IDC_NFG_Edit:
\r
9331 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9332 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9334 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9337 case IDC_NFG_Random:
\r
9338 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9339 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9352 int index = appData.defaultFrcPosition;
\r
9353 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9355 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9357 if( result == 0 ) {
\r
9358 appData.defaultFrcPosition = index;
\r
9364 /* [AS] Game list options */
\r
9370 static GLT_Item GLT_ItemInfo[] = {
\r
9371 { GLT_EVENT, "Event" },
\r
9372 { GLT_SITE, "Site" },
\r
9373 { GLT_DATE, "Date" },
\r
9374 { GLT_ROUND, "Round" },
\r
9375 { GLT_PLAYERS, "Players" },
\r
9376 { GLT_RESULT, "Result" },
\r
9377 { GLT_WHITE_ELO, "White Rating" },
\r
9378 { GLT_BLACK_ELO, "Black Rating" },
\r
9379 { GLT_TIME_CONTROL,"Time Control" },
\r
9380 { GLT_VARIANT, "Variant" },
\r
9381 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9385 const char * GLT_FindItem( char id )
\r
9387 const char * result = 0;
\r
9389 GLT_Item * list = GLT_ItemInfo;
\r
9391 while( list->id != 0 ) {
\r
9392 if( list->id == id ) {
\r
9393 result = list->name;
\r
9403 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9405 const char * name = GLT_FindItem( id );
\r
9408 if( index >= 0 ) {
\r
9409 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9412 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9417 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9421 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9424 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9428 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9430 pc = GLT_ALL_TAGS;
\r
9433 if( strchr( tags, *pc ) == 0 ) {
\r
9434 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9439 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9442 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9444 char result = '\0';
\r
9447 GLT_Item * list = GLT_ItemInfo;
\r
9449 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9450 while( list->id != 0 ) {
\r
9451 if( strcmp( list->name, name ) == 0 ) {
\r
9452 result = list->id;
\r
9463 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9465 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9466 int idx2 = idx1 + delta;
\r
9467 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9469 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9472 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9473 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9474 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9475 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9479 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9481 static char glt[64];
\r
9482 static char * lpUserGLT;
\r
9486 case WM_INITDIALOG:
\r
9487 lpUserGLT = (char *) lParam;
\r
9489 strcpy( glt, lpUserGLT );
\r
9491 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9493 /* Initialize list */
\r
9494 GLT_TagsToList( hDlg, glt );
\r
9496 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9501 switch( LOWORD(wParam) ) {
\r
9504 char * pc = lpUserGLT;
\r
9506 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9510 id = GLT_ListItemToTag( hDlg, idx );
\r
9514 } while( id != '\0' );
\r
9516 EndDialog( hDlg, 0 );
\r
9519 EndDialog( hDlg, 1 );
\r
9522 case IDC_GLT_Default:
\r
9523 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9524 GLT_TagsToList( hDlg, glt );
\r
9527 case IDC_GLT_Restore:
\r
9528 strcpy( glt, lpUserGLT );
\r
9529 GLT_TagsToList( hDlg, glt );
\r
9533 GLT_MoveSelection( hDlg, -1 );
\r
9536 case IDC_GLT_Down:
\r
9537 GLT_MoveSelection( hDlg, +1 );
\r
9547 int GameListOptions()
\r
9551 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9553 strcpy( glt, appData.gameListTags );
\r
9555 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9557 if( result == 0 ) {
\r
9558 /* [AS] Memory leak here! */
\r
9559 appData.gameListTags = strdup( glt );
\r
9567 DisplayIcsInteractionTitle(char *str)
\r
9569 char consoleTitle[MSG_SIZ];
\r
9571 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9572 SetWindowText(hwndConsole, consoleTitle);
\r
9576 DrawPosition(int fullRedraw, Board board)
\r
9578 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9585 fromX = fromY = -1;
\r
9586 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9587 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9588 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9589 dragInfo.lastpos = dragInfo.pos;
\r
9590 dragInfo.start.x = dragInfo.start.y = -1;
\r
9591 dragInfo.from = dragInfo.start;
\r
9593 DrawPosition(TRUE, NULL);
\r
9599 CommentPopUp(char *title, char *str)
\r
9601 HWND hwnd = GetActiveWindow();
\r
9602 EitherCommentPopUp(0, title, str, FALSE);
\r
9603 SetActiveWindow(hwnd);
\r
9607 CommentPopDown(void)
\r
9609 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9610 if (commentDialog) {
\r
9611 ShowWindow(commentDialog, SW_HIDE);
\r
9613 commentDialogUp = FALSE;
\r
9617 EditCommentPopUp(int index, char *title, char *str)
\r
9619 EitherCommentPopUp(index, title, str, TRUE);
\r
9626 MyPlaySound(&sounds[(int)SoundMove]);
\r
9629 VOID PlayIcsWinSound()
\r
9631 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9634 VOID PlayIcsLossSound()
\r
9636 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9639 VOID PlayIcsDrawSound()
\r
9641 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9644 VOID PlayIcsUnfinishedSound()
\r
9646 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9652 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9660 consoleEcho = TRUE;
\r
9661 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9662 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9663 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9672 consoleEcho = FALSE;
\r
9673 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9674 /* This works OK: set text and background both to the same color */
\r
9676 cf.crTextColor = COLOR_ECHOOFF;
\r
9677 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9678 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9681 /* No Raw()...? */
\r
9683 void Colorize(ColorClass cc, int continuation)
\r
9685 currentColorClass = cc;
\r
9686 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9687 consoleCF.crTextColor = textAttribs[cc].color;
\r
9688 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9689 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9695 static char buf[MSG_SIZ];
\r
9696 DWORD bufsiz = MSG_SIZ;
\r
9698 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9699 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9701 if (!GetUserName(buf, &bufsiz)) {
\r
9702 /*DisplayError("Error getting user name", GetLastError());*/
\r
9703 strcpy(buf, "User");
\r
9711 static char buf[MSG_SIZ];
\r
9712 DWORD bufsiz = MSG_SIZ;
\r
9714 if (!GetComputerName(buf, &bufsiz)) {
\r
9715 /*DisplayError("Error getting host name", GetLastError());*/
\r
9716 strcpy(buf, "Unknown");
\r
9723 ClockTimerRunning()
\r
9725 return clockTimerEvent != 0;
\r
9731 if (clockTimerEvent == 0) return FALSE;
\r
9732 KillTimer(hwndMain, clockTimerEvent);
\r
9733 clockTimerEvent = 0;
\r
9738 StartClockTimer(long millisec)
\r
9740 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9741 (UINT) millisec, NULL);
\r
9745 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9748 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9750 if(appData.noGUI) return;
\r
9751 hdc = GetDC(hwndMain);
\r
9752 if (!IsIconic(hwndMain)) {
\r
9753 DisplayAClock(hdc, timeRemaining, highlight,
\r
9754 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9756 if (highlight && iconCurrent == iconBlack) {
\r
9757 iconCurrent = iconWhite;
\r
9758 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9759 if (IsIconic(hwndMain)) {
\r
9760 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9763 (void) ReleaseDC(hwndMain, hdc);
\r
9765 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9769 DisplayBlackClock(long timeRemaining, int highlight)
\r
9772 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9774 if(appData.noGUI) return;
\r
9775 hdc = GetDC(hwndMain);
\r
9776 if (!IsIconic(hwndMain)) {
\r
9777 DisplayAClock(hdc, timeRemaining, highlight,
\r
9778 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9780 if (highlight && iconCurrent == iconWhite) {
\r
9781 iconCurrent = iconBlack;
\r
9782 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9783 if (IsIconic(hwndMain)) {
\r
9784 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9787 (void) ReleaseDC(hwndMain, hdc);
\r
9789 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9794 LoadGameTimerRunning()
\r
9796 return loadGameTimerEvent != 0;
\r
9800 StopLoadGameTimer()
\r
9802 if (loadGameTimerEvent == 0) return FALSE;
\r
9803 KillTimer(hwndMain, loadGameTimerEvent);
\r
9804 loadGameTimerEvent = 0;
\r
9809 StartLoadGameTimer(long millisec)
\r
9811 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9812 (UINT) millisec, NULL);
\r
9820 char fileTitle[MSG_SIZ];
\r
9822 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9823 f = OpenFileDialog(hwndMain, "a", defName,
\r
9824 appData.oldSaveStyle ? "gam" : "pgn",
\r
9826 "Save Game to File", NULL, fileTitle, NULL);
\r
9828 SaveGame(f, 0, "");
\r
9835 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9837 if (delayedTimerEvent != 0) {
\r
9838 if (appData.debugMode) {
\r
9839 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9841 KillTimer(hwndMain, delayedTimerEvent);
\r
9842 delayedTimerEvent = 0;
\r
9843 delayedTimerCallback();
\r
9845 delayedTimerCallback = cb;
\r
9846 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9847 (UINT) millisec, NULL);
\r
9850 DelayedEventCallback
\r
9853 if (delayedTimerEvent) {
\r
9854 return delayedTimerCallback;
\r
9861 CancelDelayedEvent()
\r
9863 if (delayedTimerEvent) {
\r
9864 KillTimer(hwndMain, delayedTimerEvent);
\r
9865 delayedTimerEvent = 0;
\r
9869 DWORD GetWin32Priority(int nice)
\r
9870 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9872 REALTIME_PRIORITY_CLASS 0x00000100
\r
9873 HIGH_PRIORITY_CLASS 0x00000080
\r
9874 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9875 NORMAL_PRIORITY_CLASS 0x00000020
\r
9876 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9877 IDLE_PRIORITY_CLASS 0x00000040
\r
9879 if (nice < -15) return 0x00000080;
\r
9880 if (nice < 0) return 0x00008000;
\r
9881 if (nice == 0) return 0x00000020;
\r
9882 if (nice < 15) return 0x00004000;
\r
9883 return 0x00000040;
\r
9886 /* Start a child process running the given program.
\r
9887 The process's standard output can be read from "from", and its
\r
9888 standard input can be written to "to".
\r
9889 Exit with fatal error if anything goes wrong.
\r
9890 Returns an opaque pointer that can be used to destroy the process
\r
9894 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9896 #define BUFSIZE 4096
\r
9898 HANDLE hChildStdinRd, hChildStdinWr,
\r
9899 hChildStdoutRd, hChildStdoutWr;
\r
9900 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9901 SECURITY_ATTRIBUTES saAttr;
\r
9903 PROCESS_INFORMATION piProcInfo;
\r
9904 STARTUPINFO siStartInfo;
\r
9906 char buf[MSG_SIZ];
\r
9909 if (appData.debugMode) {
\r
9910 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9915 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9916 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9917 saAttr.bInheritHandle = TRUE;
\r
9918 saAttr.lpSecurityDescriptor = NULL;
\r
9921 * The steps for redirecting child's STDOUT:
\r
9922 * 1. Create anonymous pipe to be STDOUT for child.
\r
9923 * 2. Create a noninheritable duplicate of read handle,
\r
9924 * and close the inheritable read handle.
\r
9927 /* Create a pipe for the child's STDOUT. */
\r
9928 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9929 return GetLastError();
\r
9932 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9933 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9934 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9935 FALSE, /* not inherited */
\r
9936 DUPLICATE_SAME_ACCESS);
\r
9938 return GetLastError();
\r
9940 CloseHandle(hChildStdoutRd);
\r
9943 * The steps for redirecting child's STDIN:
\r
9944 * 1. Create anonymous pipe to be STDIN for child.
\r
9945 * 2. Create a noninheritable duplicate of write handle,
\r
9946 * and close the inheritable write handle.
\r
9949 /* Create a pipe for the child's STDIN. */
\r
9950 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9951 return GetLastError();
\r
9954 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9955 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9956 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9957 FALSE, /* not inherited */
\r
9958 DUPLICATE_SAME_ACCESS);
\r
9960 return GetLastError();
\r
9962 CloseHandle(hChildStdinWr);
\r
9964 /* Arrange to (1) look in dir for the child .exe file, and
\r
9965 * (2) have dir be the child's working directory. Interpret
\r
9966 * dir relative to the directory WinBoard loaded from. */
\r
9967 GetCurrentDirectory(MSG_SIZ, buf);
\r
9968 SetCurrentDirectory(installDir);
\r
9969 SetCurrentDirectory(dir);
\r
9971 /* Now create the child process. */
\r
9973 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9974 siStartInfo.lpReserved = NULL;
\r
9975 siStartInfo.lpDesktop = NULL;
\r
9976 siStartInfo.lpTitle = NULL;
\r
9977 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9978 siStartInfo.cbReserved2 = 0;
\r
9979 siStartInfo.lpReserved2 = NULL;
\r
9980 siStartInfo.hStdInput = hChildStdinRd;
\r
9981 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9982 siStartInfo.hStdError = hChildStdoutWr;
\r
9984 fSuccess = CreateProcess(NULL,
\r
9985 cmdLine, /* command line */
\r
9986 NULL, /* process security attributes */
\r
9987 NULL, /* primary thread security attrs */
\r
9988 TRUE, /* handles are inherited */
\r
9989 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9990 NULL, /* use parent's environment */
\r
9992 &siStartInfo, /* STARTUPINFO pointer */
\r
9993 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9995 err = GetLastError();
\r
9996 SetCurrentDirectory(buf); /* return to prev directory */
\r
10001 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10002 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10003 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10006 /* Close the handles we don't need in the parent */
\r
10007 CloseHandle(piProcInfo.hThread);
\r
10008 CloseHandle(hChildStdinRd);
\r
10009 CloseHandle(hChildStdoutWr);
\r
10011 /* Prepare return value */
\r
10012 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10013 cp->kind = CPReal;
\r
10014 cp->hProcess = piProcInfo.hProcess;
\r
10015 cp->pid = piProcInfo.dwProcessId;
\r
10016 cp->hFrom = hChildStdoutRdDup;
\r
10017 cp->hTo = hChildStdinWrDup;
\r
10019 *pr = (void *) cp;
\r
10021 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10022 2000 where engines sometimes don't see the initial command(s)
\r
10023 from WinBoard and hang. I don't understand how that can happen,
\r
10024 but the Sleep is harmless, so I've put it in. Others have also
\r
10025 reported what may be the same problem, so hopefully this will fix
\r
10026 it for them too. */
\r
10034 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10036 ChildProc *cp; int result;
\r
10038 cp = (ChildProc *) pr;
\r
10039 if (cp == NULL) return;
\r
10041 switch (cp->kind) {
\r
10043 /* TerminateProcess is considered harmful, so... */
\r
10044 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10045 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10046 /* The following doesn't work because the chess program
\r
10047 doesn't "have the same console" as WinBoard. Maybe
\r
10048 we could arrange for this even though neither WinBoard
\r
10049 nor the chess program uses a console for stdio? */
\r
10050 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10052 /* [AS] Special termination modes for misbehaving programs... */
\r
10053 if( signal == 9 ) {
\r
10054 result = TerminateProcess( cp->hProcess, 0 );
\r
10056 if ( appData.debugMode) {
\r
10057 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10060 else if( signal == 10 ) {
\r
10061 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10063 if( dw != WAIT_OBJECT_0 ) {
\r
10064 result = TerminateProcess( cp->hProcess, 0 );
\r
10066 if ( appData.debugMode) {
\r
10067 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10073 CloseHandle(cp->hProcess);
\r
10077 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10081 closesocket(cp->sock);
\r
10086 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10087 closesocket(cp->sock);
\r
10088 closesocket(cp->sock2);
\r
10096 InterruptChildProcess(ProcRef pr)
\r
10100 cp = (ChildProc *) pr;
\r
10101 if (cp == NULL) return;
\r
10102 switch (cp->kind) {
\r
10104 /* The following doesn't work because the chess program
\r
10105 doesn't "have the same console" as WinBoard. Maybe
\r
10106 we could arrange for this even though neither WinBoard
\r
10107 nor the chess program uses a console for stdio */
\r
10108 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10113 /* Can't interrupt */
\r
10117 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10124 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10126 char cmdLine[MSG_SIZ];
\r
10128 if (port[0] == NULLCHAR) {
\r
10129 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10131 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10133 return StartChildProcess(cmdLine, "", pr);
\r
10137 /* Code to open TCP sockets */
\r
10140 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10145 struct sockaddr_in sa, mysa;
\r
10146 struct hostent FAR *hp;
\r
10147 unsigned short uport;
\r
10148 WORD wVersionRequested;
\r
10151 /* Initialize socket DLL */
\r
10152 wVersionRequested = MAKEWORD(1, 1);
\r
10153 err = WSAStartup(wVersionRequested, &wsaData);
\r
10154 if (err != 0) return err;
\r
10156 /* Make socket */
\r
10157 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10158 err = WSAGetLastError();
\r
10163 /* Bind local address using (mostly) don't-care values.
\r
10165 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10166 mysa.sin_family = AF_INET;
\r
10167 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10168 uport = (unsigned short) 0;
\r
10169 mysa.sin_port = htons(uport);
\r
10170 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10171 == SOCKET_ERROR) {
\r
10172 err = WSAGetLastError();
\r
10177 /* Resolve remote host name */
\r
10178 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10179 if (!(hp = gethostbyname(host))) {
\r
10180 unsigned int b0, b1, b2, b3;
\r
10182 err = WSAGetLastError();
\r
10184 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10185 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10186 hp->h_addrtype = AF_INET;
\r
10187 hp->h_length = 4;
\r
10188 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10189 hp->h_addr_list[0] = (char *) malloc(4);
\r
10190 hp->h_addr_list[0][0] = (char) b0;
\r
10191 hp->h_addr_list[0][1] = (char) b1;
\r
10192 hp->h_addr_list[0][2] = (char) b2;
\r
10193 hp->h_addr_list[0][3] = (char) b3;
\r
10199 sa.sin_family = hp->h_addrtype;
\r
10200 uport = (unsigned short) atoi(port);
\r
10201 sa.sin_port = htons(uport);
\r
10202 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10204 /* Make connection */
\r
10205 if (connect(s, (struct sockaddr *) &sa,
\r
10206 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10207 err = WSAGetLastError();
\r
10212 /* Prepare return value */
\r
10213 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10214 cp->kind = CPSock;
\r
10216 *pr = (ProcRef *) cp;
\r
10222 OpenCommPort(char *name, ProcRef *pr)
\r
10227 char fullname[MSG_SIZ];
\r
10229 if (*name != '\\')
\r
10230 sprintf(fullname, "\\\\.\\%s", name);
\r
10232 strcpy(fullname, name);
\r
10234 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10235 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10236 if (h == (HANDLE) -1) {
\r
10237 return GetLastError();
\r
10241 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10243 /* Accumulate characters until a 100ms pause, then parse */
\r
10244 ct.ReadIntervalTimeout = 100;
\r
10245 ct.ReadTotalTimeoutMultiplier = 0;
\r
10246 ct.ReadTotalTimeoutConstant = 0;
\r
10247 ct.WriteTotalTimeoutMultiplier = 0;
\r
10248 ct.WriteTotalTimeoutConstant = 0;
\r
10249 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10251 /* Prepare return value */
\r
10252 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10253 cp->kind = CPComm;
\r
10256 *pr = (ProcRef *) cp;
\r
10262 OpenLoopback(ProcRef *pr)
\r
10264 DisplayFatalError("Not implemented", 0, 1);
\r
10270 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10274 SOCKET s, s2, s3;
\r
10275 struct sockaddr_in sa, mysa;
\r
10276 struct hostent FAR *hp;
\r
10277 unsigned short uport;
\r
10278 WORD wVersionRequested;
\r
10281 char stderrPortStr[MSG_SIZ];
\r
10283 /* Initialize socket DLL */
\r
10284 wVersionRequested = MAKEWORD(1, 1);
\r
10285 err = WSAStartup(wVersionRequested, &wsaData);
\r
10286 if (err != 0) return err;
\r
10288 /* Resolve remote host name */
\r
10289 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10290 if (!(hp = gethostbyname(host))) {
\r
10291 unsigned int b0, b1, b2, b3;
\r
10293 err = WSAGetLastError();
\r
10295 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10296 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10297 hp->h_addrtype = AF_INET;
\r
10298 hp->h_length = 4;
\r
10299 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10300 hp->h_addr_list[0] = (char *) malloc(4);
\r
10301 hp->h_addr_list[0][0] = (char) b0;
\r
10302 hp->h_addr_list[0][1] = (char) b1;
\r
10303 hp->h_addr_list[0][2] = (char) b2;
\r
10304 hp->h_addr_list[0][3] = (char) b3;
\r
10310 sa.sin_family = hp->h_addrtype;
\r
10311 uport = (unsigned short) 514;
\r
10312 sa.sin_port = htons(uport);
\r
10313 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10315 /* Bind local socket to unused "privileged" port address
\r
10317 s = INVALID_SOCKET;
\r
10318 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10319 mysa.sin_family = AF_INET;
\r
10320 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10321 for (fromPort = 1023;; fromPort--) {
\r
10322 if (fromPort < 0) {
\r
10324 return WSAEADDRINUSE;
\r
10326 if (s == INVALID_SOCKET) {
\r
10327 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10328 err = WSAGetLastError();
\r
10333 uport = (unsigned short) fromPort;
\r
10334 mysa.sin_port = htons(uport);
\r
10335 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10336 == SOCKET_ERROR) {
\r
10337 err = WSAGetLastError();
\r
10338 if (err == WSAEADDRINUSE) continue;
\r
10342 if (connect(s, (struct sockaddr *) &sa,
\r
10343 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10344 err = WSAGetLastError();
\r
10345 if (err == WSAEADDRINUSE) {
\r
10356 /* Bind stderr local socket to unused "privileged" port address
\r
10358 s2 = INVALID_SOCKET;
\r
10359 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10360 mysa.sin_family = AF_INET;
\r
10361 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10362 for (fromPort = 1023;; fromPort--) {
\r
10363 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10364 if (fromPort < 0) {
\r
10365 (void) closesocket(s);
\r
10367 return WSAEADDRINUSE;
\r
10369 if (s2 == INVALID_SOCKET) {
\r
10370 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10371 err = WSAGetLastError();
\r
10377 uport = (unsigned short) fromPort;
\r
10378 mysa.sin_port = htons(uport);
\r
10379 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10380 == SOCKET_ERROR) {
\r
10381 err = WSAGetLastError();
\r
10382 if (err == WSAEADDRINUSE) continue;
\r
10383 (void) closesocket(s);
\r
10387 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10388 err = WSAGetLastError();
\r
10389 if (err == WSAEADDRINUSE) {
\r
10391 s2 = INVALID_SOCKET;
\r
10394 (void) closesocket(s);
\r
10395 (void) closesocket(s2);
\r
10401 prevStderrPort = fromPort; // remember port used
\r
10402 sprintf(stderrPortStr, "%d", fromPort);
\r
10404 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10405 err = WSAGetLastError();
\r
10406 (void) closesocket(s);
\r
10407 (void) closesocket(s2);
\r
10412 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10413 err = WSAGetLastError();
\r
10414 (void) closesocket(s);
\r
10415 (void) closesocket(s2);
\r
10419 if (*user == NULLCHAR) user = UserName();
\r
10420 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10421 err = WSAGetLastError();
\r
10422 (void) closesocket(s);
\r
10423 (void) closesocket(s2);
\r
10427 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10428 err = WSAGetLastError();
\r
10429 (void) closesocket(s);
\r
10430 (void) closesocket(s2);
\r
10435 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10436 err = WSAGetLastError();
\r
10437 (void) closesocket(s);
\r
10438 (void) closesocket(s2);
\r
10442 (void) closesocket(s2); /* Stop listening */
\r
10444 /* Prepare return value */
\r
10445 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10446 cp->kind = CPRcmd;
\r
10449 *pr = (ProcRef *) cp;
\r
10456 AddInputSource(ProcRef pr, int lineByLine,
\r
10457 InputCallback func, VOIDSTAR closure)
\r
10459 InputSource *is, *is2 = NULL;
\r
10460 ChildProc *cp = (ChildProc *) pr;
\r
10462 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10463 is->lineByLine = lineByLine;
\r
10465 is->closure = closure;
\r
10466 is->second = NULL;
\r
10467 is->next = is->buf;
\r
10468 if (pr == NoProc) {
\r
10469 is->kind = CPReal;
\r
10470 consoleInputSource = is;
\r
10472 is->kind = cp->kind;
\r
10474 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10475 we create all threads suspended so that the is->hThread variable can be
\r
10476 safely assigned, then let the threads start with ResumeThread.
\r
10478 switch (cp->kind) {
\r
10480 is->hFile = cp->hFrom;
\r
10481 cp->hFrom = NULL; /* now owned by InputThread */
\r
10483 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10484 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10488 is->hFile = cp->hFrom;
\r
10489 cp->hFrom = NULL; /* now owned by InputThread */
\r
10491 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10492 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10496 is->sock = cp->sock;
\r
10498 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10499 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10503 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10505 is->sock = cp->sock;
\r
10506 is->second = is2;
\r
10507 is2->sock = cp->sock2;
\r
10508 is2->second = is2;
\r
10510 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10511 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10513 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10514 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10518 if( is->hThread != NULL ) {
\r
10519 ResumeThread( is->hThread );
\r
10522 if( is2 != NULL && is2->hThread != NULL ) {
\r
10523 ResumeThread( is2->hThread );
\r
10527 return (InputSourceRef) is;
\r
10531 RemoveInputSource(InputSourceRef isr)
\r
10535 is = (InputSource *) isr;
\r
10536 is->hThread = NULL; /* tell thread to stop */
\r
10537 CloseHandle(is->hThread);
\r
10538 if (is->second != NULL) {
\r
10539 is->second->hThread = NULL;
\r
10540 CloseHandle(is->second->hThread);
\r
10546 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10549 int outCount = SOCKET_ERROR;
\r
10550 ChildProc *cp = (ChildProc *) pr;
\r
10551 static OVERLAPPED ovl;
\r
10553 if (pr == NoProc) {
\r
10554 ConsoleOutput(message, count, FALSE);
\r
10558 if (ovl.hEvent == NULL) {
\r
10559 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10561 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10563 switch (cp->kind) {
\r
10566 outCount = send(cp->sock, message, count, 0);
\r
10567 if (outCount == SOCKET_ERROR) {
\r
10568 *outError = WSAGetLastError();
\r
10570 *outError = NO_ERROR;
\r
10575 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10576 &dOutCount, NULL)) {
\r
10577 *outError = NO_ERROR;
\r
10578 outCount = (int) dOutCount;
\r
10580 *outError = GetLastError();
\r
10585 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10586 &dOutCount, &ovl);
\r
10587 if (*outError == NO_ERROR) {
\r
10588 outCount = (int) dOutCount;
\r
10596 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10599 /* Ignore delay, not implemented for WinBoard */
\r
10600 return OutputToProcess(pr, message, count, outError);
\r
10605 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10606 char *buf, int count, int error)
\r
10608 DisplayFatalError("Not implemented", 0, 1);
\r
10611 /* see wgamelist.c for Game List functions */
\r
10612 /* see wedittags.c for Edit Tags functions */
\r
10619 char buf[MSG_SIZ];
\r
10622 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10623 f = fopen(buf, "r");
\r
10625 ProcessICSInitScript(f);
\r
10633 StartAnalysisClock()
\r
10635 if (analysisTimerEvent) return;
\r
10636 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10637 (UINT) 2000, NULL);
\r
10641 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10643 static HANDLE hwndText;
\r
10645 static int sizeX, sizeY;
\r
10646 int newSizeX, newSizeY, flags;
\r
10649 switch (message) {
\r
10650 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10651 /* Initialize the dialog items */
\r
10652 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10653 SetWindowText(hDlg, analysisTitle);
\r
10654 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10655 /* Size and position the dialog */
\r
10656 if (!analysisDialog) {
\r
10657 analysisDialog = hDlg;
\r
10658 flags = SWP_NOZORDER;
\r
10659 GetClientRect(hDlg, &rect);
\r
10660 sizeX = rect.right;
\r
10661 sizeY = rect.bottom;
\r
10662 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10663 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10664 WINDOWPLACEMENT wp;
\r
10665 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10666 wp.length = sizeof(WINDOWPLACEMENT);
\r
10668 wp.showCmd = SW_SHOW;
\r
10669 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10670 wp.rcNormalPosition.left = analysisX;
\r
10671 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10672 wp.rcNormalPosition.top = analysisY;
\r
10673 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10674 SetWindowPlacement(hDlg, &wp);
\r
10676 GetClientRect(hDlg, &rect);
\r
10677 newSizeX = rect.right;
\r
10678 newSizeY = rect.bottom;
\r
10679 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10680 newSizeX, newSizeY);
\r
10681 sizeX = newSizeX;
\r
10682 sizeY = newSizeY;
\r
10687 case WM_COMMAND: /* message: received a command */
\r
10688 switch (LOWORD(wParam)) {
\r
10690 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10691 ExitAnalyzeMode();
\r
10703 newSizeX = LOWORD(lParam);
\r
10704 newSizeY = HIWORD(lParam);
\r
10705 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10706 sizeX = newSizeX;
\r
10707 sizeY = newSizeY;
\r
10710 case WM_GETMINMAXINFO:
\r
10711 /* Prevent resizing window too small */
\r
10712 mmi = (MINMAXINFO *) lParam;
\r
10713 mmi->ptMinTrackSize.x = 100;
\r
10714 mmi->ptMinTrackSize.y = 100;
\r
10721 AnalysisPopUp(char* title, char* str)
\r
10727 EngineOutputPopUp();
\r
10730 if (str == NULL) str = "";
\r
10731 p = (char *) malloc(2 * strlen(str) + 2);
\r
10734 if (*str == '\n') *q++ = '\r';
\r
10738 if (analysisText != NULL) free(analysisText);
\r
10739 analysisText = p;
\r
10741 if (analysisDialog) {
\r
10742 SetWindowText(analysisDialog, title);
\r
10743 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10744 ShowWindow(analysisDialog, SW_SHOW);
\r
10746 analysisTitle = title;
\r
10747 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10748 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10749 hwndMain, (DLGPROC)lpProc);
\r
10750 FreeProcInstance(lpProc);
\r
10752 analysisDialogUp = TRUE;
\r
10756 AnalysisPopDown()
\r
10758 if (analysisDialog) {
\r
10759 ShowWindow(analysisDialog, SW_HIDE);
\r
10761 analysisDialogUp = FALSE;
\r
10766 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10768 highlightInfo.sq[0].x = fromX;
\r
10769 highlightInfo.sq[0].y = fromY;
\r
10770 highlightInfo.sq[1].x = toX;
\r
10771 highlightInfo.sq[1].y = toY;
\r
10775 ClearHighlights()
\r
10777 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10778 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10782 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10784 premoveHighlightInfo.sq[0].x = fromX;
\r
10785 premoveHighlightInfo.sq[0].y = fromY;
\r
10786 premoveHighlightInfo.sq[1].x = toX;
\r
10787 premoveHighlightInfo.sq[1].y = toY;
\r
10791 ClearPremoveHighlights()
\r
10793 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10794 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10798 ShutDownFrontEnd()
\r
10800 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10801 DeleteClipboardTempFiles();
\r
10807 if (IsIconic(hwndMain))
\r
10808 ShowWindow(hwndMain, SW_RESTORE);
\r
10810 SetActiveWindow(hwndMain);
\r
10814 * Prototypes for animation support routines
\r
10816 static void ScreenSquare(int column, int row, POINT * pt);
\r
10817 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10818 POINT frames[], int * nFrames);
\r
10822 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10823 { // [HGM] atomic: animate blast wave
\r
10825 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10826 explodeInfo.fromX = fromX;
\r
10827 explodeInfo.fromY = fromY;
\r
10828 explodeInfo.toX = toX;
\r
10829 explodeInfo.toY = toY;
\r
10830 for(i=1; i<nFrames; i++) {
\r
10831 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10832 DrawPosition(FALSE, NULL);
\r
10833 Sleep(appData.animSpeed);
\r
10835 explodeInfo.radius = 0;
\r
10836 DrawPosition(TRUE, NULL);
\r
10839 #define kFactor 4
\r
10842 AnimateMove(board, fromX, fromY, toX, toY)
\r
10849 ChessSquare piece;
\r
10850 POINT start, finish, mid;
\r
10851 POINT frames[kFactor * 2 + 1];
\r
10854 if (!appData.animate) return;
\r
10855 if (doingSizing) return;
\r
10856 if (fromY < 0 || fromX < 0) return;
\r
10857 piece = board[fromY][fromX];
\r
10858 if (piece >= EmptySquare) return;
\r
10860 ScreenSquare(fromX, fromY, &start);
\r
10861 ScreenSquare(toX, toY, &finish);
\r
10863 /* All pieces except knights move in straight line */
\r
10864 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10865 mid.x = start.x + (finish.x - start.x) / 2;
\r
10866 mid.y = start.y + (finish.y - start.y) / 2;
\r
10868 /* Knight: make diagonal movement then straight */
\r
10869 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10870 mid.x = start.x + (finish.x - start.x) / 2;
\r
10871 mid.y = finish.y;
\r
10873 mid.x = finish.x;
\r
10874 mid.y = start.y + (finish.y - start.y) / 2;
\r
10878 /* Don't use as many frames for very short moves */
\r
10879 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10880 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10882 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10884 animInfo.from.x = fromX;
\r
10885 animInfo.from.y = fromY;
\r
10886 animInfo.to.x = toX;
\r
10887 animInfo.to.y = toY;
\r
10888 animInfo.lastpos = start;
\r
10889 animInfo.piece = piece;
\r
10890 for (n = 0; n < nFrames; n++) {
\r
10891 animInfo.pos = frames[n];
\r
10892 DrawPosition(FALSE, NULL);
\r
10893 animInfo.lastpos = animInfo.pos;
\r
10894 Sleep(appData.animSpeed);
\r
10896 animInfo.pos = finish;
\r
10897 DrawPosition(FALSE, NULL);
\r
10898 animInfo.piece = EmptySquare;
\r
10899 if(gameInfo.variant == VariantAtomic &&
\r
10900 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10901 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10904 /* Convert board position to corner of screen rect and color */
\r
10907 ScreenSquare(column, row, pt)
\r
10908 int column; int row; POINT * pt;
\r
10911 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10912 pt->y = lineGap + row * (squareSize + lineGap);
\r
10914 pt->x = lineGap + column * (squareSize + lineGap);
\r
10915 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10919 /* Generate a series of frame coords from start->mid->finish.
\r
10920 The movement rate doubles until the half way point is
\r
10921 reached, then halves back down to the final destination,
\r
10922 which gives a nice slow in/out effect. The algorithmn
\r
10923 may seem to generate too many intermediates for short
\r
10924 moves, but remember that the purpose is to attract the
\r
10925 viewers attention to the piece about to be moved and
\r
10926 then to where it ends up. Too few frames would be less
\r
10930 Tween(start, mid, finish, factor, frames, nFrames)
\r
10931 POINT * start; POINT * mid;
\r
10932 POINT * finish; int factor;
\r
10933 POINT frames[]; int * nFrames;
\r
10935 int n, fraction = 1, count = 0;
\r
10937 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10938 for (n = 0; n < factor; n++)
\r
10940 for (n = 0; n < factor; n++) {
\r
10941 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10942 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10944 fraction = fraction / 2;
\r
10948 frames[count] = *mid;
\r
10951 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10953 for (n = 0; n < factor; n++) {
\r
10954 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10955 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10957 fraction = fraction * 2;
\r
10959 *nFrames = count;
\r
10963 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10968 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10969 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10971 OutputDebugString( buf );
\r
10974 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10976 EvalGraphSet( first, last, current, pvInfoList );
\r
10979 void SetProgramStats( FrontEndProgramStats * stats )
\r
10984 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10985 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10987 OutputDebugString( buf );
\r
10990 EngineOutputUpdate( stats );
\r