2 * WinBoard.c -- Windows NT front end to XBoard
\r
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
\r
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
\r
10 * Enhancements Copyright 2005 Alessandro Scotti
\r
12 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
13 * which was written and is copyrighted by Wayne Christopher.
\r
15 * The following terms apply to Digital Equipment Corporation's copyright
\r
16 * interest in XBoard:
\r
17 * ------------------------------------------------------------------------
\r
18 * All Rights Reserved
\r
20 * Permission to use, copy, modify, and distribute this software and its
\r
21 * documentation for any purpose and without fee is hereby granted,
\r
22 * provided that the above copyright notice appear in all copies and that
\r
23 * both that copyright notice and this permission notice appear in
\r
24 * supporting documentation, and that the name of Digital not be
\r
25 * used in advertising or publicity pertaining to distribution of the
\r
26 * software without specific, written prior permission.
\r
28 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
29 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
30 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
31 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
32 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
33 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
35 * ------------------------------------------------------------------------
\r
37 * The following terms apply to the enhanced version of XBoard
\r
38 * distributed by the Free Software Foundation:
\r
39 * ------------------------------------------------------------------------
\r
41 * GNU XBoard is free software: you can redistribute it and/or modify
\r
42 * it under the terms of the GNU General Public License as published by
\r
43 * the Free Software Foundation, either version 3 of the License, or (at
\r
44 * your option) any later version.
\r
46 * GNU XBoard is distributed in the hope that it will be useful, but
\r
47 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
48 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
49 * General Public License for more details.
\r
51 * You should have received a copy of the GNU General Public License
\r
52 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
54 *------------------------------------------------------------------------
\r
55 ** See the file ChangeLog for a revision history. */
\r
59 #include <windows.h>
\r
60 #include <winuser.h>
\r
61 #include <winsock.h>
\r
62 #include <commctrl.h>
\r
68 #include <sys/stat.h>
\r
71 #include <commdlg.h>
\r
73 #include <richedit.h>
\r
74 #include <mmsystem.h>
\r
83 #include "winboard.h"
\r
84 #include "frontend.h"
\r
85 #include "backend.h"
\r
87 #include "wclipbrd.h"
\r
88 #include "wgamelist.h"
\r
89 #include "wedittags.h"
\r
90 #include "woptions.h"
\r
91 #include "wsockerr.h"
\r
92 #include "defaults.h"
\r
96 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
99 void mysrandom(unsigned int seed);
\r
101 extern int whiteFlag, blackFlag;
\r
102 Boolean flipClock = FALSE;
\r
103 extern HANDLE chatHandle[];
\r
104 extern int ics_type;
\r
106 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
107 VOID NewVariantPopup(HWND hwnd);
\r
108 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
109 /*char*/int promoChar));
\r
110 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
111 void DisplayMove P((int moveNumber));
\r
112 Boolean ParseFEN P((Board board, int *blackPlaysFirst, char *fen));
\r
113 void ChatPopUp P(());
\r
115 ChessSquare piece;
\r
116 POINT pos; /* window coordinates of current pos */
\r
117 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
118 POINT from; /* board coordinates of the piece's orig pos */
\r
119 POINT to; /* board coordinates of the piece's new pos */
\r
122 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
125 POINT start; /* window coordinates of start pos */
\r
126 POINT pos; /* window coordinates of current pos */
\r
127 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
128 POINT from; /* board coordinates of the piece's orig pos */
\r
131 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
134 POINT sq[2]; /* board coordinates of from, to squares */
\r
137 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
138 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
140 typedef struct { // [HGM] atomic
\r
141 int fromX, fromY, toX, toY, radius;
\r
144 static ExplodeInfo explodeInfo;
\r
146 /* Window class names */
\r
147 char szAppName[] = "WinBoard";
\r
148 char szConsoleName[] = "WBConsole";
\r
150 /* Title bar text */
\r
151 char szTitle[] = "WinBoard";
\r
152 char szConsoleTitle[] = "I C S Interaction";
\r
155 char *settingsFileName;
\r
156 BOOLEAN saveSettingsOnExit;
\r
157 char installDir[MSG_SIZ];
\r
159 BoardSize boardSize;
\r
160 BOOLEAN chessProgram;
\r
161 static int boardX, boardY;
\r
162 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
\r
163 static int squareSize, lineGap, minorSize;
\r
164 static int winWidth, winHeight, winW, winH;
\r
165 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
166 static int logoHeight = 0;
\r
167 static char messageText[MESSAGE_TEXT_MAX];
\r
168 static int clockTimerEvent = 0;
\r
169 static int loadGameTimerEvent = 0;
\r
170 static int analysisTimerEvent = 0;
\r
171 static DelayedEventCallback delayedTimerCallback;
\r
172 static int delayedTimerEvent = 0;
\r
173 static int buttonCount = 2;
\r
174 char *icsTextMenuString;
\r
176 char *firstChessProgramNames;
\r
177 char *secondChessProgramNames;
\r
179 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
181 #define PALETTESIZE 256
\r
183 HINSTANCE hInst; /* current instance */
\r
184 HWND hwndMain = NULL; /* root window*/
\r
185 HWND hwndConsole = NULL;
\r
186 BOOLEAN alwaysOnTop = FALSE;
\r
188 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
189 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
191 ColorClass currentColorClass;
\r
193 HWND hCommPort = NULL; /* currently open comm port */
\r
194 static HWND hwndPause; /* pause button */
\r
195 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
196 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
197 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
198 explodeBrush, /* [HGM] atomic */
\r
199 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
200 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
201 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
202 static HPEN gridPen = NULL;
\r
203 static HPEN highlightPen = NULL;
\r
204 static HPEN premovePen = NULL;
\r
205 static NPLOGPALETTE pLogPal;
\r
206 static BOOL paletteChanged = FALSE;
\r
207 static HICON iconWhite, iconBlack, iconCurrent;
\r
208 static int doingSizing = FALSE;
\r
209 static int lastSizing = 0;
\r
210 static int prevStderrPort;
\r
211 static HBITMAP userLogo;
\r
213 /* [AS] Support for background textures */
\r
214 #define BACK_TEXTURE_MODE_DISABLED 0
\r
215 #define BACK_TEXTURE_MODE_PLAIN 1
\r
216 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
218 static HBITMAP liteBackTexture = NULL;
\r
219 static HBITMAP darkBackTexture = NULL;
\r
220 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
221 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
222 static int backTextureSquareSize = 0;
\r
223 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
225 #if __GNUC__ && !defined(_winmajor)
\r
226 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
228 #define oldDialog (_winmajor < 4)
\r
231 char *defaultTextAttribs[] =
\r
233 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
234 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
244 int cliWidth, cliHeight;
\r
247 SizeInfo sizeInfo[] =
\r
249 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
250 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
251 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
252 { "petite", 33, 1, 1, 1, 0, 0 },
\r
253 { "slim", 37, 2, 1, 0, 0, 0 },
\r
254 { "small", 40, 2, 1, 0, 0, 0 },
\r
255 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
256 { "middling", 49, 2, 0, 0, 0, 0 },
\r
257 { "average", 54, 2, 0, 0, 0, 0 },
\r
258 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
259 { "medium", 64, 3, 0, 0, 0, 0 },
\r
260 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
261 { "large", 80, 3, 0, 0, 0, 0 },
\r
262 { "big", 87, 3, 0, 0, 0, 0 },
\r
263 { "huge", 95, 3, 0, 0, 0, 0 },
\r
264 { "giant", 108, 3, 0, 0, 0, 0 },
\r
265 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
266 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
267 { NULL, 0, 0, 0, 0, 0, 0 }
\r
270 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
271 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
273 { 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
274 { 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
275 { 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
276 { 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
277 { 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
278 { 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
279 { 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
280 { 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
281 { 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
282 { 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
283 { 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
284 { 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
285 { 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
286 { 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
287 { 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
288 { 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
289 { 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
290 { 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
293 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
302 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
303 #define N_BUTTONS 5
\r
305 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
307 {"<<", IDM_ToStart, NULL, NULL},
\r
308 {"<", IDM_Backward, NULL, NULL},
\r
309 {"P", IDM_Pause, NULL, NULL},
\r
310 {">", IDM_Forward, NULL, NULL},
\r
311 {">>", IDM_ToEnd, NULL, NULL},
\r
314 int tinyLayout = 0, smallLayout = 0;
\r
315 #define MENU_BAR_ITEMS 7
\r
316 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
317 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
318 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
322 MySound sounds[(int)NSoundClasses];
\r
323 MyTextAttribs textAttribs[(int)NColorClasses];
\r
325 MyColorizeAttribs colorizeAttribs[] = {
\r
326 { (COLORREF)0, 0, "Shout Text" },
\r
327 { (COLORREF)0, 0, "SShout/CShout" },
\r
328 { (COLORREF)0, 0, "Channel 1 Text" },
\r
329 { (COLORREF)0, 0, "Channel Text" },
\r
330 { (COLORREF)0, 0, "Kibitz Text" },
\r
331 { (COLORREF)0, 0, "Tell Text" },
\r
332 { (COLORREF)0, 0, "Challenge Text" },
\r
333 { (COLORREF)0, 0, "Request Text" },
\r
334 { (COLORREF)0, 0, "Seek Text" },
\r
335 { (COLORREF)0, 0, "Normal Text" },
\r
336 { (COLORREF)0, 0, "None" }
\r
341 static char *commentTitle;
\r
342 static char *commentText;
\r
343 static int commentIndex;
\r
344 static Boolean editComment = FALSE;
\r
345 HWND commentDialog = NULL;
\r
346 BOOLEAN commentDialogUp = FALSE;
\r
347 static int commentX, commentY, commentH, commentW;
\r
349 static char *analysisTitle;
\r
350 static char *analysisText;
\r
351 HWND analysisDialog = NULL;
\r
352 BOOLEAN analysisDialogUp = FALSE;
\r
353 static int analysisX, analysisY, analysisH, analysisW;
\r
355 char errorTitle[MSG_SIZ];
\r
356 char errorMessage[2*MSG_SIZ];
\r
357 HWND errorDialog = NULL;
\r
358 BOOLEAN moveErrorMessageUp = FALSE;
\r
359 BOOLEAN consoleEcho = TRUE;
\r
360 CHARFORMAT consoleCF;
\r
361 COLORREF consoleBackgroundColor;
\r
363 char *programVersion;
\r
369 typedef int CPKind;
\r
378 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
381 #define INPUT_SOURCE_BUF_SIZE 4096
\r
383 typedef struct _InputSource {
\r
390 char buf[INPUT_SOURCE_BUF_SIZE];
\r
394 InputCallback func;
\r
395 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
399 InputSource *consoleInputSource;
\r
404 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
405 VOID ConsoleCreate();
\r
407 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
408 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
409 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
410 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
412 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
413 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
414 void ParseIcsTextMenu(char *icsTextMenuString);
\r
415 VOID PopUpMoveDialog(char firstchar);
\r
416 VOID PopUpNameDialog(char firstchar);
\r
417 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
421 int GameListOptions();
\r
423 HWND moveHistoryDialog = NULL;
\r
424 BOOLEAN moveHistoryDialogUp = FALSE;
\r
426 WindowPlacement wpMoveHistory;
\r
428 HWND evalGraphDialog = NULL;
\r
429 BOOLEAN evalGraphDialogUp = FALSE;
\r
431 WindowPlacement wpEvalGraph;
\r
433 HWND engineOutputDialog = NULL;
\r
434 BOOLEAN engineOutputDialogUp = FALSE;
\r
436 WindowPlacement wpEngineOutput;
\r
437 WindowPlacement wpGameList;
\r
438 WindowPlacement wpConsole;
\r
440 VOID MoveHistoryPopUp();
\r
441 VOID MoveHistoryPopDown();
\r
442 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
443 BOOL MoveHistoryIsUp();
\r
445 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
446 VOID EvalGraphPopUp();
\r
447 VOID EvalGraphPopDown();
\r
448 BOOL EvalGraphIsUp();
\r
450 VOID EngineOutputPopUp();
\r
451 VOID EngineOutputPopDown();
\r
452 BOOL EngineOutputIsUp();
\r
453 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
455 VOID EngineOptionsPopup(); // [HGM] settings
\r
457 VOID GothicPopUp(char *title, VariantClass variant);
\r
459 * Setting "frozen" should disable all user input other than deleting
\r
460 * the window. We do this while engines are initializing themselves.
\r
462 static int frozen = 0;
\r
463 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
469 if (frozen) return;
\r
471 hmenu = GetMenu(hwndMain);
\r
472 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
473 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
475 DrawMenuBar(hwndMain);
\r
478 /* Undo a FreezeUI */
\r
484 if (!frozen) return;
\r
486 hmenu = GetMenu(hwndMain);
\r
487 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
488 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
490 DrawMenuBar(hwndMain);
\r
493 static int fromX = -1, fromY = -1, toX, toY; // [HGM] moved upstream, so JAWS can use them
\r
495 /* JAWS preparation patch (WinBoard for the sight impaired). Define required insertions as empty */
\r
501 #define JAWS_ALT_INTERCEPT
\r
502 #define JAWS_KB_NAVIGATION
\r
503 #define JAWS_MENU_ITEMS
\r
504 #define JAWS_SILENCE
\r
505 #define JAWS_REPLAY
\r
507 #define JAWS_COPYRIGHT
\r
508 #define JAWS_DELETE(X) X
\r
509 #define SAYMACHINEMOVE()
\r
513 /*---------------------------------------------------------------------------*\
\r
517 \*---------------------------------------------------------------------------*/
\r
520 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
521 LPSTR lpCmdLine, int nCmdShow)
\r
524 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
525 // INITCOMMONCONTROLSEX ex;
\r
529 LoadLibrary("RICHED32.DLL");
\r
530 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
532 if (!InitApplication(hInstance)) {
\r
535 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
541 // InitCommonControlsEx(&ex);
\r
542 InitCommonControls();
\r
544 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
545 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
546 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
548 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
550 while (GetMessage(&msg, /* message structure */
\r
551 NULL, /* handle of window receiving the message */
\r
552 0, /* lowest message to examine */
\r
553 0)) /* highest message to examine */
\r
556 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
557 // [HGM] navigate: switch between all windows with tab
\r
558 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
559 int i, currentElement = 0;
\r
561 // first determine what element of the chain we come from (if any)
\r
562 if(appData.icsActive) {
\r
563 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
564 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
566 if(engineOutputDialog && EngineOutputIsUp()) {
\r
567 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
568 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
570 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
571 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
573 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
574 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
575 if(msg.hwnd == e1) currentElement = 2; else
\r
576 if(msg.hwnd == e2) currentElement = 3; else
\r
577 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
578 if(msg.hwnd == mh) currentElement = 4; else
\r
579 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
580 if(msg.hwnd == hText) currentElement = 5; else
\r
581 if(msg.hwnd == hInput) currentElement = 6; else
\r
582 for (i = 0; i < N_BUTTONS; i++) {
\r
583 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
586 // determine where to go to
\r
587 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
589 currentElement = (currentElement + direction) % 7;
\r
590 switch(currentElement) {
\r
592 h = hwndMain; break; // passing this case always makes the loop exit
\r
594 h = buttonDesc[0].hwnd; break; // could be NULL
\r
596 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
599 if(!EngineOutputIsUp()) continue;
\r
602 if(!MoveHistoryIsUp()) continue;
\r
604 // case 6: // input to eval graph does not seem to get here!
\r
605 // if(!EvalGraphIsUp()) continue;
\r
606 // h = evalGraphDialog; break;
\r
608 if(!appData.icsActive) continue;
\r
612 if(!appData.icsActive) continue;
\r
618 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
619 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
622 continue; // this message now has been processed
\r
626 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
627 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
628 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
629 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
630 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
631 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
632 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
633 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
634 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
635 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
636 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
637 for(i=0; i<MAX_CHAT; i++)
\r
638 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
641 if(done) continue; // [HGM] chat: end patch
\r
642 TranslateMessage(&msg); /* Translates virtual key codes */
\r
643 DispatchMessage(&msg); /* Dispatches message to window */
\r
648 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
651 /*---------------------------------------------------------------------------*\
\r
653 * Initialization functions
\r
655 \*---------------------------------------------------------------------------*/
\r
659 { // update user logo if necessary
\r
660 static char oldUserName[MSG_SIZ], *curName;
\r
662 if(appData.autoLogo) {
\r
663 curName = UserName();
\r
664 if(strcmp(curName, oldUserName)) {
\r
665 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
666 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
667 strcpy(oldUserName, curName);
\r
673 InitApplication(HINSTANCE hInstance)
\r
677 /* Fill in window class structure with parameters that describe the */
\r
680 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
681 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
682 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
683 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
684 wc.hInstance = hInstance; /* Owner of this class */
\r
685 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
686 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
687 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
688 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
689 wc.lpszClassName = szAppName; /* Name to register as */
\r
691 /* Register the window class and return success/failure code. */
\r
692 if (!RegisterClass(&wc)) return FALSE;
\r
694 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
695 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
697 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
698 wc.hInstance = hInstance;
\r
699 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
700 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
701 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
702 wc.lpszMenuName = NULL;
\r
703 wc.lpszClassName = szConsoleName;
\r
705 if (!RegisterClass(&wc)) return FALSE;
\r
710 /* Set by InitInstance, used by EnsureOnScreen */
\r
711 int screenHeight, screenWidth;
\r
714 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
716 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
717 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
718 if (*x > screenWidth - 32) *x = 0;
\r
719 if (*y > screenHeight - 32) *y = 0;
\r
720 if (*x < minX) *x = minX;
\r
721 if (*y < minY) *y = minY;
\r
725 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
727 HWND hwnd; /* Main window handle. */
\r
729 WINDOWPLACEMENT wp;
\r
732 hInst = hInstance; /* Store instance handle in our global variable */
\r
734 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
735 *filepart = NULLCHAR;
\r
737 GetCurrentDirectory(MSG_SIZ, installDir);
\r
739 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
740 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
741 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
742 if (appData.debugMode) {
\r
743 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
744 setbuf(debugFP, NULL);
\r
749 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
750 // InitEngineUCI( installDir, &second );
\r
752 /* Create a main window for this application instance. */
\r
753 hwnd = CreateWindow(szAppName, szTitle,
\r
754 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
755 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
756 NULL, NULL, hInstance, NULL);
\r
759 /* If window could not be created, return "failure" */
\r
764 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
765 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
766 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
768 if (first.programLogo == NULL && appData.debugMode) {
\r
769 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
771 } else if(appData.autoLogo) {
\r
772 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
774 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
775 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
779 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
780 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
782 if (second.programLogo == NULL && appData.debugMode) {
\r
783 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
785 } else if(appData.autoLogo) {
\r
787 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
788 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
789 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
791 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
792 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
793 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
799 iconWhite = LoadIcon(hInstance, "icon_white");
\r
800 iconBlack = LoadIcon(hInstance, "icon_black");
\r
801 iconCurrent = iconWhite;
\r
802 InitDrawingColors();
\r
803 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
804 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
805 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
806 /* Compute window size for each board size, and use the largest
\r
807 size that fits on this screen as the default. */
\r
808 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
809 if (boardSize == (BoardSize)-1 &&
\r
810 winH <= screenHeight
\r
811 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
812 && winW <= screenWidth) {
\r
813 boardSize = (BoardSize)ibs;
\r
817 InitDrawingSizes(boardSize, 0);
\r
819 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
821 /* [AS] Load textures if specified */
\r
822 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
824 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
825 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
826 liteBackTextureMode = appData.liteBackTextureMode;
\r
828 if (liteBackTexture == NULL && appData.debugMode) {
\r
829 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
833 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
834 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
835 darkBackTextureMode = appData.darkBackTextureMode;
\r
837 if (darkBackTexture == NULL && appData.debugMode) {
\r
838 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
842 mysrandom( (unsigned) time(NULL) );
\r
844 /* [AS] Restore layout */
\r
845 if( wpMoveHistory.visible ) {
\r
846 MoveHistoryPopUp();
\r
849 if( wpEvalGraph.visible ) {
\r
853 if( wpEngineOutput.visible ) {
\r
854 EngineOutputPopUp();
\r
859 /* Make the window visible; update its client area; and return "success" */
\r
860 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
861 wp.length = sizeof(WINDOWPLACEMENT);
\r
863 wp.showCmd = nCmdShow;
\r
864 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
865 wp.rcNormalPosition.left = boardX;
\r
866 wp.rcNormalPosition.right = boardX + winWidth;
\r
867 wp.rcNormalPosition.top = boardY;
\r
868 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
869 SetWindowPlacement(hwndMain, &wp);
\r
871 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
872 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
876 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
877 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
879 ShowWindow(hwndConsole, nCmdShow);
\r
881 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
889 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
890 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
891 ArgSettingsFilename,
\r
892 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
900 String *pString; // ArgString
\r
901 int *pInt; // ArgInt
\r
902 float *pFloat; // ArgFloat
\r
903 Boolean *pBoolean; // ArgBoolean
\r
904 COLORREF *pColor; // ArgColor
\r
905 ColorClass cc; // ArgAttribs
\r
906 String *pFilename; // ArgFilename
\r
907 BoardSize *pBoardSize; // ArgBoardSize
\r
908 int whichFont; // ArgFont
\r
909 DCB *pDCB; // ArgCommSettings
\r
910 String *pFilename; // ArgSettingsFilename
\r
918 ArgDescriptor argDescriptors[] = {
\r
919 /* positional arguments */
\r
920 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
921 { "", ArgNone, NULL },
\r
922 /* keyword arguments */
\r
924 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
925 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
926 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
927 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
928 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
929 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
930 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
931 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
932 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
933 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
934 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
935 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
936 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
937 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
938 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
939 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
940 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
941 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
943 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
945 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
947 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
948 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
950 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
951 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
952 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
953 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
954 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
955 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
956 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
957 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
958 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
959 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
960 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
961 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
962 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
963 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
964 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
965 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
966 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
967 /*!!bitmapDirectory?*/
\r
968 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
969 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
970 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
971 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
972 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
973 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
974 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
975 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
976 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
977 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
978 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
979 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
980 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
981 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
982 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
983 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
984 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
985 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
986 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
987 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
988 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
989 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
990 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
991 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
992 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
993 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
994 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
995 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
996 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
997 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
998 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
999 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1000 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1001 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1002 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1003 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
1004 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
1005 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
1006 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1007 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1008 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1009 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1010 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1011 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1012 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1013 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1014 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1015 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1016 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1017 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1018 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1019 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1020 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1021 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1022 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1023 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1024 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1025 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1026 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1027 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1028 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1029 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1030 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1031 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1032 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1033 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1034 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1035 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1036 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1037 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1038 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1039 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1040 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1041 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1042 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1043 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1044 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1045 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1046 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1047 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1048 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1049 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1050 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1051 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1052 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1053 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1054 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1055 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1056 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1057 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1058 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1059 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1060 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1061 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1062 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1063 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1064 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1065 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1066 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1067 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1068 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1069 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1070 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1071 TRUE }, /* must come after all fonts */
\r
1072 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1073 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1074 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1075 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1076 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1077 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1078 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1079 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1080 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1081 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1082 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1083 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1084 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1085 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1086 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1087 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1088 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1089 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1090 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1091 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1092 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1093 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1094 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1095 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1096 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1097 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1098 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1099 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1100 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1101 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1102 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1104 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1105 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1107 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1108 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1109 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1110 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1111 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1112 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1113 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1114 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1115 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1116 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1117 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1118 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1119 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1120 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1121 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1122 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1123 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1124 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1125 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1126 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1127 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1128 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1129 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1130 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1131 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1132 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1133 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1134 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1135 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1136 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1137 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1138 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1139 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1140 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1141 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1142 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1143 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1144 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1145 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1146 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1147 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1148 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1149 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1150 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1151 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1152 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1153 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1154 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1155 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1156 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1157 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1158 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1159 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1160 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1161 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1162 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1163 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1164 { "highlightLastMove", ArgBoolean,
\r
1165 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1166 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1167 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1168 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1169 { "highlightDragging", ArgBoolean,
\r
1170 (LPVOID) &appData.highlightDragging, TRUE },
\r
1171 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1172 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1173 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1174 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1175 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1176 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1177 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1178 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1179 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1180 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1181 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1182 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1183 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1184 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1185 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1186 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1187 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1188 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1189 { "soundShout", ArgFilename,
\r
1190 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1191 { "soundSShout", ArgFilename,
\r
1192 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1193 { "soundChannel1", ArgFilename,
\r
1194 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1195 { "soundChannel", ArgFilename,
\r
1196 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1197 { "soundKibitz", ArgFilename,
\r
1198 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1199 { "soundTell", ArgFilename,
\r
1200 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1201 { "soundChallenge", ArgFilename,
\r
1202 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1203 { "soundRequest", ArgFilename,
\r
1204 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1205 { "soundSeek", ArgFilename,
\r
1206 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1207 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1208 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1209 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1210 { "soundIcsLoss", ArgFilename,
\r
1211 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1212 { "soundIcsDraw", ArgFilename,
\r
1213 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1214 { "soundIcsUnfinished", ArgFilename,
\r
1215 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1216 { "soundIcsAlarm", ArgFilename,
\r
1217 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1218 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1219 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1220 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1221 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1222 { "reuseChessPrograms", ArgBoolean,
\r
1223 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1224 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1225 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1226 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1227 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1228 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1229 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1230 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1231 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1232 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1233 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1234 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1235 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1236 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1237 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1238 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1240 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1242 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1243 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1244 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1245 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1246 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1247 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1248 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1249 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1250 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1251 /* [AS] New features */
\r
1252 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1253 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1254 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1255 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1256 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1257 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1258 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1259 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1260 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1261 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1262 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1263 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1264 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1265 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1266 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1267 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1268 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1269 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1270 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1271 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1272 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1273 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1274 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1275 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1276 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1277 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1278 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1279 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1280 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1281 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1282 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1283 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1284 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1285 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1286 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1287 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1288 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1289 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1290 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1291 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1292 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1293 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1294 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1295 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1296 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1297 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1298 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1299 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1300 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1301 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1303 /* [HGM] board-size, adjudication and misc. options */
\r
1304 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1305 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1306 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1307 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1308 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1309 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1310 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1311 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1312 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1313 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1314 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1315 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1316 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1317 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1318 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1319 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1320 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1321 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1322 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1323 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1324 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1325 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1326 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1327 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1328 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1329 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1330 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1331 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1332 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1333 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1334 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1335 { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },
\r
1336 { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },
\r
1339 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1340 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1341 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1342 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1343 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1344 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1345 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1346 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1347 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1348 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1349 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1350 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1351 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1353 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1354 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1355 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1356 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1357 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1358 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1359 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1361 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1362 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1363 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1364 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1365 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1366 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1367 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1368 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1369 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1370 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1371 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1372 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1373 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1374 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1375 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1376 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1377 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1378 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1379 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1381 /* [HGM] options for broadcasting and time odds */
\r
1382 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1383 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1384 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1385 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1386 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1387 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1388 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1389 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1390 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1391 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1392 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1394 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1395 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1396 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1397 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1398 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1399 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1400 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1401 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1402 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1403 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1404 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1405 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1406 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1407 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1408 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1409 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1410 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1411 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1412 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1413 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1414 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1415 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1416 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1417 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1418 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1419 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1420 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1421 /* [AS] Layout stuff */
\r
1422 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1423 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1424 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1425 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1426 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1428 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1429 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1430 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1431 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1432 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1434 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1435 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1436 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1437 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1438 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1440 { NULL, ArgNone, NULL, FALSE }
\r
1444 /* Kludge for indirection files on command line */
\r
1445 char* lastIndirectionFilename;
\r
1446 ArgDescriptor argDescriptorIndirection =
\r
1447 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1451 ExitArgError(char *msg, char *badArg)
\r
1453 char buf[MSG_SIZ];
\r
1455 sprintf(buf, "%s %s", msg, badArg);
\r
1456 DisplayFatalError(buf, 0, 2);
\r
1460 /* Command line font name parser. NULL name means do nothing.
\r
1461 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1462 For backward compatibility, syntax without the colon is also
\r
1463 accepted, but font names with digits in them won't work in that case.
\r
1466 ParseFontName(char *name, MyFontParams *mfp)
\r
1469 if (name == NULL) return;
\r
1471 q = strchr(p, ':');
\r
1473 if (q - p >= sizeof(mfp->faceName))
\r
1474 ExitArgError("Font name too long:", name);
\r
1475 memcpy(mfp->faceName, p, q - p);
\r
1476 mfp->faceName[q - p] = NULLCHAR;
\r
1479 q = mfp->faceName;
\r
1480 while (*p && !isdigit(*p)) {
\r
1482 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1483 ExitArgError("Font name too long:", name);
\r
1485 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1488 if (!*p) ExitArgError("Font point size missing:", name);
\r
1489 mfp->pointSize = (float) atof(p);
\r
1490 mfp->bold = (strchr(p, 'b') != NULL);
\r
1491 mfp->italic = (strchr(p, 'i') != NULL);
\r
1492 mfp->underline = (strchr(p, 'u') != NULL);
\r
1493 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1496 /* Color name parser.
\r
1497 X version accepts X color names, but this one
\r
1498 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1500 ParseColorName(char *name)
\r
1502 int red, green, blue, count;
\r
1503 char buf[MSG_SIZ];
\r
1505 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1507 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1508 &red, &green, &blue);
\r
1511 sprintf(buf, "Can't parse color name %s", name);
\r
1512 DisplayError(buf, 0);
\r
1513 return RGB(0, 0, 0);
\r
1515 return PALETTERGB(red, green, blue);
\r
1519 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1521 char *e = argValue;
\r
1525 if (*e == 'b') eff |= CFE_BOLD;
\r
1526 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1527 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1528 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1529 else if (*e == '#' || isdigit(*e)) break;
\r
1533 *color = ParseColorName(e);
\r
1538 ParseBoardSize(char *name)
\r
1540 BoardSize bs = SizeTiny;
\r
1541 while (sizeInfo[bs].name != NULL) {
\r
1542 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1545 ExitArgError("Unrecognized board size value", name);
\r
1546 return bs; /* not reached */
\r
1551 StringGet(void *getClosure)
\r
1553 char **p = (char **) getClosure;
\r
1558 FileGet(void *getClosure)
\r
1561 FILE* f = (FILE*) getClosure;
\r
1564 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1571 /* Parse settings file named "name". If file found, return the
\r
1572 full name in fullname and return TRUE; else return FALSE */
\r
1574 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1578 int ok; char buf[MSG_SIZ];
\r
1580 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1581 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1582 sprintf(buf, "%s.ini", name);
\r
1583 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1586 f = fopen(fullname, "r");
\r
1588 ParseArgs(FileGet, f);
\r
1597 ParseArgs(GetFunc get, void *cl)
\r
1599 char argName[ARG_MAX];
\r
1600 char argValue[ARG_MAX];
\r
1601 ArgDescriptor *ad;
\r
1610 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1611 if (ch == NULLCHAR) break;
\r
1613 /* Comment to end of line */
\r
1615 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1617 } else if (ch == '/' || ch == '-') {
\r
1620 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1621 ch != '\n' && ch != '\t') {
\r
1627 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1628 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1630 if (ad->argName == NULL)
\r
1631 ExitArgError("Unrecognized argument", argName);
\r
1633 } else if (ch == '@') {
\r
1634 /* Indirection file */
\r
1635 ad = &argDescriptorIndirection;
\r
1638 /* Positional argument */
\r
1639 ad = &argDescriptors[posarg++];
\r
1640 strcpy(argName, ad->argName);
\r
1643 if (ad->argType == ArgTrue) {
\r
1644 *(Boolean *) ad->argLoc = TRUE;
\r
1647 if (ad->argType == ArgFalse) {
\r
1648 *(Boolean *) ad->argLoc = FALSE;
\r
1652 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1653 if (ch == NULLCHAR || ch == '\n') {
\r
1654 ExitArgError("No value provided for argument", argName);
\r
1658 // Quoting with { }. No characters have to (or can) be escaped.
\r
1659 // Thus the string cannot contain a '}' character.
\r
1679 } else if (ch == '\'' || ch == '"') {
\r
1680 // Quoting with ' ' or " ", with \ as escape character.
\r
1681 // Inconvenient for long strings that may contain Windows filenames.
\r
1698 if (ch == start) {
\r
1707 if (ad->argType == ArgFilename
\r
1708 || ad->argType == ArgSettingsFilename) {
\r
1714 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1738 for (i = 0; i < 3; i++) {
\r
1739 if (ch >= '0' && ch <= '7') {
\r
1740 octval = octval*8 + (ch - '0');
\r
1747 *q++ = (char) octval;
\r
1758 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1765 switch (ad->argType) {
\r
1767 *(int *) ad->argLoc = atoi(argValue);
\r
1771 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1775 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1779 *(int *) ad->argLoc = atoi(argValue);
\r
1780 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1784 *(float *) ad->argLoc = (float) atof(argValue);
\r
1789 *(char **) ad->argLoc = strdup(argValue);
\r
1792 case ArgSettingsFilename:
\r
1794 char fullname[MSG_SIZ];
\r
1795 if (ParseSettingsFile(argValue, fullname)) {
\r
1796 if (ad->argLoc != NULL) {
\r
1797 *(char **) ad->argLoc = strdup(fullname);
\r
1800 if (ad->argLoc != NULL) {
\r
1802 ExitArgError("Failed to open indirection file", argValue);
\r
1809 switch (argValue[0]) {
\r
1812 *(Boolean *) ad->argLoc = TRUE;
\r
1816 *(Boolean *) ad->argLoc = FALSE;
\r
1819 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1825 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1828 case ArgAttribs: {
\r
1829 ColorClass cc = (ColorClass)ad->argLoc;
\r
1830 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1834 case ArgBoardSize:
\r
1835 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1839 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1842 case ArgCommSettings:
\r
1843 ParseCommSettings(argValue, &dcb);
\r
1847 ExitArgError("Unrecognized argument", argValue);
\r
1856 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1858 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1859 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1862 lf->lfEscapement = 0;
\r
1863 lf->lfOrientation = 0;
\r
1864 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1865 lf->lfItalic = mfp->italic;
\r
1866 lf->lfUnderline = mfp->underline;
\r
1867 lf->lfStrikeOut = mfp->strikeout;
\r
1868 lf->lfCharSet = DEFAULT_CHARSET;
\r
1869 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1870 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1871 lf->lfQuality = DEFAULT_QUALITY;
\r
1872 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1873 strcpy(lf->lfFaceName, mfp->faceName);
\r
1877 CreateFontInMF(MyFont *mf)
\r
1879 LFfromMFP(&mf->lf, &mf->mfp);
\r
1880 if (mf->hf) DeleteObject(mf->hf);
\r
1881 mf->hf = CreateFontIndirect(&mf->lf);
\r
1885 SetDefaultTextAttribs()
\r
1888 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1889 ParseAttribs(&textAttribs[cc].color,
\r
1890 &textAttribs[cc].effects,
\r
1891 defaultTextAttribs[cc]);
\r
1896 SetDefaultSounds()
\r
1900 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1901 textAttribs[cc].sound.name = strdup("");
\r
1902 textAttribs[cc].sound.data = NULL;
\r
1904 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1905 sounds[sc].name = strdup("");
\r
1906 sounds[sc].data = NULL;
\r
1908 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1916 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1917 MyLoadSound(&textAttribs[cc].sound);
\r
1919 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1920 MyLoadSound(&sounds[sc]);
\r
1925 InitAppData(LPSTR lpCmdLine)
\r
1928 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1931 programName = szAppName;
\r
1933 /* Initialize to defaults */
\r
1934 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1935 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1936 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1937 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1938 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1939 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1940 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1941 SetDefaultTextAttribs();
\r
1942 SetDefaultSounds();
\r
1943 appData.movesPerSession = MOVES_PER_SESSION;
\r
1944 appData.initString = INIT_STRING;
\r
1945 appData.secondInitString = INIT_STRING;
\r
1946 appData.firstComputerString = COMPUTER_STRING;
\r
1947 appData.secondComputerString = COMPUTER_STRING;
\r
1948 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1949 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1950 appData.firstPlaysBlack = FALSE;
\r
1951 appData.noChessProgram = FALSE;
\r
1952 chessProgram = FALSE;
\r
1953 appData.firstHost = FIRST_HOST;
\r
1954 appData.secondHost = SECOND_HOST;
\r
1955 appData.firstDirectory = FIRST_DIRECTORY;
\r
1956 appData.secondDirectory = SECOND_DIRECTORY;
\r
1957 appData.bitmapDirectory = "";
\r
1958 appData.remoteShell = REMOTE_SHELL;
\r
1959 appData.remoteUser = "";
\r
1960 appData.timeDelay = TIME_DELAY;
\r
1961 appData.timeControl = TIME_CONTROL;
\r
1962 appData.timeIncrement = TIME_INCREMENT;
\r
1963 appData.icsActive = FALSE;
\r
1964 appData.icsHost = "";
\r
1965 appData.icsPort = ICS_PORT;
\r
1966 appData.icsCommPort = ICS_COMM_PORT;
\r
1967 appData.icsLogon = ICS_LOGON;
\r
1968 appData.icsHelper = "";
\r
1969 appData.useTelnet = FALSE;
\r
1970 appData.telnetProgram = TELNET_PROGRAM;
\r
1971 appData.gateway = "";
\r
1972 appData.loadGameFile = "";
\r
1973 appData.loadGameIndex = 0;
\r
1974 appData.saveGameFile = "";
\r
1975 appData.autoSaveGames = FALSE;
\r
1976 appData.loadPositionFile = "";
\r
1977 appData.loadPositionIndex = 1;
\r
1978 appData.savePositionFile = "";
\r
1979 appData.matchMode = FALSE;
\r
1980 appData.matchGames = 0;
\r
1981 appData.monoMode = FALSE;
\r
1982 appData.debugMode = FALSE;
\r
1983 appData.clockMode = TRUE;
\r
1984 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1985 appData.Iconic = FALSE; /*unused*/
\r
1986 appData.searchTime = "";
\r
1987 appData.searchDepth = 0;
\r
1988 appData.showCoords = FALSE;
\r
1989 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1990 appData.autoCallFlag = FALSE;
\r
1991 appData.flipView = FALSE;
\r
1992 appData.autoFlipView = TRUE;
\r
1993 appData.cmailGameName = "";
\r
1994 appData.alwaysPromoteToQueen = FALSE;
\r
1995 appData.oldSaveStyle = FALSE;
\r
1996 appData.quietPlay = FALSE;
\r
1997 appData.showThinking = FALSE;
\r
1998 appData.ponderNextMove = TRUE;
\r
1999 appData.periodicUpdates = TRUE;
\r
2000 appData.popupExitMessage = TRUE;
\r
2001 appData.popupMoveErrors = FALSE;
\r
2002 appData.autoObserve = FALSE;
\r
2003 appData.autoComment = FALSE;
\r
2004 appData.animate = TRUE;
\r
2005 appData.animSpeed = 10;
\r
2006 appData.animateDragging = TRUE;
\r
2007 appData.highlightLastMove = TRUE;
\r
2008 appData.getMoveList = TRUE;
\r
2009 appData.testLegality = TRUE;
\r
2010 appData.premove = TRUE;
\r
2011 appData.premoveWhite = FALSE;
\r
2012 appData.premoveWhiteText = "";
\r
2013 appData.premoveBlack = FALSE;
\r
2014 appData.premoveBlackText = "";
\r
2015 appData.icsAlarm = TRUE;
\r
2016 appData.icsAlarmTime = 5000;
\r
2017 appData.autoRaiseBoard = TRUE;
\r
2018 appData.localLineEditing = TRUE;
\r
2019 appData.colorize = TRUE;
\r
2020 appData.reuseFirst = TRUE;
\r
2021 appData.reuseSecond = TRUE;
\r
2022 appData.blindfold = FALSE;
\r
2023 appData.icsEngineAnalyze = FALSE;
\r
2024 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2025 dcb.DCBlength = sizeof(DCB);
\r
2026 dcb.BaudRate = 9600;
\r
2027 dcb.fBinary = TRUE;
\r
2028 dcb.fParity = FALSE;
\r
2029 dcb.fOutxCtsFlow = FALSE;
\r
2030 dcb.fOutxDsrFlow = FALSE;
\r
2031 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2032 dcb.fDsrSensitivity = FALSE;
\r
2033 dcb.fTXContinueOnXoff = TRUE;
\r
2034 dcb.fOutX = FALSE;
\r
2036 dcb.fNull = FALSE;
\r
2037 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2038 dcb.fAbortOnError = FALSE;
\r
2040 dcb.Parity = SPACEPARITY;
\r
2041 dcb.StopBits = ONESTOPBIT;
\r
2042 settingsFileName = SETTINGS_FILE;
\r
2043 saveSettingsOnExit = TRUE;
\r
2044 boardX = CW_USEDEFAULT;
\r
2045 boardY = CW_USEDEFAULT;
\r
2046 analysisX = CW_USEDEFAULT;
\r
2047 analysisY = CW_USEDEFAULT;
\r
2048 analysisW = CW_USEDEFAULT;
\r
2049 analysisH = CW_USEDEFAULT;
\r
2050 commentX = CW_USEDEFAULT;
\r
2051 commentY = CW_USEDEFAULT;
\r
2052 commentW = CW_USEDEFAULT;
\r
2053 commentH = CW_USEDEFAULT;
\r
2054 editTagsX = CW_USEDEFAULT;
\r
2055 editTagsY = CW_USEDEFAULT;
\r
2056 editTagsW = CW_USEDEFAULT;
\r
2057 editTagsH = CW_USEDEFAULT;
\r
2058 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2059 icsNames = ICS_NAMES;
\r
2060 firstChessProgramNames = FCP_NAMES;
\r
2061 secondChessProgramNames = SCP_NAMES;
\r
2062 appData.initialMode = "";
\r
2063 appData.variant = "normal";
\r
2064 appData.firstProtocolVersion = PROTOVER;
\r
2065 appData.secondProtocolVersion = PROTOVER;
\r
2066 appData.showButtonBar = TRUE;
\r
2068 /* [AS] New properties (see comments in header file) */
\r
2069 appData.firstScoreIsAbsolute = FALSE;
\r
2070 appData.secondScoreIsAbsolute = FALSE;
\r
2071 appData.saveExtendedInfoInPGN = FALSE;
\r
2072 appData.hideThinkingFromHuman = FALSE;
\r
2073 appData.liteBackTextureFile = "";
\r
2074 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2075 appData.darkBackTextureFile = "";
\r
2076 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2077 appData.renderPiecesWithFont = "";
\r
2078 appData.fontToPieceTable = "";
\r
2079 appData.fontBackColorWhite = 0;
\r
2080 appData.fontForeColorWhite = 0;
\r
2081 appData.fontBackColorBlack = 0;
\r
2082 appData.fontForeColorBlack = 0;
\r
2083 appData.fontPieceSize = 80;
\r
2084 appData.overrideLineGap = 1;
\r
2085 appData.adjudicateLossThreshold = 0;
\r
2086 appData.delayBeforeQuit = 0;
\r
2087 appData.delayAfterQuit = 0;
\r
2088 appData.nameOfDebugFile = "winboard.debug";
\r
2089 appData.pgnEventHeader = "Computer Chess Game";
\r
2090 appData.defaultFrcPosition = -1;
\r
2091 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2092 appData.saveOutOfBookInfo = TRUE;
\r
2093 appData.showEvalInMoveHistory = TRUE;
\r
2094 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2095 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2096 appData.highlightMoveWithArrow = FALSE;
\r
2097 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2098 appData.useStickyWindows = TRUE;
\r
2099 appData.adjudicateDrawMoves = 0;
\r
2100 appData.autoDisplayComment = TRUE;
\r
2101 appData.autoDisplayTags = TRUE;
\r
2102 appData.firstIsUCI = FALSE;
\r
2103 appData.secondIsUCI = FALSE;
\r
2104 appData.firstHasOwnBookUCI = TRUE;
\r
2105 appData.secondHasOwnBookUCI = TRUE;
\r
2106 appData.polyglotDir = "";
\r
2107 appData.usePolyglotBook = FALSE;
\r
2108 appData.polyglotBook = "";
\r
2109 appData.defaultHashSize = 64;
\r
2110 appData.defaultCacheSizeEGTB = 4;
\r
2111 appData.defaultPathEGTB = "c:\\egtb";
\r
2112 appData.firstOptions = "";
\r
2113 appData.secondOptions = "";
\r
2115 InitWindowPlacement( &wpGameList );
\r
2116 InitWindowPlacement( &wpMoveHistory );
\r
2117 InitWindowPlacement( &wpEvalGraph );
\r
2118 InitWindowPlacement( &wpEngineOutput );
\r
2119 InitWindowPlacement( &wpConsole );
\r
2121 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2122 appData.NrFiles = -1;
\r
2123 appData.NrRanks = -1;
\r
2124 appData.holdingsSize = -1;
\r
2125 appData.testClaims = FALSE;
\r
2126 appData.checkMates = FALSE;
\r
2127 appData.materialDraws= FALSE;
\r
2128 appData.trivialDraws = FALSE;
\r
2129 appData.ruleMoves = 51;
\r
2130 appData.drawRepeats = 6;
\r
2131 appData.matchPause = 10000;
\r
2132 appData.alphaRank = FALSE;
\r
2133 appData.allWhite = FALSE;
\r
2134 appData.upsideDown = FALSE;
\r
2135 appData.serverPause = 15;
\r
2136 appData.serverMovesName = NULL;
\r
2137 appData.suppressLoadMoves = FALSE;
\r
2138 appData.firstTimeOdds = 1;
\r
2139 appData.secondTimeOdds = 1;
\r
2140 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2141 appData.secondAccumulateTC = 1;
\r
2142 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2143 appData.secondNPS = -1;
\r
2144 appData.engineComments = 1;
\r
2145 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2146 appData.egtFormats = "";
\r
2149 appData.zippyTalk = ZIPPY_TALK;
\r
2150 appData.zippyPlay = ZIPPY_PLAY;
\r
2151 appData.zippyLines = ZIPPY_LINES;
\r
2152 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2153 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2154 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2155 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2156 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2157 appData.zippyUseI = ZIPPY_USE_I;
\r
2158 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2159 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2160 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2161 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2162 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2163 appData.zippyAbort = ZIPPY_ABORT;
\r
2164 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2165 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2166 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2169 /* Point font array elements to structures and
\r
2170 parse default font names */
\r
2171 for (i=0; i<NUM_FONTS; i++) {
\r
2172 for (j=0; j<NUM_SIZES; j++) {
\r
2173 font[j][i] = &fontRec[j][i];
\r
2174 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2178 /* Parse default settings file if any */
\r
2179 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2180 settingsFileName = strdup(buf);
\r
2183 /* Parse command line */
\r
2184 ParseArgs(StringGet, &lpCmdLine);
\r
2186 /* [HGM] make sure board size is acceptable */
\r
2187 if(appData.NrFiles > BOARD_SIZE ||
\r
2188 appData.NrRanks > BOARD_SIZE )
\r
2189 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2191 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2192 * with options from the command line, we now make an even higher priority
\r
2193 * overrule by WB options attached to the engine command line. This so that
\r
2194 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2197 if(appData.firstChessProgram != NULL) {
\r
2198 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2199 static char *f = "first";
\r
2200 char buf[MSG_SIZ], *q = buf;
\r
2201 if(p != NULL) { // engine command line contains WinBoard options
\r
2202 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2203 ParseArgs(StringGet, &q);
\r
2204 p[-1] = 0; // cut them offengine command line
\r
2207 // now do same for second chess program
\r
2208 if(appData.secondChessProgram != NULL) {
\r
2209 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2210 static char *s = "second";
\r
2211 char buf[MSG_SIZ], *q = buf;
\r
2212 if(p != NULL) { // engine command line contains WinBoard options
\r
2213 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2214 ParseArgs(StringGet, &q);
\r
2215 p[-1] = 0; // cut them offengine command line
\r
2220 /* Propagate options that affect others */
\r
2221 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2222 if (appData.icsActive || appData.noChessProgram) {
\r
2223 chessProgram = FALSE; /* not local chess program mode */
\r
2226 /* Open startup dialog if needed */
\r
2227 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2228 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2229 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2230 *appData.secondChessProgram == NULLCHAR))) {
\r
2233 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2234 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2235 FreeProcInstance(lpProc);
\r
2238 /* Make sure save files land in the right (?) directory */
\r
2239 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2240 appData.saveGameFile = strdup(buf);
\r
2242 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2243 appData.savePositionFile = strdup(buf);
\r
2246 /* Finish initialization for fonts and sounds */
\r
2247 for (i=0; i<NUM_FONTS; i++) {
\r
2248 for (j=0; j<NUM_SIZES; j++) {
\r
2249 CreateFontInMF(font[j][i]);
\r
2252 /* xboard, and older WinBoards, controlled the move sound with the
\r
2253 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2254 always turn the option on (so that the backend will call us),
\r
2255 then let the user turn the sound off by setting it to silence if
\r
2256 desired. To accommodate old winboard.ini files saved by old
\r
2257 versions of WinBoard, we also turn off the sound if the option
\r
2258 was initially set to false. */
\r
2259 if (!appData.ringBellAfterMoves) {
\r
2260 sounds[(int)SoundMove].name = strdup("");
\r
2261 appData.ringBellAfterMoves = TRUE;
\r
2263 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2264 SetCurrentDirectory(installDir);
\r
2266 SetCurrentDirectory(currDir);
\r
2268 p = icsTextMenuString;
\r
2269 if (p[0] == '@') {
\r
2270 FILE* f = fopen(p + 1, "r");
\r
2272 DisplayFatalError(p + 1, errno, 2);
\r
2275 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2277 buf[i] = NULLCHAR;
\r
2280 ParseIcsTextMenu(strdup(p));
\r
2287 HMENU hmenu = GetMenu(hwndMain);
\r
2289 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2290 MF_BYCOMMAND|((appData.icsActive &&
\r
2291 *appData.icsCommPort != NULLCHAR) ?
\r
2292 MF_ENABLED : MF_GRAYED));
\r
2293 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2294 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2295 MF_CHECKED : MF_UNCHECKED));
\r
2300 SaveSettings(char* name)
\r
2303 ArgDescriptor *ad;
\r
2304 WINDOWPLACEMENT wp;
\r
2305 char dir[MSG_SIZ];
\r
2307 if (!hwndMain) return;
\r
2309 GetCurrentDirectory(MSG_SIZ, dir);
\r
2310 SetCurrentDirectory(installDir);
\r
2311 f = fopen(name, "w");
\r
2312 SetCurrentDirectory(dir);
\r
2314 DisplayError(name, errno);
\r
2317 fprintf(f, ";\n");
\r
2318 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2319 fprintf(f, ";\n");
\r
2320 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2321 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2322 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2323 fprintf(f, ";\n");
\r
2325 wp.length = sizeof(WINDOWPLACEMENT);
\r
2326 GetWindowPlacement(hwndMain, &wp);
\r
2327 boardX = wp.rcNormalPosition.left;
\r
2328 boardY = wp.rcNormalPosition.top;
\r
2330 if (hwndConsole) {
\r
2331 GetWindowPlacement(hwndConsole, &wp);
\r
2332 wpConsole.x = wp.rcNormalPosition.left;
\r
2333 wpConsole.y = wp.rcNormalPosition.top;
\r
2334 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2335 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2338 if (analysisDialog) {
\r
2339 GetWindowPlacement(analysisDialog, &wp);
\r
2340 analysisX = wp.rcNormalPosition.left;
\r
2341 analysisY = wp.rcNormalPosition.top;
\r
2342 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2343 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2346 if (commentDialog) {
\r
2347 GetWindowPlacement(commentDialog, &wp);
\r
2348 commentX = wp.rcNormalPosition.left;
\r
2349 commentY = wp.rcNormalPosition.top;
\r
2350 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2351 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2354 if (editTagsDialog) {
\r
2355 GetWindowPlacement(editTagsDialog, &wp);
\r
2356 editTagsX = wp.rcNormalPosition.left;
\r
2357 editTagsY = wp.rcNormalPosition.top;
\r
2358 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2359 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2362 if (gameListDialog) {
\r
2363 GetWindowPlacement(gameListDialog, &wp);
\r
2364 wpGameList.x = wp.rcNormalPosition.left;
\r
2365 wpGameList.y = wp.rcNormalPosition.top;
\r
2366 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2367 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2370 /* [AS] Move history */
\r
2371 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2373 if( moveHistoryDialog ) {
\r
2374 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2375 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2376 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2377 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2378 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2381 /* [AS] Eval graph */
\r
2382 wpEvalGraph.visible = EvalGraphIsUp();
\r
2384 if( evalGraphDialog ) {
\r
2385 GetWindowPlacement(evalGraphDialog, &wp);
\r
2386 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2387 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2388 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2389 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2392 /* [AS] Engine output */
\r
2393 wpEngineOutput.visible = EngineOutputIsUp();
\r
2395 if( engineOutputDialog ) {
\r
2396 GetWindowPlacement(engineOutputDialog, &wp);
\r
2397 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2398 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2399 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2400 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2403 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2404 if (!ad->save) continue;
\r
2405 switch (ad->argType) {
\r
2408 char *p = *(char **)ad->argLoc;
\r
2409 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2410 /* Quote multiline values or \-containing values
\r
2411 with { } if possible */
\r
2412 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2414 /* Else quote with " " */
\r
2415 fprintf(f, "/%s=\"", ad->argName);
\r
2417 if (*p == '\n') fprintf(f, "\n");
\r
2418 else if (*p == '\r') fprintf(f, "\\r");
\r
2419 else if (*p == '\t') fprintf(f, "\\t");
\r
2420 else if (*p == '\b') fprintf(f, "\\b");
\r
2421 else if (*p == '\f') fprintf(f, "\\f");
\r
2422 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2423 else if (*p == '\"') fprintf(f, "\\\"");
\r
2424 else if (*p == '\\') fprintf(f, "\\\\");
\r
2428 fprintf(f, "\"\n");
\r
2434 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2437 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2440 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2443 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2446 fprintf(f, "/%s=%s\n", ad->argName,
\r
2447 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2450 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2453 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2457 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2458 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2459 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2464 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2465 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2466 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2467 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2468 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2469 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2470 (ta->effects) ? " " : "",
\r
2471 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2475 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2476 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2478 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2481 case ArgBoardSize:
\r
2482 fprintf(f, "/%s=%s\n", ad->argName,
\r
2483 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2488 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2489 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2490 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2491 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2492 ad->argName, mfp->faceName, mfp->pointSize,
\r
2493 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2494 mfp->bold ? "b" : "",
\r
2495 mfp->italic ? "i" : "",
\r
2496 mfp->underline ? "u" : "",
\r
2497 mfp->strikeout ? "s" : "");
\r
2501 case ArgCommSettings:
\r
2502 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2504 case ArgSettingsFilename: ;
\r
2512 /*---------------------------------------------------------------------------*\
\r
2514 * GDI board drawing routines
\r
2516 \*---------------------------------------------------------------------------*/
\r
2518 /* [AS] Draw square using background texture */
\r
2519 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2524 return; /* Should never happen! */
\r
2527 SetGraphicsMode( dst, GM_ADVANCED );
\r
2534 /* X reflection */
\r
2539 x.eDx = (FLOAT) dw + dx - 1;
\r
2542 SetWorldTransform( dst, &x );
\r
2545 /* Y reflection */
\r
2551 x.eDy = (FLOAT) dh + dy - 1;
\r
2553 SetWorldTransform( dst, &x );
\r
2561 x.eDx = (FLOAT) dx;
\r
2562 x.eDy = (FLOAT) dy;
\r
2565 SetWorldTransform( dst, &x );
\r
2569 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2577 SetWorldTransform( dst, &x );
\r
2579 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2582 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2584 PM_WP = (int) WhitePawn,
\r
2585 PM_WN = (int) WhiteKnight,
\r
2586 PM_WB = (int) WhiteBishop,
\r
2587 PM_WR = (int) WhiteRook,
\r
2588 PM_WQ = (int) WhiteQueen,
\r
2589 PM_WF = (int) WhiteFerz,
\r
2590 PM_WW = (int) WhiteWazir,
\r
2591 PM_WE = (int) WhiteAlfil,
\r
2592 PM_WM = (int) WhiteMan,
\r
2593 PM_WO = (int) WhiteCannon,
\r
2594 PM_WU = (int) WhiteUnicorn,
\r
2595 PM_WH = (int) WhiteNightrider,
\r
2596 PM_WA = (int) WhiteAngel,
\r
2597 PM_WC = (int) WhiteMarshall,
\r
2598 PM_WAB = (int) WhiteCardinal,
\r
2599 PM_WD = (int) WhiteDragon,
\r
2600 PM_WL = (int) WhiteLance,
\r
2601 PM_WS = (int) WhiteCobra,
\r
2602 PM_WV = (int) WhiteFalcon,
\r
2603 PM_WSG = (int) WhiteSilver,
\r
2604 PM_WG = (int) WhiteGrasshopper,
\r
2605 PM_WK = (int) WhiteKing,
\r
2606 PM_BP = (int) BlackPawn,
\r
2607 PM_BN = (int) BlackKnight,
\r
2608 PM_BB = (int) BlackBishop,
\r
2609 PM_BR = (int) BlackRook,
\r
2610 PM_BQ = (int) BlackQueen,
\r
2611 PM_BF = (int) BlackFerz,
\r
2612 PM_BW = (int) BlackWazir,
\r
2613 PM_BE = (int) BlackAlfil,
\r
2614 PM_BM = (int) BlackMan,
\r
2615 PM_BO = (int) BlackCannon,
\r
2616 PM_BU = (int) BlackUnicorn,
\r
2617 PM_BH = (int) BlackNightrider,
\r
2618 PM_BA = (int) BlackAngel,
\r
2619 PM_BC = (int) BlackMarshall,
\r
2620 PM_BG = (int) BlackGrasshopper,
\r
2621 PM_BAB = (int) BlackCardinal,
\r
2622 PM_BD = (int) BlackDragon,
\r
2623 PM_BL = (int) BlackLance,
\r
2624 PM_BS = (int) BlackCobra,
\r
2625 PM_BV = (int) BlackFalcon,
\r
2626 PM_BSG = (int) BlackSilver,
\r
2627 PM_BK = (int) BlackKing
\r
2630 static HFONT hPieceFont = NULL;
\r
2631 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2632 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2633 static int fontBitmapSquareSize = 0;
\r
2634 static char pieceToFontChar[(int) EmptySquare] =
\r
2635 { 'p', 'n', 'b', 'r', 'q',
\r
2636 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2637 'k', 'o', 'm', 'v', 't', 'w',
\r
2638 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2641 extern BOOL SetCharTable( char *table, const char * map );
\r
2642 /* [HGM] moved to backend.c */
\r
2644 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2647 BYTE r1 = GetRValue( color );
\r
2648 BYTE g1 = GetGValue( color );
\r
2649 BYTE b1 = GetBValue( color );
\r
2655 /* Create a uniform background first */
\r
2656 hbrush = CreateSolidBrush( color );
\r
2657 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2658 FillRect( hdc, &rc, hbrush );
\r
2659 DeleteObject( hbrush );
\r
2662 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2663 int steps = squareSize / 2;
\r
2666 for( i=0; i<steps; i++ ) {
\r
2667 BYTE r = r1 - (r1-r2) * i / steps;
\r
2668 BYTE g = g1 - (g1-g2) * i / steps;
\r
2669 BYTE b = b1 - (b1-b2) * i / steps;
\r
2671 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2672 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2673 FillRect( hdc, &rc, hbrush );
\r
2674 DeleteObject(hbrush);
\r
2677 else if( mode == 2 ) {
\r
2678 /* Diagonal gradient, good more or less for every piece */
\r
2679 POINT triangle[3];
\r
2680 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2681 HBRUSH hbrush_old;
\r
2682 int steps = squareSize;
\r
2685 triangle[0].x = squareSize - steps;
\r
2686 triangle[0].y = squareSize;
\r
2687 triangle[1].x = squareSize;
\r
2688 triangle[1].y = squareSize;
\r
2689 triangle[2].x = squareSize;
\r
2690 triangle[2].y = squareSize - steps;
\r
2692 for( i=0; i<steps; i++ ) {
\r
2693 BYTE r = r1 - (r1-r2) * i / steps;
\r
2694 BYTE g = g1 - (g1-g2) * i / steps;
\r
2695 BYTE b = b1 - (b1-b2) * i / steps;
\r
2697 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2698 hbrush_old = SelectObject( hdc, hbrush );
\r
2699 Polygon( hdc, triangle, 3 );
\r
2700 SelectObject( hdc, hbrush_old );
\r
2701 DeleteObject(hbrush);
\r
2706 SelectObject( hdc, hpen );
\r
2711 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2712 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2713 piece: follow the steps as explained below.
\r
2715 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2719 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2723 int backColor = whitePieceColor;
\r
2724 int foreColor = blackPieceColor;
\r
2726 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2727 backColor = appData.fontBackColorWhite;
\r
2728 foreColor = appData.fontForeColorWhite;
\r
2730 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2731 backColor = appData.fontBackColorBlack;
\r
2732 foreColor = appData.fontForeColorBlack;
\r
2736 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2738 hbm_old = SelectObject( hdc, hbm );
\r
2742 rc.right = squareSize;
\r
2743 rc.bottom = squareSize;
\r
2745 /* Step 1: background is now black */
\r
2746 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2748 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2750 pt.x = (squareSize - sz.cx) / 2;
\r
2751 pt.y = (squareSize - sz.cy) / 2;
\r
2753 SetBkMode( hdc, TRANSPARENT );
\r
2754 SetTextColor( hdc, chroma );
\r
2755 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2756 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2758 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2759 /* Step 3: the area outside the piece is filled with white */
\r
2760 // FloodFill( hdc, 0, 0, chroma );
\r
2761 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2762 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2763 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2764 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2765 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2767 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2768 but if the start point is not inside the piece we're lost!
\r
2769 There should be a better way to do this... if we could create a region or path
\r
2770 from the fill operation we would be fine for example.
\r
2772 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2773 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2775 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2776 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2777 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2779 SelectObject( dc2, bm2 );
\r
2780 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2781 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2782 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2783 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2784 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2787 DeleteObject( bm2 );
\r
2790 SetTextColor( hdc, 0 );
\r
2792 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2793 draw the piece again in black for safety.
\r
2795 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2797 SelectObject( hdc, hbm_old );
\r
2799 if( hPieceMask[index] != NULL ) {
\r
2800 DeleteObject( hPieceMask[index] );
\r
2803 hPieceMask[index] = hbm;
\r
2806 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2808 SelectObject( hdc, hbm );
\r
2811 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2812 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2813 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2815 SelectObject( dc1, hPieceMask[index] );
\r
2816 SelectObject( dc2, bm2 );
\r
2817 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2818 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2821 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2822 the piece background and deletes (makes transparent) the rest.
\r
2823 Thanks to that mask, we are free to paint the background with the greates
\r
2824 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2825 We use this, to make gradients and give the pieces a "roundish" look.
\r
2827 SetPieceBackground( hdc, backColor, 2 );
\r
2828 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2832 DeleteObject( bm2 );
\r
2835 SetTextColor( hdc, foreColor );
\r
2836 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2838 SelectObject( hdc, hbm_old );
\r
2840 if( hPieceFace[index] != NULL ) {
\r
2841 DeleteObject( hPieceFace[index] );
\r
2844 hPieceFace[index] = hbm;
\r
2847 static int TranslatePieceToFontPiece( int piece )
\r
2877 case BlackMarshall:
\r
2881 case BlackNightrider:
\r
2887 case BlackUnicorn:
\r
2891 case BlackGrasshopper:
\r
2903 case BlackCardinal:
\r
2910 case WhiteMarshall:
\r
2914 case WhiteNightrider:
\r
2920 case WhiteUnicorn:
\r
2924 case WhiteGrasshopper:
\r
2936 case WhiteCardinal:
\r
2945 void CreatePiecesFromFont()
\r
2948 HDC hdc_window = NULL;
\r
2954 if( fontBitmapSquareSize < 0 ) {
\r
2955 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2959 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2960 fontBitmapSquareSize = -1;
\r
2964 if( fontBitmapSquareSize != squareSize ) {
\r
2965 hdc_window = GetDC( hwndMain );
\r
2966 hdc = CreateCompatibleDC( hdc_window );
\r
2968 if( hPieceFont != NULL ) {
\r
2969 DeleteObject( hPieceFont );
\r
2972 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2973 hPieceMask[i] = NULL;
\r
2974 hPieceFace[i] = NULL;
\r
2980 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2981 fontHeight = appData.fontPieceSize;
\r
2984 fontHeight = (fontHeight * squareSize) / 100;
\r
2986 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2988 lf.lfEscapement = 0;
\r
2989 lf.lfOrientation = 0;
\r
2990 lf.lfWeight = FW_NORMAL;
\r
2992 lf.lfUnderline = 0;
\r
2993 lf.lfStrikeOut = 0;
\r
2994 lf.lfCharSet = DEFAULT_CHARSET;
\r
2995 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2996 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2997 lf.lfQuality = PROOF_QUALITY;
\r
2998 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2999 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3000 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3002 hPieceFont = CreateFontIndirect( &lf );
\r
3004 if( hPieceFont == NULL ) {
\r
3005 fontBitmapSquareSize = -2;
\r
3008 /* Setup font-to-piece character table */
\r
3009 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3010 /* No (or wrong) global settings, try to detect the font */
\r
3011 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3013 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3015 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3016 /* DiagramTT* family */
\r
3017 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3019 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3020 /* Fairy symbols */
\r
3021 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3023 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3024 /* Good Companion (Some characters get warped as literal :-( */
\r
3025 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3026 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3027 SetCharTable(pieceToFontChar, s);
\r
3030 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3031 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3035 /* Create bitmaps */
\r
3036 hfont_old = SelectObject( hdc, hPieceFont );
\r
3038 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3039 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3040 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3042 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3043 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3048 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3051 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3055 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3056 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3063 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3064 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3065 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3066 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3067 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3068 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3069 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3070 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3071 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3072 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3073 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3074 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3075 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3076 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3077 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3078 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3079 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3080 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3081 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3082 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3084 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3085 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3086 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3088 SelectObject( hdc, hfont_old );
\r
3090 fontBitmapSquareSize = squareSize;
\r
3094 if( hdc != NULL ) {
\r
3098 if( hdc_window != NULL ) {
\r
3099 ReleaseDC( hwndMain, hdc_window );
\r
3104 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3108 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3109 if (gameInfo.event &&
\r
3110 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3111 strcmp(name, "k80s") == 0) {
\r
3112 strcpy(name, "tim");
\r
3114 return LoadBitmap(hinst, name);
\r
3118 /* Insert a color into the program's logical palette
\r
3119 structure. This code assumes the given color is
\r
3120 the result of the RGB or PALETTERGB macro, and it
\r
3121 knows how those macros work (which is documented).
\r
3124 InsertInPalette(COLORREF color)
\r
3126 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3128 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3129 DisplayFatalError("Too many colors", 0, 1);
\r
3130 pLogPal->palNumEntries--;
\r
3134 pe->peFlags = (char) 0;
\r
3135 pe->peRed = (char) (0xFF & color);
\r
3136 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3137 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3143 InitDrawingColors()
\r
3145 if (pLogPal == NULL) {
\r
3146 /* Allocate enough memory for a logical palette with
\r
3147 * PALETTESIZE entries and set the size and version fields
\r
3148 * of the logical palette structure.
\r
3150 pLogPal = (NPLOGPALETTE)
\r
3151 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3152 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3153 pLogPal->palVersion = 0x300;
\r
3155 pLogPal->palNumEntries = 0;
\r
3157 InsertInPalette(lightSquareColor);
\r
3158 InsertInPalette(darkSquareColor);
\r
3159 InsertInPalette(whitePieceColor);
\r
3160 InsertInPalette(blackPieceColor);
\r
3161 InsertInPalette(highlightSquareColor);
\r
3162 InsertInPalette(premoveHighlightColor);
\r
3164 /* create a logical color palette according the information
\r
3165 * in the LOGPALETTE structure.
\r
3167 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3169 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3170 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3171 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3172 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3173 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3174 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3175 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3176 /* [AS] Force rendering of the font-based pieces */
\r
3177 if( fontBitmapSquareSize > 0 ) {
\r
3178 fontBitmapSquareSize = 0;
\r
3184 BoardWidth(int boardSize, int n)
\r
3185 { /* [HGM] argument n added to allow different width and height */
\r
3186 int lineGap = sizeInfo[boardSize].lineGap;
\r
3188 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3189 lineGap = appData.overrideLineGap;
\r
3192 return (n + 1) * lineGap +
\r
3193 n * sizeInfo[boardSize].squareSize;
\r
3196 /* Respond to board resize by dragging edge */
\r
3198 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3200 BoardSize newSize = NUM_SIZES - 1;
\r
3201 static int recurse = 0;
\r
3202 if (IsIconic(hwndMain)) return;
\r
3203 if (recurse > 0) return;
\r
3205 while (newSize > 0) {
\r
3206 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3207 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3208 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3211 boardSize = newSize;
\r
3212 InitDrawingSizes(boardSize, flags);
\r
3219 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3221 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3222 ChessSquare piece;
\r
3223 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3225 SIZE clockSize, messageSize;
\r
3227 char buf[MSG_SIZ];
\r
3229 HMENU hmenu = GetMenu(hwndMain);
\r
3230 RECT crect, wrect, oldRect;
\r
3232 LOGBRUSH logbrush;
\r
3234 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3235 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3237 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3238 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3240 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3241 oldRect.top = boardY;
\r
3242 oldRect.right = boardX + winWidth;
\r
3243 oldRect.bottom = boardY + winHeight;
\r
3245 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3246 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3247 squareSize = sizeInfo[boardSize].squareSize;
\r
3248 lineGap = sizeInfo[boardSize].lineGap;
\r
3249 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3251 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3252 lineGap = appData.overrideLineGap;
\r
3255 if (tinyLayout != oldTinyLayout) {
\r
3256 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3258 style &= ~WS_SYSMENU;
\r
3259 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3260 "&Minimize\tCtrl+F4");
\r
3262 style |= WS_SYSMENU;
\r
3263 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3265 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3267 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3268 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3269 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3271 DrawMenuBar(hwndMain);
\r
3274 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3275 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3277 /* Get text area sizes */
\r
3278 hdc = GetDC(hwndMain);
\r
3279 if (appData.clockMode) {
\r
3280 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3282 sprintf(buf, "White");
\r
3284 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3285 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3286 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3287 str = "We only care about the height here";
\r
3288 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3289 SelectObject(hdc, oldFont);
\r
3290 ReleaseDC(hwndMain, hdc);
\r
3292 /* Compute where everything goes */
\r
3293 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3294 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3295 logoHeight = 2*clockSize.cy;
\r
3296 leftLogoRect.left = OUTER_MARGIN;
\r
3297 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3298 leftLogoRect.top = OUTER_MARGIN;
\r
3299 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3301 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3302 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3303 rightLogoRect.top = OUTER_MARGIN;
\r
3304 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3307 whiteRect.left = leftLogoRect.right;
\r
3308 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3309 whiteRect.top = OUTER_MARGIN;
\r
3310 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3312 blackRect.right = rightLogoRect.left;
\r
3313 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3314 blackRect.top = whiteRect.top;
\r
3315 blackRect.bottom = whiteRect.bottom;
\r
3317 whiteRect.left = OUTER_MARGIN;
\r
3318 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3319 whiteRect.top = OUTER_MARGIN;
\r
3320 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3322 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3323 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3324 blackRect.top = whiteRect.top;
\r
3325 blackRect.bottom = whiteRect.bottom;
\r
3328 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3329 if (appData.showButtonBar) {
\r
3330 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3331 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3333 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3335 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3336 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3338 boardRect.left = OUTER_MARGIN;
\r
3339 boardRect.right = boardRect.left + boardWidth;
\r
3340 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3341 boardRect.bottom = boardRect.top + boardHeight;
\r
3343 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3344 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3345 oldBoardSize = boardSize;
\r
3346 oldTinyLayout = tinyLayout;
\r
3347 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3348 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3349 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3350 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3351 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3352 winHeight = winH; // without disturbing window attachments
\r
3353 GetWindowRect(hwndMain, &wrect);
\r
3354 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3355 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3357 // [HGM] placement: let attached windows follow size change.
\r
3358 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3359 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3360 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3361 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3362 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3364 /* compensate if menu bar wrapped */
\r
3365 GetClientRect(hwndMain, &crect);
\r
3366 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3367 winHeight += offby;
\r
3369 case WMSZ_TOPLEFT:
\r
3370 SetWindowPos(hwndMain, NULL,
\r
3371 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3372 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3375 case WMSZ_TOPRIGHT:
\r
3377 SetWindowPos(hwndMain, NULL,
\r
3378 wrect.left, wrect.bottom - winHeight,
\r
3379 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3382 case WMSZ_BOTTOMLEFT:
\r
3384 SetWindowPos(hwndMain, NULL,
\r
3385 wrect.right - winWidth, wrect.top,
\r
3386 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3389 case WMSZ_BOTTOMRIGHT:
\r
3393 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3394 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3399 for (i = 0; i < N_BUTTONS; i++) {
\r
3400 if (buttonDesc[i].hwnd != NULL) {
\r
3401 DestroyWindow(buttonDesc[i].hwnd);
\r
3402 buttonDesc[i].hwnd = NULL;
\r
3404 if (appData.showButtonBar) {
\r
3405 buttonDesc[i].hwnd =
\r
3406 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3407 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3408 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3409 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3410 (HMENU) buttonDesc[i].id,
\r
3411 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3413 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3414 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3415 MAKELPARAM(FALSE, 0));
\r
3417 if (buttonDesc[i].id == IDM_Pause)
\r
3418 hwndPause = buttonDesc[i].hwnd;
\r
3419 buttonDesc[i].wndproc = (WNDPROC)
\r
3420 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3423 if (gridPen != NULL) DeleteObject(gridPen);
\r
3424 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3425 if (premovePen != NULL) DeleteObject(premovePen);
\r
3426 if (lineGap != 0) {
\r
3427 logbrush.lbStyle = BS_SOLID;
\r
3428 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3430 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3431 lineGap, &logbrush, 0, NULL);
\r
3432 logbrush.lbColor = highlightSquareColor;
\r
3434 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3435 lineGap, &logbrush, 0, NULL);
\r
3437 logbrush.lbColor = premoveHighlightColor;
\r
3439 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3440 lineGap, &logbrush, 0, NULL);
\r
3442 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3443 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3444 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3445 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3446 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3447 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3448 BOARD_WIDTH * (squareSize + lineGap);
\r
3449 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3451 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3452 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3453 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3454 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3455 lineGap / 2 + (i * (squareSize + lineGap));
\r
3456 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3457 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3458 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3462 /* [HGM] Licensing requirement */
\r
3464 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3467 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3469 GothicPopUp( "", VariantNormal);
\r
3472 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3474 /* Load piece bitmaps for this board size */
\r
3475 for (i=0; i<=2; i++) {
\r
3476 for (piece = WhitePawn;
\r
3477 (int) piece < (int) BlackPawn;
\r
3478 piece = (ChessSquare) ((int) piece + 1)) {
\r
3479 if (pieceBitmap[i][piece] != NULL)
\r
3480 DeleteObject(pieceBitmap[i][piece]);
\r
3484 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3485 // Orthodox Chess pieces
\r
3486 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3487 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3488 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3489 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3490 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3491 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3492 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3493 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3494 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3495 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3496 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3497 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3498 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3499 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3500 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3501 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3502 // in Shogi, Hijack the unused Queen for Lance
\r
3503 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3504 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3505 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3507 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3508 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3509 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3512 if(squareSize <= 72 && squareSize >= 33) {
\r
3513 /* A & C are available in most sizes now */
\r
3514 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3515 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3516 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3517 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3518 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3519 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3520 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3521 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3522 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3523 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3524 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3525 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3526 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3527 } else { // Smirf-like
\r
3528 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3529 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3530 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3532 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3533 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3534 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3535 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3536 } else { // WinBoard standard
\r
3537 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3538 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3539 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3544 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3545 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3546 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3547 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3548 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3549 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3550 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3551 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3552 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3553 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3554 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3555 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3556 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3557 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3558 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3559 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3560 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3561 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3562 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3563 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3564 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3565 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3566 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3567 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3568 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3569 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3570 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3571 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3572 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3573 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3574 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3576 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3577 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3578 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3579 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3580 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3581 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3582 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3583 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3584 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3585 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3586 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3587 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3588 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3590 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3591 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3592 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3593 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3594 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3595 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3596 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3597 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3598 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3599 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3600 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3601 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3604 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3605 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3606 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3607 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3608 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3609 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3610 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3611 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3612 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3613 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3614 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3615 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3616 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3617 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3618 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3622 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3623 /* special Shogi support in this size */
\r
3624 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3625 for (piece = WhitePawn;
\r
3626 (int) piece < (int) BlackPawn;
\r
3627 piece = (ChessSquare) ((int) piece + 1)) {
\r
3628 if (pieceBitmap[i][piece] != NULL)
\r
3629 DeleteObject(pieceBitmap[i][piece]);
\r
3632 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3633 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3634 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3635 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3636 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3637 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3638 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3639 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3640 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3641 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3642 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3643 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3644 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3645 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3646 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3647 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3648 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3649 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3650 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3651 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3652 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3653 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3654 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3655 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3656 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3657 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3658 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3659 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3660 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3661 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3662 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3663 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3664 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3665 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3666 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3667 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3668 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3669 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3670 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3671 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3672 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3673 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3679 PieceBitmap(ChessSquare p, int kind)
\r
3681 if ((int) p >= (int) BlackPawn)
\r
3682 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3684 return pieceBitmap[kind][(int) p];
\r
3687 /***************************************************************/
\r
3689 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3690 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3692 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3693 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3697 SquareToPos(int row, int column, int * x, int * y)
\r
3700 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3701 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3703 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3704 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3709 DrawCoordsOnDC(HDC hdc)
\r
3711 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
3712 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
3713 char str[2] = { NULLCHAR, NULLCHAR };
\r
3714 int oldMode, oldAlign, x, y, start, i;
\r
3718 if (!appData.showCoords)
\r
3721 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3723 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3724 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3725 oldAlign = GetTextAlign(hdc);
\r
3726 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3728 y = boardRect.top + lineGap;
\r
3729 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3731 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3732 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3733 str[0] = files[start + i];
\r
3734 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3735 y += squareSize + lineGap;
\r
3738 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3740 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3741 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3742 str[0] = ranks[start + i];
\r
3743 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3744 x += squareSize + lineGap;
\r
3747 SelectObject(hdc, oldBrush);
\r
3748 SetBkMode(hdc, oldMode);
\r
3749 SetTextAlign(hdc, oldAlign);
\r
3750 SelectObject(hdc, oldFont);
\r
3754 DrawGridOnDC(HDC hdc)
\r
3758 if (lineGap != 0) {
\r
3759 oldPen = SelectObject(hdc, gridPen);
\r
3760 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3761 SelectObject(hdc, oldPen);
\r
3765 #define HIGHLIGHT_PEN 0
\r
3766 #define PREMOVE_PEN 1
\r
3769 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3772 HPEN oldPen, hPen;
\r
3773 if (lineGap == 0) return;
\r
3775 x1 = boardRect.left +
\r
3776 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3777 y1 = boardRect.top +
\r
3778 lineGap/2 + y * (squareSize + lineGap);
\r
3780 x1 = boardRect.left +
\r
3781 lineGap/2 + x * (squareSize + lineGap);
\r
3782 y1 = boardRect.top +
\r
3783 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3785 hPen = pen ? premovePen : highlightPen;
\r
3786 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3787 MoveToEx(hdc, x1, y1, NULL);
\r
3788 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3789 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3790 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3791 LineTo(hdc, x1, y1);
\r
3792 SelectObject(hdc, oldPen);
\r
3796 DrawHighlightsOnDC(HDC hdc)
\r
3799 for (i=0; i<2; i++) {
\r
3800 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3801 DrawHighlightOnDC(hdc, TRUE,
\r
3802 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3805 for (i=0; i<2; i++) {
\r
3806 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3807 premoveHighlightInfo.sq[i].y >= 0) {
\r
3808 DrawHighlightOnDC(hdc, TRUE,
\r
3809 premoveHighlightInfo.sq[i].x,
\r
3810 premoveHighlightInfo.sq[i].y,
\r
3816 /* Note: sqcolor is used only in monoMode */
\r
3817 /* Note that this code is largely duplicated in woptions.c,
\r
3818 function DrawSampleSquare, so that needs to be updated too */
\r
3820 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3822 HBITMAP oldBitmap;
\r
3826 if (appData.blindfold) return;
\r
3828 /* [AS] Use font-based pieces if needed */
\r
3829 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3830 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3831 CreatePiecesFromFont();
\r
3833 if( fontBitmapSquareSize == squareSize ) {
\r
3834 int index = TranslatePieceToFontPiece(piece);
\r
3836 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3840 squareSize, squareSize,
\r
3845 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3849 squareSize, squareSize,
\r
3858 if (appData.monoMode) {
\r
3859 SelectObject(tmphdc, PieceBitmap(piece,
\r
3860 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3861 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3862 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3864 tmpSize = squareSize;
\r
3866 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3867 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3868 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3869 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3870 x += (squareSize - minorSize)>>1;
\r
3871 y += squareSize - minorSize - 2;
\r
3872 tmpSize = minorSize;
\r
3874 if (color || appData.allWhite ) {
\r
3875 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3877 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3878 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3879 if(appData.upsideDown && color==flipView)
\r
3880 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3882 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3884 /* Use black piece color for outline of white pieces */
\r
3885 /* Not sure this looks really good (though xboard does it).
\r
3886 Maybe better to have another selectable color, default black */
\r
3887 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3888 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3889 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3891 /* Use black for outline of white pieces */
\r
3892 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3893 if(appData.upsideDown && color==flipView)
\r
3894 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3896 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3900 /* Use white piece color for details of black pieces */
\r
3901 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3902 WHITE_PIECE ones aren't always the right shape. */
\r
3903 /* Not sure this looks really good (though xboard does it).
\r
3904 Maybe better to have another selectable color, default medium gray? */
\r
3905 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3906 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3907 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3908 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3909 SelectObject(hdc, blackPieceBrush);
\r
3910 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3912 /* Use square color for details of black pieces */
\r
3913 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3914 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3915 if(appData.upsideDown && !flipView)
\r
3916 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3918 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3921 SelectObject(hdc, oldBrush);
\r
3922 SelectObject(tmphdc, oldBitmap);
\r
3926 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3927 int GetBackTextureMode( int algo )
\r
3929 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3933 case BACK_TEXTURE_MODE_PLAIN:
\r
3934 result = 1; /* Always use identity map */
\r
3936 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3937 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3945 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3946 to handle redraws cleanly (as random numbers would always be different).
\r
3948 VOID RebuildTextureSquareInfo()
\r
3958 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3960 if( liteBackTexture != NULL ) {
\r
3961 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3962 lite_w = bi.bmWidth;
\r
3963 lite_h = bi.bmHeight;
\r
3967 if( darkBackTexture != NULL ) {
\r
3968 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3969 dark_w = bi.bmWidth;
\r
3970 dark_h = bi.bmHeight;
\r
3974 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3975 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3976 if( (col + row) & 1 ) {
\r
3978 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3979 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3980 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3981 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3986 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3987 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3988 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3989 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3996 /* [AS] Arrow highlighting support */
\r
3998 static int A_WIDTH = 5; /* Width of arrow body */
\r
4000 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
4001 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
4003 static double Sqr( double x )
\r
4008 static int Round( double x )
\r
4010 return (int) (x + 0.5);
\r
4013 /* Draw an arrow between two points using current settings */
\r
4014 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
4017 double dx, dy, j, k, x, y;
\r
4019 if( d_x == s_x ) {
\r
4020 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4022 arrow[0].x = s_x + A_WIDTH;
\r
4025 arrow[1].x = s_x + A_WIDTH;
\r
4026 arrow[1].y = d_y - h;
\r
4028 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4029 arrow[2].y = d_y - h;
\r
4034 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4035 arrow[4].y = d_y - h;
\r
4037 arrow[5].x = s_x - A_WIDTH;
\r
4038 arrow[5].y = d_y - h;
\r
4040 arrow[6].x = s_x - A_WIDTH;
\r
4043 else if( d_y == s_y ) {
\r
4044 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4047 arrow[0].y = s_y + A_WIDTH;
\r
4049 arrow[1].x = d_x - w;
\r
4050 arrow[1].y = s_y + A_WIDTH;
\r
4052 arrow[2].x = d_x - w;
\r
4053 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4058 arrow[4].x = d_x - w;
\r
4059 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4061 arrow[5].x = d_x - w;
\r
4062 arrow[5].y = s_y - A_WIDTH;
\r
4065 arrow[6].y = s_y - A_WIDTH;
\r
4068 /* [AS] Needed a lot of paper for this! :-) */
\r
4069 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4070 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4072 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4074 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4079 arrow[0].x = Round(x - j);
\r
4080 arrow[0].y = Round(y + j*dx);
\r
4082 arrow[1].x = Round(x + j);
\r
4083 arrow[1].y = Round(y - j*dx);
\r
4086 x = (double) d_x - k;
\r
4087 y = (double) d_y - k*dy;
\r
4090 x = (double) d_x + k;
\r
4091 y = (double) d_y + k*dy;
\r
4094 arrow[2].x = Round(x + j);
\r
4095 arrow[2].y = Round(y - j*dx);
\r
4097 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4098 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4103 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4104 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4106 arrow[6].x = Round(x - j);
\r
4107 arrow[6].y = Round(y + j*dx);
\r
4110 Polygon( hdc, arrow, 7 );
\r
4113 /* [AS] Draw an arrow between two squares */
\r
4114 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4116 int s_x, s_y, d_x, d_y;
\r
4123 if( s_col == d_col && s_row == d_row ) {
\r
4127 /* Get source and destination points */
\r
4128 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4129 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4132 d_y += squareSize / 4;
\r
4134 else if( d_y < s_y ) {
\r
4135 d_y += 3 * squareSize / 4;
\r
4138 d_y += squareSize / 2;
\r
4142 d_x += squareSize / 4;
\r
4144 else if( d_x < s_x ) {
\r
4145 d_x += 3 * squareSize / 4;
\r
4148 d_x += squareSize / 2;
\r
4151 s_x += squareSize / 2;
\r
4152 s_y += squareSize / 2;
\r
4154 /* Adjust width */
\r
4155 A_WIDTH = squareSize / 14;
\r
4158 stLB.lbStyle = BS_SOLID;
\r
4159 stLB.lbColor = appData.highlightArrowColor;
\r
4162 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4163 holdpen = SelectObject( hdc, hpen );
\r
4164 hbrush = CreateBrushIndirect( &stLB );
\r
4165 holdbrush = SelectObject( hdc, hbrush );
\r
4167 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4169 SelectObject( hdc, holdpen );
\r
4170 SelectObject( hdc, holdbrush );
\r
4171 DeleteObject( hpen );
\r
4172 DeleteObject( hbrush );
\r
4175 BOOL HasHighlightInfo()
\r
4177 BOOL result = FALSE;
\r
4179 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4180 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4188 BOOL IsDrawArrowEnabled()
\r
4190 BOOL result = FALSE;
\r
4192 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4199 VOID DrawArrowHighlight( HDC hdc )
\r
4201 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4202 DrawArrowBetweenSquares( hdc,
\r
4203 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4204 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4208 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4210 HRGN result = NULL;
\r
4212 if( HasHighlightInfo() ) {
\r
4213 int x1, y1, x2, y2;
\r
4214 int sx, sy, dx, dy;
\r
4216 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4217 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4219 sx = MIN( x1, x2 );
\r
4220 sy = MIN( y1, y2 );
\r
4221 dx = MAX( x1, x2 ) + squareSize;
\r
4222 dy = MAX( y1, y2 ) + squareSize;
\r
4224 result = CreateRectRgn( sx, sy, dx, dy );
\r
4231 Warning: this function modifies the behavior of several other functions.
\r
4233 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4234 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4235 repaint is scattered all over the place, which is not good for features such as
\r
4236 "arrow highlighting" that require a full repaint of the board.
\r
4238 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4239 user interaction, when speed is not so important) but especially to avoid errors
\r
4240 in the displayed graphics.
\r
4242 In such patched places, I always try refer to this function so there is a single
\r
4243 place to maintain knowledge.
\r
4245 To restore the original behavior, just return FALSE unconditionally.
\r
4247 BOOL IsFullRepaintPreferrable()
\r
4249 BOOL result = FALSE;
\r
4251 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4252 /* Arrow may appear on the board */
\r
4260 This function is called by DrawPosition to know whether a full repaint must
\r
4263 Only DrawPosition may directly call this function, which makes use of
\r
4264 some state information. Other function should call DrawPosition specifying
\r
4265 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4267 BOOL DrawPositionNeedsFullRepaint()
\r
4269 BOOL result = FALSE;
\r
4272 Probably a slightly better policy would be to trigger a full repaint
\r
4273 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4274 but animation is fast enough that it's difficult to notice.
\r
4276 if( animInfo.piece == EmptySquare ) {
\r
4277 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4286 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4288 int row, column, x, y, square_color, piece_color;
\r
4289 ChessSquare piece;
\r
4291 HDC texture_hdc = NULL;
\r
4293 /* [AS] Initialize background textures if needed */
\r
4294 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4295 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4296 if( backTextureSquareSize != squareSize
\r
4297 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4298 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4299 backTextureSquareSize = squareSize;
\r
4300 RebuildTextureSquareInfo();
\r
4303 texture_hdc = CreateCompatibleDC( hdc );
\r
4306 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4307 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4309 SquareToPos(row, column, &x, &y);
\r
4311 piece = board[row][column];
\r
4313 square_color = ((column + row) % 2) == 1;
\r
4314 if( gameInfo.variant == VariantXiangqi ) {
\r
4315 square_color = !InPalace(row, column);
\r
4316 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4317 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4319 piece_color = (int) piece < (int) BlackPawn;
\r
4322 /* [HGM] holdings file: light square or black */
\r
4323 if(column == BOARD_LEFT-2) {
\r
4324 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4327 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4331 if(column == BOARD_RGHT + 1 ) {
\r
4332 if( row < gameInfo.holdingsSize )
\r
4335 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4339 if(column == BOARD_LEFT-1 ) /* left align */
\r
4340 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4341 else if( column == BOARD_RGHT) /* right align */
\r
4342 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4344 if (appData.monoMode) {
\r
4345 if (piece == EmptySquare) {
\r
4346 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4347 square_color ? WHITENESS : BLACKNESS);
\r
4349 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4352 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4353 /* [AS] Draw the square using a texture bitmap */
\r
4354 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4355 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4356 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4359 squareSize, squareSize,
\r
4362 backTextureSquareInfo[r][c].mode,
\r
4363 backTextureSquareInfo[r][c].x,
\r
4364 backTextureSquareInfo[r][c].y );
\r
4366 SelectObject( texture_hdc, hbm );
\r
4368 if (piece != EmptySquare) {
\r
4369 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4373 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4375 oldBrush = SelectObject(hdc, brush );
\r
4376 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4377 SelectObject(hdc, oldBrush);
\r
4378 if (piece != EmptySquare)
\r
4379 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4384 if( texture_hdc != NULL ) {
\r
4385 DeleteDC( texture_hdc );
\r
4389 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4390 void fputDW(FILE *f, int x)
\r
4392 fputc(x & 255, f);
\r
4393 fputc(x>>8 & 255, f);
\r
4394 fputc(x>>16 & 255, f);
\r
4395 fputc(x>>24 & 255, f);
\r
4398 #define MAX_CLIPS 200 /* more than enough */
\r
4401 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4403 // HBITMAP bufferBitmap;
\r
4408 int w = 100, h = 50;
\r
4410 if(logo == NULL) return;
\r
4411 // GetClientRect(hwndMain, &Rect);
\r
4412 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4413 // Rect.bottom-Rect.top+1);
\r
4414 tmphdc = CreateCompatibleDC(hdc);
\r
4415 hbm = SelectObject(tmphdc, logo);
\r
4416 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4420 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4421 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4422 SelectObject(tmphdc, hbm);
\r
4427 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4429 static Board lastReq, lastDrawn;
\r
4430 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4431 static int lastDrawnFlipView = 0;
\r
4432 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4433 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4436 HBITMAP bufferBitmap;
\r
4437 HBITMAP oldBitmap;
\r
4439 HRGN clips[MAX_CLIPS];
\r
4440 ChessSquare dragged_piece = EmptySquare;
\r
4442 /* I'm undecided on this - this function figures out whether a full
\r
4443 * repaint is necessary on its own, so there's no real reason to have the
\r
4444 * caller tell it that. I think this can safely be set to FALSE - but
\r
4445 * if we trust the callers not to request full repaints unnessesarily, then
\r
4446 * we could skip some clipping work. In other words, only request a full
\r
4447 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4448 * gamestart and similar) --Hawk
\r
4450 Boolean fullrepaint = repaint;
\r
4452 if( DrawPositionNeedsFullRepaint() ) {
\r
4453 fullrepaint = TRUE;
\r
4457 if( fullrepaint ) {
\r
4458 static int repaint_count = 0;
\r
4462 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4463 OutputDebugString( buf );
\r
4467 if (board == NULL) {
\r
4468 if (!lastReqValid) {
\r
4473 CopyBoard(lastReq, board);
\r
4477 if (doingSizing) {
\r
4481 if (IsIconic(hwndMain)) {
\r
4485 if (hdc == NULL) {
\r
4486 hdc = GetDC(hwndMain);
\r
4487 if (!appData.monoMode) {
\r
4488 SelectPalette(hdc, hPal, FALSE);
\r
4489 RealizePalette(hdc);
\r
4493 releaseDC = FALSE;
\r
4497 fprintf(debugFP, "*******************************\n"
\r
4499 "dragInfo.from (%d,%d)\n"
\r
4500 "dragInfo.start (%d,%d)\n"
\r
4501 "dragInfo.pos (%d,%d)\n"
\r
4502 "dragInfo.lastpos (%d,%d)\n",
\r
4503 repaint ? "TRUE" : "FALSE",
\r
4504 dragInfo.from.x, dragInfo.from.y,
\r
4505 dragInfo.start.x, dragInfo.start.y,
\r
4506 dragInfo.pos.x, dragInfo.pos.y,
\r
4507 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4508 fprintf(debugFP, "prev: ");
\r
4509 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4510 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4511 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4514 fprintf(debugFP, "\n");
\r
4515 fprintf(debugFP, "board: ");
\r
4516 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4517 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4518 fprintf(debugFP, "%d ", board[row][column]);
\r
4521 fprintf(debugFP, "\n");
\r
4525 /* Create some work-DCs */
\r
4526 hdcmem = CreateCompatibleDC(hdc);
\r
4527 tmphdc = CreateCompatibleDC(hdc);
\r
4529 /* If dragging is in progress, we temporarely remove the piece */
\r
4530 /* [HGM] or temporarily decrease count if stacked */
\r
4531 /* !! Moved to before board compare !! */
\r
4532 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4533 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4534 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4535 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4536 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4538 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4539 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4540 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4542 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4545 /* Figure out which squares need updating by comparing the
\r
4546 * newest board with the last drawn board and checking if
\r
4547 * flipping has changed.
\r
4549 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4550 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4551 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4552 if (lastDrawn[row][column] != board[row][column]) {
\r
4553 SquareToPos(row, column, &x, &y);
\r
4554 clips[num_clips++] =
\r
4555 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4559 for (i=0; i<2; i++) {
\r
4560 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4561 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4562 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4563 lastDrawnHighlight.sq[i].y >= 0) {
\r
4564 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4565 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4566 clips[num_clips++] =
\r
4567 CreateRectRgn(x - lineGap, y - lineGap,
\r
4568 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4570 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4571 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4572 clips[num_clips++] =
\r
4573 CreateRectRgn(x - lineGap, y - lineGap,
\r
4574 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4578 for (i=0; i<2; i++) {
\r
4579 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4580 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4581 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4582 lastDrawnPremove.sq[i].y >= 0) {
\r
4583 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4584 lastDrawnPremove.sq[i].x, &x, &y);
\r
4585 clips[num_clips++] =
\r
4586 CreateRectRgn(x - lineGap, y - lineGap,
\r
4587 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4589 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4590 premoveHighlightInfo.sq[i].y >= 0) {
\r
4591 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4592 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4593 clips[num_clips++] =
\r
4594 CreateRectRgn(x - lineGap, y - lineGap,
\r
4595 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4600 fullrepaint = TRUE;
\r
4603 /* Create a buffer bitmap - this is the actual bitmap
\r
4604 * being written to. When all the work is done, we can
\r
4605 * copy it to the real DC (the screen). This avoids
\r
4606 * the problems with flickering.
\r
4608 GetClientRect(hwndMain, &Rect);
\r
4609 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4610 Rect.bottom-Rect.top+1);
\r
4611 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4612 if (!appData.monoMode) {
\r
4613 SelectPalette(hdcmem, hPal, FALSE);
\r
4616 /* Create clips for dragging */
\r
4617 if (!fullrepaint) {
\r
4618 if (dragInfo.from.x >= 0) {
\r
4619 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4620 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4622 if (dragInfo.start.x >= 0) {
\r
4623 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4624 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4626 if (dragInfo.pos.x >= 0) {
\r
4627 x = dragInfo.pos.x - squareSize / 2;
\r
4628 y = dragInfo.pos.y - squareSize / 2;
\r
4629 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4631 if (dragInfo.lastpos.x >= 0) {
\r
4632 x = dragInfo.lastpos.x - squareSize / 2;
\r
4633 y = dragInfo.lastpos.y - squareSize / 2;
\r
4634 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4638 /* Are we animating a move?
\r
4640 * - remove the piece from the board (temporarely)
\r
4641 * - calculate the clipping region
\r
4643 if (!fullrepaint) {
\r
4644 if (animInfo.piece != EmptySquare) {
\r
4645 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4646 x = boardRect.left + animInfo.lastpos.x;
\r
4647 y = boardRect.top + animInfo.lastpos.y;
\r
4648 x2 = boardRect.left + animInfo.pos.x;
\r
4649 y2 = boardRect.top + animInfo.pos.y;
\r
4650 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4651 /* Slight kludge. The real problem is that after AnimateMove is
\r
4652 done, the position on the screen does not match lastDrawn.
\r
4653 This currently causes trouble only on e.p. captures in
\r
4654 atomic, where the piece moves to an empty square and then
\r
4655 explodes. The old and new positions both had an empty square
\r
4656 at the destination, but animation has drawn a piece there and
\r
4657 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4658 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4662 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4663 if (num_clips == 0)
\r
4664 fullrepaint = TRUE;
\r
4666 /* Set clipping on the memory DC */
\r
4667 if (!fullrepaint) {
\r
4668 SelectClipRgn(hdcmem, clips[0]);
\r
4669 for (x = 1; x < num_clips; x++) {
\r
4670 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4671 abort(); // this should never ever happen!
\r
4675 /* Do all the drawing to the memory DC */
\r
4676 if(explodeInfo.radius) { // [HGM] atomic
\r
4678 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4679 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4680 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4681 x += squareSize/2;
\r
4682 y += squareSize/2;
\r
4683 if(!fullrepaint) {
\r
4684 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4685 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4687 DrawGridOnDC(hdcmem);
\r
4688 DrawHighlightsOnDC(hdcmem);
\r
4689 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4690 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4691 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4692 SelectObject(hdcmem, oldBrush);
\r
4694 DrawGridOnDC(hdcmem);
\r
4695 DrawHighlightsOnDC(hdcmem);
\r
4696 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4699 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4700 if(appData.autoLogo) {
\r
4702 switch(gameMode) { // pick logos based on game mode
\r
4703 case IcsObserving:
\r
4704 whiteLogo = second.programLogo; // ICS logo
\r
4705 blackLogo = second.programLogo;
\r
4708 case IcsPlayingWhite:
\r
4709 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4710 blackLogo = second.programLogo; // ICS logo
\r
4712 case IcsPlayingBlack:
\r
4713 whiteLogo = second.programLogo; // ICS logo
\r
4714 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4716 case TwoMachinesPlay:
\r
4717 if(first.twoMachinesColor[0] == 'b') {
\r
4718 whiteLogo = second.programLogo;
\r
4719 blackLogo = first.programLogo;
\r
4722 case MachinePlaysWhite:
\r
4723 blackLogo = userLogo;
\r
4725 case MachinePlaysBlack:
\r
4726 whiteLogo = userLogo;
\r
4727 blackLogo = first.programLogo;
\r
4730 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4731 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4734 if( appData.highlightMoveWithArrow ) {
\r
4735 DrawArrowHighlight(hdcmem);
\r
4738 DrawCoordsOnDC(hdcmem);
\r
4740 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4741 /* to make sure lastDrawn contains what is actually drawn */
\r
4743 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4744 if (dragged_piece != EmptySquare) {
\r
4745 /* [HGM] or restack */
\r
4746 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4747 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4749 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4750 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4751 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4752 x = dragInfo.pos.x - squareSize / 2;
\r
4753 y = dragInfo.pos.y - squareSize / 2;
\r
4754 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4755 ((int) dragged_piece < (int) BlackPawn),
\r
4756 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4759 /* Put the animated piece back into place and draw it */
\r
4760 if (animInfo.piece != EmptySquare) {
\r
4761 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4762 x = boardRect.left + animInfo.pos.x;
\r
4763 y = boardRect.top + animInfo.pos.y;
\r
4764 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4765 ((int) animInfo.piece < (int) BlackPawn),
\r
4766 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4769 /* Release the bufferBitmap by selecting in the old bitmap
\r
4770 * and delete the memory DC
\r
4772 SelectObject(hdcmem, oldBitmap);
\r
4775 /* Set clipping on the target DC */
\r
4776 if (!fullrepaint) {
\r
4777 SelectClipRgn(hdc, clips[0]);
\r
4778 for (x = 1; x < num_clips; x++) {
\r
4779 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4780 abort(); // this should never ever happen!
\r
4784 /* Copy the new bitmap onto the screen in one go.
\r
4785 * This way we avoid any flickering
\r
4787 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4788 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4789 boardRect.right - boardRect.left,
\r
4790 boardRect.bottom - boardRect.top,
\r
4791 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4792 if(saveDiagFlag) {
\r
4793 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4794 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4796 GetObject(bufferBitmap, sizeof(b), &b);
\r
4797 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4798 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4799 bih.biWidth = b.bmWidth;
\r
4800 bih.biHeight = b.bmHeight;
\r
4802 bih.biBitCount = b.bmBitsPixel;
\r
4803 bih.biCompression = 0;
\r
4804 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4805 bih.biXPelsPerMeter = 0;
\r
4806 bih.biYPelsPerMeter = 0;
\r
4807 bih.biClrUsed = 0;
\r
4808 bih.biClrImportant = 0;
\r
4809 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4810 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4811 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4812 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4815 wb = b.bmWidthBytes;
\r
4817 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4818 int k = ((int*) pData)[i];
\r
4819 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4820 if(j >= 16) break;
\r
4822 if(j >= nrColors) nrColors = j+1;
\r
4824 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4826 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4827 for(w=0; w<(wb>>2); w+=2) {
\r
4828 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4829 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4830 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4831 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4832 pData[p++] = m | j<<4;
\r
4834 while(p&3) pData[p++] = 0;
\r
4837 wb = ((wb+31)>>5)<<2;
\r
4839 // write BITMAPFILEHEADER
\r
4840 fprintf(diagFile, "BM");
\r
4841 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4842 fputDW(diagFile, 0);
\r
4843 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4844 // write BITMAPINFOHEADER
\r
4845 fputDW(diagFile, 40);
\r
4846 fputDW(diagFile, b.bmWidth);
\r
4847 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4848 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4849 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4850 fputDW(diagFile, 0);
\r
4851 fputDW(diagFile, 0);
\r
4852 fputDW(diagFile, 0);
\r
4853 fputDW(diagFile, 0);
\r
4854 fputDW(diagFile, 0);
\r
4855 fputDW(diagFile, 0);
\r
4856 // write color table
\r
4858 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4859 // write bitmap data
\r
4860 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4861 fputc(pData[i], diagFile);
\r
4866 SelectObject(tmphdc, oldBitmap);
\r
4868 /* Massive cleanup */
\r
4869 for (x = 0; x < num_clips; x++)
\r
4870 DeleteObject(clips[x]);
\r
4873 DeleteObject(bufferBitmap);
\r
4876 ReleaseDC(hwndMain, hdc);
\r
4878 if (lastDrawnFlipView != flipView) {
\r
4880 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4882 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4885 /* CopyBoard(lastDrawn, board);*/
\r
4886 lastDrawnHighlight = highlightInfo;
\r
4887 lastDrawnPremove = premoveHighlightInfo;
\r
4888 lastDrawnFlipView = flipView;
\r
4889 lastDrawnValid = 1;
\r
4892 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4897 saveDiagFlag = 1; diagFile = f;
\r
4898 HDCDrawPosition(NULL, TRUE, NULL);
\r
4902 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4909 /*---------------------------------------------------------------------------*\
\r
4910 | CLIENT PAINT PROCEDURE
\r
4911 | This is the main event-handler for the WM_PAINT message.
\r
4913 \*---------------------------------------------------------------------------*/
\r
4915 PaintProc(HWND hwnd)
\r
4921 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4922 if (IsIconic(hwnd)) {
\r
4923 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4925 if (!appData.monoMode) {
\r
4926 SelectPalette(hdc, hPal, FALSE);
\r
4927 RealizePalette(hdc);
\r
4929 HDCDrawPosition(hdc, 1, NULL);
\r
4931 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4932 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4933 ETO_CLIPPED|ETO_OPAQUE,
\r
4934 &messageRect, messageText, strlen(messageText), NULL);
\r
4935 SelectObject(hdc, oldFont);
\r
4936 DisplayBothClocks();
\r
4938 EndPaint(hwnd,&ps);
\r
4946 * If the user selects on a border boundary, return -1; if off the board,
\r
4947 * return -2. Otherwise map the event coordinate to the square.
\r
4948 * The offset boardRect.left or boardRect.top must already have been
\r
4949 * subtracted from x.
\r
4952 EventToSquare(int x)
\r
4959 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4961 x /= (squareSize + lineGap);
\r
4962 if (x >= BOARD_SIZE)
\r
4973 DropEnable dropEnables[] = {
\r
4974 { 'P', DP_Pawn, "Pawn" },
\r
4975 { 'N', DP_Knight, "Knight" },
\r
4976 { 'B', DP_Bishop, "Bishop" },
\r
4977 { 'R', DP_Rook, "Rook" },
\r
4978 { 'Q', DP_Queen, "Queen" },
\r
4982 SetupDropMenu(HMENU hmenu)
\r
4984 int i, count, enable;
\r
4986 extern char white_holding[], black_holding[];
\r
4987 char item[MSG_SIZ];
\r
4989 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4990 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4991 dropEnables[i].piece);
\r
4993 while (p && *p++ == dropEnables[i].piece) count++;
\r
4994 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4995 enable = count > 0 || !appData.testLegality
\r
4996 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4997 && !appData.icsActive);
\r
4998 ModifyMenu(hmenu, dropEnables[i].command,
\r
4999 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
5000 dropEnables[i].command, item);
\r
5004 /* Event handler for mouse messages */
\r
5006 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5010 static int recursive = 0;
\r
5012 // BOOLEAN needsRedraw = FALSE;
\r
5013 BOOLEAN saveAnimate;
\r
5014 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
5015 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
5016 ChessMove moveType;
\r
5019 if (message == WM_MBUTTONUP) {
\r
5020 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5021 to the middle button: we simulate pressing the left button too!
\r
5023 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5024 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5030 pt.x = LOWORD(lParam);
\r
5031 pt.y = HIWORD(lParam);
\r
5032 x = EventToSquare(pt.x - boardRect.left);
\r
5033 y = EventToSquare(pt.y - boardRect.top);
\r
5034 if (!flipView && y >= 0) {
\r
5035 y = BOARD_HEIGHT - 1 - y;
\r
5037 if (flipView && x >= 0) {
\r
5038 x = BOARD_WIDTH - 1 - x;
\r
5041 switch (message) {
\r
5042 case WM_LBUTTONDOWN:
\r
5043 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5044 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5045 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5046 if(gameInfo.holdingsWidth &&
\r
5047 (WhiteOnMove(currentMove)
\r
5048 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5049 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5050 // click in right holdings, for determining promotion piece
\r
5051 ChessSquare p = boards[currentMove][y][x];
\r
5052 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5053 if(p != EmptySquare) {
\r
5054 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5055 fromX = fromY = -1;
\r
5059 DrawPosition(FALSE, boards[currentMove]);
\r
5063 sameAgain = FALSE;
\r
5065 /* Downclick vertically off board; check if on clock */
\r
5066 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5067 if (gameMode == EditPosition) {
\r
5068 SetWhiteToPlayEvent();
\r
5069 } else if (gameMode == IcsPlayingBlack ||
\r
5070 gameMode == MachinePlaysWhite) {
\r
5072 } else if (gameMode == EditGame) {
\r
5073 AdjustClock(flipClock, -1);
\r
5075 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5076 if (gameMode == EditPosition) {
\r
5077 SetBlackToPlayEvent();
\r
5078 } else if (gameMode == IcsPlayingWhite ||
\r
5079 gameMode == MachinePlaysBlack) {
\r
5081 } else if (gameMode == EditGame) {
\r
5082 AdjustClock(!flipClock, -1);
\r
5085 if (!appData.highlightLastMove) {
\r
5086 ClearHighlights();
\r
5087 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5089 fromX = fromY = -1;
\r
5090 dragInfo.start.x = dragInfo.start.y = -1;
\r
5091 dragInfo.from = dragInfo.start;
\r
5093 } else if (x < 0 || y < 0
\r
5094 /* [HGM] block clicks between board and holdings */
\r
5095 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5096 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5097 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5098 /* EditPosition, empty square, or different color piece;
\r
5099 click-click move is possible */
\r
5102 } else if (fromX == x && fromY == y) {
\r
5103 /* Downclick on same square again */
\r
5104 ClearHighlights();
\r
5105 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5106 sameAgain = TRUE;
\r
5107 } else if (fromX != -1 &&
\r
5108 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5110 /* Downclick on different square. */
\r
5111 /* [HGM] if on holdings file, should count as new first click ! */
\r
5112 /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5115 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5116 to make sure move is legal before showing promotion popup */
\r
5117 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5118 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5119 fromX = fromY = -1;
\r
5120 ClearHighlights();
\r
5121 DrawPosition(FALSE, boards[currentMove]);
\r
5124 if(moveType != ImpossibleMove) {
\r
5125 if(moveType == IllegalMove) {
\r
5128 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5129 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5130 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5131 appData.alwaysPromoteToQueen)) {
\r
5132 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5133 if (!appData.highlightLastMove) {
\r
5134 ClearHighlights();
\r
5135 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5138 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5139 SetHighlights(fromX, fromY, toX, toY);
\r
5140 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5141 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5142 If promotion to Q is legal, all are legal! */
\r
5143 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5144 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5145 // kludge to temporarily execute move on display, without promoting yet
\r
5146 promotionChoice = TRUE;
\r
5147 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5148 boards[currentMove][toY][toX] = p;
\r
5149 DrawPosition(FALSE, boards[currentMove]);
\r
5150 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5151 boards[currentMove][toY][toX] = q;
\r
5153 PromotionPopup(hwnd);
\r
5154 } else { /* not a promotion */
\r
5155 if (appData.animate || appData.highlightLastMove) {
\r
5156 SetHighlights(fromX, fromY, toX, toY);
\r
5158 ClearHighlights();
\r
5160 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5161 if (appData.animate && !appData.highlightLastMove) {
\r
5162 ClearHighlights();
\r
5163 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5166 fromX = fromY = -1;
\r
5170 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5171 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5172 } else ClearHighlights();
\r
5173 fromX = fromY = -1;
\r
5174 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5176 /* First downclick, or restart on a square with same color piece */
\r
5177 if (!frozen && OKToStartUserMove(x, y)) {
\r
5180 dragInfo.lastpos = pt;
\r
5181 dragInfo.from.x = fromX;
\r
5182 dragInfo.from.y = fromY;
\r
5183 dragInfo.start = dragInfo.from;
\r
5184 SetCapture(hwndMain);
\r
5186 fromX = fromY = -1;
\r
5187 dragInfo.start.x = dragInfo.start.y = -1;
\r
5188 dragInfo.from = dragInfo.start;
\r
5189 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5193 case WM_LBUTTONUP:
\r
5195 if (fromX == -1) break;
\r
5196 if (x == fromX && y == fromY) {
\r
5197 dragInfo.from.x = dragInfo.from.y = -1;
\r
5198 /* Upclick on same square */
\r
5200 /* Clicked same square twice: abort click-click move */
\r
5201 fromX = fromY = -1;
\r
5203 ClearPremoveHighlights();
\r
5205 /* First square clicked: start click-click move */
\r
5206 SetHighlights(fromX, fromY, -1, -1);
\r
5208 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5209 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5210 /* Errant click; ignore */
\r
5213 /* Finish drag move. */
\r
5214 if (appData.debugMode) {
\r
5215 fprintf(debugFP, "release\n");
\r
5217 dragInfo.from.x = dragInfo.from.y = -1;
\r
5220 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5221 appData.animate = appData.animate && !appData.animateDragging;
\r
5222 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5223 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5224 fromX = fromY = -1;
\r
5225 ClearHighlights();
\r
5226 DrawPosition(FALSE, boards[currentMove]);
\r
5227 appData.animate = saveAnimate;
\r
5230 if(moveType != ImpossibleMove) {
\r
5231 /* [HGM] use move type to determine if move is promotion.
\r
5232 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5233 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5234 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5235 appData.alwaysPromoteToQueen))
\r
5236 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5238 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5239 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5240 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5241 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5242 // kludge to temporarily execute move on display, wthout promotng yet
\r
5243 promotionChoice = TRUE;
\r
5244 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5245 boards[currentMove][toY][toX] = p;
\r
5246 DrawPosition(FALSE, boards[currentMove]);
\r
5247 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5248 boards[currentMove][toY][toX] = q;
\r
5249 appData.animate = saveAnimate;
\r
5252 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5254 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5255 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5256 moveType == WhiteCapturesEnPassant ||
\r
5257 moveType == BlackCapturesEnPassant ) )
\r
5258 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5259 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5262 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5263 appData.animate = saveAnimate;
\r
5264 fromX = fromY = -1;
\r
5265 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5266 ClearHighlights();
\r
5268 if (appData.animate || appData.animateDragging ||
\r
5269 appData.highlightDragging || gotPremove) {
\r
5270 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5273 dragInfo.start.x = dragInfo.start.y = -1;
\r
5274 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5277 case WM_MOUSEMOVE:
\r
5278 if ((appData.animateDragging || appData.highlightDragging)
\r
5279 && (wParam & MK_LBUTTON)
\r
5280 && dragInfo.from.x >= 0)
\r
5282 BOOL full_repaint = FALSE;
\r
5284 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5285 if (appData.animateDragging) {
\r
5286 dragInfo.pos = pt;
\r
5288 if (appData.highlightDragging) {
\r
5289 SetHighlights(fromX, fromY, x, y);
\r
5290 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5291 full_repaint = TRUE;
\r
5295 DrawPosition( full_repaint, NULL);
\r
5297 dragInfo.lastpos = dragInfo.pos;
\r
5301 case WM_MOUSEWHEEL: // [DM]
\r
5302 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5303 /* Mouse Wheel is being rolled forward
\r
5304 * Play moves forward
\r
5306 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5307 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5308 /* Mouse Wheel is being rolled backward
\r
5309 * Play moves backward
\r
5311 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5312 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5316 case WM_MBUTTONDOWN:
\r
5317 case WM_RBUTTONDOWN:
\r
5320 fromX = fromY = -1;
\r
5321 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5322 dragInfo.start.x = dragInfo.start.y = -1;
\r
5323 dragInfo.from = dragInfo.start;
\r
5324 dragInfo.lastpos = dragInfo.pos;
\r
5325 if (appData.highlightDragging) {
\r
5326 ClearHighlights();
\r
5329 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5330 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5331 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5332 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5333 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5336 DrawPosition(TRUE, NULL);
\r
5338 switch (gameMode) {
\r
5339 case EditPosition:
\r
5340 case IcsExamining:
\r
5341 if (x < 0 || y < 0) break;
\r
5344 if (message == WM_MBUTTONDOWN) {
\r
5345 buttonCount = 3; /* even if system didn't think so */
\r
5346 if (wParam & MK_SHIFT)
\r
5347 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5349 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5350 } else { /* message == WM_RBUTTONDOWN */
\r
5352 if (buttonCount == 3) {
\r
5353 if (wParam & MK_SHIFT)
\r
5354 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5356 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5358 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5361 /* Just have one menu, on the right button. Windows users don't
\r
5362 think to try the middle one, and sometimes other software steals
\r
5363 it, or it doesn't really exist. */
\r
5364 if(gameInfo.variant != VariantShogi)
\r
5365 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5367 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5371 case IcsPlayingWhite:
\r
5372 case IcsPlayingBlack:
\r
5374 case MachinePlaysWhite:
\r
5375 case MachinePlaysBlack:
\r
5376 if (appData.testLegality &&
\r
5377 gameInfo.variant != VariantBughouse &&
\r
5378 gameInfo.variant != VariantCrazyhouse) break;
\r
5379 if (x < 0 || y < 0) break;
\r
5382 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5383 SetupDropMenu(hmenu);
\r
5384 MenuPopup(hwnd, pt, hmenu, -1);
\r
5395 /* Preprocess messages for buttons in main window */
\r
5397 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5399 int id = GetWindowLong(hwnd, GWL_ID);
\r
5402 for (i=0; i<N_BUTTONS; i++) {
\r
5403 if (buttonDesc[i].id == id) break;
\r
5405 if (i == N_BUTTONS) return 0;
\r
5406 switch (message) {
\r
5411 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5412 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5419 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5422 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5423 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5424 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5425 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5427 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5429 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5430 PopUpMoveDialog((char)wParam);
\r
5436 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5439 /* Process messages for Promotion dialog box */
\r
5441 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5445 switch (message) {
\r
5446 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5447 /* Center the dialog over the application window */
\r
5448 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5449 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5450 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5451 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5452 SW_SHOW : SW_HIDE);
\r
5453 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5454 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5455 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5456 PieceToChar(WhiteAngel) != '~') ||
\r
5457 (PieceToChar(BlackAngel) >= 'A' &&
\r
5458 PieceToChar(BlackAngel) != '~') ) ?
\r
5459 SW_SHOW : SW_HIDE);
\r
5460 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5461 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5462 PieceToChar(WhiteMarshall) != '~') ||
\r
5463 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5464 PieceToChar(BlackMarshall) != '~') ) ?
\r
5465 SW_SHOW : SW_HIDE);
\r
5466 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5467 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5468 gameInfo.variant != VariantShogi ?
\r
5469 SW_SHOW : SW_HIDE);
\r
5470 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5471 gameInfo.variant != VariantShogi ?
\r
5472 SW_SHOW : SW_HIDE);
\r
5473 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5474 gameInfo.variant == VariantShogi ?
\r
5475 SW_SHOW : SW_HIDE);
\r
5476 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5477 gameInfo.variant == VariantShogi ?
\r
5478 SW_SHOW : SW_HIDE);
\r
5479 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5480 gameInfo.variant == VariantSuper ?
\r
5481 SW_SHOW : SW_HIDE);
\r
5484 case WM_COMMAND: /* message: received a command */
\r
5485 switch (LOWORD(wParam)) {
\r
5487 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5488 ClearHighlights();
\r
5489 DrawPosition(FALSE, NULL);
\r
5492 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5495 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5498 promoChar = PieceToChar(BlackRook);
\r
5501 promoChar = PieceToChar(BlackBishop);
\r
5503 case PB_Chancellor:
\r
5504 promoChar = PieceToChar(BlackMarshall);
\r
5506 case PB_Archbishop:
\r
5507 promoChar = PieceToChar(BlackAngel);
\r
5510 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5515 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5516 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5517 only show the popup when we are already sure the move is valid or
\r
5518 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5519 will figure out it is a promotion from the promoChar. */
\r
5520 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5521 if (!appData.highlightLastMove) {
\r
5522 ClearHighlights();
\r
5523 DrawPosition(FALSE, NULL);
\r
5530 /* Pop up promotion dialog */
\r
5532 PromotionPopup(HWND hwnd)
\r
5536 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5537 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5538 hwnd, (DLGPROC)lpProc);
\r
5539 FreeProcInstance(lpProc);
\r
5542 /* Toggle ShowThinking */
\r
5544 ToggleShowThinking()
\r
5546 appData.showThinking = !appData.showThinking;
\r
5547 ShowThinkingEvent();
\r
5551 LoadGameDialog(HWND hwnd, char* title)
\r
5555 char fileTitle[MSG_SIZ];
\r
5556 f = OpenFileDialog(hwnd, "rb", "",
\r
5557 appData.oldSaveStyle ? "gam" : "pgn",
\r
5559 title, &number, fileTitle, NULL);
\r
5561 cmailMsgLoaded = FALSE;
\r
5562 if (number == 0) {
\r
5563 int error = GameListBuild(f);
\r
5565 DisplayError("Cannot build game list", error);
\r
5566 } else if (!ListEmpty(&gameList) &&
\r
5567 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5568 GameListPopUp(f, fileTitle);
\r
5571 GameListDestroy();
\r
5574 LoadGame(f, number, fileTitle, FALSE);
\r
5579 ChangedConsoleFont()
\r
5582 CHARRANGE tmpsel, sel;
\r
5583 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5584 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5585 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5588 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5589 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5590 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5591 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5592 * size. This was undocumented in the version of MSVC++ that I had
\r
5593 * when I wrote the code, but is apparently documented now.
\r
5595 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5596 cfmt.bCharSet = f->lf.lfCharSet;
\r
5597 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5598 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5599 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5600 /* Why are the following seemingly needed too? */
\r
5601 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5602 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5603 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5605 tmpsel.cpMax = -1; /*999999?*/
\r
5606 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5607 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5608 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5609 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5611 paraf.cbSize = sizeof(paraf);
\r
5612 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5613 paraf.dxStartIndent = 0;
\r
5614 paraf.dxOffset = WRAP_INDENT;
\r
5615 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5616 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5619 /*---------------------------------------------------------------------------*\
\r
5621 * Window Proc for main window
\r
5623 \*---------------------------------------------------------------------------*/
\r
5625 /* Process messages for main window, etc. */
\r
5627 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5630 int wmId, wmEvent;
\r
5634 char fileTitle[MSG_SIZ];
\r
5635 char buf[MSG_SIZ];
\r
5636 static SnapData sd;
\r
5638 switch (message) {
\r
5640 case WM_PAINT: /* message: repaint portion of window */
\r
5644 case WM_ERASEBKGND:
\r
5645 if (IsIconic(hwnd)) {
\r
5646 /* Cheat; change the message */
\r
5647 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5649 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5653 case WM_LBUTTONDOWN:
\r
5654 case WM_MBUTTONDOWN:
\r
5655 case WM_RBUTTONDOWN:
\r
5656 case WM_LBUTTONUP:
\r
5657 case WM_MBUTTONUP:
\r
5658 case WM_RBUTTONUP:
\r
5659 case WM_MOUSEMOVE:
\r
5660 case WM_MOUSEWHEEL:
\r
5661 MouseEvent(hwnd, message, wParam, lParam);
\r
5664 JAWS_KB_NAVIGATION
\r
5668 JAWS_ALT_INTERCEPT
\r
5670 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5671 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5672 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5673 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5675 SendMessage(h, message, wParam, lParam);
\r
5676 } else if(lParam != KF_REPEAT) {
\r
5677 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5678 PopUpMoveDialog((char)wParam);
\r
5679 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5680 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5685 case WM_PALETTECHANGED:
\r
5686 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5688 HDC hdc = GetDC(hwndMain);
\r
5689 SelectPalette(hdc, hPal, TRUE);
\r
5690 nnew = RealizePalette(hdc);
\r
5692 paletteChanged = TRUE;
\r
5694 UpdateColors(hdc);
\r
5696 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5699 ReleaseDC(hwnd, hdc);
\r
5703 case WM_QUERYNEWPALETTE:
\r
5704 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5706 HDC hdc = GetDC(hwndMain);
\r
5707 paletteChanged = FALSE;
\r
5708 SelectPalette(hdc, hPal, FALSE);
\r
5709 nnew = RealizePalette(hdc);
\r
5711 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5713 ReleaseDC(hwnd, hdc);
\r
5718 case WM_COMMAND: /* message: command from application menu */
\r
5719 wmId = LOWORD(wParam);
\r
5720 wmEvent = HIWORD(wParam);
\r
5725 AnalysisPopDown();
\r
5726 SAY("new game enter a move to play against the computer with white");
\r
5729 case IDM_NewGameFRC:
\r
5730 if( NewGameFRC() == 0 ) {
\r
5732 AnalysisPopDown();
\r
5736 case IDM_NewVariant:
\r
5737 NewVariantPopup(hwnd);
\r
5740 case IDM_LoadGame:
\r
5741 LoadGameDialog(hwnd, "Load Game from File");
\r
5744 case IDM_LoadNextGame:
\r
5748 case IDM_LoadPrevGame:
\r
5752 case IDM_ReloadGame:
\r
5756 case IDM_LoadPosition:
\r
5757 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5758 Reset(FALSE, TRUE);
\r
5761 f = OpenFileDialog(hwnd, "rb", "",
\r
5762 appData.oldSaveStyle ? "pos" : "fen",
\r
5764 "Load Position from File", &number, fileTitle, NULL);
\r
5766 LoadPosition(f, number, fileTitle);
\r
5770 case IDM_LoadNextPosition:
\r
5771 ReloadPosition(1);
\r
5774 case IDM_LoadPrevPosition:
\r
5775 ReloadPosition(-1);
\r
5778 case IDM_ReloadPosition:
\r
5779 ReloadPosition(0);
\r
5782 case IDM_SaveGame:
\r
5783 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5784 f = OpenFileDialog(hwnd, "a", defName,
\r
5785 appData.oldSaveStyle ? "gam" : "pgn",
\r
5787 "Save Game to File", NULL, fileTitle, NULL);
\r
5789 SaveGame(f, 0, "");
\r
5793 case IDM_SavePosition:
\r
5794 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5795 f = OpenFileDialog(hwnd, "a", defName,
\r
5796 appData.oldSaveStyle ? "pos" : "fen",
\r
5798 "Save Position to File", NULL, fileTitle, NULL);
\r
5800 SavePosition(f, 0, "");
\r
5804 case IDM_SaveDiagram:
\r
5805 defName = "diagram";
\r
5806 f = OpenFileDialog(hwnd, "wb", defName,
\r
5809 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5815 case IDM_CopyGame:
\r
5816 CopyGameToClipboard();
\r
5819 case IDM_PasteGame:
\r
5820 PasteGameFromClipboard();
\r
5823 case IDM_CopyGameListToClipboard:
\r
5824 CopyGameListToClipboard();
\r
5827 /* [AS] Autodetect FEN or PGN data */
\r
5828 case IDM_PasteAny:
\r
5829 PasteGameOrFENFromClipboard();
\r
5832 /* [AS] Move history */
\r
5833 case IDM_ShowMoveHistory:
\r
5834 if( MoveHistoryIsUp() ) {
\r
5835 MoveHistoryPopDown();
\r
5838 MoveHistoryPopUp();
\r
5842 /* [AS] Eval graph */
\r
5843 case IDM_ShowEvalGraph:
\r
5844 if( EvalGraphIsUp() ) {
\r
5845 EvalGraphPopDown();
\r
5849 SetFocus(hwndMain);
\r
5853 /* [AS] Engine output */
\r
5854 case IDM_ShowEngineOutput:
\r
5855 if( EngineOutputIsUp() ) {
\r
5856 EngineOutputPopDown();
\r
5859 EngineOutputPopUp();
\r
5863 /* [AS] User adjudication */
\r
5864 case IDM_UserAdjudication_White:
\r
5865 UserAdjudicationEvent( +1 );
\r
5868 case IDM_UserAdjudication_Black:
\r
5869 UserAdjudicationEvent( -1 );
\r
5872 case IDM_UserAdjudication_Draw:
\r
5873 UserAdjudicationEvent( 0 );
\r
5876 /* [AS] Game list options dialog */
\r
5877 case IDM_GameListOptions:
\r
5878 GameListOptions();
\r
5885 case IDM_CopyPosition:
\r
5886 CopyFENToClipboard();
\r
5889 case IDM_PastePosition:
\r
5890 PasteFENFromClipboard();
\r
5893 case IDM_MailMove:
\r
5897 case IDM_ReloadCMailMsg:
\r
5898 Reset(TRUE, TRUE);
\r
5899 ReloadCmailMsgEvent(FALSE);
\r
5902 case IDM_Minimize:
\r
5903 ShowWindow(hwnd, SW_MINIMIZE);
\r
5910 case IDM_MachineWhite:
\r
5911 MachineWhiteEvent();
\r
5913 * refresh the tags dialog only if it's visible
\r
5915 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5917 tags = PGNTags(&gameInfo);
\r
5918 TagsPopUp(tags, CmailMsg());
\r
5921 SAY("computer starts playing white");
\r
5924 case IDM_MachineBlack:
\r
5925 MachineBlackEvent();
\r
5927 * refresh the tags dialog only if it's visible
\r
5929 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5931 tags = PGNTags(&gameInfo);
\r
5932 TagsPopUp(tags, CmailMsg());
\r
5935 SAY("computer starts playing black");
\r
5938 case IDM_TwoMachines:
\r
5939 TwoMachinesEvent();
\r
5941 * refresh the tags dialog only if it's visible
\r
5943 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5945 tags = PGNTags(&gameInfo);
\r
5946 TagsPopUp(tags, CmailMsg());
\r
5949 SAY("programs start playing each other");
\r
5952 case IDM_AnalysisMode:
\r
5953 if (!first.analysisSupport) {
\r
5954 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5955 DisplayError(buf, 0);
\r
5957 SAY("analyzing current position");
\r
5958 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5959 if (appData.icsActive) {
\r
5960 if (gameMode != IcsObserving) {
\r
5961 sprintf(buf, "You are not observing a game");
\r
5962 DisplayError(buf, 0);
\r
5963 /* secure check */
\r
5964 if (appData.icsEngineAnalyze) {
\r
5965 if (appData.debugMode)
\r
5966 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5967 ExitAnalyzeMode();
\r
5973 /* if enable, user want disable icsEngineAnalyze */
\r
5974 if (appData.icsEngineAnalyze) {
\r
5975 ExitAnalyzeMode();
\r
5979 appData.icsEngineAnalyze = TRUE;
\r
5980 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5983 if (!appData.showThinking) ToggleShowThinking();
\r
5984 AnalyzeModeEvent();
\r
5988 case IDM_AnalyzeFile:
\r
5989 if (!first.analysisSupport) {
\r
5990 char buf[MSG_SIZ];
\r
5991 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5992 DisplayError(buf, 0);
\r
5994 if (!appData.showThinking) ToggleShowThinking();
\r
5995 AnalyzeFileEvent();
\r
5996 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5997 AnalysisPeriodicEvent(1);
\r
6001 case IDM_IcsClient:
\r
6005 case IDM_EditGame:
\r
6010 case IDM_EditPosition:
\r
6011 EditPositionEvent();
\r
6012 SAY("to set up a position type a FEN");
\r
6015 case IDM_Training:
\r
6019 case IDM_ShowGameList:
\r
6020 ShowGameListProc();
\r
6023 case IDM_EditTags:
\r
6027 case IDM_EditComment:
\r
6028 if (commentDialogUp && editComment) {
\r
6031 EditCommentEvent();
\r
6051 case IDM_CallFlag:
\r
6071 case IDM_StopObserving:
\r
6072 StopObservingEvent();
\r
6075 case IDM_StopExamining:
\r
6076 StopExaminingEvent();
\r
6079 case IDM_TypeInMove:
\r
6080 PopUpMoveDialog('\000');
\r
6083 case IDM_TypeInName:
\r
6084 PopUpNameDialog('\000');
\r
6087 case IDM_Backward:
\r
6089 SetFocus(hwndMain);
\r
6096 SetFocus(hwndMain);
\r
6101 SetFocus(hwndMain);
\r
6106 SetFocus(hwndMain);
\r
6113 case IDM_TruncateGame:
\r
6114 TruncateGameEvent();
\r
6121 case IDM_RetractMove:
\r
6122 RetractMoveEvent();
\r
6125 case IDM_FlipView:
\r
6126 flipView = !flipView;
\r
6127 DrawPosition(FALSE, NULL);
\r
6130 case IDM_FlipClock:
\r
6131 flipClock = !flipClock;
\r
6132 DisplayBothClocks();
\r
6133 DrawPosition(FALSE, NULL);
\r
6136 case IDM_GeneralOptions:
\r
6137 GeneralOptionsPopup(hwnd);
\r
6138 DrawPosition(TRUE, NULL);
\r
6141 case IDM_BoardOptions:
\r
6142 BoardOptionsPopup(hwnd);
\r
6145 case IDM_EnginePlayOptions:
\r
6146 EnginePlayOptionsPopup(hwnd);
\r
6149 case IDM_Engine1Options:
\r
6150 EngineOptionsPopup(hwnd, &first);
\r
6153 case IDM_Engine2Options:
\r
6154 EngineOptionsPopup(hwnd, &second);
\r
6157 case IDM_OptionsUCI:
\r
6158 UciOptionsPopup(hwnd);
\r
6161 case IDM_IcsOptions:
\r
6162 IcsOptionsPopup(hwnd);
\r
6166 FontsOptionsPopup(hwnd);
\r
6170 SoundOptionsPopup(hwnd);
\r
6173 case IDM_CommPort:
\r
6174 CommPortOptionsPopup(hwnd);
\r
6177 case IDM_LoadOptions:
\r
6178 LoadOptionsPopup(hwnd);
\r
6181 case IDM_SaveOptions:
\r
6182 SaveOptionsPopup(hwnd);
\r
6185 case IDM_TimeControl:
\r
6186 TimeControlOptionsPopup(hwnd);
\r
6189 case IDM_SaveSettings:
\r
6190 SaveSettings(settingsFileName);
\r
6193 case IDM_SaveSettingsOnExit:
\r
6194 saveSettingsOnExit = !saveSettingsOnExit;
\r
6195 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6196 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6197 MF_CHECKED : MF_UNCHECKED));
\r
6208 case IDM_AboutGame:
\r
6213 appData.debugMode = !appData.debugMode;
\r
6214 if (appData.debugMode) {
\r
6215 char dir[MSG_SIZ];
\r
6216 GetCurrentDirectory(MSG_SIZ, dir);
\r
6217 SetCurrentDirectory(installDir);
\r
6218 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6219 SetCurrentDirectory(dir);
\r
6220 setbuf(debugFP, NULL);
\r
6227 case IDM_HELPCONTENTS:
\r
6228 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6229 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6230 MessageBox (GetFocus(),
\r
6231 "Unable to activate help",
\r
6232 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6236 case IDM_HELPSEARCH:
\r
6237 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6238 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6239 MessageBox (GetFocus(),
\r
6240 "Unable to activate help",
\r
6241 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6245 case IDM_HELPHELP:
\r
6246 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6247 MessageBox (GetFocus(),
\r
6248 "Unable to activate help",
\r
6249 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6254 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6256 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6257 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6258 FreeProcInstance(lpProc);
\r
6261 case IDM_DirectCommand1:
\r
6262 AskQuestionEvent("Direct Command",
\r
6263 "Send to chess program:", "", "1");
\r
6265 case IDM_DirectCommand2:
\r
6266 AskQuestionEvent("Direct Command",
\r
6267 "Send to second chess program:", "", "2");
\r
6270 case EP_WhitePawn:
\r
6271 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6272 fromX = fromY = -1;
\r
6275 case EP_WhiteKnight:
\r
6276 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6277 fromX = fromY = -1;
\r
6280 case EP_WhiteBishop:
\r
6281 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6282 fromX = fromY = -1;
\r
6285 case EP_WhiteRook:
\r
6286 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6287 fromX = fromY = -1;
\r
6290 case EP_WhiteQueen:
\r
6291 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6292 fromX = fromY = -1;
\r
6295 case EP_WhiteFerz:
\r
6296 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6297 fromX = fromY = -1;
\r
6300 case EP_WhiteWazir:
\r
6301 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6302 fromX = fromY = -1;
\r
6305 case EP_WhiteAlfil:
\r
6306 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6307 fromX = fromY = -1;
\r
6310 case EP_WhiteCannon:
\r
6311 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6312 fromX = fromY = -1;
\r
6315 case EP_WhiteCardinal:
\r
6316 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6317 fromX = fromY = -1;
\r
6320 case EP_WhiteMarshall:
\r
6321 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6322 fromX = fromY = -1;
\r
6325 case EP_WhiteKing:
\r
6326 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6327 fromX = fromY = -1;
\r
6330 case EP_BlackPawn:
\r
6331 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6332 fromX = fromY = -1;
\r
6335 case EP_BlackKnight:
\r
6336 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6337 fromX = fromY = -1;
\r
6340 case EP_BlackBishop:
\r
6341 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6342 fromX = fromY = -1;
\r
6345 case EP_BlackRook:
\r
6346 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6347 fromX = fromY = -1;
\r
6350 case EP_BlackQueen:
\r
6351 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6352 fromX = fromY = -1;
\r
6355 case EP_BlackFerz:
\r
6356 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6357 fromX = fromY = -1;
\r
6360 case EP_BlackWazir:
\r
6361 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6362 fromX = fromY = -1;
\r
6365 case EP_BlackAlfil:
\r
6366 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6367 fromX = fromY = -1;
\r
6370 case EP_BlackCannon:
\r
6371 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6372 fromX = fromY = -1;
\r
6375 case EP_BlackCardinal:
\r
6376 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6377 fromX = fromY = -1;
\r
6380 case EP_BlackMarshall:
\r
6381 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6382 fromX = fromY = -1;
\r
6385 case EP_BlackKing:
\r
6386 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6387 fromX = fromY = -1;
\r
6390 case EP_EmptySquare:
\r
6391 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6392 fromX = fromY = -1;
\r
6395 case EP_ClearBoard:
\r
6396 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6397 fromX = fromY = -1;
\r
6401 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6402 fromX = fromY = -1;
\r
6406 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6407 fromX = fromY = -1;
\r
6411 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6412 fromX = fromY = -1;
\r
6416 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6417 fromX = fromY = -1;
\r
6421 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6422 fromX = fromY = -1;
\r
6426 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6427 fromX = fromY = -1;
\r
6431 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6432 fromX = fromY = -1;
\r
6436 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6437 fromX = fromY = -1;
\r
6441 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6442 fromX = fromY = -1;
\r
6446 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6452 case CLOCK_TIMER_ID:
\r
6453 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6454 clockTimerEvent = 0;
\r
6455 DecrementClocks(); /* call into back end */
\r
6457 case LOAD_GAME_TIMER_ID:
\r
6458 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6459 loadGameTimerEvent = 0;
\r
6460 AutoPlayGameLoop(); /* call into back end */
\r
6462 case ANALYSIS_TIMER_ID:
\r
6463 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6464 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6465 AnalysisPeriodicEvent(0);
\r
6467 KillTimer(hwnd, analysisTimerEvent);
\r
6468 analysisTimerEvent = 0;
\r
6471 case DELAYED_TIMER_ID:
\r
6472 KillTimer(hwnd, delayedTimerEvent);
\r
6473 delayedTimerEvent = 0;
\r
6474 delayedTimerCallback();
\r
6479 case WM_USER_Input:
\r
6480 InputEvent(hwnd, message, wParam, lParam);
\r
6483 /* [AS] Also move "attached" child windows */
\r
6484 case WM_WINDOWPOSCHANGING:
\r
6486 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6487 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6489 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6490 /* Window is moving */
\r
6493 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6494 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6495 rcMain.right = boardX + winWidth;
\r
6496 rcMain.top = boardY;
\r
6497 rcMain.bottom = boardY + winHeight;
\r
6499 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6500 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6501 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6502 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6503 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6510 /* [AS] Snapping */
\r
6511 case WM_ENTERSIZEMOVE:
\r
6512 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6513 if (hwnd == hwndMain) {
\r
6514 doingSizing = TRUE;
\r
6517 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6521 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6522 if (hwnd == hwndMain) {
\r
6523 lastSizing = wParam;
\r
6528 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6529 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6531 case WM_EXITSIZEMOVE:
\r
6532 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6533 if (hwnd == hwndMain) {
\r
6535 doingSizing = FALSE;
\r
6536 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6537 GetClientRect(hwnd, &client);
\r
6538 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6540 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6542 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6545 case WM_DESTROY: /* message: window being destroyed */
\r
6546 PostQuitMessage(0);
\r
6550 if (hwnd == hwndMain) {
\r
6555 default: /* Passes it on if unprocessed */
\r
6556 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6561 /*---------------------------------------------------------------------------*\
\r
6563 * Misc utility routines
\r
6565 \*---------------------------------------------------------------------------*/
\r
6568 * Decent random number generator, at least not as bad as Windows
\r
6569 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6571 unsigned int randstate;
\r
6576 randstate = randstate * 1664525 + 1013904223;
\r
6577 return (int) randstate & 0x7fffffff;
\r
6581 mysrandom(unsigned int seed)
\r
6588 * returns TRUE if user selects a different color, FALSE otherwise
\r
6592 ChangeColor(HWND hwnd, COLORREF *which)
\r
6594 static BOOL firstTime = TRUE;
\r
6595 static DWORD customColors[16];
\r
6597 COLORREF newcolor;
\r
6602 /* Make initial colors in use available as custom colors */
\r
6603 /* Should we put the compiled-in defaults here instead? */
\r
6605 customColors[i++] = lightSquareColor & 0xffffff;
\r
6606 customColors[i++] = darkSquareColor & 0xffffff;
\r
6607 customColors[i++] = whitePieceColor & 0xffffff;
\r
6608 customColors[i++] = blackPieceColor & 0xffffff;
\r
6609 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6610 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6612 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6613 customColors[i++] = textAttribs[ccl].color;
\r
6615 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6616 firstTime = FALSE;
\r
6619 cc.lStructSize = sizeof(cc);
\r
6620 cc.hwndOwner = hwnd;
\r
6621 cc.hInstance = NULL;
\r
6622 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6623 cc.lpCustColors = (LPDWORD) customColors;
\r
6624 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6626 if (!ChooseColor(&cc)) return FALSE;
\r
6628 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6629 if (newcolor == *which) return FALSE;
\r
6630 *which = newcolor;
\r
6634 InitDrawingColors();
\r
6635 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6640 MyLoadSound(MySound *ms)
\r
6646 if (ms->data) free(ms->data);
\r
6649 switch (ms->name[0]) {
\r
6655 /* System sound from Control Panel. Don't preload here. */
\r
6659 if (ms->name[1] == NULLCHAR) {
\r
6660 /* "!" alone = silence */
\r
6663 /* Builtin wave resource. Error if not found. */
\r
6664 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6665 if (h == NULL) break;
\r
6666 ms->data = (void *)LoadResource(hInst, h);
\r
6667 if (h == NULL) break;
\r
6672 /* .wav file. Error if not found. */
\r
6673 f = fopen(ms->name, "rb");
\r
6674 if (f == NULL) break;
\r
6675 if (fstat(fileno(f), &st) < 0) break;
\r
6676 ms->data = malloc(st.st_size);
\r
6677 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6683 char buf[MSG_SIZ];
\r
6684 sprintf(buf, "Error loading sound %s", ms->name);
\r
6685 DisplayError(buf, GetLastError());
\r
6691 MyPlaySound(MySound *ms)
\r
6693 BOOLEAN ok = FALSE;
\r
6695 switch (ms->name[0]) {
\r
6697 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6702 /* System sound from Control Panel (deprecated feature).
\r
6703 "$" alone or an unset sound name gets default beep (still in use). */
\r
6704 if (ms->name[1]) {
\r
6705 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6707 if (!ok) ok = MessageBeep(MB_OK);
\r
6710 /* Builtin wave resource, or "!" alone for silence */
\r
6711 if (ms->name[1]) {
\r
6712 if (ms->data == NULL) return FALSE;
\r
6713 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6719 /* .wav file. Error if not found. */
\r
6720 if (ms->data == NULL) return FALSE;
\r
6721 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6724 /* Don't print an error: this can happen innocently if the sound driver
\r
6725 is busy; for instance, if another instance of WinBoard is playing
\r
6726 a sound at about the same time. */
\r
6729 char buf[MSG_SIZ];
\r
6730 sprintf(buf, "Error playing sound %s", ms->name);
\r
6731 DisplayError(buf, GetLastError());
\r
6739 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6742 OPENFILENAME *ofn;
\r
6743 static UINT *number; /* gross that this is static */
\r
6745 switch (message) {
\r
6746 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6747 /* Center the dialog over the application window */
\r
6748 ofn = (OPENFILENAME *) lParam;
\r
6749 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6750 number = (UINT *) ofn->lCustData;
\r
6751 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6755 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6756 return FALSE; /* Allow for further processing */
\r
6759 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6760 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6762 return FALSE; /* Allow for further processing */
\r
6768 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6770 static UINT *number;
\r
6771 OPENFILENAME *ofname;
\r
6774 case WM_INITDIALOG:
\r
6775 ofname = (OPENFILENAME *)lParam;
\r
6776 number = (UINT *)(ofname->lCustData);
\r
6779 ofnot = (OFNOTIFY *)lParam;
\r
6780 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6781 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6790 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6791 char *nameFilt, char *dlgTitle, UINT *number,
\r
6792 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6794 OPENFILENAME openFileName;
\r
6795 char buf1[MSG_SIZ];
\r
6798 if (fileName == NULL) fileName = buf1;
\r
6799 if (defName == NULL) {
\r
6800 strcpy(fileName, "*.");
\r
6801 strcat(fileName, defExt);
\r
6803 strcpy(fileName, defName);
\r
6805 if (fileTitle) strcpy(fileTitle, "");
\r
6806 if (number) *number = 0;
\r
6808 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6809 openFileName.hwndOwner = hwnd;
\r
6810 openFileName.hInstance = (HANDLE) hInst;
\r
6811 openFileName.lpstrFilter = nameFilt;
\r
6812 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6813 openFileName.nMaxCustFilter = 0L;
\r
6814 openFileName.nFilterIndex = 1L;
\r
6815 openFileName.lpstrFile = fileName;
\r
6816 openFileName.nMaxFile = MSG_SIZ;
\r
6817 openFileName.lpstrFileTitle = fileTitle;
\r
6818 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6819 openFileName.lpstrInitialDir = NULL;
\r
6820 openFileName.lpstrTitle = dlgTitle;
\r
6821 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6822 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6823 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6824 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6825 openFileName.nFileOffset = 0;
\r
6826 openFileName.nFileExtension = 0;
\r
6827 openFileName.lpstrDefExt = defExt;
\r
6828 openFileName.lCustData = (LONG) number;
\r
6829 openFileName.lpfnHook = oldDialog ?
\r
6830 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6831 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6833 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6834 GetOpenFileName(&openFileName)) {
\r
6835 /* open the file */
\r
6836 f = fopen(openFileName.lpstrFile, write);
\r
6838 MessageBox(hwnd, "File open failed", NULL,
\r
6839 MB_OK|MB_ICONEXCLAMATION);
\r
6843 int err = CommDlgExtendedError();
\r
6844 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6853 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6855 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6858 * Get the first pop-up menu in the menu template. This is the
\r
6859 * menu that TrackPopupMenu displays.
\r
6861 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6863 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6866 * TrackPopup uses screen coordinates, so convert the
\r
6867 * coordinates of the mouse click to screen coordinates.
\r
6869 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6871 /* Draw and track the floating pop-up menu. */
\r
6872 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6873 pt.x, pt.y, 0, hwnd, NULL);
\r
6875 /* Destroy the menu.*/
\r
6876 DestroyMenu(hmenu);
\r
6881 int sizeX, sizeY, newSizeX, newSizeY;
\r
6883 } ResizeEditPlusButtonsClosure;
\r
6886 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6888 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6892 if (hChild == cl->hText) return TRUE;
\r
6893 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6894 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6895 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6896 ScreenToClient(cl->hDlg, &pt);
\r
6897 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6898 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6902 /* Resize a dialog that has a (rich) edit field filling most of
\r
6903 the top, with a row of buttons below */
\r
6905 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6908 int newTextHeight, newTextWidth;
\r
6909 ResizeEditPlusButtonsClosure cl;
\r
6911 /*if (IsIconic(hDlg)) return;*/
\r
6912 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6914 cl.hdwp = BeginDeferWindowPos(8);
\r
6916 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6917 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6918 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6919 if (newTextHeight < 0) {
\r
6920 newSizeY += -newTextHeight;
\r
6921 newTextHeight = 0;
\r
6923 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6924 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6930 cl.newSizeX = newSizeX;
\r
6931 cl.newSizeY = newSizeY;
\r
6932 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6934 EndDeferWindowPos(cl.hdwp);
\r
6937 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6939 RECT rChild, rParent;
\r
6940 int wChild, hChild, wParent, hParent;
\r
6941 int wScreen, hScreen, xNew, yNew;
\r
6944 /* Get the Height and Width of the child window */
\r
6945 GetWindowRect (hwndChild, &rChild);
\r
6946 wChild = rChild.right - rChild.left;
\r
6947 hChild = rChild.bottom - rChild.top;
\r
6949 /* Get the Height and Width of the parent window */
\r
6950 GetWindowRect (hwndParent, &rParent);
\r
6951 wParent = rParent.right - rParent.left;
\r
6952 hParent = rParent.bottom - rParent.top;
\r
6954 /* Get the display limits */
\r
6955 hdc = GetDC (hwndChild);
\r
6956 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6957 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6958 ReleaseDC(hwndChild, hdc);
\r
6960 /* Calculate new X position, then adjust for screen */
\r
6961 xNew = rParent.left + ((wParent - wChild) /2);
\r
6964 } else if ((xNew+wChild) > wScreen) {
\r
6965 xNew = wScreen - wChild;
\r
6968 /* Calculate new Y position, then adjust for screen */
\r
6970 yNew = rParent.top + ((hParent - hChild) /2);
\r
6973 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6978 } else if ((yNew+hChild) > hScreen) {
\r
6979 yNew = hScreen - hChild;
\r
6982 /* Set it, and return */
\r
6983 return SetWindowPos (hwndChild, NULL,
\r
6984 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6987 /* Center one window over another */
\r
6988 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6990 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6993 /*---------------------------------------------------------------------------*\
\r
6995 * Startup Dialog functions
\r
6997 \*---------------------------------------------------------------------------*/
\r
6999 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
7001 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7003 while (*cd != NULL) {
\r
7004 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
7010 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
7012 char buf1[ARG_MAX];
\r
7015 if (str[0] == '@') {
\r
7016 FILE* f = fopen(str + 1, "r");
\r
7018 DisplayFatalError(str + 1, errno, 2);
\r
7021 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
7023 buf1[len] = NULLCHAR;
\r
7027 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7030 char buf[MSG_SIZ];
\r
7031 char *end = strchr(str, '\n');
\r
7032 if (end == NULL) return;
\r
7033 memcpy(buf, str, end - str);
\r
7034 buf[end - str] = NULLCHAR;
\r
7035 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7041 SetStartupDialogEnables(HWND hDlg)
\r
7043 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7044 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7045 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7046 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7047 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7048 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7049 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7050 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7051 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7052 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7053 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7054 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7055 IsDlgButtonChecked(hDlg, OPT_View));
\r
7059 QuoteForFilename(char *filename)
\r
7061 int dquote, space;
\r
7062 dquote = strchr(filename, '"') != NULL;
\r
7063 space = strchr(filename, ' ') != NULL;
\r
7064 if (dquote || space) {
\r
7076 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7078 char buf[MSG_SIZ];
\r
7081 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7082 q = QuoteForFilename(nthcp);
\r
7083 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7084 if (*nthdir != NULLCHAR) {
\r
7085 q = QuoteForFilename(nthdir);
\r
7086 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7088 if (*nthcp == NULLCHAR) {
\r
7089 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7090 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7091 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7092 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7097 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7099 char buf[MSG_SIZ];
\r
7103 switch (message) {
\r
7104 case WM_INITDIALOG:
\r
7105 /* Center the dialog */
\r
7106 CenterWindow (hDlg, GetDesktopWindow());
\r
7107 /* Initialize the dialog items */
\r
7108 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7109 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7110 firstChessProgramNames);
\r
7111 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7112 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7113 secondChessProgramNames);
\r
7114 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7115 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7116 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7117 if (*appData.icsHelper != NULLCHAR) {
\r
7118 char *q = QuoteForFilename(appData.icsHelper);
\r
7119 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7121 if (*appData.icsHost == NULLCHAR) {
\r
7122 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7123 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7124 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7125 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7126 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7129 if (appData.icsActive) {
\r
7130 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7132 else if (appData.noChessProgram) {
\r
7133 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7136 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7139 SetStartupDialogEnables(hDlg);
\r
7143 switch (LOWORD(wParam)) {
\r
7145 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7146 strcpy(buf, "/fcp=");
\r
7147 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7149 ParseArgs(StringGet, &p);
\r
7150 strcpy(buf, "/scp=");
\r
7151 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7153 ParseArgs(StringGet, &p);
\r
7154 appData.noChessProgram = FALSE;
\r
7155 appData.icsActive = FALSE;
\r
7156 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7157 strcpy(buf, "/ics /icshost=");
\r
7158 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7160 ParseArgs(StringGet, &p);
\r
7161 if (appData.zippyPlay) {
\r
7162 strcpy(buf, "/fcp=");
\r
7163 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7165 ParseArgs(StringGet, &p);
\r
7167 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7168 appData.noChessProgram = TRUE;
\r
7169 appData.icsActive = FALSE;
\r
7171 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7172 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7175 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7176 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7178 ParseArgs(StringGet, &p);
\r
7180 EndDialog(hDlg, TRUE);
\r
7187 case IDM_HELPCONTENTS:
\r
7188 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7189 MessageBox (GetFocus(),
\r
7190 "Unable to activate help",
\r
7191 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7196 SetStartupDialogEnables(hDlg);
\r
7204 /*---------------------------------------------------------------------------*\
\r
7206 * About box dialog functions
\r
7208 \*---------------------------------------------------------------------------*/
\r
7210 /* Process messages for "About" dialog box */
\r
7212 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7214 switch (message) {
\r
7215 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7216 /* Center the dialog over the application window */
\r
7217 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7218 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7222 case WM_COMMAND: /* message: received a command */
\r
7223 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7224 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7225 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7233 /*---------------------------------------------------------------------------*\
\r
7235 * Comment Dialog functions
\r
7237 \*---------------------------------------------------------------------------*/
\r
7240 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7242 static HANDLE hwndText = NULL;
\r
7243 int len, newSizeX, newSizeY, flags;
\r
7244 static int sizeX, sizeY;
\r
7249 switch (message) {
\r
7250 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7251 /* Initialize the dialog items */
\r
7252 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7253 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7254 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7255 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7256 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7257 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7258 SetWindowText(hDlg, commentTitle);
\r
7259 if (editComment) {
\r
7260 SetFocus(hwndText);
\r
7262 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7264 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7265 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7266 MAKELPARAM(FALSE, 0));
\r
7267 /* Size and position the dialog */
\r
7268 if (!commentDialog) {
\r
7269 commentDialog = hDlg;
\r
7270 flags = SWP_NOZORDER;
\r
7271 GetClientRect(hDlg, &rect);
\r
7272 sizeX = rect.right;
\r
7273 sizeY = rect.bottom;
\r
7274 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7275 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7276 WINDOWPLACEMENT wp;
\r
7277 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7278 wp.length = sizeof(WINDOWPLACEMENT);
\r
7280 wp.showCmd = SW_SHOW;
\r
7281 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7282 wp.rcNormalPosition.left = commentX;
\r
7283 wp.rcNormalPosition.right = commentX + commentW;
\r
7284 wp.rcNormalPosition.top = commentY;
\r
7285 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7286 SetWindowPlacement(hDlg, &wp);
\r
7288 GetClientRect(hDlg, &rect);
\r
7289 newSizeX = rect.right;
\r
7290 newSizeY = rect.bottom;
\r
7291 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7292 newSizeX, newSizeY);
\r
7299 case WM_COMMAND: /* message: received a command */
\r
7300 switch (LOWORD(wParam)) {
\r
7302 if (editComment) {
\r
7304 /* Read changed options from the dialog box */
\r
7305 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7306 len = GetWindowTextLength(hwndText);
\r
7307 str = (char *) malloc(len + 1);
\r
7308 GetWindowText(hwndText, str, len + 1);
\r
7317 ReplaceComment(commentIndex, str);
\r
7324 case OPT_CancelComment:
\r
7328 case OPT_ClearComment:
\r
7329 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7332 case OPT_EditComment:
\r
7333 EditCommentEvent();
\r
7342 newSizeX = LOWORD(lParam);
\r
7343 newSizeY = HIWORD(lParam);
\r
7344 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7349 case WM_GETMINMAXINFO:
\r
7350 /* Prevent resizing window too small */
\r
7351 mmi = (MINMAXINFO *) lParam;
\r
7352 mmi->ptMinTrackSize.x = 100;
\r
7353 mmi->ptMinTrackSize.y = 100;
\r
7360 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7365 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7367 if (str == NULL) str = "";
\r
7368 p = (char *) malloc(2 * strlen(str) + 2);
\r
7371 if (*str == '\n') *q++ = '\r';
\r
7375 if (commentText != NULL) free(commentText);
\r
7377 commentIndex = index;
\r
7378 commentTitle = title;
\r
7380 editComment = edit;
\r
7382 if (commentDialog) {
\r
7383 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7384 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7386 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7387 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7388 hwndMain, (DLGPROC)lpProc);
\r
7389 FreeProcInstance(lpProc);
\r
7391 commentDialogUp = TRUE;
\r
7395 /*---------------------------------------------------------------------------*\
\r
7397 * Type-in move dialog functions
\r
7399 \*---------------------------------------------------------------------------*/
\r
7402 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7404 char move[MSG_SIZ];
\r
7406 ChessMove moveType;
\r
7407 int fromX, fromY, toX, toY;
\r
7410 switch (message) {
\r
7411 case WM_INITDIALOG:
\r
7412 move[0] = (char) lParam;
\r
7413 move[1] = NULLCHAR;
\r
7414 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7415 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7416 SetWindowText(hInput, move);
\r
7418 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7422 switch (LOWORD(wParam)) {
\r
7424 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7425 { int n; Board board;
\r
7427 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7428 EditPositionPasteFEN(move);
\r
7429 EndDialog(hDlg, TRUE);
\r
7432 // [HGM] movenum: allow move number to be typed in any mode
\r
7433 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7434 currentMove = 2*n-1;
\r
7435 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7436 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7437 EndDialog(hDlg, TRUE);
\r
7438 DrawPosition(TRUE, boards[currentMove]);
\r
7439 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7440 else DisplayMessage("", "");
\r
7444 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7445 gameMode != Training) {
\r
7446 DisplayMoveError("Displayed move is not current");
\r
7448 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7449 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7450 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7451 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7452 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7453 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7454 if (gameMode != Training)
\r
7455 forwardMostMove = currentMove;
\r
7456 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7458 DisplayMoveError("Could not parse move");
\r
7461 EndDialog(hDlg, TRUE);
\r
7464 EndDialog(hDlg, FALSE);
\r
7475 PopUpMoveDialog(char firstchar)
\r
7479 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7480 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7481 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7482 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7483 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7484 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7485 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7486 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7487 gameMode == Training) {
\r
7488 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7489 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7490 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7491 FreeProcInstance(lpProc);
\r
7495 /*---------------------------------------------------------------------------*\
\r
7497 * Type-in name dialog functions
\r
7499 \*---------------------------------------------------------------------------*/
\r
7502 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7504 char move[MSG_SIZ];
\r
7507 switch (message) {
\r
7508 case WM_INITDIALOG:
\r
7509 move[0] = (char) lParam;
\r
7510 move[1] = NULLCHAR;
\r
7511 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7512 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7513 SetWindowText(hInput, move);
\r
7515 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7519 switch (LOWORD(wParam)) {
\r
7521 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7522 appData.userName = strdup(move);
\r
7525 EndDialog(hDlg, TRUE);
\r
7528 EndDialog(hDlg, FALSE);
\r
7539 PopUpNameDialog(char firstchar)
\r
7543 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7544 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7545 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7546 FreeProcInstance(lpProc);
\r
7549 /*---------------------------------------------------------------------------*\
\r
7553 \*---------------------------------------------------------------------------*/
\r
7555 /* Nonmodal error box */
\r
7556 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7557 WPARAM wParam, LPARAM lParam);
\r
7560 ErrorPopUp(char *title, char *content)
\r
7564 BOOLEAN modal = hwndMain == NULL;
\r
7582 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7583 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7586 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7588 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7589 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7590 hwndMain, (DLGPROC)lpProc);
\r
7591 FreeProcInstance(lpProc);
\r
7598 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7599 if (errorDialog == NULL) return;
\r
7600 DestroyWindow(errorDialog);
\r
7601 errorDialog = NULL;
\r
7605 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7610 switch (message) {
\r
7611 case WM_INITDIALOG:
\r
7612 GetWindowRect(hDlg, &rChild);
\r
7615 SetWindowPos(hDlg, NULL, rChild.left,
\r
7616 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7617 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7621 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7622 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7623 and it doesn't work when you resize the dialog.
\r
7624 For now, just give it a default position.
\r
7626 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7628 errorDialog = hDlg;
\r
7629 SetWindowText(hDlg, errorTitle);
\r
7630 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7631 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7635 switch (LOWORD(wParam)) {
\r
7638 if (errorDialog == hDlg) errorDialog = NULL;
\r
7639 DestroyWindow(hDlg);
\r
7651 HWND gothicDialog = NULL;
\r
7654 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7658 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7660 switch (message) {
\r
7661 case WM_INITDIALOG:
\r
7662 GetWindowRect(hDlg, &rChild);
\r
7664 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7668 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7669 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7670 and it doesn't work when you resize the dialog.
\r
7671 For now, just give it a default position.
\r
7673 gothicDialog = hDlg;
\r
7674 SetWindowText(hDlg, errorTitle);
\r
7675 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7676 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7680 switch (LOWORD(wParam)) {
\r
7683 if (errorDialog == hDlg) errorDialog = NULL;
\r
7684 DestroyWindow(hDlg);
\r
7696 GothicPopUp(char *title, VariantClass variant)
\r
7699 static char *lastTitle;
\r
7701 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7702 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7704 if(lastTitle != title && gothicDialog != NULL) {
\r
7705 DestroyWindow(gothicDialog);
\r
7706 gothicDialog = NULL;
\r
7708 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7709 title = lastTitle;
\r
7710 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7711 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7712 hwndMain, (DLGPROC)lpProc);
\r
7713 FreeProcInstance(lpProc);
\r
7718 /*---------------------------------------------------------------------------*\
\r
7720 * Ics Interaction console functions
\r
7722 \*---------------------------------------------------------------------------*/
\r
7724 #define HISTORY_SIZE 64
\r
7725 static char *history[HISTORY_SIZE];
\r
7726 int histIn = 0, histP = 0;
\r
7729 SaveInHistory(char *cmd)
\r
7731 if (history[histIn] != NULL) {
\r
7732 free(history[histIn]);
\r
7733 history[histIn] = NULL;
\r
7735 if (*cmd == NULLCHAR) return;
\r
7736 history[histIn] = StrSave(cmd);
\r
7737 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7738 if (history[histIn] != NULL) {
\r
7739 free(history[histIn]);
\r
7740 history[histIn] = NULL;
\r
7746 PrevInHistory(char *cmd)
\r
7749 if (histP == histIn) {
\r
7750 if (history[histIn] != NULL) free(history[histIn]);
\r
7751 history[histIn] = StrSave(cmd);
\r
7753 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7754 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7756 return history[histP];
\r
7762 if (histP == histIn) return NULL;
\r
7763 histP = (histP + 1) % HISTORY_SIZE;
\r
7764 return history[histP];
\r
7771 BOOLEAN immediate;
\r
7772 } IcsTextMenuEntry;
\r
7773 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7774 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7777 ParseIcsTextMenu(char *icsTextMenuString)
\r
7780 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7781 char *p = icsTextMenuString;
\r
7782 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7785 if (e->command != NULL) {
\r
7787 e->command = NULL;
\r
7791 e = icsTextMenuEntry;
\r
7792 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7793 if (*p == ';' || *p == '\n') {
\r
7794 e->item = strdup("-");
\r
7795 e->command = NULL;
\r
7797 } else if (*p == '-') {
\r
7798 e->item = strdup("-");
\r
7799 e->command = NULL;
\r
7803 char *q, *r, *s, *t;
\r
7805 q = strchr(p, ',');
\r
7806 if (q == NULL) break;
\r
7808 r = strchr(q + 1, ',');
\r
7809 if (r == NULL) break;
\r
7811 s = strchr(r + 1, ',');
\r
7812 if (s == NULL) break;
\r
7815 t = strchr(s + 1, c);
\r
7818 t = strchr(s + 1, c);
\r
7820 if (t != NULL) *t = NULLCHAR;
\r
7821 e->item = strdup(p);
\r
7822 e->command = strdup(q + 1);
\r
7823 e->getname = *(r + 1) != '0';
\r
7824 e->immediate = *(s + 1) != '0';
\r
7828 if (t == NULL) break;
\r
7837 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7841 hmenu = LoadMenu(hInst, "TextMenu");
\r
7842 h = GetSubMenu(hmenu, 0);
\r
7844 if (strcmp(e->item, "-") == 0) {
\r
7845 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7847 if (e->item[0] == '|') {
\r
7848 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7849 IDM_CommandX + i, &e->item[1]);
\r
7851 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7860 WNDPROC consoleTextWindowProc;
\r
7863 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7865 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7866 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7870 SetWindowText(hInput, command);
\r
7872 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7874 sel.cpMin = 999999;
\r
7875 sel.cpMax = 999999;
\r
7876 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7881 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7882 if (sel.cpMin == sel.cpMax) {
\r
7883 /* Expand to surrounding word */
\r
7886 tr.chrg.cpMax = sel.cpMin;
\r
7887 tr.chrg.cpMin = --sel.cpMin;
\r
7888 if (sel.cpMin < 0) break;
\r
7889 tr.lpstrText = name;
\r
7890 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7891 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7895 tr.chrg.cpMin = sel.cpMax;
\r
7896 tr.chrg.cpMax = ++sel.cpMax;
\r
7897 tr.lpstrText = name;
\r
7898 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7899 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7902 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7903 MessageBeep(MB_ICONEXCLAMATION);
\r
7907 tr.lpstrText = name;
\r
7908 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7910 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7911 MessageBeep(MB_ICONEXCLAMATION);
\r
7914 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7917 sprintf(buf, "%s %s", command, name);
\r
7918 SetWindowText(hInput, buf);
\r
7919 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7921 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7922 SetWindowText(hInput, buf);
\r
7923 sel.cpMin = 999999;
\r
7924 sel.cpMax = 999999;
\r
7925 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7931 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7936 switch (message) {
\r
7938 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7941 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7944 sel.cpMin = 999999;
\r
7945 sel.cpMax = 999999;
\r
7946 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7947 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7952 if(wParam != '\022') {
\r
7953 if (wParam == '\t') {
\r
7954 if (GetKeyState(VK_SHIFT) < 0) {
\r
7956 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7957 if (buttonDesc[0].hwnd) {
\r
7958 SetFocus(buttonDesc[0].hwnd);
\r
7960 SetFocus(hwndMain);
\r
7964 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7967 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7968 JAWS_DELETE( SetFocus(hInput); )
\r
7969 SendMessage(hInput, message, wParam, lParam);
\r
7972 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7973 case WM_RBUTTONUP:
\r
7974 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7975 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7976 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7979 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7980 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7981 if (sel.cpMin == sel.cpMax) {
\r
7982 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7983 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7985 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7986 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7988 pt.x = LOWORD(lParam);
\r
7989 pt.y = HIWORD(lParam);
\r
7990 MenuPopup(hwnd, pt, hmenu, -1);
\r
7994 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7996 return SendMessage(hInput, message, wParam, lParam);
\r
7997 case WM_MBUTTONDOWN:
\r
7998 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7999 case WM_RBUTTONDOWN:
\r
8000 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
8001 /* Move selection here if it was empty */
\r
8003 pt.x = LOWORD(lParam);
\r
8004 pt.y = HIWORD(lParam);
\r
8005 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8006 if (sel.cpMin == sel.cpMax) {
\r
8007 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
8008 sel.cpMax = sel.cpMin;
\r
8009 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8011 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
8015 switch (LOWORD(wParam)) {
\r
8016 case IDM_QuickPaste:
\r
8018 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8019 if (sel.cpMin == sel.cpMax) {
\r
8020 MessageBeep(MB_ICONEXCLAMATION);
\r
8023 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8024 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8025 SendMessage(hInput, WM_PASTE, 0, 0);
\r
8030 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8033 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8036 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8040 int i = LOWORD(wParam) - IDM_CommandX;
\r
8041 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8042 icsTextMenuEntry[i].command != NULL) {
\r
8043 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8044 icsTextMenuEntry[i].getname,
\r
8045 icsTextMenuEntry[i].immediate);
\r
8053 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8056 WNDPROC consoleInputWindowProc;
\r
8059 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8061 char buf[MSG_SIZ];
\r
8063 static BOOL sendNextChar = FALSE;
\r
8064 static BOOL quoteNextChar = FALSE;
\r
8065 InputSource *is = consoleInputSource;
\r
8069 switch (message) {
\r
8071 if (!appData.localLineEditing || sendNextChar) {
\r
8072 is->buf[0] = (CHAR) wParam;
\r
8074 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8075 sendNextChar = FALSE;
\r
8078 if (quoteNextChar) {
\r
8079 buf[0] = (char) wParam;
\r
8080 buf[1] = NULLCHAR;
\r
8081 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8082 quoteNextChar = FALSE;
\r
8086 case '\r': /* Enter key */
\r
8087 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8088 if (consoleEcho) SaveInHistory(is->buf);
\r
8089 is->buf[is->count++] = '\n';
\r
8090 is->buf[is->count] = NULLCHAR;
\r
8091 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8092 if (consoleEcho) {
\r
8093 ConsoleOutput(is->buf, is->count, TRUE);
\r
8094 } else if (appData.localLineEditing) {
\r
8095 ConsoleOutput("\n", 1, TRUE);
\r
8098 case '\033': /* Escape key */
\r
8099 SetWindowText(hwnd, "");
\r
8100 cf.cbSize = sizeof(CHARFORMAT);
\r
8101 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8102 if (consoleEcho) {
\r
8103 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8105 cf.crTextColor = COLOR_ECHOOFF;
\r
8107 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8108 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8110 case '\t': /* Tab key */
\r
8111 if (GetKeyState(VK_SHIFT) < 0) {
\r
8113 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8116 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8117 if (buttonDesc[0].hwnd) {
\r
8118 SetFocus(buttonDesc[0].hwnd);
\r
8120 SetFocus(hwndMain);
\r
8124 case '\023': /* Ctrl+S */
\r
8125 sendNextChar = TRUE;
\r
8127 case '\021': /* Ctrl+Q */
\r
8128 quoteNextChar = TRUE;
\r
8138 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8139 p = PrevInHistory(buf);
\r
8141 SetWindowText(hwnd, p);
\r
8142 sel.cpMin = 999999;
\r
8143 sel.cpMax = 999999;
\r
8144 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8149 p = NextInHistory();
\r
8151 SetWindowText(hwnd, p);
\r
8152 sel.cpMin = 999999;
\r
8153 sel.cpMax = 999999;
\r
8154 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8160 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8164 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8168 case WM_MBUTTONDOWN:
\r
8169 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8170 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8172 case WM_RBUTTONUP:
\r
8173 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8174 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8175 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8179 hmenu = LoadMenu(hInst, "InputMenu");
\r
8180 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8181 if (sel.cpMin == sel.cpMax) {
\r
8182 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8183 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8185 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8186 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8188 pt.x = LOWORD(lParam);
\r
8189 pt.y = HIWORD(lParam);
\r
8190 MenuPopup(hwnd, pt, hmenu, -1);
\r
8194 switch (LOWORD(wParam)) {
\r
8196 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8198 case IDM_SelectAll:
\r
8200 sel.cpMax = -1; /*999999?*/
\r
8201 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8204 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8207 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8210 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8215 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8218 #define CO_MAX 100000
\r
8219 #define CO_TRIM 1000
\r
8222 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8224 static SnapData sd;
\r
8225 static HWND hText, hInput /*, hFocus*/;
\r
8226 // InputSource *is = consoleInputSource;
\r
8228 static int sizeX, sizeY;
\r
8229 int newSizeX, newSizeY;
\r
8232 switch (message) {
\r
8233 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8234 hwndConsole = hDlg;
\r
8235 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8236 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8238 consoleTextWindowProc = (WNDPROC)
\r
8239 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8240 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8241 consoleInputWindowProc = (WNDPROC)
\r
8242 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8243 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8244 Colorize(ColorNormal, TRUE);
\r
8245 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8246 ChangedConsoleFont();
\r
8247 GetClientRect(hDlg, &rect);
\r
8248 sizeX = rect.right;
\r
8249 sizeY = rect.bottom;
\r
8250 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8251 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8252 WINDOWPLACEMENT wp;
\r
8253 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8254 wp.length = sizeof(WINDOWPLACEMENT);
\r
8256 wp.showCmd = SW_SHOW;
\r
8257 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8258 wp.rcNormalPosition.left = wpConsole.x;
\r
8259 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8260 wp.rcNormalPosition.top = wpConsole.y;
\r
8261 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8262 SetWindowPlacement(hDlg, &wp);
\r
8265 // [HGM] Chessknight's change 2004-07-13
\r
8266 else { /* Determine Defaults */
\r
8267 WINDOWPLACEMENT wp;
\r
8268 wpConsole.x = winWidth + 1;
\r
8269 wpConsole.y = boardY;
\r
8270 wpConsole.width = screenWidth - winWidth;
\r
8271 wpConsole.height = winHeight;
\r
8272 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8273 wp.length = sizeof(WINDOWPLACEMENT);
\r
8275 wp.showCmd = SW_SHOW;
\r
8276 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8277 wp.rcNormalPosition.left = wpConsole.x;
\r
8278 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8279 wp.rcNormalPosition.top = wpConsole.y;
\r
8280 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8281 SetWindowPlacement(hDlg, &wp);
\r
8296 if (IsIconic(hDlg)) break;
\r
8297 newSizeX = LOWORD(lParam);
\r
8298 newSizeY = HIWORD(lParam);
\r
8299 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8300 RECT rectText, rectInput;
\r
8302 int newTextHeight, newTextWidth;
\r
8303 GetWindowRect(hText, &rectText);
\r
8304 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8305 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8306 if (newTextHeight < 0) {
\r
8307 newSizeY += -newTextHeight;
\r
8308 newTextHeight = 0;
\r
8310 SetWindowPos(hText, NULL, 0, 0,
\r
8311 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8312 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8313 pt.x = rectInput.left;
\r
8314 pt.y = rectInput.top + newSizeY - sizeY;
\r
8315 ScreenToClient(hDlg, &pt);
\r
8316 SetWindowPos(hInput, NULL,
\r
8317 pt.x, pt.y, /* needs client coords */
\r
8318 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8319 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8325 case WM_GETMINMAXINFO:
\r
8326 /* Prevent resizing window too small */
\r
8327 mmi = (MINMAXINFO *) lParam;
\r
8328 mmi->ptMinTrackSize.x = 100;
\r
8329 mmi->ptMinTrackSize.y = 100;
\r
8332 /* [AS] Snapping */
\r
8333 case WM_ENTERSIZEMOVE:
\r
8334 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8337 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8340 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8342 case WM_EXITSIZEMOVE:
\r
8343 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8346 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8354 if (hwndConsole) return;
\r
8355 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8356 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8361 ConsoleOutput(char* data, int length, int forceVisible)
\r
8366 char buf[CO_MAX+1];
\r
8369 static int delayLF = 0;
\r
8370 CHARRANGE savesel, sel;
\r
8372 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8380 while (length--) {
\r
8388 } else if (*p == '\007') {
\r
8389 MyPlaySound(&sounds[(int)SoundBell]);
\r
8396 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8397 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8398 /* Save current selection */
\r
8399 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8400 exlen = GetWindowTextLength(hText);
\r
8401 /* Find out whether current end of text is visible */
\r
8402 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8403 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8404 /* Trim existing text if it's too long */
\r
8405 if (exlen + (q - buf) > CO_MAX) {
\r
8406 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8409 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8410 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8412 savesel.cpMin -= trim;
\r
8413 savesel.cpMax -= trim;
\r
8414 if (exlen < 0) exlen = 0;
\r
8415 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8416 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8418 /* Append the new text */
\r
8419 sel.cpMin = exlen;
\r
8420 sel.cpMax = exlen;
\r
8421 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8422 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8423 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8424 if (forceVisible || exlen == 0 ||
\r
8425 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8426 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8427 /* Scroll to make new end of text visible if old end of text
\r
8428 was visible or new text is an echo of user typein */
\r
8429 sel.cpMin = 9999999;
\r
8430 sel.cpMax = 9999999;
\r
8431 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8432 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8433 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8434 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8436 if (savesel.cpMax == exlen || forceVisible) {
\r
8437 /* Move insert point to new end of text if it was at the old
\r
8438 end of text or if the new text is an echo of user typein */
\r
8439 sel.cpMin = 9999999;
\r
8440 sel.cpMax = 9999999;
\r
8441 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8443 /* Restore previous selection */
\r
8444 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8446 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8453 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8457 COLORREF oldFg, oldBg;
\r
8461 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8463 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8464 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8465 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8468 rect.right = x + squareSize;
\r
8470 rect.bottom = y + squareSize;
\r
8473 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8474 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8475 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8476 &rect, str, strlen(str), NULL);
\r
8478 (void) SetTextColor(hdc, oldFg);
\r
8479 (void) SetBkColor(hdc, oldBg);
\r
8480 (void) SelectObject(hdc, oldFont);
\r
8484 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8485 RECT *rect, char *color, char *flagFell)
\r
8489 COLORREF oldFg, oldBg;
\r
8492 if (appData.clockMode) {
\r
8494 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8496 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8503 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8504 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8506 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8507 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8509 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8513 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8514 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8515 rect, str, strlen(str), NULL);
\r
8516 if(logoHeight > 0 && appData.clockMode) {
\r
8518 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8519 r.top = rect->top + logoHeight/2;
\r
8520 r.left = rect->left;
\r
8521 r.right = rect->right;
\r
8522 r.bottom = rect->bottom;
\r
8523 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8524 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8525 &r, str, strlen(str), NULL);
\r
8527 (void) SetTextColor(hdc, oldFg);
\r
8528 (void) SetBkColor(hdc, oldBg);
\r
8529 (void) SelectObject(hdc, oldFont);
\r
8534 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8540 if( count <= 0 ) {
\r
8541 if (appData.debugMode) {
\r
8542 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8545 return ERROR_INVALID_USER_BUFFER;
\r
8548 ResetEvent(ovl->hEvent);
\r
8549 ovl->Offset = ovl->OffsetHigh = 0;
\r
8550 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8554 err = GetLastError();
\r
8555 if (err == ERROR_IO_PENDING) {
\r
8556 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8560 err = GetLastError();
\r
8567 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8572 ResetEvent(ovl->hEvent);
\r
8573 ovl->Offset = ovl->OffsetHigh = 0;
\r
8574 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8578 err = GetLastError();
\r
8579 if (err == ERROR_IO_PENDING) {
\r
8580 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8584 err = GetLastError();
\r
8590 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8591 void CheckForInputBufferFull( InputSource * is )
\r
8593 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8594 /* Look for end of line */
\r
8595 char * p = is->buf;
\r
8597 while( p < is->next && *p != '\n' ) {
\r
8601 if( p >= is->next ) {
\r
8602 if (appData.debugMode) {
\r
8603 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8606 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8607 is->count = (DWORD) -1;
\r
8608 is->next = is->buf;
\r
8614 InputThread(LPVOID arg)
\r
8619 is = (InputSource *) arg;
\r
8620 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8621 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8622 while (is->hThread != NULL) {
\r
8623 is->error = DoReadFile(is->hFile, is->next,
\r
8624 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8625 &is->count, &ovl);
\r
8626 if (is->error == NO_ERROR) {
\r
8627 is->next += is->count;
\r
8629 if (is->error == ERROR_BROKEN_PIPE) {
\r
8630 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8633 is->count = (DWORD) -1;
\r
8634 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8639 CheckForInputBufferFull( is );
\r
8641 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8643 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8645 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8648 CloseHandle(ovl.hEvent);
\r
8649 CloseHandle(is->hFile);
\r
8651 if (appData.debugMode) {
\r
8652 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8659 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8661 NonOvlInputThread(LPVOID arg)
\r
8668 is = (InputSource *) arg;
\r
8669 while (is->hThread != NULL) {
\r
8670 is->error = ReadFile(is->hFile, is->next,
\r
8671 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8672 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8673 if (is->error == NO_ERROR) {
\r
8674 /* Change CRLF to LF */
\r
8675 if (is->next > is->buf) {
\r
8677 i = is->count + 1;
\r
8685 if (prev == '\r' && *p == '\n') {
\r
8697 if (is->error == ERROR_BROKEN_PIPE) {
\r
8698 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8701 is->count = (DWORD) -1;
\r
8705 CheckForInputBufferFull( is );
\r
8707 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8709 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8711 if (is->count < 0) break; /* Quit on error */
\r
8713 CloseHandle(is->hFile);
\r
8718 SocketInputThread(LPVOID arg)
\r
8722 is = (InputSource *) arg;
\r
8723 while (is->hThread != NULL) {
\r
8724 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8725 if ((int)is->count == SOCKET_ERROR) {
\r
8726 is->count = (DWORD) -1;
\r
8727 is->error = WSAGetLastError();
\r
8729 is->error = NO_ERROR;
\r
8730 is->next += is->count;
\r
8731 if (is->count == 0 && is->second == is) {
\r
8732 /* End of file on stderr; quit with no message */
\r
8736 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8738 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8740 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8746 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8750 is = (InputSource *) lParam;
\r
8751 if (is->lineByLine) {
\r
8752 /* Feed in lines one by one */
\r
8753 char *p = is->buf;
\r
8755 while (q < is->next) {
\r
8756 if (*q++ == '\n') {
\r
8757 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8762 /* Move any partial line to the start of the buffer */
\r
8764 while (p < is->next) {
\r
8769 if (is->error != NO_ERROR || is->count == 0) {
\r
8770 /* Notify backend of the error. Note: If there was a partial
\r
8771 line at the end, it is not flushed through. */
\r
8772 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8775 /* Feed in the whole chunk of input at once */
\r
8776 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8777 is->next = is->buf;
\r
8781 /*---------------------------------------------------------------------------*\
\r
8783 * Menu enables. Used when setting various modes.
\r
8785 \*---------------------------------------------------------------------------*/
\r
8793 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8795 while (enab->item > 0) {
\r
8796 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8801 Enables gnuEnables[] = {
\r
8802 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8803 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8804 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8805 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8806 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8807 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8808 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8809 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8810 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8811 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8815 Enables icsEnables[] = {
\r
8816 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8817 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8818 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8819 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8820 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8822 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8823 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8824 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8825 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8826 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8827 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8832 Enables zippyEnables[] = {
\r
8833 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8834 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8835 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8840 Enables ncpEnables[] = {
\r
8841 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8842 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8843 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8844 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8845 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8846 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8847 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8848 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8849 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8850 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8851 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8852 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8853 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8854 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8855 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8859 Enables trainingOnEnables[] = {
\r
8860 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8861 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8862 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8863 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8864 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8865 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8866 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8867 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8871 Enables trainingOffEnables[] = {
\r
8872 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8873 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8874 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8875 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8876 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8877 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8878 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8879 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8883 /* These modify either ncpEnables or gnuEnables */
\r
8884 Enables cmailEnables[] = {
\r
8885 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8886 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8887 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8888 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8889 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8890 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8891 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8895 Enables machineThinkingEnables[] = {
\r
8896 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8897 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8898 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8899 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8900 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8901 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8902 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8903 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8904 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8905 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8906 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8907 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8908 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8909 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8910 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8914 Enables userThinkingEnables[] = {
\r
8915 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8916 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8917 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8918 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8919 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8920 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8921 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8922 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8923 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8924 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8925 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8926 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8927 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8928 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8929 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8933 /*---------------------------------------------------------------------------*\
\r
8935 * Front-end interface functions exported by XBoard.
\r
8936 * Functions appear in same order as prototypes in frontend.h.
\r
8938 \*---------------------------------------------------------------------------*/
\r
8942 static UINT prevChecked = 0;
\r
8943 static int prevPausing = 0;
\r
8946 if (pausing != prevPausing) {
\r
8947 prevPausing = pausing;
\r
8948 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8949 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8950 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8953 switch (gameMode) {
\r
8954 case BeginningOfGame:
\r
8955 if (appData.icsActive)
\r
8956 nowChecked = IDM_IcsClient;
\r
8957 else if (appData.noChessProgram)
\r
8958 nowChecked = IDM_EditGame;
\r
8960 nowChecked = IDM_MachineBlack;
\r
8962 case MachinePlaysBlack:
\r
8963 nowChecked = IDM_MachineBlack;
\r
8965 case MachinePlaysWhite:
\r
8966 nowChecked = IDM_MachineWhite;
\r
8968 case TwoMachinesPlay:
\r
8969 nowChecked = IDM_TwoMachines;
\r
8972 nowChecked = IDM_AnalysisMode;
\r
8975 nowChecked = IDM_AnalyzeFile;
\r
8978 nowChecked = IDM_EditGame;
\r
8980 case PlayFromGameFile:
\r
8981 nowChecked = IDM_LoadGame;
\r
8983 case EditPosition:
\r
8984 nowChecked = IDM_EditPosition;
\r
8987 nowChecked = IDM_Training;
\r
8989 case IcsPlayingWhite:
\r
8990 case IcsPlayingBlack:
\r
8991 case IcsObserving:
\r
8993 nowChecked = IDM_IcsClient;
\r
9000 if (prevChecked != 0)
\r
9001 (void) CheckMenuItem(GetMenu(hwndMain),
\r
9002 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
9003 if (nowChecked != 0)
\r
9004 (void) CheckMenuItem(GetMenu(hwndMain),
\r
9005 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
9007 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
9008 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
9009 MF_BYCOMMAND|MF_ENABLED);
\r
9011 (void) EnableMenuItem(GetMenu(hwndMain),
\r
9012 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
9015 prevChecked = nowChecked;
\r
9017 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
9018 if (appData.icsActive) {
\r
9019 if (appData.icsEngineAnalyze) {
\r
9020 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9021 MF_BYCOMMAND|MF_CHECKED);
\r
9023 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9024 MF_BYCOMMAND|MF_UNCHECKED);
\r
9032 HMENU hmenu = GetMenu(hwndMain);
\r
9033 SetMenuEnables(hmenu, icsEnables);
\r
9034 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9035 MF_BYPOSITION|MF_ENABLED);
\r
9037 if (appData.zippyPlay) {
\r
9038 SetMenuEnables(hmenu, zippyEnables);
\r
9039 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9040 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9041 MF_BYCOMMAND|MF_ENABLED);
\r
9049 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9055 HMENU hmenu = GetMenu(hwndMain);
\r
9056 SetMenuEnables(hmenu, ncpEnables);
\r
9057 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9058 MF_BYPOSITION|MF_GRAYED);
\r
9059 DrawMenuBar(hwndMain);
\r
9065 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9069 SetTrainingModeOn()
\r
9072 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9073 for (i = 0; i < N_BUTTONS; i++) {
\r
9074 if (buttonDesc[i].hwnd != NULL)
\r
9075 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9080 VOID SetTrainingModeOff()
\r
9083 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9084 for (i = 0; i < N_BUTTONS; i++) {
\r
9085 if (buttonDesc[i].hwnd != NULL)
\r
9086 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9092 SetUserThinkingEnables()
\r
9094 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9098 SetMachineThinkingEnables()
\r
9100 HMENU hMenu = GetMenu(hwndMain);
\r
9101 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9103 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9105 if (gameMode == MachinePlaysBlack) {
\r
9106 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9107 } else if (gameMode == MachinePlaysWhite) {
\r
9108 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9109 } else if (gameMode == TwoMachinesPlay) {
\r
9110 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9116 DisplayTitle(char *str)
\r
9118 char title[MSG_SIZ], *host;
\r
9119 if (str[0] != NULLCHAR) {
\r
9120 strcpy(title, str);
\r
9121 } else if (appData.icsActive) {
\r
9122 if (appData.icsCommPort[0] != NULLCHAR)
\r
9125 host = appData.icsHost;
\r
9126 sprintf(title, "%s: %s", szTitle, host);
\r
9127 } else if (appData.noChessProgram) {
\r
9128 strcpy(title, szTitle);
\r
9130 strcpy(title, szTitle);
\r
9131 strcat(title, ": ");
\r
9132 strcat(title, first.tidy);
\r
9134 SetWindowText(hwndMain, title);
\r
9139 DisplayMessage(char *str1, char *str2)
\r
9143 int remain = MESSAGE_TEXT_MAX - 1;
\r
9146 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9147 messageText[0] = NULLCHAR;
\r
9149 len = strlen(str1);
\r
9150 if (len > remain) len = remain;
\r
9151 strncpy(messageText, str1, len);
\r
9152 messageText[len] = NULLCHAR;
\r
9155 if (*str2 && remain >= 2) {
\r
9157 strcat(messageText, " ");
\r
9160 len = strlen(str2);
\r
9161 if (len > remain) len = remain;
\r
9162 strncat(messageText, str2, len);
\r
9164 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9166 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9170 hdc = GetDC(hwndMain);
\r
9171 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9172 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9173 &messageRect, messageText, strlen(messageText), NULL);
\r
9174 (void) SelectObject(hdc, oldFont);
\r
9175 (void) ReleaseDC(hwndMain, hdc);
\r
9179 DisplayError(char *str, int error)
\r
9181 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9187 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9188 NULL, error, LANG_NEUTRAL,
\r
9189 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9191 sprintf(buf, "%s:\n%s", str, buf2);
\r
9193 ErrorMap *em = errmap;
\r
9194 while (em->err != 0 && em->err != error) em++;
\r
9195 if (em->err != 0) {
\r
9196 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9198 sprintf(buf, "%s:\nError code %d", str, error);
\r
9203 ErrorPopUp("Error", buf);
\r
9208 DisplayMoveError(char *str)
\r
9210 fromX = fromY = -1;
\r
9211 ClearHighlights();
\r
9212 DrawPosition(FALSE, NULL);
\r
9213 if (appData.popupMoveErrors) {
\r
9214 ErrorPopUp("Error", str);
\r
9216 DisplayMessage(str, "");
\r
9217 moveErrorMessageUp = TRUE;
\r
9222 DisplayFatalError(char *str, int error, int exitStatus)
\r
9224 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9226 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9229 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9230 NULL, error, LANG_NEUTRAL,
\r
9231 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9233 sprintf(buf, "%s:\n%s", str, buf2);
\r
9235 ErrorMap *em = errmap;
\r
9236 while (em->err != 0 && em->err != error) em++;
\r
9237 if (em->err != 0) {
\r
9238 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9240 sprintf(buf, "%s:\nError code %d", str, error);
\r
9245 if (appData.debugMode) {
\r
9246 fprintf(debugFP, "%s: %s\n", label, str);
\r
9248 if (appData.popupExitMessage) {
\r
9249 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9250 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9252 ExitEvent(exitStatus);
\r
9257 DisplayInformation(char *str)
\r
9259 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9264 DisplayNote(char *str)
\r
9266 ErrorPopUp("Note", str);
\r
9271 char *title, *question, *replyPrefix;
\r
9276 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9278 static QuestionParams *qp;
\r
9279 char reply[MSG_SIZ];
\r
9282 switch (message) {
\r
9283 case WM_INITDIALOG:
\r
9284 qp = (QuestionParams *) lParam;
\r
9285 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9286 SetWindowText(hDlg, qp->title);
\r
9287 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9288 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9292 switch (LOWORD(wParam)) {
\r
9294 strcpy(reply, qp->replyPrefix);
\r
9295 if (*reply) strcat(reply, " ");
\r
9296 len = strlen(reply);
\r
9297 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9298 strcat(reply, "\n");
\r
9299 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9300 EndDialog(hDlg, TRUE);
\r
9301 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9304 EndDialog(hDlg, FALSE);
\r
9315 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9317 QuestionParams qp;
\r
9321 qp.question = question;
\r
9322 qp.replyPrefix = replyPrefix;
\r
9324 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9325 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9326 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9327 FreeProcInstance(lpProc);
\r
9330 /* [AS] Pick FRC position */
\r
9331 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9333 static int * lpIndexFRC;
\r
9339 case WM_INITDIALOG:
\r
9340 lpIndexFRC = (int *) lParam;
\r
9342 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9344 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9345 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9346 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9347 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9352 switch( LOWORD(wParam) ) {
\r
9354 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9355 EndDialog( hDlg, 0 );
\r
9356 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9359 EndDialog( hDlg, 1 );
\r
9361 case IDC_NFG_Edit:
\r
9362 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9363 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9365 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9368 case IDC_NFG_Random:
\r
9369 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9370 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9383 int index = appData.defaultFrcPosition;
\r
9384 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9386 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9388 if( result == 0 ) {
\r
9389 appData.defaultFrcPosition = index;
\r
9395 /* [AS] Game list options */
\r
9401 static GLT_Item GLT_ItemInfo[] = {
\r
9402 { GLT_EVENT, "Event" },
\r
9403 { GLT_SITE, "Site" },
\r
9404 { GLT_DATE, "Date" },
\r
9405 { GLT_ROUND, "Round" },
\r
9406 { GLT_PLAYERS, "Players" },
\r
9407 { GLT_RESULT, "Result" },
\r
9408 { GLT_WHITE_ELO, "White Rating" },
\r
9409 { GLT_BLACK_ELO, "Black Rating" },
\r
9410 { GLT_TIME_CONTROL,"Time Control" },
\r
9411 { GLT_VARIANT, "Variant" },
\r
9412 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9413 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9417 const char * GLT_FindItem( char id )
\r
9419 const char * result = 0;
\r
9421 GLT_Item * list = GLT_ItemInfo;
\r
9423 while( list->id != 0 ) {
\r
9424 if( list->id == id ) {
\r
9425 result = list->name;
\r
9435 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9437 const char * name = GLT_FindItem( id );
\r
9440 if( index >= 0 ) {
\r
9441 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9444 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9449 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9453 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9456 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9460 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9462 pc = GLT_ALL_TAGS;
\r
9465 if( strchr( tags, *pc ) == 0 ) {
\r
9466 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9471 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9474 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9476 char result = '\0';
\r
9479 GLT_Item * list = GLT_ItemInfo;
\r
9481 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9482 while( list->id != 0 ) {
\r
9483 if( strcmp( list->name, name ) == 0 ) {
\r
9484 result = list->id;
\r
9495 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9497 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9498 int idx2 = idx1 + delta;
\r
9499 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9501 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9504 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9505 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9506 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9507 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9511 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9513 static char glt[64];
\r
9514 static char * lpUserGLT;
\r
9518 case WM_INITDIALOG:
\r
9519 lpUserGLT = (char *) lParam;
\r
9521 strcpy( glt, lpUserGLT );
\r
9523 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9525 /* Initialize list */
\r
9526 GLT_TagsToList( hDlg, glt );
\r
9528 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9533 switch( LOWORD(wParam) ) {
\r
9536 char * pc = lpUserGLT;
\r
9538 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9542 id = GLT_ListItemToTag( hDlg, idx );
\r
9546 } while( id != '\0' );
\r
9548 EndDialog( hDlg, 0 );
\r
9551 EndDialog( hDlg, 1 );
\r
9554 case IDC_GLT_Default:
\r
9555 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9556 GLT_TagsToList( hDlg, glt );
\r
9559 case IDC_GLT_Restore:
\r
9560 strcpy( glt, lpUserGLT );
\r
9561 GLT_TagsToList( hDlg, glt );
\r
9565 GLT_MoveSelection( hDlg, -1 );
\r
9568 case IDC_GLT_Down:
\r
9569 GLT_MoveSelection( hDlg, +1 );
\r
9579 int GameListOptions()
\r
9583 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9585 strcpy( glt, appData.gameListTags );
\r
9587 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9589 if( result == 0 ) {
\r
9590 /* [AS] Memory leak here! */
\r
9591 appData.gameListTags = strdup( glt );
\r
9599 DisplayIcsInteractionTitle(char *str)
\r
9601 char consoleTitle[MSG_SIZ];
\r
9603 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9604 SetWindowText(hwndConsole, consoleTitle);
\r
9608 DrawPosition(int fullRedraw, Board board)
\r
9610 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9617 fromX = fromY = -1;
\r
9618 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9619 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9620 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9621 dragInfo.lastpos = dragInfo.pos;
\r
9622 dragInfo.start.x = dragInfo.start.y = -1;
\r
9623 dragInfo.from = dragInfo.start;
\r
9625 DrawPosition(TRUE, NULL);
\r
9631 CommentPopUp(char *title, char *str)
\r
9633 HWND hwnd = GetActiveWindow();
\r
9634 EitherCommentPopUp(0, title, str, FALSE);
\r
9635 SetActiveWindow(hwnd);
\r
9639 CommentPopDown(void)
\r
9641 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9642 if (commentDialog) {
\r
9643 ShowWindow(commentDialog, SW_HIDE);
\r
9645 commentDialogUp = FALSE;
\r
9649 EditCommentPopUp(int index, char *title, char *str)
\r
9651 EitherCommentPopUp(index, title, str, TRUE);
\r
9658 MyPlaySound(&sounds[(int)SoundMove]);
\r
9661 VOID PlayIcsWinSound()
\r
9663 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9666 VOID PlayIcsLossSound()
\r
9668 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9671 VOID PlayIcsDrawSound()
\r
9673 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9676 VOID PlayIcsUnfinishedSound()
\r
9678 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9684 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9692 consoleEcho = TRUE;
\r
9693 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9694 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9695 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9704 consoleEcho = FALSE;
\r
9705 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9706 /* This works OK: set text and background both to the same color */
\r
9708 cf.crTextColor = COLOR_ECHOOFF;
\r
9709 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9710 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9713 /* No Raw()...? */
\r
9715 void Colorize(ColorClass cc, int continuation)
\r
9717 currentColorClass = cc;
\r
9718 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9719 consoleCF.crTextColor = textAttribs[cc].color;
\r
9720 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9721 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9727 static char buf[MSG_SIZ];
\r
9728 DWORD bufsiz = MSG_SIZ;
\r
9730 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9731 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9733 if (!GetUserName(buf, &bufsiz)) {
\r
9734 /*DisplayError("Error getting user name", GetLastError());*/
\r
9735 strcpy(buf, "User");
\r
9743 static char buf[MSG_SIZ];
\r
9744 DWORD bufsiz = MSG_SIZ;
\r
9746 if (!GetComputerName(buf, &bufsiz)) {
\r
9747 /*DisplayError("Error getting host name", GetLastError());*/
\r
9748 strcpy(buf, "Unknown");
\r
9755 ClockTimerRunning()
\r
9757 return clockTimerEvent != 0;
\r
9763 if (clockTimerEvent == 0) return FALSE;
\r
9764 KillTimer(hwndMain, clockTimerEvent);
\r
9765 clockTimerEvent = 0;
\r
9770 StartClockTimer(long millisec)
\r
9772 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9773 (UINT) millisec, NULL);
\r
9777 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9780 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9782 if(appData.noGUI) return;
\r
9783 hdc = GetDC(hwndMain);
\r
9784 if (!IsIconic(hwndMain)) {
\r
9785 DisplayAClock(hdc, timeRemaining, highlight,
\r
9786 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9788 if (highlight && iconCurrent == iconBlack) {
\r
9789 iconCurrent = iconWhite;
\r
9790 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9791 if (IsIconic(hwndMain)) {
\r
9792 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9795 (void) ReleaseDC(hwndMain, hdc);
\r
9797 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9801 DisplayBlackClock(long timeRemaining, int highlight)
\r
9804 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9806 if(appData.noGUI) return;
\r
9807 hdc = GetDC(hwndMain);
\r
9808 if (!IsIconic(hwndMain)) {
\r
9809 DisplayAClock(hdc, timeRemaining, highlight,
\r
9810 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9812 if (highlight && iconCurrent == iconWhite) {
\r
9813 iconCurrent = iconBlack;
\r
9814 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9815 if (IsIconic(hwndMain)) {
\r
9816 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9819 (void) ReleaseDC(hwndMain, hdc);
\r
9821 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9826 LoadGameTimerRunning()
\r
9828 return loadGameTimerEvent != 0;
\r
9832 StopLoadGameTimer()
\r
9834 if (loadGameTimerEvent == 0) return FALSE;
\r
9835 KillTimer(hwndMain, loadGameTimerEvent);
\r
9836 loadGameTimerEvent = 0;
\r
9841 StartLoadGameTimer(long millisec)
\r
9843 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9844 (UINT) millisec, NULL);
\r
9852 char fileTitle[MSG_SIZ];
\r
9854 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9855 f = OpenFileDialog(hwndMain, "a", defName,
\r
9856 appData.oldSaveStyle ? "gam" : "pgn",
\r
9858 "Save Game to File", NULL, fileTitle, NULL);
\r
9860 SaveGame(f, 0, "");
\r
9867 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9869 if (delayedTimerEvent != 0) {
\r
9870 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9871 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9873 KillTimer(hwndMain, delayedTimerEvent);
\r
9874 delayedTimerEvent = 0;
\r
9875 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9876 delayedTimerCallback();
\r
9878 delayedTimerCallback = cb;
\r
9879 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9880 (UINT) millisec, NULL);
\r
9883 DelayedEventCallback
\r
9886 if (delayedTimerEvent) {
\r
9887 return delayedTimerCallback;
\r
9894 CancelDelayedEvent()
\r
9896 if (delayedTimerEvent) {
\r
9897 KillTimer(hwndMain, delayedTimerEvent);
\r
9898 delayedTimerEvent = 0;
\r
9902 DWORD GetWin32Priority(int nice)
\r
9903 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9905 REALTIME_PRIORITY_CLASS 0x00000100
\r
9906 HIGH_PRIORITY_CLASS 0x00000080
\r
9907 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9908 NORMAL_PRIORITY_CLASS 0x00000020
\r
9909 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9910 IDLE_PRIORITY_CLASS 0x00000040
\r
9912 if (nice < -15) return 0x00000080;
\r
9913 if (nice < 0) return 0x00008000;
\r
9914 if (nice == 0) return 0x00000020;
\r
9915 if (nice < 15) return 0x00004000;
\r
9916 return 0x00000040;
\r
9919 /* Start a child process running the given program.
\r
9920 The process's standard output can be read from "from", and its
\r
9921 standard input can be written to "to".
\r
9922 Exit with fatal error if anything goes wrong.
\r
9923 Returns an opaque pointer that can be used to destroy the process
\r
9927 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9929 #define BUFSIZE 4096
\r
9931 HANDLE hChildStdinRd, hChildStdinWr,
\r
9932 hChildStdoutRd, hChildStdoutWr;
\r
9933 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9934 SECURITY_ATTRIBUTES saAttr;
\r
9936 PROCESS_INFORMATION piProcInfo;
\r
9937 STARTUPINFO siStartInfo;
\r
9939 char buf[MSG_SIZ];
\r
9942 if (appData.debugMode) {
\r
9943 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9948 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9949 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9950 saAttr.bInheritHandle = TRUE;
\r
9951 saAttr.lpSecurityDescriptor = NULL;
\r
9954 * The steps for redirecting child's STDOUT:
\r
9955 * 1. Create anonymous pipe to be STDOUT for child.
\r
9956 * 2. Create a noninheritable duplicate of read handle,
\r
9957 * and close the inheritable read handle.
\r
9960 /* Create a pipe for the child's STDOUT. */
\r
9961 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9962 return GetLastError();
\r
9965 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9966 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9967 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9968 FALSE, /* not inherited */
\r
9969 DUPLICATE_SAME_ACCESS);
\r
9971 return GetLastError();
\r
9973 CloseHandle(hChildStdoutRd);
\r
9976 * The steps for redirecting child's STDIN:
\r
9977 * 1. Create anonymous pipe to be STDIN for child.
\r
9978 * 2. Create a noninheritable duplicate of write handle,
\r
9979 * and close the inheritable write handle.
\r
9982 /* Create a pipe for the child's STDIN. */
\r
9983 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9984 return GetLastError();
\r
9987 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9988 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9989 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9990 FALSE, /* not inherited */
\r
9991 DUPLICATE_SAME_ACCESS);
\r
9993 return GetLastError();
\r
9995 CloseHandle(hChildStdinWr);
\r
9997 /* Arrange to (1) look in dir for the child .exe file, and
\r
9998 * (2) have dir be the child's working directory. Interpret
\r
9999 * dir relative to the directory WinBoard loaded from. */
\r
10000 GetCurrentDirectory(MSG_SIZ, buf);
\r
10001 SetCurrentDirectory(installDir);
\r
10002 SetCurrentDirectory(dir);
\r
10004 /* Now create the child process. */
\r
10006 siStartInfo.cb = sizeof(STARTUPINFO);
\r
10007 siStartInfo.lpReserved = NULL;
\r
10008 siStartInfo.lpDesktop = NULL;
\r
10009 siStartInfo.lpTitle = NULL;
\r
10010 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
10011 siStartInfo.cbReserved2 = 0;
\r
10012 siStartInfo.lpReserved2 = NULL;
\r
10013 siStartInfo.hStdInput = hChildStdinRd;
\r
10014 siStartInfo.hStdOutput = hChildStdoutWr;
\r
10015 siStartInfo.hStdError = hChildStdoutWr;
\r
10017 fSuccess = CreateProcess(NULL,
\r
10018 cmdLine, /* command line */
\r
10019 NULL, /* process security attributes */
\r
10020 NULL, /* primary thread security attrs */
\r
10021 TRUE, /* handles are inherited */
\r
10022 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
10023 NULL, /* use parent's environment */
\r
10025 &siStartInfo, /* STARTUPINFO pointer */
\r
10026 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
10028 err = GetLastError();
\r
10029 SetCurrentDirectory(buf); /* return to prev directory */
\r
10030 if (! fSuccess) {
\r
10034 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10035 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10036 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10039 /* Close the handles we don't need in the parent */
\r
10040 CloseHandle(piProcInfo.hThread);
\r
10041 CloseHandle(hChildStdinRd);
\r
10042 CloseHandle(hChildStdoutWr);
\r
10044 /* Prepare return value */
\r
10045 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10046 cp->kind = CPReal;
\r
10047 cp->hProcess = piProcInfo.hProcess;
\r
10048 cp->pid = piProcInfo.dwProcessId;
\r
10049 cp->hFrom = hChildStdoutRdDup;
\r
10050 cp->hTo = hChildStdinWrDup;
\r
10052 *pr = (void *) cp;
\r
10054 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10055 2000 where engines sometimes don't see the initial command(s)
\r
10056 from WinBoard and hang. I don't understand how that can happen,
\r
10057 but the Sleep is harmless, so I've put it in. Others have also
\r
10058 reported what may be the same problem, so hopefully this will fix
\r
10059 it for them too. */
\r
10067 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10069 ChildProc *cp; int result;
\r
10071 cp = (ChildProc *) pr;
\r
10072 if (cp == NULL) return;
\r
10074 switch (cp->kind) {
\r
10076 /* TerminateProcess is considered harmful, so... */
\r
10077 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10078 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10079 /* The following doesn't work because the chess program
\r
10080 doesn't "have the same console" as WinBoard. Maybe
\r
10081 we could arrange for this even though neither WinBoard
\r
10082 nor the chess program uses a console for stdio? */
\r
10083 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10085 /* [AS] Special termination modes for misbehaving programs... */
\r
10086 if( signal == 9 ) {
\r
10087 result = TerminateProcess( cp->hProcess, 0 );
\r
10089 if ( appData.debugMode) {
\r
10090 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10093 else if( signal == 10 ) {
\r
10094 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10096 if( dw != WAIT_OBJECT_0 ) {
\r
10097 result = TerminateProcess( cp->hProcess, 0 );
\r
10099 if ( appData.debugMode) {
\r
10100 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10106 CloseHandle(cp->hProcess);
\r
10110 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10114 closesocket(cp->sock);
\r
10119 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10120 closesocket(cp->sock);
\r
10121 closesocket(cp->sock2);
\r
10129 InterruptChildProcess(ProcRef pr)
\r
10133 cp = (ChildProc *) pr;
\r
10134 if (cp == NULL) return;
\r
10135 switch (cp->kind) {
\r
10137 /* The following doesn't work because the chess program
\r
10138 doesn't "have the same console" as WinBoard. Maybe
\r
10139 we could arrange for this even though neither WinBoard
\r
10140 nor the chess program uses a console for stdio */
\r
10141 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10146 /* Can't interrupt */
\r
10150 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10157 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10159 char cmdLine[MSG_SIZ];
\r
10161 if (port[0] == NULLCHAR) {
\r
10162 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10164 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10166 return StartChildProcess(cmdLine, "", pr);
\r
10170 /* Code to open TCP sockets */
\r
10173 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10178 struct sockaddr_in sa, mysa;
\r
10179 struct hostent FAR *hp;
\r
10180 unsigned short uport;
\r
10181 WORD wVersionRequested;
\r
10184 /* Initialize socket DLL */
\r
10185 wVersionRequested = MAKEWORD(1, 1);
\r
10186 err = WSAStartup(wVersionRequested, &wsaData);
\r
10187 if (err != 0) return err;
\r
10189 /* Make socket */
\r
10190 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10191 err = WSAGetLastError();
\r
10196 /* Bind local address using (mostly) don't-care values.
\r
10198 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10199 mysa.sin_family = AF_INET;
\r
10200 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10201 uport = (unsigned short) 0;
\r
10202 mysa.sin_port = htons(uport);
\r
10203 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10204 == SOCKET_ERROR) {
\r
10205 err = WSAGetLastError();
\r
10210 /* Resolve remote host name */
\r
10211 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10212 if (!(hp = gethostbyname(host))) {
\r
10213 unsigned int b0, b1, b2, b3;
\r
10215 err = WSAGetLastError();
\r
10217 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10218 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10219 hp->h_addrtype = AF_INET;
\r
10220 hp->h_length = 4;
\r
10221 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10222 hp->h_addr_list[0] = (char *) malloc(4);
\r
10223 hp->h_addr_list[0][0] = (char) b0;
\r
10224 hp->h_addr_list[0][1] = (char) b1;
\r
10225 hp->h_addr_list[0][2] = (char) b2;
\r
10226 hp->h_addr_list[0][3] = (char) b3;
\r
10232 sa.sin_family = hp->h_addrtype;
\r
10233 uport = (unsigned short) atoi(port);
\r
10234 sa.sin_port = htons(uport);
\r
10235 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10237 /* Make connection */
\r
10238 if (connect(s, (struct sockaddr *) &sa,
\r
10239 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10240 err = WSAGetLastError();
\r
10245 /* Prepare return value */
\r
10246 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10247 cp->kind = CPSock;
\r
10249 *pr = (ProcRef *) cp;
\r
10255 OpenCommPort(char *name, ProcRef *pr)
\r
10260 char fullname[MSG_SIZ];
\r
10262 if (*name != '\\')
\r
10263 sprintf(fullname, "\\\\.\\%s", name);
\r
10265 strcpy(fullname, name);
\r
10267 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10268 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10269 if (h == (HANDLE) -1) {
\r
10270 return GetLastError();
\r
10274 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10276 /* Accumulate characters until a 100ms pause, then parse */
\r
10277 ct.ReadIntervalTimeout = 100;
\r
10278 ct.ReadTotalTimeoutMultiplier = 0;
\r
10279 ct.ReadTotalTimeoutConstant = 0;
\r
10280 ct.WriteTotalTimeoutMultiplier = 0;
\r
10281 ct.WriteTotalTimeoutConstant = 0;
\r
10282 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10284 /* Prepare return value */
\r
10285 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10286 cp->kind = CPComm;
\r
10289 *pr = (ProcRef *) cp;
\r
10295 OpenLoopback(ProcRef *pr)
\r
10297 DisplayFatalError("Not implemented", 0, 1);
\r
10303 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10307 SOCKET s, s2, s3;
\r
10308 struct sockaddr_in sa, mysa;
\r
10309 struct hostent FAR *hp;
\r
10310 unsigned short uport;
\r
10311 WORD wVersionRequested;
\r
10314 char stderrPortStr[MSG_SIZ];
\r
10316 /* Initialize socket DLL */
\r
10317 wVersionRequested = MAKEWORD(1, 1);
\r
10318 err = WSAStartup(wVersionRequested, &wsaData);
\r
10319 if (err != 0) return err;
\r
10321 /* Resolve remote host name */
\r
10322 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10323 if (!(hp = gethostbyname(host))) {
\r
10324 unsigned int b0, b1, b2, b3;
\r
10326 err = WSAGetLastError();
\r
10328 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10329 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10330 hp->h_addrtype = AF_INET;
\r
10331 hp->h_length = 4;
\r
10332 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10333 hp->h_addr_list[0] = (char *) malloc(4);
\r
10334 hp->h_addr_list[0][0] = (char) b0;
\r
10335 hp->h_addr_list[0][1] = (char) b1;
\r
10336 hp->h_addr_list[0][2] = (char) b2;
\r
10337 hp->h_addr_list[0][3] = (char) b3;
\r
10343 sa.sin_family = hp->h_addrtype;
\r
10344 uport = (unsigned short) 514;
\r
10345 sa.sin_port = htons(uport);
\r
10346 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10348 /* Bind local socket to unused "privileged" port address
\r
10350 s = INVALID_SOCKET;
\r
10351 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10352 mysa.sin_family = AF_INET;
\r
10353 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10354 for (fromPort = 1023;; fromPort--) {
\r
10355 if (fromPort < 0) {
\r
10357 return WSAEADDRINUSE;
\r
10359 if (s == INVALID_SOCKET) {
\r
10360 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10361 err = WSAGetLastError();
\r
10366 uport = (unsigned short) fromPort;
\r
10367 mysa.sin_port = htons(uport);
\r
10368 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10369 == SOCKET_ERROR) {
\r
10370 err = WSAGetLastError();
\r
10371 if (err == WSAEADDRINUSE) continue;
\r
10375 if (connect(s, (struct sockaddr *) &sa,
\r
10376 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10377 err = WSAGetLastError();
\r
10378 if (err == WSAEADDRINUSE) {
\r
10389 /* Bind stderr local socket to unused "privileged" port address
\r
10391 s2 = INVALID_SOCKET;
\r
10392 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10393 mysa.sin_family = AF_INET;
\r
10394 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10395 for (fromPort = 1023;; fromPort--) {
\r
10396 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10397 if (fromPort < 0) {
\r
10398 (void) closesocket(s);
\r
10400 return WSAEADDRINUSE;
\r
10402 if (s2 == INVALID_SOCKET) {
\r
10403 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10404 err = WSAGetLastError();
\r
10410 uport = (unsigned short) fromPort;
\r
10411 mysa.sin_port = htons(uport);
\r
10412 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10413 == SOCKET_ERROR) {
\r
10414 err = WSAGetLastError();
\r
10415 if (err == WSAEADDRINUSE) continue;
\r
10416 (void) closesocket(s);
\r
10420 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10421 err = WSAGetLastError();
\r
10422 if (err == WSAEADDRINUSE) {
\r
10424 s2 = INVALID_SOCKET;
\r
10427 (void) closesocket(s);
\r
10428 (void) closesocket(s2);
\r
10434 prevStderrPort = fromPort; // remember port used
\r
10435 sprintf(stderrPortStr, "%d", fromPort);
\r
10437 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10438 err = WSAGetLastError();
\r
10439 (void) closesocket(s);
\r
10440 (void) closesocket(s2);
\r
10445 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10446 err = WSAGetLastError();
\r
10447 (void) closesocket(s);
\r
10448 (void) closesocket(s2);
\r
10452 if (*user == NULLCHAR) user = UserName();
\r
10453 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10454 err = WSAGetLastError();
\r
10455 (void) closesocket(s);
\r
10456 (void) closesocket(s2);
\r
10460 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10461 err = WSAGetLastError();
\r
10462 (void) closesocket(s);
\r
10463 (void) closesocket(s2);
\r
10468 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10469 err = WSAGetLastError();
\r
10470 (void) closesocket(s);
\r
10471 (void) closesocket(s2);
\r
10475 (void) closesocket(s2); /* Stop listening */
\r
10477 /* Prepare return value */
\r
10478 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10479 cp->kind = CPRcmd;
\r
10482 *pr = (ProcRef *) cp;
\r
10489 AddInputSource(ProcRef pr, int lineByLine,
\r
10490 InputCallback func, VOIDSTAR closure)
\r
10492 InputSource *is, *is2 = NULL;
\r
10493 ChildProc *cp = (ChildProc *) pr;
\r
10495 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10496 is->lineByLine = lineByLine;
\r
10498 is->closure = closure;
\r
10499 is->second = NULL;
\r
10500 is->next = is->buf;
\r
10501 if (pr == NoProc) {
\r
10502 is->kind = CPReal;
\r
10503 consoleInputSource = is;
\r
10505 is->kind = cp->kind;
\r
10507 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10508 we create all threads suspended so that the is->hThread variable can be
\r
10509 safely assigned, then let the threads start with ResumeThread.
\r
10511 switch (cp->kind) {
\r
10513 is->hFile = cp->hFrom;
\r
10514 cp->hFrom = NULL; /* now owned by InputThread */
\r
10516 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10517 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10521 is->hFile = cp->hFrom;
\r
10522 cp->hFrom = NULL; /* now owned by InputThread */
\r
10524 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10525 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10529 is->sock = cp->sock;
\r
10531 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10532 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10536 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10538 is->sock = cp->sock;
\r
10539 is->second = is2;
\r
10540 is2->sock = cp->sock2;
\r
10541 is2->second = is2;
\r
10543 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10544 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10546 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10547 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10551 if( is->hThread != NULL ) {
\r
10552 ResumeThread( is->hThread );
\r
10555 if( is2 != NULL && is2->hThread != NULL ) {
\r
10556 ResumeThread( is2->hThread );
\r
10560 return (InputSourceRef) is;
\r
10564 RemoveInputSource(InputSourceRef isr)
\r
10568 is = (InputSource *) isr;
\r
10569 is->hThread = NULL; /* tell thread to stop */
\r
10570 CloseHandle(is->hThread);
\r
10571 if (is->second != NULL) {
\r
10572 is->second->hThread = NULL;
\r
10573 CloseHandle(is->second->hThread);
\r
10579 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10582 int outCount = SOCKET_ERROR;
\r
10583 ChildProc *cp = (ChildProc *) pr;
\r
10584 static OVERLAPPED ovl;
\r
10586 if (pr == NoProc) {
\r
10587 ConsoleOutput(message, count, FALSE);
\r
10591 if (ovl.hEvent == NULL) {
\r
10592 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10594 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10596 switch (cp->kind) {
\r
10599 outCount = send(cp->sock, message, count, 0);
\r
10600 if (outCount == SOCKET_ERROR) {
\r
10601 *outError = WSAGetLastError();
\r
10603 *outError = NO_ERROR;
\r
10608 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10609 &dOutCount, NULL)) {
\r
10610 *outError = NO_ERROR;
\r
10611 outCount = (int) dOutCount;
\r
10613 *outError = GetLastError();
\r
10618 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10619 &dOutCount, &ovl);
\r
10620 if (*outError == NO_ERROR) {
\r
10621 outCount = (int) dOutCount;
\r
10629 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10632 /* Ignore delay, not implemented for WinBoard */
\r
10633 return OutputToProcess(pr, message, count, outError);
\r
10638 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10639 char *buf, int count, int error)
\r
10641 DisplayFatalError("Not implemented", 0, 1);
\r
10644 /* see wgamelist.c for Game List functions */
\r
10645 /* see wedittags.c for Edit Tags functions */
\r
10652 char buf[MSG_SIZ];
\r
10655 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10656 f = fopen(buf, "r");
\r
10658 ProcessICSInitScript(f);
\r
10666 StartAnalysisClock()
\r
10668 if (analysisTimerEvent) return;
\r
10669 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10670 (UINT) 2000, NULL);
\r
10674 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10676 static HANDLE hwndText;
\r
10678 static int sizeX, sizeY;
\r
10679 int newSizeX, newSizeY, flags;
\r
10682 switch (message) {
\r
10683 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10684 /* Initialize the dialog items */
\r
10685 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10686 SetWindowText(hDlg, analysisTitle);
\r
10687 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10688 /* Size and position the dialog */
\r
10689 if (!analysisDialog) {
\r
10690 analysisDialog = hDlg;
\r
10691 flags = SWP_NOZORDER;
\r
10692 GetClientRect(hDlg, &rect);
\r
10693 sizeX = rect.right;
\r
10694 sizeY = rect.bottom;
\r
10695 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10696 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10697 WINDOWPLACEMENT wp;
\r
10698 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10699 wp.length = sizeof(WINDOWPLACEMENT);
\r
10701 wp.showCmd = SW_SHOW;
\r
10702 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10703 wp.rcNormalPosition.left = analysisX;
\r
10704 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10705 wp.rcNormalPosition.top = analysisY;
\r
10706 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10707 SetWindowPlacement(hDlg, &wp);
\r
10709 GetClientRect(hDlg, &rect);
\r
10710 newSizeX = rect.right;
\r
10711 newSizeY = rect.bottom;
\r
10712 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10713 newSizeX, newSizeY);
\r
10714 sizeX = newSizeX;
\r
10715 sizeY = newSizeY;
\r
10720 case WM_COMMAND: /* message: received a command */
\r
10721 switch (LOWORD(wParam)) {
\r
10723 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10724 ExitAnalyzeMode();
\r
10736 newSizeX = LOWORD(lParam);
\r
10737 newSizeY = HIWORD(lParam);
\r
10738 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10739 sizeX = newSizeX;
\r
10740 sizeY = newSizeY;
\r
10743 case WM_GETMINMAXINFO:
\r
10744 /* Prevent resizing window too small */
\r
10745 mmi = (MINMAXINFO *) lParam;
\r
10746 mmi->ptMinTrackSize.x = 100;
\r
10747 mmi->ptMinTrackSize.y = 100;
\r
10754 AnalysisPopUp(char* title, char* str)
\r
10760 EngineOutputPopUp();
\r
10763 if (str == NULL) str = "";
\r
10764 p = (char *) malloc(2 * strlen(str) + 2);
\r
10767 if (*str == '\n') *q++ = '\r';
\r
10771 if (analysisText != NULL) free(analysisText);
\r
10772 analysisText = p;
\r
10774 if (analysisDialog) {
\r
10775 SetWindowText(analysisDialog, title);
\r
10776 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10777 ShowWindow(analysisDialog, SW_SHOW);
\r
10779 analysisTitle = title;
\r
10780 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10781 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10782 hwndMain, (DLGPROC)lpProc);
\r
10783 FreeProcInstance(lpProc);
\r
10785 analysisDialogUp = TRUE;
\r
10789 AnalysisPopDown()
\r
10791 if (analysisDialog) {
\r
10792 ShowWindow(analysisDialog, SW_HIDE);
\r
10794 analysisDialogUp = FALSE;
\r
10799 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10801 highlightInfo.sq[0].x = fromX;
\r
10802 highlightInfo.sq[0].y = fromY;
\r
10803 highlightInfo.sq[1].x = toX;
\r
10804 highlightInfo.sq[1].y = toY;
\r
10808 ClearHighlights()
\r
10810 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10811 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10815 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10817 premoveHighlightInfo.sq[0].x = fromX;
\r
10818 premoveHighlightInfo.sq[0].y = fromY;
\r
10819 premoveHighlightInfo.sq[1].x = toX;
\r
10820 premoveHighlightInfo.sq[1].y = toY;
\r
10824 ClearPremoveHighlights()
\r
10826 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10827 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10831 ShutDownFrontEnd()
\r
10833 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10834 DeleteClipboardTempFiles();
\r
10840 if (IsIconic(hwndMain))
\r
10841 ShowWindow(hwndMain, SW_RESTORE);
\r
10843 SetActiveWindow(hwndMain);
\r
10847 * Prototypes for animation support routines
\r
10849 static void ScreenSquare(int column, int row, POINT * pt);
\r
10850 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10851 POINT frames[], int * nFrames);
\r
10855 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10856 { // [HGM] atomic: animate blast wave
\r
10858 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10859 explodeInfo.fromX = fromX;
\r
10860 explodeInfo.fromY = fromY;
\r
10861 explodeInfo.toX = toX;
\r
10862 explodeInfo.toY = toY;
\r
10863 for(i=1; i<nFrames; i++) {
\r
10864 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10865 DrawPosition(FALSE, NULL);
\r
10866 Sleep(appData.animSpeed);
\r
10868 explodeInfo.radius = 0;
\r
10869 DrawPosition(TRUE, NULL);
\r
10872 #define kFactor 4
\r
10875 AnimateMove(board, fromX, fromY, toX, toY)
\r
10882 ChessSquare piece;
\r
10883 POINT start, finish, mid;
\r
10884 POINT frames[kFactor * 2 + 1];
\r
10887 if (!appData.animate) return;
\r
10888 if (doingSizing) return;
\r
10889 if (fromY < 0 || fromX < 0) return;
\r
10890 piece = board[fromY][fromX];
\r
10891 if (piece >= EmptySquare) return;
\r
10893 ScreenSquare(fromX, fromY, &start);
\r
10894 ScreenSquare(toX, toY, &finish);
\r
10896 /* All pieces except knights move in straight line */
\r
10897 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10898 mid.x = start.x + (finish.x - start.x) / 2;
\r
10899 mid.y = start.y + (finish.y - start.y) / 2;
\r
10901 /* Knight: make diagonal movement then straight */
\r
10902 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10903 mid.x = start.x + (finish.x - start.x) / 2;
\r
10904 mid.y = finish.y;
\r
10906 mid.x = finish.x;
\r
10907 mid.y = start.y + (finish.y - start.y) / 2;
\r
10911 /* Don't use as many frames for very short moves */
\r
10912 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10913 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10915 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10917 animInfo.from.x = fromX;
\r
10918 animInfo.from.y = fromY;
\r
10919 animInfo.to.x = toX;
\r
10920 animInfo.to.y = toY;
\r
10921 animInfo.lastpos = start;
\r
10922 animInfo.piece = piece;
\r
10923 for (n = 0; n < nFrames; n++) {
\r
10924 animInfo.pos = frames[n];
\r
10925 DrawPosition(FALSE, NULL);
\r
10926 animInfo.lastpos = animInfo.pos;
\r
10927 Sleep(appData.animSpeed);
\r
10929 animInfo.pos = finish;
\r
10930 DrawPosition(FALSE, NULL);
\r
10931 animInfo.piece = EmptySquare;
\r
10932 if(gameInfo.variant == VariantAtomic &&
\r
10933 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10934 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10937 /* Convert board position to corner of screen rect and color */
\r
10940 ScreenSquare(column, row, pt)
\r
10941 int column; int row; POINT * pt;
\r
10944 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10945 pt->y = lineGap + row * (squareSize + lineGap);
\r
10947 pt->x = lineGap + column * (squareSize + lineGap);
\r
10948 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10952 /* Generate a series of frame coords from start->mid->finish.
\r
10953 The movement rate doubles until the half way point is
\r
10954 reached, then halves back down to the final destination,
\r
10955 which gives a nice slow in/out effect. The algorithmn
\r
10956 may seem to generate too many intermediates for short
\r
10957 moves, but remember that the purpose is to attract the
\r
10958 viewers attention to the piece about to be moved and
\r
10959 then to where it ends up. Too few frames would be less
\r
10963 Tween(start, mid, finish, factor, frames, nFrames)
\r
10964 POINT * start; POINT * mid;
\r
10965 POINT * finish; int factor;
\r
10966 POINT frames[]; int * nFrames;
\r
10968 int n, fraction = 1, count = 0;
\r
10970 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10971 for (n = 0; n < factor; n++)
\r
10973 for (n = 0; n < factor; n++) {
\r
10974 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10975 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10977 fraction = fraction / 2;
\r
10981 frames[count] = *mid;
\r
10984 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10986 for (n = 0; n < factor; n++) {
\r
10987 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10988 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10990 fraction = fraction * 2;
\r
10992 *nFrames = count;
\r
10996 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
11001 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
11002 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
11004 OutputDebugString( buf );
\r
11007 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
11009 EvalGraphSet( first, last, current, pvInfoList );
\r
11012 void SetProgramStats( FrontEndProgramStats * stats )
\r
11017 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
11018 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
11020 OutputDebugString( buf );
\r
11023 EngineOutputUpdate( stats );
\r