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
882 if(gameListDialog) SetFocus(gameListDialog); // [HGM] jaws: for if we clicked multi-game game file
\r
890 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
891 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
892 ArgSettingsFilename,
\r
893 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
901 String *pString; // ArgString
\r
902 int *pInt; // ArgInt
\r
903 float *pFloat; // ArgFloat
\r
904 Boolean *pBoolean; // ArgBoolean
\r
905 COLORREF *pColor; // ArgColor
\r
906 ColorClass cc; // ArgAttribs
\r
907 String *pFilename; // ArgFilename
\r
908 BoardSize *pBoardSize; // ArgBoardSize
\r
909 int whichFont; // ArgFont
\r
910 DCB *pDCB; // ArgCommSettings
\r
911 String *pFilename; // ArgSettingsFilename
\r
919 ArgDescriptor argDescriptors[] = {
\r
920 /* positional arguments */
\r
921 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
922 { "", ArgNone, NULL },
\r
923 /* keyword arguments */
\r
925 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
926 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
927 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
928 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
929 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
930 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
931 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
932 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
933 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
934 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
935 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
936 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
937 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
938 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
939 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
940 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
941 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
942 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
944 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
946 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
948 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
949 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
951 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
952 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
953 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
954 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
955 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
956 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
957 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
958 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
959 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
960 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
961 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
962 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
963 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
964 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
965 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
966 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
967 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
968 /*!!bitmapDirectory?*/
\r
969 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
970 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
971 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
972 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
973 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
974 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
975 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
976 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
977 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
978 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
979 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
980 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
981 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
982 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
983 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
984 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
985 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
986 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
987 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
988 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
989 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
990 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
991 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
992 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
993 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
994 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
995 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
996 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
997 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
998 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
999 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
1000 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1001 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
1002 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1003 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1004 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
1005 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
1006 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
1007 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1008 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1009 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1010 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1011 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1012 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1013 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1014 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1015 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1016 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1017 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1018 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1019 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1020 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1021 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1022 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1023 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1024 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1025 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1026 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1027 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1028 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1029 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1030 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1031 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1032 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1033 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1034 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1035 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1036 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1037 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1038 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1039 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1040 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1041 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1042 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1043 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1044 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1045 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1046 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1047 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1048 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1049 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1050 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1051 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1052 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1053 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1054 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1055 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1056 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1057 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1058 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1059 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1060 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1061 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1062 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1063 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1064 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1065 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1066 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1067 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1068 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1069 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1070 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1071 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1072 TRUE }, /* must come after all fonts */
\r
1073 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1074 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1075 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1076 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1077 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1078 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1079 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1080 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1081 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1082 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1083 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1084 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1085 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1086 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1087 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1088 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1089 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1090 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1091 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1092 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1093 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1094 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1095 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1096 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1097 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1098 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1099 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1100 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1101 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1102 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1103 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1105 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1106 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1108 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1109 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1110 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1111 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1112 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1113 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1114 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1115 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1116 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1117 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1118 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1119 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1120 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1121 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1122 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1123 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1124 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1125 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1126 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1127 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1128 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1129 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1130 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1131 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1132 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1133 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1134 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1135 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1136 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1137 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1138 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1139 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1140 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1141 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1142 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1143 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1144 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1145 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1146 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1147 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1148 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1149 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1150 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1151 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1152 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1153 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1154 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1155 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1156 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1157 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1158 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1159 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1160 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1161 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1162 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1163 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1164 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1165 { "highlightLastMove", ArgBoolean,
\r
1166 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1167 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1168 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1169 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1170 { "highlightDragging", ArgBoolean,
\r
1171 (LPVOID) &appData.highlightDragging, TRUE },
\r
1172 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1173 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1174 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1175 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1176 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1177 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1178 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1179 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1180 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1181 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1182 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1183 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1184 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1185 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1186 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1187 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1188 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1189 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1190 { "soundShout", ArgFilename,
\r
1191 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1192 { "soundSShout", ArgFilename,
\r
1193 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1194 { "soundChannel1", ArgFilename,
\r
1195 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1196 { "soundChannel", ArgFilename,
\r
1197 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1198 { "soundKibitz", ArgFilename,
\r
1199 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1200 { "soundTell", ArgFilename,
\r
1201 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1202 { "soundChallenge", ArgFilename,
\r
1203 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1204 { "soundRequest", ArgFilename,
\r
1205 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1206 { "soundSeek", ArgFilename,
\r
1207 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1208 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1209 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1210 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1211 { "soundIcsLoss", ArgFilename,
\r
1212 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1213 { "soundIcsDraw", ArgFilename,
\r
1214 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1215 { "soundIcsUnfinished", ArgFilename,
\r
1216 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1217 { "soundIcsAlarm", ArgFilename,
\r
1218 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1219 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1220 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1221 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1222 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1223 { "reuseChessPrograms", ArgBoolean,
\r
1224 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1225 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1226 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1227 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1228 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1229 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1230 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1231 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1232 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1233 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1234 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1235 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1236 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1237 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1238 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1239 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1241 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1243 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1244 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1245 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1246 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1247 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1248 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1249 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1250 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1251 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1252 /* [AS] New features */
\r
1253 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1254 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1255 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1256 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1257 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1258 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1259 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1260 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1261 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1262 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1263 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1264 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1265 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1266 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1267 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1268 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1269 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1270 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1271 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1272 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1273 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1274 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1275 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1276 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1277 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1278 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1279 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1280 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1281 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1282 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1283 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1284 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1285 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1286 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1287 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1288 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1289 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1290 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1291 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1292 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1293 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1294 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1295 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1296 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1297 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1298 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1299 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1300 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1301 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1302 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1304 /* [HGM] board-size, adjudication and misc. options */
\r
1305 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1306 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1307 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1308 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1309 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1310 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1311 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1312 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1313 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1314 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1315 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1316 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1317 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1318 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1319 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1320 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1321 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1322 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1323 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1324 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1325 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1326 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1327 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1328 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1329 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1330 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1331 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1332 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1333 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1334 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1335 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1336 { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },
\r
1337 { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },
\r
1340 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1341 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1342 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1343 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1344 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1345 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1346 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1347 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1348 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1349 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1350 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1351 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1352 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1354 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1355 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1356 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1357 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1358 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1359 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1360 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1362 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1363 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1364 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1365 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1366 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1367 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1368 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1369 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1370 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1371 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1372 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1373 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1374 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1375 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1376 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1377 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1378 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1379 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1380 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1382 /* [HGM] options for broadcasting and time odds */
\r
1383 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1384 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1385 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1386 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1387 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1388 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1389 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1390 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1391 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1392 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1393 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1395 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1396 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1397 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1398 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1399 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1400 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1401 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1402 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1403 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1404 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1405 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1406 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1407 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1408 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1409 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1410 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1411 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1412 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1413 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1414 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1415 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1416 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1417 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1418 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1419 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1420 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1421 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1422 /* [AS] Layout stuff */
\r
1423 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1424 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1425 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1426 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1427 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1429 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1430 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1431 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1432 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1433 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1435 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1436 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1437 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1438 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1439 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1441 { NULL, ArgNone, NULL, FALSE }
\r
1445 /* Kludge for indirection files on command line */
\r
1446 char* lastIndirectionFilename;
\r
1447 ArgDescriptor argDescriptorIndirection =
\r
1448 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1452 ExitArgError(char *msg, char *badArg)
\r
1454 char buf[MSG_SIZ];
\r
1456 sprintf(buf, "%s %s", msg, badArg);
\r
1457 DisplayFatalError(buf, 0, 2);
\r
1461 /* Command line font name parser. NULL name means do nothing.
\r
1462 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1463 For backward compatibility, syntax without the colon is also
\r
1464 accepted, but font names with digits in them won't work in that case.
\r
1467 ParseFontName(char *name, MyFontParams *mfp)
\r
1470 if (name == NULL) return;
\r
1472 q = strchr(p, ':');
\r
1474 if (q - p >= sizeof(mfp->faceName))
\r
1475 ExitArgError("Font name too long:", name);
\r
1476 memcpy(mfp->faceName, p, q - p);
\r
1477 mfp->faceName[q - p] = NULLCHAR;
\r
1480 q = mfp->faceName;
\r
1481 while (*p && !isdigit(*p)) {
\r
1483 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1484 ExitArgError("Font name too long:", name);
\r
1486 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1489 if (!*p) ExitArgError("Font point size missing:", name);
\r
1490 mfp->pointSize = (float) atof(p);
\r
1491 mfp->bold = (strchr(p, 'b') != NULL);
\r
1492 mfp->italic = (strchr(p, 'i') != NULL);
\r
1493 mfp->underline = (strchr(p, 'u') != NULL);
\r
1494 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1497 /* Color name parser.
\r
1498 X version accepts X color names, but this one
\r
1499 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1501 ParseColorName(char *name)
\r
1503 int red, green, blue, count;
\r
1504 char buf[MSG_SIZ];
\r
1506 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1508 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1509 &red, &green, &blue);
\r
1512 sprintf(buf, "Can't parse color name %s", name);
\r
1513 DisplayError(buf, 0);
\r
1514 return RGB(0, 0, 0);
\r
1516 return PALETTERGB(red, green, blue);
\r
1520 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1522 char *e = argValue;
\r
1526 if (*e == 'b') eff |= CFE_BOLD;
\r
1527 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1528 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1529 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1530 else if (*e == '#' || isdigit(*e)) break;
\r
1534 *color = ParseColorName(e);
\r
1539 ParseBoardSize(char *name)
\r
1541 BoardSize bs = SizeTiny;
\r
1542 while (sizeInfo[bs].name != NULL) {
\r
1543 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1546 ExitArgError("Unrecognized board size value", name);
\r
1547 return bs; /* not reached */
\r
1552 StringGet(void *getClosure)
\r
1554 char **p = (char **) getClosure;
\r
1559 FileGet(void *getClosure)
\r
1562 FILE* f = (FILE*) getClosure;
\r
1565 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1572 /* Parse settings file named "name". If file found, return the
\r
1573 full name in fullname and return TRUE; else return FALSE */
\r
1575 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1579 int ok; char buf[MSG_SIZ];
\r
1581 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1582 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1583 sprintf(buf, "%s.ini", name);
\r
1584 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1587 f = fopen(fullname, "r");
\r
1589 ParseArgs(FileGet, f);
\r
1598 ParseArgs(GetFunc get, void *cl)
\r
1600 char argName[ARG_MAX];
\r
1601 char argValue[ARG_MAX];
\r
1602 ArgDescriptor *ad;
\r
1611 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1612 if (ch == NULLCHAR) break;
\r
1614 /* Comment to end of line */
\r
1616 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1618 } else if (ch == '/' || ch == '-') {
\r
1621 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1622 ch != '\n' && ch != '\t') {
\r
1628 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1629 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1631 if (ad->argName == NULL)
\r
1632 ExitArgError("Unrecognized argument", argName);
\r
1634 } else if (ch == '@') {
\r
1635 /* Indirection file */
\r
1636 ad = &argDescriptorIndirection;
\r
1639 /* Positional argument */
\r
1640 ad = &argDescriptors[posarg++];
\r
1641 strcpy(argName, ad->argName);
\r
1644 if (ad->argType == ArgTrue) {
\r
1645 *(Boolean *) ad->argLoc = TRUE;
\r
1648 if (ad->argType == ArgFalse) {
\r
1649 *(Boolean *) ad->argLoc = FALSE;
\r
1653 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1654 if (ch == NULLCHAR || ch == '\n') {
\r
1655 ExitArgError("No value provided for argument", argName);
\r
1659 // Quoting with { }. No characters have to (or can) be escaped.
\r
1660 // Thus the string cannot contain a '}' character.
\r
1680 } else if (ch == '\'' || ch == '"') {
\r
1681 // Quoting with ' ' or " ", with \ as escape character.
\r
1682 // Inconvenient for long strings that may contain Windows filenames.
\r
1699 if (ch == start) {
\r
1708 if (ad->argType == ArgFilename
\r
1709 || ad->argType == ArgSettingsFilename) {
\r
1715 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1739 for (i = 0; i < 3; i++) {
\r
1740 if (ch >= '0' && ch <= '7') {
\r
1741 octval = octval*8 + (ch - '0');
\r
1748 *q++ = (char) octval;
\r
1759 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1766 switch (ad->argType) {
\r
1768 *(int *) ad->argLoc = atoi(argValue);
\r
1772 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1776 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1780 *(int *) ad->argLoc = atoi(argValue);
\r
1781 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1785 *(float *) ad->argLoc = (float) atof(argValue);
\r
1790 *(char **) ad->argLoc = strdup(argValue);
\r
1793 case ArgSettingsFilename:
\r
1795 char fullname[MSG_SIZ];
\r
1796 if (ParseSettingsFile(argValue, fullname)) {
\r
1797 if (ad->argLoc != NULL) {
\r
1798 *(char **) ad->argLoc = strdup(fullname);
\r
1801 if (ad->argLoc != NULL) {
\r
1803 ExitArgError("Failed to open indirection file", argValue);
\r
1810 switch (argValue[0]) {
\r
1813 *(Boolean *) ad->argLoc = TRUE;
\r
1817 *(Boolean *) ad->argLoc = FALSE;
\r
1820 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1826 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1829 case ArgAttribs: {
\r
1830 ColorClass cc = (ColorClass)ad->argLoc;
\r
1831 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1835 case ArgBoardSize:
\r
1836 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1840 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1843 case ArgCommSettings:
\r
1844 ParseCommSettings(argValue, &dcb);
\r
1848 ExitArgError("Unrecognized argument", argValue);
\r
1857 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1859 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1860 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1863 lf->lfEscapement = 0;
\r
1864 lf->lfOrientation = 0;
\r
1865 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1866 lf->lfItalic = mfp->italic;
\r
1867 lf->lfUnderline = mfp->underline;
\r
1868 lf->lfStrikeOut = mfp->strikeout;
\r
1869 lf->lfCharSet = DEFAULT_CHARSET;
\r
1870 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1871 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1872 lf->lfQuality = DEFAULT_QUALITY;
\r
1873 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1874 strcpy(lf->lfFaceName, mfp->faceName);
\r
1878 CreateFontInMF(MyFont *mf)
\r
1880 LFfromMFP(&mf->lf, &mf->mfp);
\r
1881 if (mf->hf) DeleteObject(mf->hf);
\r
1882 mf->hf = CreateFontIndirect(&mf->lf);
\r
1886 SetDefaultTextAttribs()
\r
1889 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1890 ParseAttribs(&textAttribs[cc].color,
\r
1891 &textAttribs[cc].effects,
\r
1892 defaultTextAttribs[cc]);
\r
1897 SetDefaultSounds()
\r
1901 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1902 textAttribs[cc].sound.name = strdup("");
\r
1903 textAttribs[cc].sound.data = NULL;
\r
1905 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1906 sounds[sc].name = strdup("");
\r
1907 sounds[sc].data = NULL;
\r
1909 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1917 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1918 MyLoadSound(&textAttribs[cc].sound);
\r
1920 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1921 MyLoadSound(&sounds[sc]);
\r
1926 InitAppData(LPSTR lpCmdLine)
\r
1929 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1932 programName = szAppName;
\r
1934 /* Initialize to defaults */
\r
1935 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1936 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1937 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1938 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1939 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1940 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1941 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1942 SetDefaultTextAttribs();
\r
1943 SetDefaultSounds();
\r
1944 appData.movesPerSession = MOVES_PER_SESSION;
\r
1945 appData.initString = INIT_STRING;
\r
1946 appData.secondInitString = INIT_STRING;
\r
1947 appData.firstComputerString = COMPUTER_STRING;
\r
1948 appData.secondComputerString = COMPUTER_STRING;
\r
1949 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1950 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1951 appData.firstPlaysBlack = FALSE;
\r
1952 appData.noChessProgram = FALSE;
\r
1953 chessProgram = FALSE;
\r
1954 appData.firstHost = FIRST_HOST;
\r
1955 appData.secondHost = SECOND_HOST;
\r
1956 appData.firstDirectory = FIRST_DIRECTORY;
\r
1957 appData.secondDirectory = SECOND_DIRECTORY;
\r
1958 appData.bitmapDirectory = "";
\r
1959 appData.remoteShell = REMOTE_SHELL;
\r
1960 appData.remoteUser = "";
\r
1961 appData.timeDelay = TIME_DELAY;
\r
1962 appData.timeControl = TIME_CONTROL;
\r
1963 appData.timeIncrement = TIME_INCREMENT;
\r
1964 appData.icsActive = FALSE;
\r
1965 appData.icsHost = "";
\r
1966 appData.icsPort = ICS_PORT;
\r
1967 appData.icsCommPort = ICS_COMM_PORT;
\r
1968 appData.icsLogon = ICS_LOGON;
\r
1969 appData.icsHelper = "";
\r
1970 appData.useTelnet = FALSE;
\r
1971 appData.telnetProgram = TELNET_PROGRAM;
\r
1972 appData.gateway = "";
\r
1973 appData.loadGameFile = "";
\r
1974 appData.loadGameIndex = 0;
\r
1975 appData.saveGameFile = "";
\r
1976 appData.autoSaveGames = FALSE;
\r
1977 appData.loadPositionFile = "";
\r
1978 appData.loadPositionIndex = 1;
\r
1979 appData.savePositionFile = "";
\r
1980 appData.matchMode = FALSE;
\r
1981 appData.matchGames = 0;
\r
1982 appData.monoMode = FALSE;
\r
1983 appData.debugMode = FALSE;
\r
1984 appData.clockMode = TRUE;
\r
1985 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1986 appData.Iconic = FALSE; /*unused*/
\r
1987 appData.searchTime = "";
\r
1988 appData.searchDepth = 0;
\r
1989 appData.showCoords = FALSE;
\r
1990 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1991 appData.autoCallFlag = FALSE;
\r
1992 appData.flipView = FALSE;
\r
1993 appData.autoFlipView = TRUE;
\r
1994 appData.cmailGameName = "";
\r
1995 appData.alwaysPromoteToQueen = FALSE;
\r
1996 appData.oldSaveStyle = FALSE;
\r
1997 appData.quietPlay = FALSE;
\r
1998 appData.showThinking = FALSE;
\r
1999 appData.ponderNextMove = TRUE;
\r
2000 appData.periodicUpdates = TRUE;
\r
2001 appData.popupExitMessage = TRUE;
\r
2002 appData.popupMoveErrors = FALSE;
\r
2003 appData.autoObserve = FALSE;
\r
2004 appData.autoComment = FALSE;
\r
2005 appData.animate = TRUE;
\r
2006 appData.animSpeed = 10;
\r
2007 appData.animateDragging = TRUE;
\r
2008 appData.highlightLastMove = TRUE;
\r
2009 appData.getMoveList = TRUE;
\r
2010 appData.testLegality = TRUE;
\r
2011 appData.premove = TRUE;
\r
2012 appData.premoveWhite = FALSE;
\r
2013 appData.premoveWhiteText = "";
\r
2014 appData.premoveBlack = FALSE;
\r
2015 appData.premoveBlackText = "";
\r
2016 appData.icsAlarm = TRUE;
\r
2017 appData.icsAlarmTime = 5000;
\r
2018 appData.autoRaiseBoard = TRUE;
\r
2019 appData.localLineEditing = TRUE;
\r
2020 appData.colorize = TRUE;
\r
2021 appData.reuseFirst = TRUE;
\r
2022 appData.reuseSecond = TRUE;
\r
2023 appData.blindfold = FALSE;
\r
2024 appData.icsEngineAnalyze = FALSE;
\r
2025 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2026 dcb.DCBlength = sizeof(DCB);
\r
2027 dcb.BaudRate = 9600;
\r
2028 dcb.fBinary = TRUE;
\r
2029 dcb.fParity = FALSE;
\r
2030 dcb.fOutxCtsFlow = FALSE;
\r
2031 dcb.fOutxDsrFlow = FALSE;
\r
2032 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2033 dcb.fDsrSensitivity = FALSE;
\r
2034 dcb.fTXContinueOnXoff = TRUE;
\r
2035 dcb.fOutX = FALSE;
\r
2037 dcb.fNull = FALSE;
\r
2038 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2039 dcb.fAbortOnError = FALSE;
\r
2041 dcb.Parity = SPACEPARITY;
\r
2042 dcb.StopBits = ONESTOPBIT;
\r
2043 settingsFileName = SETTINGS_FILE;
\r
2044 saveSettingsOnExit = TRUE;
\r
2045 boardX = CW_USEDEFAULT;
\r
2046 boardY = CW_USEDEFAULT;
\r
2047 analysisX = CW_USEDEFAULT;
\r
2048 analysisY = CW_USEDEFAULT;
\r
2049 analysisW = CW_USEDEFAULT;
\r
2050 analysisH = CW_USEDEFAULT;
\r
2051 commentX = CW_USEDEFAULT;
\r
2052 commentY = CW_USEDEFAULT;
\r
2053 commentW = CW_USEDEFAULT;
\r
2054 commentH = CW_USEDEFAULT;
\r
2055 editTagsX = CW_USEDEFAULT;
\r
2056 editTagsY = CW_USEDEFAULT;
\r
2057 editTagsW = CW_USEDEFAULT;
\r
2058 editTagsH = CW_USEDEFAULT;
\r
2059 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2060 icsNames = ICS_NAMES;
\r
2061 firstChessProgramNames = FCP_NAMES;
\r
2062 secondChessProgramNames = SCP_NAMES;
\r
2063 appData.initialMode = "";
\r
2064 appData.variant = "normal";
\r
2065 appData.firstProtocolVersion = PROTOVER;
\r
2066 appData.secondProtocolVersion = PROTOVER;
\r
2067 appData.showButtonBar = TRUE;
\r
2069 /* [AS] New properties (see comments in header file) */
\r
2070 appData.firstScoreIsAbsolute = FALSE;
\r
2071 appData.secondScoreIsAbsolute = FALSE;
\r
2072 appData.saveExtendedInfoInPGN = FALSE;
\r
2073 appData.hideThinkingFromHuman = FALSE;
\r
2074 appData.liteBackTextureFile = "";
\r
2075 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2076 appData.darkBackTextureFile = "";
\r
2077 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2078 appData.renderPiecesWithFont = "";
\r
2079 appData.fontToPieceTable = "";
\r
2080 appData.fontBackColorWhite = 0;
\r
2081 appData.fontForeColorWhite = 0;
\r
2082 appData.fontBackColorBlack = 0;
\r
2083 appData.fontForeColorBlack = 0;
\r
2084 appData.fontPieceSize = 80;
\r
2085 appData.overrideLineGap = 1;
\r
2086 appData.adjudicateLossThreshold = 0;
\r
2087 appData.delayBeforeQuit = 0;
\r
2088 appData.delayAfterQuit = 0;
\r
2089 appData.nameOfDebugFile = "winboard.debug";
\r
2090 appData.pgnEventHeader = "Computer Chess Game";
\r
2091 appData.defaultFrcPosition = -1;
\r
2092 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2093 appData.saveOutOfBookInfo = TRUE;
\r
2094 appData.showEvalInMoveHistory = TRUE;
\r
2095 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2096 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2097 appData.highlightMoveWithArrow = FALSE;
\r
2098 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2099 appData.useStickyWindows = TRUE;
\r
2100 appData.adjudicateDrawMoves = 0;
\r
2101 appData.autoDisplayComment = TRUE;
\r
2102 appData.autoDisplayTags = TRUE;
\r
2103 appData.firstIsUCI = FALSE;
\r
2104 appData.secondIsUCI = FALSE;
\r
2105 appData.firstHasOwnBookUCI = TRUE;
\r
2106 appData.secondHasOwnBookUCI = TRUE;
\r
2107 appData.polyglotDir = "";
\r
2108 appData.usePolyglotBook = FALSE;
\r
2109 appData.polyglotBook = "";
\r
2110 appData.defaultHashSize = 64;
\r
2111 appData.defaultCacheSizeEGTB = 4;
\r
2112 appData.defaultPathEGTB = "c:\\egtb";
\r
2113 appData.firstOptions = "";
\r
2114 appData.secondOptions = "";
\r
2116 InitWindowPlacement( &wpGameList );
\r
2117 InitWindowPlacement( &wpMoveHistory );
\r
2118 InitWindowPlacement( &wpEvalGraph );
\r
2119 InitWindowPlacement( &wpEngineOutput );
\r
2120 InitWindowPlacement( &wpConsole );
\r
2122 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2123 appData.NrFiles = -1;
\r
2124 appData.NrRanks = -1;
\r
2125 appData.holdingsSize = -1;
\r
2126 appData.testClaims = FALSE;
\r
2127 appData.checkMates = FALSE;
\r
2128 appData.materialDraws= FALSE;
\r
2129 appData.trivialDraws = FALSE;
\r
2130 appData.ruleMoves = 51;
\r
2131 appData.drawRepeats = 6;
\r
2132 appData.matchPause = 10000;
\r
2133 appData.alphaRank = FALSE;
\r
2134 appData.allWhite = FALSE;
\r
2135 appData.upsideDown = FALSE;
\r
2136 appData.serverPause = 15;
\r
2137 appData.serverMovesName = NULL;
\r
2138 appData.suppressLoadMoves = FALSE;
\r
2139 appData.firstTimeOdds = 1;
\r
2140 appData.secondTimeOdds = 1;
\r
2141 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2142 appData.secondAccumulateTC = 1;
\r
2143 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2144 appData.secondNPS = -1;
\r
2145 appData.engineComments = 1;
\r
2146 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2147 appData.egtFormats = "";
\r
2150 appData.zippyTalk = ZIPPY_TALK;
\r
2151 appData.zippyPlay = ZIPPY_PLAY;
\r
2152 appData.zippyLines = ZIPPY_LINES;
\r
2153 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2154 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2155 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2156 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2157 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2158 appData.zippyUseI = ZIPPY_USE_I;
\r
2159 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2160 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2161 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2162 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2163 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2164 appData.zippyAbort = ZIPPY_ABORT;
\r
2165 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2166 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2167 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2170 /* Point font array elements to structures and
\r
2171 parse default font names */
\r
2172 for (i=0; i<NUM_FONTS; i++) {
\r
2173 for (j=0; j<NUM_SIZES; j++) {
\r
2174 font[j][i] = &fontRec[j][i];
\r
2175 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2179 /* Parse default settings file if any */
\r
2180 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2181 settingsFileName = strdup(buf);
\r
2184 /* Parse command line */
\r
2185 ParseArgs(StringGet, &lpCmdLine);
\r
2187 /* [HGM] make sure board size is acceptable */
\r
2188 if(appData.NrFiles > BOARD_SIZE ||
\r
2189 appData.NrRanks > BOARD_SIZE )
\r
2190 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2192 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2193 * with options from the command line, we now make an even higher priority
\r
2194 * overrule by WB options attached to the engine command line. This so that
\r
2195 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2198 if(appData.firstChessProgram != NULL) {
\r
2199 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2200 static char *f = "first";
\r
2201 char buf[MSG_SIZ], *q = buf;
\r
2202 if(p != NULL) { // engine command line contains WinBoard options
\r
2203 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2204 ParseArgs(StringGet, &q);
\r
2205 p[-1] = 0; // cut them offengine command line
\r
2208 // now do same for second chess program
\r
2209 if(appData.secondChessProgram != NULL) {
\r
2210 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2211 static char *s = "second";
\r
2212 char buf[MSG_SIZ], *q = buf;
\r
2213 if(p != NULL) { // engine command line contains WinBoard options
\r
2214 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2215 ParseArgs(StringGet, &q);
\r
2216 p[-1] = 0; // cut them offengine command line
\r
2221 /* Propagate options that affect others */
\r
2222 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2223 if (appData.icsActive || appData.noChessProgram) {
\r
2224 chessProgram = FALSE; /* not local chess program mode */
\r
2227 /* Open startup dialog if needed */
\r
2228 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2229 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2230 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2231 *appData.secondChessProgram == NULLCHAR))) {
\r
2234 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2235 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2236 FreeProcInstance(lpProc);
\r
2239 /* Make sure save files land in the right (?) directory */
\r
2240 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2241 appData.saveGameFile = strdup(buf);
\r
2243 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2244 appData.savePositionFile = strdup(buf);
\r
2247 /* Finish initialization for fonts and sounds */
\r
2248 for (i=0; i<NUM_FONTS; i++) {
\r
2249 for (j=0; j<NUM_SIZES; j++) {
\r
2250 CreateFontInMF(font[j][i]);
\r
2253 /* xboard, and older WinBoards, controlled the move sound with the
\r
2254 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2255 always turn the option on (so that the backend will call us),
\r
2256 then let the user turn the sound off by setting it to silence if
\r
2257 desired. To accommodate old winboard.ini files saved by old
\r
2258 versions of WinBoard, we also turn off the sound if the option
\r
2259 was initially set to false. */
\r
2260 if (!appData.ringBellAfterMoves) {
\r
2261 sounds[(int)SoundMove].name = strdup("");
\r
2262 appData.ringBellAfterMoves = TRUE;
\r
2264 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2265 SetCurrentDirectory(installDir);
\r
2267 SetCurrentDirectory(currDir);
\r
2269 p = icsTextMenuString;
\r
2270 if (p[0] == '@') {
\r
2271 FILE* f = fopen(p + 1, "r");
\r
2273 DisplayFatalError(p + 1, errno, 2);
\r
2276 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2278 buf[i] = NULLCHAR;
\r
2281 ParseIcsTextMenu(strdup(p));
\r
2288 HMENU hmenu = GetMenu(hwndMain);
\r
2290 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2291 MF_BYCOMMAND|((appData.icsActive &&
\r
2292 *appData.icsCommPort != NULLCHAR) ?
\r
2293 MF_ENABLED : MF_GRAYED));
\r
2294 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2295 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2296 MF_CHECKED : MF_UNCHECKED));
\r
2301 SaveSettings(char* name)
\r
2304 ArgDescriptor *ad;
\r
2305 WINDOWPLACEMENT wp;
\r
2306 char dir[MSG_SIZ];
\r
2308 if (!hwndMain) return;
\r
2310 GetCurrentDirectory(MSG_SIZ, dir);
\r
2311 SetCurrentDirectory(installDir);
\r
2312 f = fopen(name, "w");
\r
2313 SetCurrentDirectory(dir);
\r
2315 DisplayError(name, errno);
\r
2318 fprintf(f, ";\n");
\r
2319 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2320 fprintf(f, ";\n");
\r
2321 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2322 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2323 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2324 fprintf(f, ";\n");
\r
2326 wp.length = sizeof(WINDOWPLACEMENT);
\r
2327 GetWindowPlacement(hwndMain, &wp);
\r
2328 boardX = wp.rcNormalPosition.left;
\r
2329 boardY = wp.rcNormalPosition.top;
\r
2331 if (hwndConsole) {
\r
2332 GetWindowPlacement(hwndConsole, &wp);
\r
2333 wpConsole.x = wp.rcNormalPosition.left;
\r
2334 wpConsole.y = wp.rcNormalPosition.top;
\r
2335 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2336 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2339 if (analysisDialog) {
\r
2340 GetWindowPlacement(analysisDialog, &wp);
\r
2341 analysisX = wp.rcNormalPosition.left;
\r
2342 analysisY = wp.rcNormalPosition.top;
\r
2343 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2344 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2347 if (commentDialog) {
\r
2348 GetWindowPlacement(commentDialog, &wp);
\r
2349 commentX = wp.rcNormalPosition.left;
\r
2350 commentY = wp.rcNormalPosition.top;
\r
2351 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2352 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2355 if (editTagsDialog) {
\r
2356 GetWindowPlacement(editTagsDialog, &wp);
\r
2357 editTagsX = wp.rcNormalPosition.left;
\r
2358 editTagsY = wp.rcNormalPosition.top;
\r
2359 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2360 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2363 if (gameListDialog) {
\r
2364 GetWindowPlacement(gameListDialog, &wp);
\r
2365 wpGameList.x = wp.rcNormalPosition.left;
\r
2366 wpGameList.y = wp.rcNormalPosition.top;
\r
2367 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2368 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2371 /* [AS] Move history */
\r
2372 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2374 if( moveHistoryDialog ) {
\r
2375 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2376 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2377 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2378 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2379 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2382 /* [AS] Eval graph */
\r
2383 wpEvalGraph.visible = EvalGraphIsUp();
\r
2385 if( evalGraphDialog ) {
\r
2386 GetWindowPlacement(evalGraphDialog, &wp);
\r
2387 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2388 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2389 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2390 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2393 /* [AS] Engine output */
\r
2394 wpEngineOutput.visible = EngineOutputIsUp();
\r
2396 if( engineOutputDialog ) {
\r
2397 GetWindowPlacement(engineOutputDialog, &wp);
\r
2398 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2399 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2400 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2401 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2404 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2405 if (!ad->save) continue;
\r
2406 switch (ad->argType) {
\r
2409 char *p = *(char **)ad->argLoc;
\r
2410 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2411 /* Quote multiline values or \-containing values
\r
2412 with { } if possible */
\r
2413 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2415 /* Else quote with " " */
\r
2416 fprintf(f, "/%s=\"", ad->argName);
\r
2418 if (*p == '\n') fprintf(f, "\n");
\r
2419 else if (*p == '\r') fprintf(f, "\\r");
\r
2420 else if (*p == '\t') fprintf(f, "\\t");
\r
2421 else if (*p == '\b') fprintf(f, "\\b");
\r
2422 else if (*p == '\f') fprintf(f, "\\f");
\r
2423 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2424 else if (*p == '\"') fprintf(f, "\\\"");
\r
2425 else if (*p == '\\') fprintf(f, "\\\\");
\r
2429 fprintf(f, "\"\n");
\r
2435 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2438 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2441 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2444 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2447 fprintf(f, "/%s=%s\n", ad->argName,
\r
2448 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2451 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2454 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2458 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2459 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2460 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2465 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2466 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2467 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2468 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2469 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2470 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2471 (ta->effects) ? " " : "",
\r
2472 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2476 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2477 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2479 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2482 case ArgBoardSize:
\r
2483 fprintf(f, "/%s=%s\n", ad->argName,
\r
2484 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2489 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2490 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2491 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2492 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2493 ad->argName, mfp->faceName, mfp->pointSize,
\r
2494 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2495 mfp->bold ? "b" : "",
\r
2496 mfp->italic ? "i" : "",
\r
2497 mfp->underline ? "u" : "",
\r
2498 mfp->strikeout ? "s" : "");
\r
2502 case ArgCommSettings:
\r
2503 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2505 case ArgSettingsFilename: ;
\r
2513 /*---------------------------------------------------------------------------*\
\r
2515 * GDI board drawing routines
\r
2517 \*---------------------------------------------------------------------------*/
\r
2519 /* [AS] Draw square using background texture */
\r
2520 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2525 return; /* Should never happen! */
\r
2528 SetGraphicsMode( dst, GM_ADVANCED );
\r
2535 /* X reflection */
\r
2540 x.eDx = (FLOAT) dw + dx - 1;
\r
2543 SetWorldTransform( dst, &x );
\r
2546 /* Y reflection */
\r
2552 x.eDy = (FLOAT) dh + dy - 1;
\r
2554 SetWorldTransform( dst, &x );
\r
2562 x.eDx = (FLOAT) dx;
\r
2563 x.eDy = (FLOAT) dy;
\r
2566 SetWorldTransform( dst, &x );
\r
2570 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2578 SetWorldTransform( dst, &x );
\r
2580 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2583 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2585 PM_WP = (int) WhitePawn,
\r
2586 PM_WN = (int) WhiteKnight,
\r
2587 PM_WB = (int) WhiteBishop,
\r
2588 PM_WR = (int) WhiteRook,
\r
2589 PM_WQ = (int) WhiteQueen,
\r
2590 PM_WF = (int) WhiteFerz,
\r
2591 PM_WW = (int) WhiteWazir,
\r
2592 PM_WE = (int) WhiteAlfil,
\r
2593 PM_WM = (int) WhiteMan,
\r
2594 PM_WO = (int) WhiteCannon,
\r
2595 PM_WU = (int) WhiteUnicorn,
\r
2596 PM_WH = (int) WhiteNightrider,
\r
2597 PM_WA = (int) WhiteAngel,
\r
2598 PM_WC = (int) WhiteMarshall,
\r
2599 PM_WAB = (int) WhiteCardinal,
\r
2600 PM_WD = (int) WhiteDragon,
\r
2601 PM_WL = (int) WhiteLance,
\r
2602 PM_WS = (int) WhiteCobra,
\r
2603 PM_WV = (int) WhiteFalcon,
\r
2604 PM_WSG = (int) WhiteSilver,
\r
2605 PM_WG = (int) WhiteGrasshopper,
\r
2606 PM_WK = (int) WhiteKing,
\r
2607 PM_BP = (int) BlackPawn,
\r
2608 PM_BN = (int) BlackKnight,
\r
2609 PM_BB = (int) BlackBishop,
\r
2610 PM_BR = (int) BlackRook,
\r
2611 PM_BQ = (int) BlackQueen,
\r
2612 PM_BF = (int) BlackFerz,
\r
2613 PM_BW = (int) BlackWazir,
\r
2614 PM_BE = (int) BlackAlfil,
\r
2615 PM_BM = (int) BlackMan,
\r
2616 PM_BO = (int) BlackCannon,
\r
2617 PM_BU = (int) BlackUnicorn,
\r
2618 PM_BH = (int) BlackNightrider,
\r
2619 PM_BA = (int) BlackAngel,
\r
2620 PM_BC = (int) BlackMarshall,
\r
2621 PM_BG = (int) BlackGrasshopper,
\r
2622 PM_BAB = (int) BlackCardinal,
\r
2623 PM_BD = (int) BlackDragon,
\r
2624 PM_BL = (int) BlackLance,
\r
2625 PM_BS = (int) BlackCobra,
\r
2626 PM_BV = (int) BlackFalcon,
\r
2627 PM_BSG = (int) BlackSilver,
\r
2628 PM_BK = (int) BlackKing
\r
2631 static HFONT hPieceFont = NULL;
\r
2632 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2633 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2634 static int fontBitmapSquareSize = 0;
\r
2635 static char pieceToFontChar[(int) EmptySquare] =
\r
2636 { 'p', 'n', 'b', 'r', 'q',
\r
2637 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2638 'k', 'o', 'm', 'v', 't', 'w',
\r
2639 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2642 extern BOOL SetCharTable( char *table, const char * map );
\r
2643 /* [HGM] moved to backend.c */
\r
2645 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2648 BYTE r1 = GetRValue( color );
\r
2649 BYTE g1 = GetGValue( color );
\r
2650 BYTE b1 = GetBValue( color );
\r
2656 /* Create a uniform background first */
\r
2657 hbrush = CreateSolidBrush( color );
\r
2658 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2659 FillRect( hdc, &rc, hbrush );
\r
2660 DeleteObject( hbrush );
\r
2663 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2664 int steps = squareSize / 2;
\r
2667 for( i=0; i<steps; i++ ) {
\r
2668 BYTE r = r1 - (r1-r2) * i / steps;
\r
2669 BYTE g = g1 - (g1-g2) * i / steps;
\r
2670 BYTE b = b1 - (b1-b2) * i / steps;
\r
2672 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2673 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2674 FillRect( hdc, &rc, hbrush );
\r
2675 DeleteObject(hbrush);
\r
2678 else if( mode == 2 ) {
\r
2679 /* Diagonal gradient, good more or less for every piece */
\r
2680 POINT triangle[3];
\r
2681 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2682 HBRUSH hbrush_old;
\r
2683 int steps = squareSize;
\r
2686 triangle[0].x = squareSize - steps;
\r
2687 triangle[0].y = squareSize;
\r
2688 triangle[1].x = squareSize;
\r
2689 triangle[1].y = squareSize;
\r
2690 triangle[2].x = squareSize;
\r
2691 triangle[2].y = squareSize - steps;
\r
2693 for( i=0; i<steps; i++ ) {
\r
2694 BYTE r = r1 - (r1-r2) * i / steps;
\r
2695 BYTE g = g1 - (g1-g2) * i / steps;
\r
2696 BYTE b = b1 - (b1-b2) * i / steps;
\r
2698 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2699 hbrush_old = SelectObject( hdc, hbrush );
\r
2700 Polygon( hdc, triangle, 3 );
\r
2701 SelectObject( hdc, hbrush_old );
\r
2702 DeleteObject(hbrush);
\r
2707 SelectObject( hdc, hpen );
\r
2712 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2713 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2714 piece: follow the steps as explained below.
\r
2716 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2720 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2724 int backColor = whitePieceColor;
\r
2725 int foreColor = blackPieceColor;
\r
2727 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2728 backColor = appData.fontBackColorWhite;
\r
2729 foreColor = appData.fontForeColorWhite;
\r
2731 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2732 backColor = appData.fontBackColorBlack;
\r
2733 foreColor = appData.fontForeColorBlack;
\r
2737 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2739 hbm_old = SelectObject( hdc, hbm );
\r
2743 rc.right = squareSize;
\r
2744 rc.bottom = squareSize;
\r
2746 /* Step 1: background is now black */
\r
2747 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2749 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2751 pt.x = (squareSize - sz.cx) / 2;
\r
2752 pt.y = (squareSize - sz.cy) / 2;
\r
2754 SetBkMode( hdc, TRANSPARENT );
\r
2755 SetTextColor( hdc, chroma );
\r
2756 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2757 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2759 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2760 /* Step 3: the area outside the piece is filled with white */
\r
2761 // FloodFill( hdc, 0, 0, chroma );
\r
2762 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2763 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2764 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2765 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2766 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2768 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2769 but if the start point is not inside the piece we're lost!
\r
2770 There should be a better way to do this... if we could create a region or path
\r
2771 from the fill operation we would be fine for example.
\r
2773 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2774 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2776 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2777 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2778 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2780 SelectObject( dc2, bm2 );
\r
2781 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2782 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2783 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2784 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2785 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2788 DeleteObject( bm2 );
\r
2791 SetTextColor( hdc, 0 );
\r
2793 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2794 draw the piece again in black for safety.
\r
2796 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2798 SelectObject( hdc, hbm_old );
\r
2800 if( hPieceMask[index] != NULL ) {
\r
2801 DeleteObject( hPieceMask[index] );
\r
2804 hPieceMask[index] = hbm;
\r
2807 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2809 SelectObject( hdc, hbm );
\r
2812 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2813 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2814 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2816 SelectObject( dc1, hPieceMask[index] );
\r
2817 SelectObject( dc2, bm2 );
\r
2818 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2819 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2822 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2823 the piece background and deletes (makes transparent) the rest.
\r
2824 Thanks to that mask, we are free to paint the background with the greates
\r
2825 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2826 We use this, to make gradients and give the pieces a "roundish" look.
\r
2828 SetPieceBackground( hdc, backColor, 2 );
\r
2829 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2833 DeleteObject( bm2 );
\r
2836 SetTextColor( hdc, foreColor );
\r
2837 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2839 SelectObject( hdc, hbm_old );
\r
2841 if( hPieceFace[index] != NULL ) {
\r
2842 DeleteObject( hPieceFace[index] );
\r
2845 hPieceFace[index] = hbm;
\r
2848 static int TranslatePieceToFontPiece( int piece )
\r
2878 case BlackMarshall:
\r
2882 case BlackNightrider:
\r
2888 case BlackUnicorn:
\r
2892 case BlackGrasshopper:
\r
2904 case BlackCardinal:
\r
2911 case WhiteMarshall:
\r
2915 case WhiteNightrider:
\r
2921 case WhiteUnicorn:
\r
2925 case WhiteGrasshopper:
\r
2937 case WhiteCardinal:
\r
2946 void CreatePiecesFromFont()
\r
2949 HDC hdc_window = NULL;
\r
2955 if( fontBitmapSquareSize < 0 ) {
\r
2956 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2960 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2961 fontBitmapSquareSize = -1;
\r
2965 if( fontBitmapSquareSize != squareSize ) {
\r
2966 hdc_window = GetDC( hwndMain );
\r
2967 hdc = CreateCompatibleDC( hdc_window );
\r
2969 if( hPieceFont != NULL ) {
\r
2970 DeleteObject( hPieceFont );
\r
2973 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2974 hPieceMask[i] = NULL;
\r
2975 hPieceFace[i] = NULL;
\r
2981 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2982 fontHeight = appData.fontPieceSize;
\r
2985 fontHeight = (fontHeight * squareSize) / 100;
\r
2987 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2989 lf.lfEscapement = 0;
\r
2990 lf.lfOrientation = 0;
\r
2991 lf.lfWeight = FW_NORMAL;
\r
2993 lf.lfUnderline = 0;
\r
2994 lf.lfStrikeOut = 0;
\r
2995 lf.lfCharSet = DEFAULT_CHARSET;
\r
2996 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2997 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2998 lf.lfQuality = PROOF_QUALITY;
\r
2999 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
3000 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
3001 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3003 hPieceFont = CreateFontIndirect( &lf );
\r
3005 if( hPieceFont == NULL ) {
\r
3006 fontBitmapSquareSize = -2;
\r
3009 /* Setup font-to-piece character table */
\r
3010 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3011 /* No (or wrong) global settings, try to detect the font */
\r
3012 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3014 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3016 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3017 /* DiagramTT* family */
\r
3018 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3020 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3021 /* Fairy symbols */
\r
3022 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3024 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3025 /* Good Companion (Some characters get warped as literal :-( */
\r
3026 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3027 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3028 SetCharTable(pieceToFontChar, s);
\r
3031 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3032 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3036 /* Create bitmaps */
\r
3037 hfont_old = SelectObject( hdc, hPieceFont );
\r
3039 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3040 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3042 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3043 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3048 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3050 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3055 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3056 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3063 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3064 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3065 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3066 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3067 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3068 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3069 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3070 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3071 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3072 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3073 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3074 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3075 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3076 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3077 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3078 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3079 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3080 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3081 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3082 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3083 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3085 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3086 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3087 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3089 SelectObject( hdc, hfont_old );
\r
3091 fontBitmapSquareSize = squareSize;
\r
3095 if( hdc != NULL ) {
\r
3099 if( hdc_window != NULL ) {
\r
3100 ReleaseDC( hwndMain, hdc_window );
\r
3105 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3109 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3110 if (gameInfo.event &&
\r
3111 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3112 strcmp(name, "k80s") == 0) {
\r
3113 strcpy(name, "tim");
\r
3115 return LoadBitmap(hinst, name);
\r
3119 /* Insert a color into the program's logical palette
\r
3120 structure. This code assumes the given color is
\r
3121 the result of the RGB or PALETTERGB macro, and it
\r
3122 knows how those macros work (which is documented).
\r
3125 InsertInPalette(COLORREF color)
\r
3127 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3129 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3130 DisplayFatalError("Too many colors", 0, 1);
\r
3131 pLogPal->palNumEntries--;
\r
3135 pe->peFlags = (char) 0;
\r
3136 pe->peRed = (char) (0xFF & color);
\r
3137 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3138 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3144 InitDrawingColors()
\r
3146 if (pLogPal == NULL) {
\r
3147 /* Allocate enough memory for a logical palette with
\r
3148 * PALETTESIZE entries and set the size and version fields
\r
3149 * of the logical palette structure.
\r
3151 pLogPal = (NPLOGPALETTE)
\r
3152 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3153 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3154 pLogPal->palVersion = 0x300;
\r
3156 pLogPal->palNumEntries = 0;
\r
3158 InsertInPalette(lightSquareColor);
\r
3159 InsertInPalette(darkSquareColor);
\r
3160 InsertInPalette(whitePieceColor);
\r
3161 InsertInPalette(blackPieceColor);
\r
3162 InsertInPalette(highlightSquareColor);
\r
3163 InsertInPalette(premoveHighlightColor);
\r
3165 /* create a logical color palette according the information
\r
3166 * in the LOGPALETTE structure.
\r
3168 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3170 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3171 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3172 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3173 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3174 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3175 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3176 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3177 /* [AS] Force rendering of the font-based pieces */
\r
3178 if( fontBitmapSquareSize > 0 ) {
\r
3179 fontBitmapSquareSize = 0;
\r
3185 BoardWidth(int boardSize, int n)
\r
3186 { /* [HGM] argument n added to allow different width and height */
\r
3187 int lineGap = sizeInfo[boardSize].lineGap;
\r
3189 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3190 lineGap = appData.overrideLineGap;
\r
3193 return (n + 1) * lineGap +
\r
3194 n * sizeInfo[boardSize].squareSize;
\r
3197 /* Respond to board resize by dragging edge */
\r
3199 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3201 BoardSize newSize = NUM_SIZES - 1;
\r
3202 static int recurse = 0;
\r
3203 if (IsIconic(hwndMain)) return;
\r
3204 if (recurse > 0) return;
\r
3206 while (newSize > 0) {
\r
3207 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3208 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3209 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3212 boardSize = newSize;
\r
3213 InitDrawingSizes(boardSize, flags);
\r
3220 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3222 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3223 ChessSquare piece;
\r
3224 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3226 SIZE clockSize, messageSize;
\r
3228 char buf[MSG_SIZ];
\r
3230 HMENU hmenu = GetMenu(hwndMain);
\r
3231 RECT crect, wrect, oldRect;
\r
3233 LOGBRUSH logbrush;
\r
3235 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3236 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3238 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3239 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3241 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3242 oldRect.top = boardY;
\r
3243 oldRect.right = boardX + winWidth;
\r
3244 oldRect.bottom = boardY + winHeight;
\r
3246 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3247 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3248 squareSize = sizeInfo[boardSize].squareSize;
\r
3249 lineGap = sizeInfo[boardSize].lineGap;
\r
3250 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3252 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3253 lineGap = appData.overrideLineGap;
\r
3256 if (tinyLayout != oldTinyLayout) {
\r
3257 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3259 style &= ~WS_SYSMENU;
\r
3260 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3261 "&Minimize\tCtrl+F4");
\r
3263 style |= WS_SYSMENU;
\r
3264 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3266 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3268 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3269 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3270 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3272 DrawMenuBar(hwndMain);
\r
3275 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3276 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3278 /* Get text area sizes */
\r
3279 hdc = GetDC(hwndMain);
\r
3280 if (appData.clockMode) {
\r
3281 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3283 sprintf(buf, "White");
\r
3285 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3286 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3287 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3288 str = "We only care about the height here";
\r
3289 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3290 SelectObject(hdc, oldFont);
\r
3291 ReleaseDC(hwndMain, hdc);
\r
3293 /* Compute where everything goes */
\r
3294 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3295 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3296 logoHeight = 2*clockSize.cy;
\r
3297 leftLogoRect.left = OUTER_MARGIN;
\r
3298 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3299 leftLogoRect.top = OUTER_MARGIN;
\r
3300 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3302 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3303 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3304 rightLogoRect.top = OUTER_MARGIN;
\r
3305 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3308 whiteRect.left = leftLogoRect.right;
\r
3309 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3310 whiteRect.top = OUTER_MARGIN;
\r
3311 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3313 blackRect.right = rightLogoRect.left;
\r
3314 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3315 blackRect.top = whiteRect.top;
\r
3316 blackRect.bottom = whiteRect.bottom;
\r
3318 whiteRect.left = OUTER_MARGIN;
\r
3319 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3320 whiteRect.top = OUTER_MARGIN;
\r
3321 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3323 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3324 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3325 blackRect.top = whiteRect.top;
\r
3326 blackRect.bottom = whiteRect.bottom;
\r
3329 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3330 if (appData.showButtonBar) {
\r
3331 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3332 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3334 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3336 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3337 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3339 boardRect.left = OUTER_MARGIN;
\r
3340 boardRect.right = boardRect.left + boardWidth;
\r
3341 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3342 boardRect.bottom = boardRect.top + boardHeight;
\r
3344 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3345 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3346 oldBoardSize = boardSize;
\r
3347 oldTinyLayout = tinyLayout;
\r
3348 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3349 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3350 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3351 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3352 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3353 winHeight = winH; // without disturbing window attachments
\r
3354 GetWindowRect(hwndMain, &wrect);
\r
3355 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3356 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3358 // [HGM] placement: let attached windows follow size change.
\r
3359 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3360 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3361 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3362 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3363 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3365 /* compensate if menu bar wrapped */
\r
3366 GetClientRect(hwndMain, &crect);
\r
3367 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3368 winHeight += offby;
\r
3370 case WMSZ_TOPLEFT:
\r
3371 SetWindowPos(hwndMain, NULL,
\r
3372 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3373 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3376 case WMSZ_TOPRIGHT:
\r
3378 SetWindowPos(hwndMain, NULL,
\r
3379 wrect.left, wrect.bottom - winHeight,
\r
3380 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3383 case WMSZ_BOTTOMLEFT:
\r
3385 SetWindowPos(hwndMain, NULL,
\r
3386 wrect.right - winWidth, wrect.top,
\r
3387 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3390 case WMSZ_BOTTOMRIGHT:
\r
3394 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3395 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3400 for (i = 0; i < N_BUTTONS; i++) {
\r
3401 if (buttonDesc[i].hwnd != NULL) {
\r
3402 DestroyWindow(buttonDesc[i].hwnd);
\r
3403 buttonDesc[i].hwnd = NULL;
\r
3405 if (appData.showButtonBar) {
\r
3406 buttonDesc[i].hwnd =
\r
3407 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3408 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3409 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3410 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3411 (HMENU) buttonDesc[i].id,
\r
3412 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3414 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3415 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3416 MAKELPARAM(FALSE, 0));
\r
3418 if (buttonDesc[i].id == IDM_Pause)
\r
3419 hwndPause = buttonDesc[i].hwnd;
\r
3420 buttonDesc[i].wndproc = (WNDPROC)
\r
3421 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3424 if (gridPen != NULL) DeleteObject(gridPen);
\r
3425 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3426 if (premovePen != NULL) DeleteObject(premovePen);
\r
3427 if (lineGap != 0) {
\r
3428 logbrush.lbStyle = BS_SOLID;
\r
3429 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3431 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3432 lineGap, &logbrush, 0, NULL);
\r
3433 logbrush.lbColor = highlightSquareColor;
\r
3435 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3436 lineGap, &logbrush, 0, NULL);
\r
3438 logbrush.lbColor = premoveHighlightColor;
\r
3440 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3441 lineGap, &logbrush, 0, NULL);
\r
3443 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3444 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3445 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3446 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3447 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3448 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3449 BOARD_WIDTH * (squareSize + lineGap);
\r
3450 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3452 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3453 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3454 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3455 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3456 lineGap / 2 + (i * (squareSize + lineGap));
\r
3457 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3458 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3459 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3463 /* [HGM] Licensing requirement */
\r
3465 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3468 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3470 GothicPopUp( "", VariantNormal);
\r
3473 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3475 /* Load piece bitmaps for this board size */
\r
3476 for (i=0; i<=2; i++) {
\r
3477 for (piece = WhitePawn;
\r
3478 (int) piece < (int) BlackPawn;
\r
3479 piece = (ChessSquare) ((int) piece + 1)) {
\r
3480 if (pieceBitmap[i][piece] != NULL)
\r
3481 DeleteObject(pieceBitmap[i][piece]);
\r
3485 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3486 // Orthodox Chess pieces
\r
3487 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3488 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3489 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3490 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3491 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3492 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3493 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3494 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3495 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3496 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3497 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3498 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3499 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3500 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3501 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3502 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3503 // in Shogi, Hijack the unused Queen for Lance
\r
3504 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3505 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3506 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3508 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3509 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3510 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3513 if(squareSize <= 72 && squareSize >= 33) {
\r
3514 /* A & C are available in most sizes now */
\r
3515 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3516 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3517 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3518 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3519 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3520 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3521 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3522 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3523 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3524 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3525 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3526 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3527 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3528 } else { // Smirf-like
\r
3529 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3530 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3531 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3533 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3534 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3535 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3536 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3537 } else { // WinBoard standard
\r
3538 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3539 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3540 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3545 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3546 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3547 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3548 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3549 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3550 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3551 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3552 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3553 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3554 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3555 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3556 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3557 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3558 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3559 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3560 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3561 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3562 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3563 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3564 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3565 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3566 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3567 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3568 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3569 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3570 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3571 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3572 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3573 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3574 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3575 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3577 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3578 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3579 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3580 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3581 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3582 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3583 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3584 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3585 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3586 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3587 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3588 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3589 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3591 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3592 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3593 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3594 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3595 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3596 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3597 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3598 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3599 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3600 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3601 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3602 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3605 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3606 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3607 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3608 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3609 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3610 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3611 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3612 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3613 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3614 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3615 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3616 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3617 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3618 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3619 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3623 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3624 /* special Shogi support in this size */
\r
3625 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3626 for (piece = WhitePawn;
\r
3627 (int) piece < (int) BlackPawn;
\r
3628 piece = (ChessSquare) ((int) piece + 1)) {
\r
3629 if (pieceBitmap[i][piece] != NULL)
\r
3630 DeleteObject(pieceBitmap[i][piece]);
\r
3633 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3634 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3635 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3636 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3637 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3638 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3639 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3640 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3641 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3642 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3643 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3644 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3645 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3646 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3647 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3648 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3649 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3650 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3651 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3652 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3653 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3654 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3655 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3656 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3657 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3658 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3659 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3660 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3661 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3662 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3663 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3664 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3665 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3666 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3667 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3668 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3669 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3670 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3671 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3672 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3673 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3674 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3680 PieceBitmap(ChessSquare p, int kind)
\r
3682 if ((int) p >= (int) BlackPawn)
\r
3683 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3685 return pieceBitmap[kind][(int) p];
\r
3688 /***************************************************************/
\r
3690 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3691 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3693 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3694 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3698 SquareToPos(int row, int column, int * x, int * y)
\r
3701 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3702 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3704 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3705 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3710 DrawCoordsOnDC(HDC hdc)
\r
3712 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
3713 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
3714 char str[2] = { NULLCHAR, NULLCHAR };
\r
3715 int oldMode, oldAlign, x, y, start, i;
\r
3719 if (!appData.showCoords)
\r
3722 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3724 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3725 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3726 oldAlign = GetTextAlign(hdc);
\r
3727 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3729 y = boardRect.top + lineGap;
\r
3730 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3732 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3733 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3734 str[0] = files[start + i];
\r
3735 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3736 y += squareSize + lineGap;
\r
3739 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3741 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3742 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3743 str[0] = ranks[start + i];
\r
3744 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3745 x += squareSize + lineGap;
\r
3748 SelectObject(hdc, oldBrush);
\r
3749 SetBkMode(hdc, oldMode);
\r
3750 SetTextAlign(hdc, oldAlign);
\r
3751 SelectObject(hdc, oldFont);
\r
3755 DrawGridOnDC(HDC hdc)
\r
3759 if (lineGap != 0) {
\r
3760 oldPen = SelectObject(hdc, gridPen);
\r
3761 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3762 SelectObject(hdc, oldPen);
\r
3766 #define HIGHLIGHT_PEN 0
\r
3767 #define PREMOVE_PEN 1
\r
3770 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3773 HPEN oldPen, hPen;
\r
3774 if (lineGap == 0) return;
\r
3776 x1 = boardRect.left +
\r
3777 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3778 y1 = boardRect.top +
\r
3779 lineGap/2 + y * (squareSize + lineGap);
\r
3781 x1 = boardRect.left +
\r
3782 lineGap/2 + x * (squareSize + lineGap);
\r
3783 y1 = boardRect.top +
\r
3784 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3786 hPen = pen ? premovePen : highlightPen;
\r
3787 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3788 MoveToEx(hdc, x1, y1, NULL);
\r
3789 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3790 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3791 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3792 LineTo(hdc, x1, y1);
\r
3793 SelectObject(hdc, oldPen);
\r
3797 DrawHighlightsOnDC(HDC hdc)
\r
3800 for (i=0; i<2; i++) {
\r
3801 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3802 DrawHighlightOnDC(hdc, TRUE,
\r
3803 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3806 for (i=0; i<2; i++) {
\r
3807 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3808 premoveHighlightInfo.sq[i].y >= 0) {
\r
3809 DrawHighlightOnDC(hdc, TRUE,
\r
3810 premoveHighlightInfo.sq[i].x,
\r
3811 premoveHighlightInfo.sq[i].y,
\r
3817 /* Note: sqcolor is used only in monoMode */
\r
3818 /* Note that this code is largely duplicated in woptions.c,
\r
3819 function DrawSampleSquare, so that needs to be updated too */
\r
3821 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3823 HBITMAP oldBitmap;
\r
3827 if (appData.blindfold) return;
\r
3829 /* [AS] Use font-based pieces if needed */
\r
3830 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3831 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3832 CreatePiecesFromFont();
\r
3834 if( fontBitmapSquareSize == squareSize ) {
\r
3835 int index = TranslatePieceToFontPiece(piece);
\r
3837 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3841 squareSize, squareSize,
\r
3846 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3850 squareSize, squareSize,
\r
3859 if (appData.monoMode) {
\r
3860 SelectObject(tmphdc, PieceBitmap(piece,
\r
3861 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3862 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3863 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3865 tmpSize = squareSize;
\r
3867 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3868 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3869 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3870 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3871 x += (squareSize - minorSize)>>1;
\r
3872 y += squareSize - minorSize - 2;
\r
3873 tmpSize = minorSize;
\r
3875 if (color || appData.allWhite ) {
\r
3876 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3878 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3879 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3880 if(appData.upsideDown && color==flipView)
\r
3881 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3883 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3885 /* Use black piece color for outline of white pieces */
\r
3886 /* Not sure this looks really good (though xboard does it).
\r
3887 Maybe better to have another selectable color, default black */
\r
3888 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3889 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3890 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3892 /* Use black for outline of white pieces */
\r
3893 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3894 if(appData.upsideDown && color==flipView)
\r
3895 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3897 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3901 /* Use white piece color for details of black pieces */
\r
3902 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3903 WHITE_PIECE ones aren't always the right shape. */
\r
3904 /* Not sure this looks really good (though xboard does it).
\r
3905 Maybe better to have another selectable color, default medium gray? */
\r
3906 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3907 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3908 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3909 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3910 SelectObject(hdc, blackPieceBrush);
\r
3911 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3913 /* Use square color for details of black pieces */
\r
3914 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3915 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3916 if(appData.upsideDown && !flipView)
\r
3917 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3919 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3922 SelectObject(hdc, oldBrush);
\r
3923 SelectObject(tmphdc, oldBitmap);
\r
3927 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3928 int GetBackTextureMode( int algo )
\r
3930 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3934 case BACK_TEXTURE_MODE_PLAIN:
\r
3935 result = 1; /* Always use identity map */
\r
3937 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3938 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3946 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3947 to handle redraws cleanly (as random numbers would always be different).
\r
3949 VOID RebuildTextureSquareInfo()
\r
3959 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3961 if( liteBackTexture != NULL ) {
\r
3962 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3963 lite_w = bi.bmWidth;
\r
3964 lite_h = bi.bmHeight;
\r
3968 if( darkBackTexture != NULL ) {
\r
3969 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3970 dark_w = bi.bmWidth;
\r
3971 dark_h = bi.bmHeight;
\r
3975 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3976 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3977 if( (col + row) & 1 ) {
\r
3979 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3980 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3981 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3982 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3987 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3988 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3989 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3990 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3997 /* [AS] Arrow highlighting support */
\r
3999 static int A_WIDTH = 5; /* Width of arrow body */
\r
4001 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
4002 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
4004 static double Sqr( double x )
\r
4009 static int Round( double x )
\r
4011 return (int) (x + 0.5);
\r
4014 /* Draw an arrow between two points using current settings */
\r
4015 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
4018 double dx, dy, j, k, x, y;
\r
4020 if( d_x == s_x ) {
\r
4021 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4023 arrow[0].x = s_x + A_WIDTH;
\r
4026 arrow[1].x = s_x + A_WIDTH;
\r
4027 arrow[1].y = d_y - h;
\r
4029 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4030 arrow[2].y = d_y - h;
\r
4035 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4036 arrow[4].y = d_y - h;
\r
4038 arrow[5].x = s_x - A_WIDTH;
\r
4039 arrow[5].y = d_y - h;
\r
4041 arrow[6].x = s_x - A_WIDTH;
\r
4044 else if( d_y == s_y ) {
\r
4045 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4048 arrow[0].y = s_y + A_WIDTH;
\r
4050 arrow[1].x = d_x - w;
\r
4051 arrow[1].y = s_y + A_WIDTH;
\r
4053 arrow[2].x = d_x - w;
\r
4054 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4059 arrow[4].x = d_x - w;
\r
4060 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4062 arrow[5].x = d_x - w;
\r
4063 arrow[5].y = s_y - A_WIDTH;
\r
4066 arrow[6].y = s_y - A_WIDTH;
\r
4069 /* [AS] Needed a lot of paper for this! :-) */
\r
4070 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4071 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4073 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4075 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4080 arrow[0].x = Round(x - j);
\r
4081 arrow[0].y = Round(y + j*dx);
\r
4083 arrow[1].x = Round(x + j);
\r
4084 arrow[1].y = Round(y - j*dx);
\r
4087 x = (double) d_x - k;
\r
4088 y = (double) d_y - k*dy;
\r
4091 x = (double) d_x + k;
\r
4092 y = (double) d_y + k*dy;
\r
4095 arrow[2].x = Round(x + j);
\r
4096 arrow[2].y = Round(y - j*dx);
\r
4098 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4099 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4104 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4105 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4107 arrow[6].x = Round(x - j);
\r
4108 arrow[6].y = Round(y + j*dx);
\r
4111 Polygon( hdc, arrow, 7 );
\r
4114 /* [AS] Draw an arrow between two squares */
\r
4115 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4117 int s_x, s_y, d_x, d_y;
\r
4124 if( s_col == d_col && s_row == d_row ) {
\r
4128 /* Get source and destination points */
\r
4129 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4130 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4133 d_y += squareSize / 4;
\r
4135 else if( d_y < s_y ) {
\r
4136 d_y += 3 * squareSize / 4;
\r
4139 d_y += squareSize / 2;
\r
4143 d_x += squareSize / 4;
\r
4145 else if( d_x < s_x ) {
\r
4146 d_x += 3 * squareSize / 4;
\r
4149 d_x += squareSize / 2;
\r
4152 s_x += squareSize / 2;
\r
4153 s_y += squareSize / 2;
\r
4155 /* Adjust width */
\r
4156 A_WIDTH = squareSize / 14;
\r
4159 stLB.lbStyle = BS_SOLID;
\r
4160 stLB.lbColor = appData.highlightArrowColor;
\r
4163 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4164 holdpen = SelectObject( hdc, hpen );
\r
4165 hbrush = CreateBrushIndirect( &stLB );
\r
4166 holdbrush = SelectObject( hdc, hbrush );
\r
4168 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4170 SelectObject( hdc, holdpen );
\r
4171 SelectObject( hdc, holdbrush );
\r
4172 DeleteObject( hpen );
\r
4173 DeleteObject( hbrush );
\r
4176 BOOL HasHighlightInfo()
\r
4178 BOOL result = FALSE;
\r
4180 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4181 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4189 BOOL IsDrawArrowEnabled()
\r
4191 BOOL result = FALSE;
\r
4193 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4200 VOID DrawArrowHighlight( HDC hdc )
\r
4202 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4203 DrawArrowBetweenSquares( hdc,
\r
4204 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4205 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4209 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4211 HRGN result = NULL;
\r
4213 if( HasHighlightInfo() ) {
\r
4214 int x1, y1, x2, y2;
\r
4215 int sx, sy, dx, dy;
\r
4217 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4218 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4220 sx = MIN( x1, x2 );
\r
4221 sy = MIN( y1, y2 );
\r
4222 dx = MAX( x1, x2 ) + squareSize;
\r
4223 dy = MAX( y1, y2 ) + squareSize;
\r
4225 result = CreateRectRgn( sx, sy, dx, dy );
\r
4232 Warning: this function modifies the behavior of several other functions.
\r
4234 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4235 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4236 repaint is scattered all over the place, which is not good for features such as
\r
4237 "arrow highlighting" that require a full repaint of the board.
\r
4239 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4240 user interaction, when speed is not so important) but especially to avoid errors
\r
4241 in the displayed graphics.
\r
4243 In such patched places, I always try refer to this function so there is a single
\r
4244 place to maintain knowledge.
\r
4246 To restore the original behavior, just return FALSE unconditionally.
\r
4248 BOOL IsFullRepaintPreferrable()
\r
4250 BOOL result = FALSE;
\r
4252 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4253 /* Arrow may appear on the board */
\r
4261 This function is called by DrawPosition to know whether a full repaint must
\r
4264 Only DrawPosition may directly call this function, which makes use of
\r
4265 some state information. Other function should call DrawPosition specifying
\r
4266 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4268 BOOL DrawPositionNeedsFullRepaint()
\r
4270 BOOL result = FALSE;
\r
4273 Probably a slightly better policy would be to trigger a full repaint
\r
4274 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4275 but animation is fast enough that it's difficult to notice.
\r
4277 if( animInfo.piece == EmptySquare ) {
\r
4278 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4287 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4289 int row, column, x, y, square_color, piece_color;
\r
4290 ChessSquare piece;
\r
4292 HDC texture_hdc = NULL;
\r
4294 /* [AS] Initialize background textures if needed */
\r
4295 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4296 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4297 if( backTextureSquareSize != squareSize
\r
4298 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4299 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4300 backTextureSquareSize = squareSize;
\r
4301 RebuildTextureSquareInfo();
\r
4304 texture_hdc = CreateCompatibleDC( hdc );
\r
4307 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4308 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4310 SquareToPos(row, column, &x, &y);
\r
4312 piece = board[row][column];
\r
4314 square_color = ((column + row) % 2) == 1;
\r
4315 if( gameInfo.variant == VariantXiangqi ) {
\r
4316 square_color = !InPalace(row, column);
\r
4317 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4318 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4320 piece_color = (int) piece < (int) BlackPawn;
\r
4323 /* [HGM] holdings file: light square or black */
\r
4324 if(column == BOARD_LEFT-2) {
\r
4325 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4328 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4332 if(column == BOARD_RGHT + 1 ) {
\r
4333 if( row < gameInfo.holdingsSize )
\r
4336 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4340 if(column == BOARD_LEFT-1 ) /* left align */
\r
4341 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4342 else if( column == BOARD_RGHT) /* right align */
\r
4343 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4345 if (appData.monoMode) {
\r
4346 if (piece == EmptySquare) {
\r
4347 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4348 square_color ? WHITENESS : BLACKNESS);
\r
4350 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4353 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4354 /* [AS] Draw the square using a texture bitmap */
\r
4355 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4356 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4357 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4360 squareSize, squareSize,
\r
4363 backTextureSquareInfo[r][c].mode,
\r
4364 backTextureSquareInfo[r][c].x,
\r
4365 backTextureSquareInfo[r][c].y );
\r
4367 SelectObject( texture_hdc, hbm );
\r
4369 if (piece != EmptySquare) {
\r
4370 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4374 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4376 oldBrush = SelectObject(hdc, brush );
\r
4377 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4378 SelectObject(hdc, oldBrush);
\r
4379 if (piece != EmptySquare)
\r
4380 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4385 if( texture_hdc != NULL ) {
\r
4386 DeleteDC( texture_hdc );
\r
4390 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4391 void fputDW(FILE *f, int x)
\r
4393 fputc(x & 255, f);
\r
4394 fputc(x>>8 & 255, f);
\r
4395 fputc(x>>16 & 255, f);
\r
4396 fputc(x>>24 & 255, f);
\r
4399 #define MAX_CLIPS 200 /* more than enough */
\r
4402 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4404 // HBITMAP bufferBitmap;
\r
4409 int w = 100, h = 50;
\r
4411 if(logo == NULL) return;
\r
4412 // GetClientRect(hwndMain, &Rect);
\r
4413 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4414 // Rect.bottom-Rect.top+1);
\r
4415 tmphdc = CreateCompatibleDC(hdc);
\r
4416 hbm = SelectObject(tmphdc, logo);
\r
4417 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4421 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4422 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4423 SelectObject(tmphdc, hbm);
\r
4428 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4430 static Board lastReq, lastDrawn;
\r
4431 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4432 static int lastDrawnFlipView = 0;
\r
4433 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4434 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4437 HBITMAP bufferBitmap;
\r
4438 HBITMAP oldBitmap;
\r
4440 HRGN clips[MAX_CLIPS];
\r
4441 ChessSquare dragged_piece = EmptySquare;
\r
4443 /* I'm undecided on this - this function figures out whether a full
\r
4444 * repaint is necessary on its own, so there's no real reason to have the
\r
4445 * caller tell it that. I think this can safely be set to FALSE - but
\r
4446 * if we trust the callers not to request full repaints unnessesarily, then
\r
4447 * we could skip some clipping work. In other words, only request a full
\r
4448 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4449 * gamestart and similar) --Hawk
\r
4451 Boolean fullrepaint = repaint;
\r
4453 if( DrawPositionNeedsFullRepaint() ) {
\r
4454 fullrepaint = TRUE;
\r
4458 if( fullrepaint ) {
\r
4459 static int repaint_count = 0;
\r
4463 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4464 OutputDebugString( buf );
\r
4468 if (board == NULL) {
\r
4469 if (!lastReqValid) {
\r
4474 CopyBoard(lastReq, board);
\r
4478 if (doingSizing) {
\r
4482 if (IsIconic(hwndMain)) {
\r
4486 if (hdc == NULL) {
\r
4487 hdc = GetDC(hwndMain);
\r
4488 if (!appData.monoMode) {
\r
4489 SelectPalette(hdc, hPal, FALSE);
\r
4490 RealizePalette(hdc);
\r
4494 releaseDC = FALSE;
\r
4498 fprintf(debugFP, "*******************************\n"
\r
4500 "dragInfo.from (%d,%d)\n"
\r
4501 "dragInfo.start (%d,%d)\n"
\r
4502 "dragInfo.pos (%d,%d)\n"
\r
4503 "dragInfo.lastpos (%d,%d)\n",
\r
4504 repaint ? "TRUE" : "FALSE",
\r
4505 dragInfo.from.x, dragInfo.from.y,
\r
4506 dragInfo.start.x, dragInfo.start.y,
\r
4507 dragInfo.pos.x, dragInfo.pos.y,
\r
4508 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4509 fprintf(debugFP, "prev: ");
\r
4510 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4511 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4512 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4515 fprintf(debugFP, "\n");
\r
4516 fprintf(debugFP, "board: ");
\r
4517 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4518 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4519 fprintf(debugFP, "%d ", board[row][column]);
\r
4522 fprintf(debugFP, "\n");
\r
4526 /* Create some work-DCs */
\r
4527 hdcmem = CreateCompatibleDC(hdc);
\r
4528 tmphdc = CreateCompatibleDC(hdc);
\r
4530 /* If dragging is in progress, we temporarely remove the piece */
\r
4531 /* [HGM] or temporarily decrease count if stacked */
\r
4532 /* !! Moved to before board compare !! */
\r
4533 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4534 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4535 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4536 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4537 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4539 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4540 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4541 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4543 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4546 /* Figure out which squares need updating by comparing the
\r
4547 * newest board with the last drawn board and checking if
\r
4548 * flipping has changed.
\r
4550 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4551 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4552 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4553 if (lastDrawn[row][column] != board[row][column]) {
\r
4554 SquareToPos(row, column, &x, &y);
\r
4555 clips[num_clips++] =
\r
4556 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4560 for (i=0; i<2; i++) {
\r
4561 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4562 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4563 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4564 lastDrawnHighlight.sq[i].y >= 0) {
\r
4565 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4566 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4567 clips[num_clips++] =
\r
4568 CreateRectRgn(x - lineGap, y - lineGap,
\r
4569 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4571 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4572 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4573 clips[num_clips++] =
\r
4574 CreateRectRgn(x - lineGap, y - lineGap,
\r
4575 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4579 for (i=0; i<2; i++) {
\r
4580 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4581 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4582 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4583 lastDrawnPremove.sq[i].y >= 0) {
\r
4584 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4585 lastDrawnPremove.sq[i].x, &x, &y);
\r
4586 clips[num_clips++] =
\r
4587 CreateRectRgn(x - lineGap, y - lineGap,
\r
4588 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4590 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4591 premoveHighlightInfo.sq[i].y >= 0) {
\r
4592 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4593 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4594 clips[num_clips++] =
\r
4595 CreateRectRgn(x - lineGap, y - lineGap,
\r
4596 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4601 fullrepaint = TRUE;
\r
4604 /* Create a buffer bitmap - this is the actual bitmap
\r
4605 * being written to. When all the work is done, we can
\r
4606 * copy it to the real DC (the screen). This avoids
\r
4607 * the problems with flickering.
\r
4609 GetClientRect(hwndMain, &Rect);
\r
4610 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4611 Rect.bottom-Rect.top+1);
\r
4612 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4613 if (!appData.monoMode) {
\r
4614 SelectPalette(hdcmem, hPal, FALSE);
\r
4617 /* Create clips for dragging */
\r
4618 if (!fullrepaint) {
\r
4619 if (dragInfo.from.x >= 0) {
\r
4620 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4621 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4623 if (dragInfo.start.x >= 0) {
\r
4624 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4625 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4627 if (dragInfo.pos.x >= 0) {
\r
4628 x = dragInfo.pos.x - squareSize / 2;
\r
4629 y = dragInfo.pos.y - squareSize / 2;
\r
4630 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4632 if (dragInfo.lastpos.x >= 0) {
\r
4633 x = dragInfo.lastpos.x - squareSize / 2;
\r
4634 y = dragInfo.lastpos.y - squareSize / 2;
\r
4635 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4639 /* Are we animating a move?
\r
4641 * - remove the piece from the board (temporarely)
\r
4642 * - calculate the clipping region
\r
4644 if (!fullrepaint) {
\r
4645 if (animInfo.piece != EmptySquare) {
\r
4646 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4647 x = boardRect.left + animInfo.lastpos.x;
\r
4648 y = boardRect.top + animInfo.lastpos.y;
\r
4649 x2 = boardRect.left + animInfo.pos.x;
\r
4650 y2 = boardRect.top + animInfo.pos.y;
\r
4651 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4652 /* Slight kludge. The real problem is that after AnimateMove is
\r
4653 done, the position on the screen does not match lastDrawn.
\r
4654 This currently causes trouble only on e.p. captures in
\r
4655 atomic, where the piece moves to an empty square and then
\r
4656 explodes. The old and new positions both had an empty square
\r
4657 at the destination, but animation has drawn a piece there and
\r
4658 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4659 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4663 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4664 if (num_clips == 0)
\r
4665 fullrepaint = TRUE;
\r
4667 /* Set clipping on the memory DC */
\r
4668 if (!fullrepaint) {
\r
4669 SelectClipRgn(hdcmem, clips[0]);
\r
4670 for (x = 1; x < num_clips; x++) {
\r
4671 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4672 abort(); // this should never ever happen!
\r
4676 /* Do all the drawing to the memory DC */
\r
4677 if(explodeInfo.radius) { // [HGM] atomic
\r
4679 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4680 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4681 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4682 x += squareSize/2;
\r
4683 y += squareSize/2;
\r
4684 if(!fullrepaint) {
\r
4685 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4686 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4688 DrawGridOnDC(hdcmem);
\r
4689 DrawHighlightsOnDC(hdcmem);
\r
4690 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4691 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4692 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4693 SelectObject(hdcmem, oldBrush);
\r
4695 DrawGridOnDC(hdcmem);
\r
4696 DrawHighlightsOnDC(hdcmem);
\r
4697 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4700 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4701 if(appData.autoLogo) {
\r
4703 switch(gameMode) { // pick logos based on game mode
\r
4704 case IcsObserving:
\r
4705 whiteLogo = second.programLogo; // ICS logo
\r
4706 blackLogo = second.programLogo;
\r
4709 case IcsPlayingWhite:
\r
4710 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4711 blackLogo = second.programLogo; // ICS logo
\r
4713 case IcsPlayingBlack:
\r
4714 whiteLogo = second.programLogo; // ICS logo
\r
4715 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4717 case TwoMachinesPlay:
\r
4718 if(first.twoMachinesColor[0] == 'b') {
\r
4719 whiteLogo = second.programLogo;
\r
4720 blackLogo = first.programLogo;
\r
4723 case MachinePlaysWhite:
\r
4724 blackLogo = userLogo;
\r
4726 case MachinePlaysBlack:
\r
4727 whiteLogo = userLogo;
\r
4728 blackLogo = first.programLogo;
\r
4731 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4732 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4735 if( appData.highlightMoveWithArrow ) {
\r
4736 DrawArrowHighlight(hdcmem);
\r
4739 DrawCoordsOnDC(hdcmem);
\r
4741 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4742 /* to make sure lastDrawn contains what is actually drawn */
\r
4744 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4745 if (dragged_piece != EmptySquare) {
\r
4746 /* [HGM] or restack */
\r
4747 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4748 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4750 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4751 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4752 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4753 x = dragInfo.pos.x - squareSize / 2;
\r
4754 y = dragInfo.pos.y - squareSize / 2;
\r
4755 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4756 ((int) dragged_piece < (int) BlackPawn),
\r
4757 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4760 /* Put the animated piece back into place and draw it */
\r
4761 if (animInfo.piece != EmptySquare) {
\r
4762 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4763 x = boardRect.left + animInfo.pos.x;
\r
4764 y = boardRect.top + animInfo.pos.y;
\r
4765 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4766 ((int) animInfo.piece < (int) BlackPawn),
\r
4767 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4770 /* Release the bufferBitmap by selecting in the old bitmap
\r
4771 * and delete the memory DC
\r
4773 SelectObject(hdcmem, oldBitmap);
\r
4776 /* Set clipping on the target DC */
\r
4777 if (!fullrepaint) {
\r
4778 SelectClipRgn(hdc, clips[0]);
\r
4779 for (x = 1; x < num_clips; x++) {
\r
4780 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4781 abort(); // this should never ever happen!
\r
4785 /* Copy the new bitmap onto the screen in one go.
\r
4786 * This way we avoid any flickering
\r
4788 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4789 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4790 boardRect.right - boardRect.left,
\r
4791 boardRect.bottom - boardRect.top,
\r
4792 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4793 if(saveDiagFlag) {
\r
4794 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4795 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4797 GetObject(bufferBitmap, sizeof(b), &b);
\r
4798 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4799 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4800 bih.biWidth = b.bmWidth;
\r
4801 bih.biHeight = b.bmHeight;
\r
4803 bih.biBitCount = b.bmBitsPixel;
\r
4804 bih.biCompression = 0;
\r
4805 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4806 bih.biXPelsPerMeter = 0;
\r
4807 bih.biYPelsPerMeter = 0;
\r
4808 bih.biClrUsed = 0;
\r
4809 bih.biClrImportant = 0;
\r
4810 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4811 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4812 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4813 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4816 wb = b.bmWidthBytes;
\r
4818 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4819 int k = ((int*) pData)[i];
\r
4820 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4821 if(j >= 16) break;
\r
4823 if(j >= nrColors) nrColors = j+1;
\r
4825 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4827 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4828 for(w=0; w<(wb>>2); w+=2) {
\r
4829 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4830 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4831 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4832 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4833 pData[p++] = m | j<<4;
\r
4835 while(p&3) pData[p++] = 0;
\r
4838 wb = ((wb+31)>>5)<<2;
\r
4840 // write BITMAPFILEHEADER
\r
4841 fprintf(diagFile, "BM");
\r
4842 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4843 fputDW(diagFile, 0);
\r
4844 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4845 // write BITMAPINFOHEADER
\r
4846 fputDW(diagFile, 40);
\r
4847 fputDW(diagFile, b.bmWidth);
\r
4848 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4849 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4850 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\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 fputDW(diagFile, 0);
\r
4857 // write color table
\r
4859 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4860 // write bitmap data
\r
4861 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4862 fputc(pData[i], diagFile);
\r
4867 SelectObject(tmphdc, oldBitmap);
\r
4869 /* Massive cleanup */
\r
4870 for (x = 0; x < num_clips; x++)
\r
4871 DeleteObject(clips[x]);
\r
4874 DeleteObject(bufferBitmap);
\r
4877 ReleaseDC(hwndMain, hdc);
\r
4879 if (lastDrawnFlipView != flipView) {
\r
4881 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4883 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4886 /* CopyBoard(lastDrawn, board);*/
\r
4887 lastDrawnHighlight = highlightInfo;
\r
4888 lastDrawnPremove = premoveHighlightInfo;
\r
4889 lastDrawnFlipView = flipView;
\r
4890 lastDrawnValid = 1;
\r
4893 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4898 saveDiagFlag = 1; diagFile = f;
\r
4899 HDCDrawPosition(NULL, TRUE, NULL);
\r
4903 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4910 /*---------------------------------------------------------------------------*\
\r
4911 | CLIENT PAINT PROCEDURE
\r
4912 | This is the main event-handler for the WM_PAINT message.
\r
4914 \*---------------------------------------------------------------------------*/
\r
4916 PaintProc(HWND hwnd)
\r
4922 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4923 if (IsIconic(hwnd)) {
\r
4924 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4926 if (!appData.monoMode) {
\r
4927 SelectPalette(hdc, hPal, FALSE);
\r
4928 RealizePalette(hdc);
\r
4930 HDCDrawPosition(hdc, 1, NULL);
\r
4932 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4933 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4934 ETO_CLIPPED|ETO_OPAQUE,
\r
4935 &messageRect, messageText, strlen(messageText), NULL);
\r
4936 SelectObject(hdc, oldFont);
\r
4937 DisplayBothClocks();
\r
4939 EndPaint(hwnd,&ps);
\r
4947 * If the user selects on a border boundary, return -1; if off the board,
\r
4948 * return -2. Otherwise map the event coordinate to the square.
\r
4949 * The offset boardRect.left or boardRect.top must already have been
\r
4950 * subtracted from x.
\r
4953 EventToSquare(int x)
\r
4960 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4962 x /= (squareSize + lineGap);
\r
4963 if (x >= BOARD_SIZE)
\r
4974 DropEnable dropEnables[] = {
\r
4975 { 'P', DP_Pawn, "Pawn" },
\r
4976 { 'N', DP_Knight, "Knight" },
\r
4977 { 'B', DP_Bishop, "Bishop" },
\r
4978 { 'R', DP_Rook, "Rook" },
\r
4979 { 'Q', DP_Queen, "Queen" },
\r
4983 SetupDropMenu(HMENU hmenu)
\r
4985 int i, count, enable;
\r
4987 extern char white_holding[], black_holding[];
\r
4988 char item[MSG_SIZ];
\r
4990 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4991 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4992 dropEnables[i].piece);
\r
4994 while (p && *p++ == dropEnables[i].piece) count++;
\r
4995 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4996 enable = count > 0 || !appData.testLegality
\r
4997 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4998 && !appData.icsActive);
\r
4999 ModifyMenu(hmenu, dropEnables[i].command,
\r
5000 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
5001 dropEnables[i].command, item);
\r
5005 /* Event handler for mouse messages */
\r
5007 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5011 static int recursive = 0;
\r
5013 // BOOLEAN needsRedraw = FALSE;
\r
5014 BOOLEAN saveAnimate;
\r
5015 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
5016 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
5017 ChessMove moveType;
\r
5020 if (message == WM_MBUTTONUP) {
\r
5021 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5022 to the middle button: we simulate pressing the left button too!
\r
5024 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5025 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5031 pt.x = LOWORD(lParam);
\r
5032 pt.y = HIWORD(lParam);
\r
5033 x = EventToSquare(pt.x - boardRect.left);
\r
5034 y = EventToSquare(pt.y - boardRect.top);
\r
5035 if (!flipView && y >= 0) {
\r
5036 y = BOARD_HEIGHT - 1 - y;
\r
5038 if (flipView && x >= 0) {
\r
5039 x = BOARD_WIDTH - 1 - x;
\r
5042 switch (message) {
\r
5043 case WM_LBUTTONDOWN:
\r
5044 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5045 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5046 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5047 if(gameInfo.holdingsWidth &&
\r
5048 (WhiteOnMove(currentMove)
\r
5049 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5050 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5051 // click in right holdings, for determining promotion piece
\r
5052 ChessSquare p = boards[currentMove][y][x];
\r
5053 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5054 if(p != EmptySquare) {
\r
5055 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5056 fromX = fromY = -1;
\r
5060 DrawPosition(FALSE, boards[currentMove]);
\r
5064 sameAgain = FALSE;
\r
5066 /* Downclick vertically off board; check if on clock */
\r
5067 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5068 if (gameMode == EditPosition) {
\r
5069 SetWhiteToPlayEvent();
\r
5070 } else if (gameMode == IcsPlayingBlack ||
\r
5071 gameMode == MachinePlaysWhite) {
\r
5073 } else if (gameMode == EditGame) {
\r
5074 AdjustClock(flipClock, -1);
\r
5076 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5077 if (gameMode == EditPosition) {
\r
5078 SetBlackToPlayEvent();
\r
5079 } else if (gameMode == IcsPlayingWhite ||
\r
5080 gameMode == MachinePlaysBlack) {
\r
5082 } else if (gameMode == EditGame) {
\r
5083 AdjustClock(!flipClock, -1);
\r
5086 if (!appData.highlightLastMove) {
\r
5087 ClearHighlights();
\r
5088 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5090 fromX = fromY = -1;
\r
5091 dragInfo.start.x = dragInfo.start.y = -1;
\r
5092 dragInfo.from = dragInfo.start;
\r
5094 } else if (x < 0 || y < 0
\r
5095 /* [HGM] block clicks between board and holdings */
\r
5096 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5097 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5098 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5099 /* EditPosition, empty square, or different color piece;
\r
5100 click-click move is possible */
\r
5103 } else if (fromX == x && fromY == y) {
\r
5104 /* Downclick on same square again */
\r
5105 ClearHighlights();
\r
5106 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5107 sameAgain = TRUE;
\r
5108 } else if (fromX != -1 &&
\r
5109 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5111 /* Downclick on different square. */
\r
5112 /* [HGM] if on holdings file, should count as new first click ! */
\r
5113 /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5116 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5117 to make sure move is legal before showing promotion popup */
\r
5118 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5119 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5120 fromX = fromY = -1;
\r
5121 ClearHighlights();
\r
5122 DrawPosition(FALSE, boards[currentMove]);
\r
5125 if(moveType != ImpossibleMove) {
\r
5126 if(moveType == IllegalMove) {
\r
5129 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5130 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5131 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5132 appData.alwaysPromoteToQueen)) {
\r
5133 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5134 if (!appData.highlightLastMove) {
\r
5135 ClearHighlights();
\r
5136 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5139 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5140 SetHighlights(fromX, fromY, toX, toY);
\r
5141 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5142 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5143 If promotion to Q is legal, all are legal! */
\r
5144 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5145 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5146 // kludge to temporarily execute move on display, without promoting yet
\r
5147 promotionChoice = TRUE;
\r
5148 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5149 boards[currentMove][toY][toX] = p;
\r
5150 DrawPosition(FALSE, boards[currentMove]);
\r
5151 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5152 boards[currentMove][toY][toX] = q;
\r
5154 PromotionPopup(hwnd);
\r
5155 } else { /* not a promotion */
\r
5156 if (appData.animate || appData.highlightLastMove) {
\r
5157 SetHighlights(fromX, fromY, toX, toY);
\r
5159 ClearHighlights();
\r
5161 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5162 if (appData.animate && !appData.highlightLastMove) {
\r
5163 ClearHighlights();
\r
5164 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5167 fromX = fromY = -1;
\r
5171 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5172 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5173 } else ClearHighlights();
\r
5174 fromX = fromY = -1;
\r
5175 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5177 /* First downclick, or restart on a square with same color piece */
\r
5178 if (!frozen && OKToStartUserMove(x, y)) {
\r
5181 dragInfo.lastpos = pt;
\r
5182 dragInfo.from.x = fromX;
\r
5183 dragInfo.from.y = fromY;
\r
5184 dragInfo.start = dragInfo.from;
\r
5185 SetCapture(hwndMain);
\r
5187 fromX = fromY = -1;
\r
5188 dragInfo.start.x = dragInfo.start.y = -1;
\r
5189 dragInfo.from = dragInfo.start;
\r
5190 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5194 case WM_LBUTTONUP:
\r
5196 if (fromX == -1) break;
\r
5197 if (x == fromX && y == fromY) {
\r
5198 dragInfo.from.x = dragInfo.from.y = -1;
\r
5199 /* Upclick on same square */
\r
5201 /* Clicked same square twice: abort click-click move */
\r
5202 fromX = fromY = -1;
\r
5204 ClearPremoveHighlights();
\r
5206 /* First square clicked: start click-click move */
\r
5207 SetHighlights(fromX, fromY, -1, -1);
\r
5209 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5210 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5211 /* Errant click; ignore */
\r
5214 /* Finish drag move. */
\r
5215 if (appData.debugMode) {
\r
5216 fprintf(debugFP, "release\n");
\r
5218 dragInfo.from.x = dragInfo.from.y = -1;
\r
5221 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5222 appData.animate = appData.animate && !appData.animateDragging;
\r
5223 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5224 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5225 fromX = fromY = -1;
\r
5226 ClearHighlights();
\r
5227 DrawPosition(FALSE, boards[currentMove]);
\r
5228 appData.animate = saveAnimate;
\r
5231 if(moveType != ImpossibleMove) {
\r
5232 /* [HGM] use move type to determine if move is promotion.
\r
5233 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5234 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5235 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5236 appData.alwaysPromoteToQueen))
\r
5237 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5239 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5240 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5241 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5242 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5243 // kludge to temporarily execute move on display, wthout promotng yet
\r
5244 promotionChoice = TRUE;
\r
5245 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5246 boards[currentMove][toY][toX] = p;
\r
5247 DrawPosition(FALSE, boards[currentMove]);
\r
5248 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5249 boards[currentMove][toY][toX] = q;
\r
5250 appData.animate = saveAnimate;
\r
5253 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5255 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5256 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5257 moveType == WhiteCapturesEnPassant ||
\r
5258 moveType == BlackCapturesEnPassant ) )
\r
5259 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5260 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5263 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5264 appData.animate = saveAnimate;
\r
5265 fromX = fromY = -1;
\r
5266 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5267 ClearHighlights();
\r
5269 if (appData.animate || appData.animateDragging ||
\r
5270 appData.highlightDragging || gotPremove) {
\r
5271 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5274 dragInfo.start.x = dragInfo.start.y = -1;
\r
5275 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5278 case WM_MOUSEMOVE:
\r
5279 if ((appData.animateDragging || appData.highlightDragging)
\r
5280 && (wParam & MK_LBUTTON)
\r
5281 && dragInfo.from.x >= 0)
\r
5283 BOOL full_repaint = FALSE;
\r
5285 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5286 if (appData.animateDragging) {
\r
5287 dragInfo.pos = pt;
\r
5289 if (appData.highlightDragging) {
\r
5290 SetHighlights(fromX, fromY, x, y);
\r
5291 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5292 full_repaint = TRUE;
\r
5296 DrawPosition( full_repaint, NULL);
\r
5298 dragInfo.lastpos = dragInfo.pos;
\r
5302 case WM_MOUSEWHEEL: // [DM]
\r
5303 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5304 /* Mouse Wheel is being rolled forward
\r
5305 * Play moves forward
\r
5307 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5308 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5309 /* Mouse Wheel is being rolled backward
\r
5310 * Play moves backward
\r
5312 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5313 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5317 case WM_MBUTTONDOWN:
\r
5318 case WM_RBUTTONDOWN:
\r
5321 fromX = fromY = -1;
\r
5322 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5323 dragInfo.start.x = dragInfo.start.y = -1;
\r
5324 dragInfo.from = dragInfo.start;
\r
5325 dragInfo.lastpos = dragInfo.pos;
\r
5326 if (appData.highlightDragging) {
\r
5327 ClearHighlights();
\r
5330 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5331 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5332 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5333 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5334 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5337 DrawPosition(TRUE, NULL);
\r
5339 switch (gameMode) {
\r
5340 case EditPosition:
\r
5341 case IcsExamining:
\r
5342 if (x < 0 || y < 0) break;
\r
5345 if (message == WM_MBUTTONDOWN) {
\r
5346 buttonCount = 3; /* even if system didn't think so */
\r
5347 if (wParam & MK_SHIFT)
\r
5348 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5350 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5351 } else { /* message == WM_RBUTTONDOWN */
\r
5353 if (buttonCount == 3) {
\r
5354 if (wParam & MK_SHIFT)
\r
5355 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5357 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5359 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5362 /* Just have one menu, on the right button. Windows users don't
\r
5363 think to try the middle one, and sometimes other software steals
\r
5364 it, or it doesn't really exist. */
\r
5365 if(gameInfo.variant != VariantShogi)
\r
5366 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5368 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5372 case IcsPlayingWhite:
\r
5373 case IcsPlayingBlack:
\r
5375 case MachinePlaysWhite:
\r
5376 case MachinePlaysBlack:
\r
5377 if (appData.testLegality &&
\r
5378 gameInfo.variant != VariantBughouse &&
\r
5379 gameInfo.variant != VariantCrazyhouse) break;
\r
5380 if (x < 0 || y < 0) break;
\r
5383 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5384 SetupDropMenu(hmenu);
\r
5385 MenuPopup(hwnd, pt, hmenu, -1);
\r
5396 /* Preprocess messages for buttons in main window */
\r
5398 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5400 int id = GetWindowLong(hwnd, GWL_ID);
\r
5403 for (i=0; i<N_BUTTONS; i++) {
\r
5404 if (buttonDesc[i].id == id) break;
\r
5406 if (i == N_BUTTONS) return 0;
\r
5407 switch (message) {
\r
5412 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5413 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5420 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5423 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5424 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5425 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5426 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5428 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5430 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5431 PopUpMoveDialog((char)wParam);
\r
5437 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5440 /* Process messages for Promotion dialog box */
\r
5442 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5446 switch (message) {
\r
5447 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5448 /* Center the dialog over the application window */
\r
5449 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5450 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5451 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5452 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5453 SW_SHOW : SW_HIDE);
\r
5454 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5455 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5456 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5457 PieceToChar(WhiteAngel) != '~') ||
\r
5458 (PieceToChar(BlackAngel) >= 'A' &&
\r
5459 PieceToChar(BlackAngel) != '~') ) ?
\r
5460 SW_SHOW : SW_HIDE);
\r
5461 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5462 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5463 PieceToChar(WhiteMarshall) != '~') ||
\r
5464 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5465 PieceToChar(BlackMarshall) != '~') ) ?
\r
5466 SW_SHOW : SW_HIDE);
\r
5467 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5468 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5469 gameInfo.variant != VariantShogi ?
\r
5470 SW_SHOW : SW_HIDE);
\r
5471 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5472 gameInfo.variant != VariantShogi ?
\r
5473 SW_SHOW : SW_HIDE);
\r
5474 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5475 gameInfo.variant == VariantShogi ?
\r
5476 SW_SHOW : SW_HIDE);
\r
5477 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5478 gameInfo.variant == VariantShogi ?
\r
5479 SW_SHOW : SW_HIDE);
\r
5480 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5481 gameInfo.variant == VariantSuper ?
\r
5482 SW_SHOW : SW_HIDE);
\r
5485 case WM_COMMAND: /* message: received a command */
\r
5486 switch (LOWORD(wParam)) {
\r
5488 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5489 ClearHighlights();
\r
5490 DrawPosition(FALSE, NULL);
\r
5493 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5496 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5499 promoChar = PieceToChar(BlackRook);
\r
5502 promoChar = PieceToChar(BlackBishop);
\r
5504 case PB_Chancellor:
\r
5505 promoChar = PieceToChar(BlackMarshall);
\r
5507 case PB_Archbishop:
\r
5508 promoChar = PieceToChar(BlackAngel);
\r
5511 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5516 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5517 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5518 only show the popup when we are already sure the move is valid or
\r
5519 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5520 will figure out it is a promotion from the promoChar. */
\r
5521 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5522 if (!appData.highlightLastMove) {
\r
5523 ClearHighlights();
\r
5524 DrawPosition(FALSE, NULL);
\r
5531 /* Pop up promotion dialog */
\r
5533 PromotionPopup(HWND hwnd)
\r
5537 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5538 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5539 hwnd, (DLGPROC)lpProc);
\r
5540 FreeProcInstance(lpProc);
\r
5543 /* Toggle ShowThinking */
\r
5545 ToggleShowThinking()
\r
5547 appData.showThinking = !appData.showThinking;
\r
5548 ShowThinkingEvent();
\r
5552 LoadGameDialog(HWND hwnd, char* title)
\r
5556 char fileTitle[MSG_SIZ];
\r
5557 f = OpenFileDialog(hwnd, "rb", "",
\r
5558 appData.oldSaveStyle ? "gam" : "pgn",
\r
5560 title, &number, fileTitle, NULL);
\r
5562 cmailMsgLoaded = FALSE;
\r
5563 if (number == 0) {
\r
5564 int error = GameListBuild(f);
\r
5566 DisplayError("Cannot build game list", error);
\r
5567 } else if (!ListEmpty(&gameList) &&
\r
5568 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5569 GameListPopUp(f, fileTitle);
\r
5572 GameListDestroy();
\r
5575 LoadGame(f, number, fileTitle, FALSE);
\r
5580 ChangedConsoleFont()
\r
5583 CHARRANGE tmpsel, sel;
\r
5584 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5585 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5586 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5589 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5590 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5591 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5592 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5593 * size. This was undocumented in the version of MSVC++ that I had
\r
5594 * when I wrote the code, but is apparently documented now.
\r
5596 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5597 cfmt.bCharSet = f->lf.lfCharSet;
\r
5598 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5599 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5600 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5601 /* Why are the following seemingly needed too? */
\r
5602 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5603 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5604 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5606 tmpsel.cpMax = -1; /*999999?*/
\r
5607 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5608 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5609 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5610 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5612 paraf.cbSize = sizeof(paraf);
\r
5613 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5614 paraf.dxStartIndent = 0;
\r
5615 paraf.dxOffset = WRAP_INDENT;
\r
5616 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5617 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5620 /*---------------------------------------------------------------------------*\
\r
5622 * Window Proc for main window
\r
5624 \*---------------------------------------------------------------------------*/
\r
5626 /* Process messages for main window, etc. */
\r
5628 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5631 int wmId, wmEvent;
\r
5635 char fileTitle[MSG_SIZ];
\r
5636 char buf[MSG_SIZ];
\r
5637 static SnapData sd;
\r
5639 switch (message) {
\r
5641 case WM_PAINT: /* message: repaint portion of window */
\r
5645 case WM_ERASEBKGND:
\r
5646 if (IsIconic(hwnd)) {
\r
5647 /* Cheat; change the message */
\r
5648 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5650 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5654 case WM_LBUTTONDOWN:
\r
5655 case WM_MBUTTONDOWN:
\r
5656 case WM_RBUTTONDOWN:
\r
5657 case WM_LBUTTONUP:
\r
5658 case WM_MBUTTONUP:
\r
5659 case WM_RBUTTONUP:
\r
5660 case WM_MOUSEMOVE:
\r
5661 case WM_MOUSEWHEEL:
\r
5662 MouseEvent(hwnd, message, wParam, lParam);
\r
5665 JAWS_KB_NAVIGATION
\r
5669 JAWS_ALT_INTERCEPT
\r
5671 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5672 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5673 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5674 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5676 SendMessage(h, message, wParam, lParam);
\r
5677 } else if(lParam != KF_REPEAT) {
\r
5678 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5679 PopUpMoveDialog((char)wParam);
\r
5680 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5681 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5686 case WM_PALETTECHANGED:
\r
5687 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5689 HDC hdc = GetDC(hwndMain);
\r
5690 SelectPalette(hdc, hPal, TRUE);
\r
5691 nnew = RealizePalette(hdc);
\r
5693 paletteChanged = TRUE;
\r
5695 UpdateColors(hdc);
\r
5697 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5700 ReleaseDC(hwnd, hdc);
\r
5704 case WM_QUERYNEWPALETTE:
\r
5705 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5707 HDC hdc = GetDC(hwndMain);
\r
5708 paletteChanged = FALSE;
\r
5709 SelectPalette(hdc, hPal, FALSE);
\r
5710 nnew = RealizePalette(hdc);
\r
5712 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5714 ReleaseDC(hwnd, hdc);
\r
5719 case WM_COMMAND: /* message: command from application menu */
\r
5720 wmId = LOWORD(wParam);
\r
5721 wmEvent = HIWORD(wParam);
\r
5726 AnalysisPopDown();
\r
5727 SAY("new game enter a move to play against the computer with white");
\r
5730 case IDM_NewGameFRC:
\r
5731 if( NewGameFRC() == 0 ) {
\r
5733 AnalysisPopDown();
\r
5737 case IDM_NewVariant:
\r
5738 NewVariantPopup(hwnd);
\r
5741 case IDM_LoadGame:
\r
5742 LoadGameDialog(hwnd, "Load Game from File");
\r
5745 case IDM_LoadNextGame:
\r
5749 case IDM_LoadPrevGame:
\r
5753 case IDM_ReloadGame:
\r
5757 case IDM_LoadPosition:
\r
5758 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5759 Reset(FALSE, TRUE);
\r
5762 f = OpenFileDialog(hwnd, "rb", "",
\r
5763 appData.oldSaveStyle ? "pos" : "fen",
\r
5765 "Load Position from File", &number, fileTitle, NULL);
\r
5767 LoadPosition(f, number, fileTitle);
\r
5771 case IDM_LoadNextPosition:
\r
5772 ReloadPosition(1);
\r
5775 case IDM_LoadPrevPosition:
\r
5776 ReloadPosition(-1);
\r
5779 case IDM_ReloadPosition:
\r
5780 ReloadPosition(0);
\r
5783 case IDM_SaveGame:
\r
5784 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5785 f = OpenFileDialog(hwnd, "a", defName,
\r
5786 appData.oldSaveStyle ? "gam" : "pgn",
\r
5788 "Save Game to File", NULL, fileTitle, NULL);
\r
5790 SaveGame(f, 0, "");
\r
5794 case IDM_SavePosition:
\r
5795 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5796 f = OpenFileDialog(hwnd, "a", defName,
\r
5797 appData.oldSaveStyle ? "pos" : "fen",
\r
5799 "Save Position to File", NULL, fileTitle, NULL);
\r
5801 SavePosition(f, 0, "");
\r
5805 case IDM_SaveDiagram:
\r
5806 defName = "diagram";
\r
5807 f = OpenFileDialog(hwnd, "wb", defName,
\r
5810 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5816 case IDM_CopyGame:
\r
5817 CopyGameToClipboard();
\r
5820 case IDM_PasteGame:
\r
5821 PasteGameFromClipboard();
\r
5824 case IDM_CopyGameListToClipboard:
\r
5825 CopyGameListToClipboard();
\r
5828 /* [AS] Autodetect FEN or PGN data */
\r
5829 case IDM_PasteAny:
\r
5830 PasteGameOrFENFromClipboard();
\r
5833 /* [AS] Move history */
\r
5834 case IDM_ShowMoveHistory:
\r
5835 if( MoveHistoryIsUp() ) {
\r
5836 MoveHistoryPopDown();
\r
5839 MoveHistoryPopUp();
\r
5843 /* [AS] Eval graph */
\r
5844 case IDM_ShowEvalGraph:
\r
5845 if( EvalGraphIsUp() ) {
\r
5846 EvalGraphPopDown();
\r
5850 SetFocus(hwndMain);
\r
5854 /* [AS] Engine output */
\r
5855 case IDM_ShowEngineOutput:
\r
5856 if( EngineOutputIsUp() ) {
\r
5857 EngineOutputPopDown();
\r
5860 EngineOutputPopUp();
\r
5864 /* [AS] User adjudication */
\r
5865 case IDM_UserAdjudication_White:
\r
5866 UserAdjudicationEvent( +1 );
\r
5869 case IDM_UserAdjudication_Black:
\r
5870 UserAdjudicationEvent( -1 );
\r
5873 case IDM_UserAdjudication_Draw:
\r
5874 UserAdjudicationEvent( 0 );
\r
5877 /* [AS] Game list options dialog */
\r
5878 case IDM_GameListOptions:
\r
5879 GameListOptions();
\r
5886 case IDM_CopyPosition:
\r
5887 CopyFENToClipboard();
\r
5890 case IDM_PastePosition:
\r
5891 PasteFENFromClipboard();
\r
5894 case IDM_MailMove:
\r
5898 case IDM_ReloadCMailMsg:
\r
5899 Reset(TRUE, TRUE);
\r
5900 ReloadCmailMsgEvent(FALSE);
\r
5903 case IDM_Minimize:
\r
5904 ShowWindow(hwnd, SW_MINIMIZE);
\r
5911 case IDM_MachineWhite:
\r
5912 MachineWhiteEvent();
\r
5914 * refresh the tags dialog only if it's visible
\r
5916 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5918 tags = PGNTags(&gameInfo);
\r
5919 TagsPopUp(tags, CmailMsg());
\r
5922 SAY("computer starts playing white");
\r
5925 case IDM_MachineBlack:
\r
5926 MachineBlackEvent();
\r
5928 * refresh the tags dialog only if it's visible
\r
5930 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5932 tags = PGNTags(&gameInfo);
\r
5933 TagsPopUp(tags, CmailMsg());
\r
5936 SAY("computer starts playing black");
\r
5939 case IDM_TwoMachines:
\r
5940 TwoMachinesEvent();
\r
5942 * refresh the tags dialog only if it's visible
\r
5944 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5946 tags = PGNTags(&gameInfo);
\r
5947 TagsPopUp(tags, CmailMsg());
\r
5950 SAY("programs start playing each other");
\r
5953 case IDM_AnalysisMode:
\r
5954 if (!first.analysisSupport) {
\r
5955 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5956 DisplayError(buf, 0);
\r
5958 SAY("analyzing current position");
\r
5959 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5960 if (appData.icsActive) {
\r
5961 if (gameMode != IcsObserving) {
\r
5962 sprintf(buf, "You are not observing a game");
\r
5963 DisplayError(buf, 0);
\r
5964 /* secure check */
\r
5965 if (appData.icsEngineAnalyze) {
\r
5966 if (appData.debugMode)
\r
5967 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5968 ExitAnalyzeMode();
\r
5974 /* if enable, user want disable icsEngineAnalyze */
\r
5975 if (appData.icsEngineAnalyze) {
\r
5976 ExitAnalyzeMode();
\r
5980 appData.icsEngineAnalyze = TRUE;
\r
5981 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5984 if (!appData.showThinking) ToggleShowThinking();
\r
5985 AnalyzeModeEvent();
\r
5989 case IDM_AnalyzeFile:
\r
5990 if (!first.analysisSupport) {
\r
5991 char buf[MSG_SIZ];
\r
5992 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5993 DisplayError(buf, 0);
\r
5995 if (!appData.showThinking) ToggleShowThinking();
\r
5996 AnalyzeFileEvent();
\r
5997 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5998 AnalysisPeriodicEvent(1);
\r
6002 case IDM_IcsClient:
\r
6006 case IDM_EditGame:
\r
6011 case IDM_EditPosition:
\r
6012 EditPositionEvent();
\r
6013 SAY("to set up a position type a FEN");
\r
6016 case IDM_Training:
\r
6020 case IDM_ShowGameList:
\r
6021 ShowGameListProc();
\r
6024 case IDM_EditTags:
\r
6028 case IDM_EditComment:
\r
6029 if (commentDialogUp && editComment) {
\r
6032 EditCommentEvent();
\r
6052 case IDM_CallFlag:
\r
6072 case IDM_StopObserving:
\r
6073 StopObservingEvent();
\r
6076 case IDM_StopExamining:
\r
6077 StopExaminingEvent();
\r
6080 case IDM_TypeInMove:
\r
6081 PopUpMoveDialog('\000');
\r
6084 case IDM_TypeInName:
\r
6085 PopUpNameDialog('\000');
\r
6088 case IDM_Backward:
\r
6090 SetFocus(hwndMain);
\r
6097 SetFocus(hwndMain);
\r
6102 SetFocus(hwndMain);
\r
6107 SetFocus(hwndMain);
\r
6114 case IDM_TruncateGame:
\r
6115 TruncateGameEvent();
\r
6122 case IDM_RetractMove:
\r
6123 RetractMoveEvent();
\r
6126 case IDM_FlipView:
\r
6127 flipView = !flipView;
\r
6128 DrawPosition(FALSE, NULL);
\r
6131 case IDM_FlipClock:
\r
6132 flipClock = !flipClock;
\r
6133 DisplayBothClocks();
\r
6134 DrawPosition(FALSE, NULL);
\r
6137 case IDM_MuteSounds:
\r
6138 mute = !mute; // [HGM] mute: keep track of global muting variable
\r
6139 CheckMenuItem(GetMenu(hwndMain),IDM_MuteSounds,
\r
6140 MF_BYCOMMAND|(mute?MF_CHECKED:MF_UNCHECKED));
\r
6143 case IDM_GeneralOptions:
\r
6144 GeneralOptionsPopup(hwnd);
\r
6145 DrawPosition(TRUE, NULL);
\r
6148 case IDM_BoardOptions:
\r
6149 BoardOptionsPopup(hwnd);
\r
6152 case IDM_EnginePlayOptions:
\r
6153 EnginePlayOptionsPopup(hwnd);
\r
6156 case IDM_Engine1Options:
\r
6157 EngineOptionsPopup(hwnd, &first);
\r
6160 case IDM_Engine2Options:
\r
6161 EngineOptionsPopup(hwnd, &second);
\r
6164 case IDM_OptionsUCI:
\r
6165 UciOptionsPopup(hwnd);
\r
6168 case IDM_IcsOptions:
\r
6169 IcsOptionsPopup(hwnd);
\r
6173 FontsOptionsPopup(hwnd);
\r
6177 SoundOptionsPopup(hwnd);
\r
6180 case IDM_CommPort:
\r
6181 CommPortOptionsPopup(hwnd);
\r
6184 case IDM_LoadOptions:
\r
6185 LoadOptionsPopup(hwnd);
\r
6188 case IDM_SaveOptions:
\r
6189 SaveOptionsPopup(hwnd);
\r
6192 case IDM_TimeControl:
\r
6193 TimeControlOptionsPopup(hwnd);
\r
6196 case IDM_SaveSettings:
\r
6197 SaveSettings(settingsFileName);
\r
6200 case IDM_SaveSettingsOnExit:
\r
6201 saveSettingsOnExit = !saveSettingsOnExit;
\r
6202 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6203 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6204 MF_CHECKED : MF_UNCHECKED));
\r
6215 case IDM_AboutGame:
\r
6220 appData.debugMode = !appData.debugMode;
\r
6221 if (appData.debugMode) {
\r
6222 char dir[MSG_SIZ];
\r
6223 GetCurrentDirectory(MSG_SIZ, dir);
\r
6224 SetCurrentDirectory(installDir);
\r
6225 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6226 SetCurrentDirectory(dir);
\r
6227 setbuf(debugFP, NULL);
\r
6234 case IDM_HELPCONTENTS:
\r
6235 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6236 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6237 MessageBox (GetFocus(),
\r
6238 "Unable to activate help",
\r
6239 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6243 case IDM_HELPSEARCH:
\r
6244 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\r
6245 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6246 MessageBox (GetFocus(),
\r
6247 "Unable to activate help",
\r
6248 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6252 case IDM_HELPHELP:
\r
6253 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6254 MessageBox (GetFocus(),
\r
6255 "Unable to activate help",
\r
6256 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6261 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6263 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6264 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6265 FreeProcInstance(lpProc);
\r
6268 case IDM_DirectCommand1:
\r
6269 AskQuestionEvent("Direct Command",
\r
6270 "Send to chess program:", "", "1");
\r
6272 case IDM_DirectCommand2:
\r
6273 AskQuestionEvent("Direct Command",
\r
6274 "Send to second chess program:", "", "2");
\r
6277 case EP_WhitePawn:
\r
6278 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6279 fromX = fromY = -1;
\r
6282 case EP_WhiteKnight:
\r
6283 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6284 fromX = fromY = -1;
\r
6287 case EP_WhiteBishop:
\r
6288 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6289 fromX = fromY = -1;
\r
6292 case EP_WhiteRook:
\r
6293 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6294 fromX = fromY = -1;
\r
6297 case EP_WhiteQueen:
\r
6298 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6299 fromX = fromY = -1;
\r
6302 case EP_WhiteFerz:
\r
6303 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6304 fromX = fromY = -1;
\r
6307 case EP_WhiteWazir:
\r
6308 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6309 fromX = fromY = -1;
\r
6312 case EP_WhiteAlfil:
\r
6313 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6314 fromX = fromY = -1;
\r
6317 case EP_WhiteCannon:
\r
6318 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6319 fromX = fromY = -1;
\r
6322 case EP_WhiteCardinal:
\r
6323 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6324 fromX = fromY = -1;
\r
6327 case EP_WhiteMarshall:
\r
6328 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6329 fromX = fromY = -1;
\r
6332 case EP_WhiteKing:
\r
6333 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6334 fromX = fromY = -1;
\r
6337 case EP_BlackPawn:
\r
6338 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6339 fromX = fromY = -1;
\r
6342 case EP_BlackKnight:
\r
6343 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6344 fromX = fromY = -1;
\r
6347 case EP_BlackBishop:
\r
6348 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6349 fromX = fromY = -1;
\r
6352 case EP_BlackRook:
\r
6353 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6354 fromX = fromY = -1;
\r
6357 case EP_BlackQueen:
\r
6358 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6359 fromX = fromY = -1;
\r
6362 case EP_BlackFerz:
\r
6363 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6364 fromX = fromY = -1;
\r
6367 case EP_BlackWazir:
\r
6368 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6369 fromX = fromY = -1;
\r
6372 case EP_BlackAlfil:
\r
6373 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6374 fromX = fromY = -1;
\r
6377 case EP_BlackCannon:
\r
6378 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6379 fromX = fromY = -1;
\r
6382 case EP_BlackCardinal:
\r
6383 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6384 fromX = fromY = -1;
\r
6387 case EP_BlackMarshall:
\r
6388 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6389 fromX = fromY = -1;
\r
6392 case EP_BlackKing:
\r
6393 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6394 fromX = fromY = -1;
\r
6397 case EP_EmptySquare:
\r
6398 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6399 fromX = fromY = -1;
\r
6402 case EP_ClearBoard:
\r
6403 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6404 fromX = fromY = -1;
\r
6408 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6409 fromX = fromY = -1;
\r
6413 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6414 fromX = fromY = -1;
\r
6418 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6419 fromX = fromY = -1;
\r
6423 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6424 fromX = fromY = -1;
\r
6428 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6429 fromX = fromY = -1;
\r
6433 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6434 fromX = fromY = -1;
\r
6438 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6439 fromX = fromY = -1;
\r
6443 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6444 fromX = fromY = -1;
\r
6448 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6449 fromX = fromY = -1;
\r
6453 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6459 case CLOCK_TIMER_ID:
\r
6460 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6461 clockTimerEvent = 0;
\r
6462 DecrementClocks(); /* call into back end */
\r
6464 case LOAD_GAME_TIMER_ID:
\r
6465 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6466 loadGameTimerEvent = 0;
\r
6467 AutoPlayGameLoop(); /* call into back end */
\r
6469 case ANALYSIS_TIMER_ID:
\r
6470 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6471 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6472 AnalysisPeriodicEvent(0);
\r
6474 KillTimer(hwnd, analysisTimerEvent);
\r
6475 analysisTimerEvent = 0;
\r
6478 case DELAYED_TIMER_ID:
\r
6479 KillTimer(hwnd, delayedTimerEvent);
\r
6480 delayedTimerEvent = 0;
\r
6481 delayedTimerCallback();
\r
6486 case WM_USER_Input:
\r
6487 InputEvent(hwnd, message, wParam, lParam);
\r
6490 /* [AS] Also move "attached" child windows */
\r
6491 case WM_WINDOWPOSCHANGING:
\r
6493 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6494 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6496 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6497 /* Window is moving */
\r
6500 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6501 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6502 rcMain.right = boardX + winWidth;
\r
6503 rcMain.top = boardY;
\r
6504 rcMain.bottom = boardY + winHeight;
\r
6506 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6507 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6508 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6509 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6510 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6517 /* [AS] Snapping */
\r
6518 case WM_ENTERSIZEMOVE:
\r
6519 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6520 if (hwnd == hwndMain) {
\r
6521 doingSizing = TRUE;
\r
6524 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6528 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6529 if (hwnd == hwndMain) {
\r
6530 lastSizing = wParam;
\r
6535 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6536 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6538 case WM_EXITSIZEMOVE:
\r
6539 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6540 if (hwnd == hwndMain) {
\r
6542 doingSizing = FALSE;
\r
6543 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6544 GetClientRect(hwnd, &client);
\r
6545 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6547 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6549 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6552 case WM_DESTROY: /* message: window being destroyed */
\r
6553 PostQuitMessage(0);
\r
6557 if (hwnd == hwndMain) {
\r
6562 default: /* Passes it on if unprocessed */
\r
6563 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6568 /*---------------------------------------------------------------------------*\
\r
6570 * Misc utility routines
\r
6572 \*---------------------------------------------------------------------------*/
\r
6575 * Decent random number generator, at least not as bad as Windows
\r
6576 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6578 unsigned int randstate;
\r
6583 randstate = randstate * 1664525 + 1013904223;
\r
6584 return (int) randstate & 0x7fffffff;
\r
6588 mysrandom(unsigned int seed)
\r
6595 * returns TRUE if user selects a different color, FALSE otherwise
\r
6599 ChangeColor(HWND hwnd, COLORREF *which)
\r
6601 static BOOL firstTime = TRUE;
\r
6602 static DWORD customColors[16];
\r
6604 COLORREF newcolor;
\r
6609 /* Make initial colors in use available as custom colors */
\r
6610 /* Should we put the compiled-in defaults here instead? */
\r
6612 customColors[i++] = lightSquareColor & 0xffffff;
\r
6613 customColors[i++] = darkSquareColor & 0xffffff;
\r
6614 customColors[i++] = whitePieceColor & 0xffffff;
\r
6615 customColors[i++] = blackPieceColor & 0xffffff;
\r
6616 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6617 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6619 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6620 customColors[i++] = textAttribs[ccl].color;
\r
6622 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6623 firstTime = FALSE;
\r
6626 cc.lStructSize = sizeof(cc);
\r
6627 cc.hwndOwner = hwnd;
\r
6628 cc.hInstance = NULL;
\r
6629 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6630 cc.lpCustColors = (LPDWORD) customColors;
\r
6631 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6633 if (!ChooseColor(&cc)) return FALSE;
\r
6635 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6636 if (newcolor == *which) return FALSE;
\r
6637 *which = newcolor;
\r
6641 InitDrawingColors();
\r
6642 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6647 MyLoadSound(MySound *ms)
\r
6653 if (ms->data) free(ms->data);
\r
6656 switch (ms->name[0]) {
\r
6662 /* System sound from Control Panel. Don't preload here. */
\r
6666 if (ms->name[1] == NULLCHAR) {
\r
6667 /* "!" alone = silence */
\r
6670 /* Builtin wave resource. Error if not found. */
\r
6671 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6672 if (h == NULL) break;
\r
6673 ms->data = (void *)LoadResource(hInst, h);
\r
6674 if (h == NULL) break;
\r
6679 /* .wav file. Error if not found. */
\r
6680 f = fopen(ms->name, "rb");
\r
6681 if (f == NULL) break;
\r
6682 if (fstat(fileno(f), &st) < 0) break;
\r
6683 ms->data = malloc(st.st_size);
\r
6684 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6690 char buf[MSG_SIZ];
\r
6691 sprintf(buf, "Error loading sound %s", ms->name);
\r
6692 DisplayError(buf, GetLastError());
\r
6698 MyPlaySound(MySound *ms)
\r
6700 BOOLEAN ok = FALSE;
\r
6702 if(mute) return TRUE; // [HGM] mute: suppress all sound play when muted
\r
6703 switch (ms->name[0]) {
\r
6705 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6710 /* System sound from Control Panel (deprecated feature).
\r
6711 "$" alone or an unset sound name gets default beep (still in use). */
\r
6712 if (ms->name[1]) {
\r
6713 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6715 if (!ok) ok = MessageBeep(MB_OK);
\r
6718 /* Builtin wave resource, or "!" alone for silence */
\r
6719 if (ms->name[1]) {
\r
6720 if (ms->data == NULL) return FALSE;
\r
6721 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6727 /* .wav file. Error if not found. */
\r
6728 if (ms->data == NULL) return FALSE;
\r
6729 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6732 /* Don't print an error: this can happen innocently if the sound driver
\r
6733 is busy; for instance, if another instance of WinBoard is playing
\r
6734 a sound at about the same time. */
\r
6737 char buf[MSG_SIZ];
\r
6738 sprintf(buf, "Error playing sound %s", ms->name);
\r
6739 DisplayError(buf, GetLastError());
\r
6747 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6750 OPENFILENAME *ofn;
\r
6751 static UINT *number; /* gross that this is static */
\r
6753 switch (message) {
\r
6754 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6755 /* Center the dialog over the application window */
\r
6756 ofn = (OPENFILENAME *) lParam;
\r
6757 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6758 number = (UINT *) ofn->lCustData;
\r
6759 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6763 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6764 return FALSE; /* Allow for further processing */
\r
6767 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6768 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6770 return FALSE; /* Allow for further processing */
\r
6776 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6778 static UINT *number;
\r
6779 OPENFILENAME *ofname;
\r
6782 case WM_INITDIALOG:
\r
6783 ofname = (OPENFILENAME *)lParam;
\r
6784 number = (UINT *)(ofname->lCustData);
\r
6787 ofnot = (OFNOTIFY *)lParam;
\r
6788 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6789 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6798 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6799 char *nameFilt, char *dlgTitle, UINT *number,
\r
6800 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6802 OPENFILENAME openFileName;
\r
6803 char buf1[MSG_SIZ];
\r
6806 if (fileName == NULL) fileName = buf1;
\r
6807 if (defName == NULL) {
\r
6808 strcpy(fileName, "*.");
\r
6809 strcat(fileName, defExt);
\r
6811 strcpy(fileName, defName);
\r
6813 if (fileTitle) strcpy(fileTitle, "");
\r
6814 if (number) *number = 0;
\r
6816 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6817 openFileName.hwndOwner = hwnd;
\r
6818 openFileName.hInstance = (HANDLE) hInst;
\r
6819 openFileName.lpstrFilter = nameFilt;
\r
6820 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6821 openFileName.nMaxCustFilter = 0L;
\r
6822 openFileName.nFilterIndex = 1L;
\r
6823 openFileName.lpstrFile = fileName;
\r
6824 openFileName.nMaxFile = MSG_SIZ;
\r
6825 openFileName.lpstrFileTitle = fileTitle;
\r
6826 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6827 openFileName.lpstrInitialDir = NULL;
\r
6828 openFileName.lpstrTitle = dlgTitle;
\r
6829 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6830 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6831 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6832 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6833 openFileName.nFileOffset = 0;
\r
6834 openFileName.nFileExtension = 0;
\r
6835 openFileName.lpstrDefExt = defExt;
\r
6836 openFileName.lCustData = (LONG) number;
\r
6837 openFileName.lpfnHook = oldDialog ?
\r
6838 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6839 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6841 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6842 GetOpenFileName(&openFileName)) {
\r
6843 /* open the file */
\r
6844 f = fopen(openFileName.lpstrFile, write);
\r
6846 MessageBox(hwnd, "File open failed", NULL,
\r
6847 MB_OK|MB_ICONEXCLAMATION);
\r
6851 int err = CommDlgExtendedError();
\r
6852 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6861 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6863 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6866 * Get the first pop-up menu in the menu template. This is the
\r
6867 * menu that TrackPopupMenu displays.
\r
6869 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6871 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6874 * TrackPopup uses screen coordinates, so convert the
\r
6875 * coordinates of the mouse click to screen coordinates.
\r
6877 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6879 /* Draw and track the floating pop-up menu. */
\r
6880 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6881 pt.x, pt.y, 0, hwnd, NULL);
\r
6883 /* Destroy the menu.*/
\r
6884 DestroyMenu(hmenu);
\r
6889 int sizeX, sizeY, newSizeX, newSizeY;
\r
6891 } ResizeEditPlusButtonsClosure;
\r
6894 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6896 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6900 if (hChild == cl->hText) return TRUE;
\r
6901 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6902 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6903 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6904 ScreenToClient(cl->hDlg, &pt);
\r
6905 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6906 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6910 /* Resize a dialog that has a (rich) edit field filling most of
\r
6911 the top, with a row of buttons below */
\r
6913 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6916 int newTextHeight, newTextWidth;
\r
6917 ResizeEditPlusButtonsClosure cl;
\r
6919 /*if (IsIconic(hDlg)) return;*/
\r
6920 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6922 cl.hdwp = BeginDeferWindowPos(8);
\r
6924 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6925 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6926 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6927 if (newTextHeight < 0) {
\r
6928 newSizeY += -newTextHeight;
\r
6929 newTextHeight = 0;
\r
6931 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6932 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6938 cl.newSizeX = newSizeX;
\r
6939 cl.newSizeY = newSizeY;
\r
6940 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6942 EndDeferWindowPos(cl.hdwp);
\r
6945 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6947 RECT rChild, rParent;
\r
6948 int wChild, hChild, wParent, hParent;
\r
6949 int wScreen, hScreen, xNew, yNew;
\r
6952 /* Get the Height and Width of the child window */
\r
6953 GetWindowRect (hwndChild, &rChild);
\r
6954 wChild = rChild.right - rChild.left;
\r
6955 hChild = rChild.bottom - rChild.top;
\r
6957 /* Get the Height and Width of the parent window */
\r
6958 GetWindowRect (hwndParent, &rParent);
\r
6959 wParent = rParent.right - rParent.left;
\r
6960 hParent = rParent.bottom - rParent.top;
\r
6962 /* Get the display limits */
\r
6963 hdc = GetDC (hwndChild);
\r
6964 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6965 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6966 ReleaseDC(hwndChild, hdc);
\r
6968 /* Calculate new X position, then adjust for screen */
\r
6969 xNew = rParent.left + ((wParent - wChild) /2);
\r
6972 } else if ((xNew+wChild) > wScreen) {
\r
6973 xNew = wScreen - wChild;
\r
6976 /* Calculate new Y position, then adjust for screen */
\r
6978 yNew = rParent.top + ((hParent - hChild) /2);
\r
6981 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6986 } else if ((yNew+hChild) > hScreen) {
\r
6987 yNew = hScreen - hChild;
\r
6990 /* Set it, and return */
\r
6991 return SetWindowPos (hwndChild, NULL,
\r
6992 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6995 /* Center one window over another */
\r
6996 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6998 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
7001 /*---------------------------------------------------------------------------*\
\r
7003 * Startup Dialog functions
\r
7005 \*---------------------------------------------------------------------------*/
\r
7007 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
7009 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7011 while (*cd != NULL) {
\r
7012 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
7018 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
7020 char buf1[ARG_MAX];
\r
7023 if (str[0] == '@') {
\r
7024 FILE* f = fopen(str + 1, "r");
\r
7026 DisplayFatalError(str + 1, errno, 2);
\r
7029 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
7031 buf1[len] = NULLCHAR;
\r
7035 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7038 char buf[MSG_SIZ];
\r
7039 char *end = strchr(str, '\n');
\r
7040 if (end == NULL) return;
\r
7041 memcpy(buf, str, end - str);
\r
7042 buf[end - str] = NULLCHAR;
\r
7043 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7049 SetStartupDialogEnables(HWND hDlg)
\r
7051 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7052 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7053 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7054 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7055 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7056 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7057 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7058 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7059 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7060 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7061 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7062 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7063 IsDlgButtonChecked(hDlg, OPT_View));
\r
7067 QuoteForFilename(char *filename)
\r
7069 int dquote, space;
\r
7070 dquote = strchr(filename, '"') != NULL;
\r
7071 space = strchr(filename, ' ') != NULL;
\r
7072 if (dquote || space) {
\r
7084 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7086 char buf[MSG_SIZ];
\r
7089 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7090 q = QuoteForFilename(nthcp);
\r
7091 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7092 if (*nthdir != NULLCHAR) {
\r
7093 q = QuoteForFilename(nthdir);
\r
7094 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7096 if (*nthcp == NULLCHAR) {
\r
7097 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7098 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7099 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7100 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7105 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7107 char buf[MSG_SIZ];
\r
7111 switch (message) {
\r
7112 case WM_INITDIALOG:
\r
7113 /* Center the dialog */
\r
7114 CenterWindow (hDlg, GetDesktopWindow());
\r
7115 /* Initialize the dialog items */
\r
7116 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7117 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7118 firstChessProgramNames);
\r
7119 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7120 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7121 secondChessProgramNames);
\r
7122 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7123 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7124 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7125 if (*appData.icsHelper != NULLCHAR) {
\r
7126 char *q = QuoteForFilename(appData.icsHelper);
\r
7127 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7129 if (*appData.icsHost == NULLCHAR) {
\r
7130 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7131 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7132 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7133 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7134 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7137 if (appData.icsActive) {
\r
7138 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7140 else if (appData.noChessProgram) {
\r
7141 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7144 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7147 SetStartupDialogEnables(hDlg);
\r
7151 switch (LOWORD(wParam)) {
\r
7153 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7154 strcpy(buf, "/fcp=");
\r
7155 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7157 ParseArgs(StringGet, &p);
\r
7158 strcpy(buf, "/scp=");
\r
7159 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7161 ParseArgs(StringGet, &p);
\r
7162 appData.noChessProgram = FALSE;
\r
7163 appData.icsActive = FALSE;
\r
7164 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7165 strcpy(buf, "/ics /icshost=");
\r
7166 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7168 ParseArgs(StringGet, &p);
\r
7169 if (appData.zippyPlay) {
\r
7170 strcpy(buf, "/fcp=");
\r
7171 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7173 ParseArgs(StringGet, &p);
\r
7175 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7176 appData.noChessProgram = TRUE;
\r
7177 appData.icsActive = FALSE;
\r
7179 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7180 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7183 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7184 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7186 ParseArgs(StringGet, &p);
\r
7188 EndDialog(hDlg, TRUE);
\r
7195 case IDM_HELPCONTENTS:
\r
7196 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7197 MessageBox (GetFocus(),
\r
7198 "Unable to activate help",
\r
7199 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7204 SetStartupDialogEnables(hDlg);
\r
7212 /*---------------------------------------------------------------------------*\
\r
7214 * About box dialog functions
\r
7216 \*---------------------------------------------------------------------------*/
\r
7218 /* Process messages for "About" dialog box */
\r
7220 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7222 switch (message) {
\r
7223 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7224 /* Center the dialog over the application window */
\r
7225 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7226 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7230 case WM_COMMAND: /* message: received a command */
\r
7231 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7232 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7233 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7241 /*---------------------------------------------------------------------------*\
\r
7243 * Comment Dialog functions
\r
7245 \*---------------------------------------------------------------------------*/
\r
7248 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7250 static HANDLE hwndText = NULL;
\r
7251 int len, newSizeX, newSizeY, flags;
\r
7252 static int sizeX, sizeY;
\r
7257 switch (message) {
\r
7258 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7259 /* Initialize the dialog items */
\r
7260 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7261 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7262 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7263 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7264 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7265 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7266 SetWindowText(hDlg, commentTitle);
\r
7267 if (editComment) {
\r
7268 SetFocus(hwndText);
\r
7270 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7272 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7273 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7274 MAKELPARAM(FALSE, 0));
\r
7275 /* Size and position the dialog */
\r
7276 if (!commentDialog) {
\r
7277 commentDialog = hDlg;
\r
7278 flags = SWP_NOZORDER;
\r
7279 GetClientRect(hDlg, &rect);
\r
7280 sizeX = rect.right;
\r
7281 sizeY = rect.bottom;
\r
7282 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7283 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7284 WINDOWPLACEMENT wp;
\r
7285 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7286 wp.length = sizeof(WINDOWPLACEMENT);
\r
7288 wp.showCmd = SW_SHOW;
\r
7289 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7290 wp.rcNormalPosition.left = commentX;
\r
7291 wp.rcNormalPosition.right = commentX + commentW;
\r
7292 wp.rcNormalPosition.top = commentY;
\r
7293 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7294 SetWindowPlacement(hDlg, &wp);
\r
7296 GetClientRect(hDlg, &rect);
\r
7297 newSizeX = rect.right;
\r
7298 newSizeY = rect.bottom;
\r
7299 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7300 newSizeX, newSizeY);
\r
7307 case WM_COMMAND: /* message: received a command */
\r
7308 switch (LOWORD(wParam)) {
\r
7310 if (editComment) {
\r
7312 /* Read changed options from the dialog box */
\r
7313 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7314 len = GetWindowTextLength(hwndText);
\r
7315 str = (char *) malloc(len + 1);
\r
7316 GetWindowText(hwndText, str, len + 1);
\r
7325 ReplaceComment(commentIndex, str);
\r
7332 case OPT_CancelComment:
\r
7336 case OPT_ClearComment:
\r
7337 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7340 case OPT_EditComment:
\r
7341 EditCommentEvent();
\r
7350 newSizeX = LOWORD(lParam);
\r
7351 newSizeY = HIWORD(lParam);
\r
7352 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7357 case WM_GETMINMAXINFO:
\r
7358 /* Prevent resizing window too small */
\r
7359 mmi = (MINMAXINFO *) lParam;
\r
7360 mmi->ptMinTrackSize.x = 100;
\r
7361 mmi->ptMinTrackSize.y = 100;
\r
7368 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7373 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7375 if (str == NULL) str = "";
\r
7376 p = (char *) malloc(2 * strlen(str) + 2);
\r
7379 if (*str == '\n') *q++ = '\r';
\r
7383 if (commentText != NULL) free(commentText);
\r
7385 commentIndex = index;
\r
7386 commentTitle = title;
\r
7388 editComment = edit;
\r
7390 if (commentDialog) {
\r
7391 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7392 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7394 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7395 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7396 hwndMain, (DLGPROC)lpProc);
\r
7397 FreeProcInstance(lpProc);
\r
7399 commentDialogUp = TRUE;
\r
7403 /*---------------------------------------------------------------------------*\
\r
7405 * Type-in move dialog functions
\r
7407 \*---------------------------------------------------------------------------*/
\r
7410 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7412 char move[MSG_SIZ];
\r
7414 ChessMove moveType;
\r
7415 int fromX, fromY, toX, toY;
\r
7418 switch (message) {
\r
7419 case WM_INITDIALOG:
\r
7420 move[0] = (char) lParam;
\r
7421 move[1] = NULLCHAR;
\r
7422 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7423 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7424 SetWindowText(hInput, move);
\r
7426 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7430 switch (LOWORD(wParam)) {
\r
7432 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7433 { int n; Board board;
\r
7435 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7436 EditPositionPasteFEN(move);
\r
7437 EndDialog(hDlg, TRUE);
\r
7440 // [HGM] movenum: allow move number to be typed in any mode
\r
7441 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7442 currentMove = 2*n-1;
\r
7443 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7444 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7445 EndDialog(hDlg, TRUE);
\r
7446 DrawPosition(TRUE, boards[currentMove]);
\r
7447 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7448 else DisplayMessage("", "");
\r
7452 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7453 gameMode != Training) {
\r
7454 DisplayMoveError("Displayed move is not current");
\r
7456 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7457 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7458 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7459 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7460 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7461 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7462 if (gameMode != Training)
\r
7463 forwardMostMove = currentMove;
\r
7464 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7466 DisplayMoveError("Could not parse move");
\r
7469 EndDialog(hDlg, TRUE);
\r
7472 EndDialog(hDlg, FALSE);
\r
7483 PopUpMoveDialog(char firstchar)
\r
7487 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7488 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7489 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7490 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7491 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7492 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7493 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7494 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7495 gameMode == Training) {
\r
7496 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7497 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7498 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7499 FreeProcInstance(lpProc);
\r
7503 /*---------------------------------------------------------------------------*\
\r
7505 * Type-in name dialog functions
\r
7507 \*---------------------------------------------------------------------------*/
\r
7510 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7512 char move[MSG_SIZ];
\r
7515 switch (message) {
\r
7516 case WM_INITDIALOG:
\r
7517 move[0] = (char) lParam;
\r
7518 move[1] = NULLCHAR;
\r
7519 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7520 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7521 SetWindowText(hInput, move);
\r
7523 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7527 switch (LOWORD(wParam)) {
\r
7529 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7530 appData.userName = strdup(move);
\r
7533 EndDialog(hDlg, TRUE);
\r
7536 EndDialog(hDlg, FALSE);
\r
7547 PopUpNameDialog(char firstchar)
\r
7551 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7552 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7553 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7554 FreeProcInstance(lpProc);
\r
7557 /*---------------------------------------------------------------------------*\
\r
7561 \*---------------------------------------------------------------------------*/
\r
7563 /* Nonmodal error box */
\r
7564 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7565 WPARAM wParam, LPARAM lParam);
\r
7568 ErrorPopUp(char *title, char *content)
\r
7572 BOOLEAN modal = hwndMain == NULL;
\r
7590 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7591 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7594 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7596 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7597 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7598 hwndMain, (DLGPROC)lpProc);
\r
7599 FreeProcInstance(lpProc);
\r
7606 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7607 if (errorDialog == NULL) return;
\r
7608 DestroyWindow(errorDialog);
\r
7609 errorDialog = NULL;
\r
7613 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7618 switch (message) {
\r
7619 case WM_INITDIALOG:
\r
7620 GetWindowRect(hDlg, &rChild);
\r
7623 SetWindowPos(hDlg, NULL, rChild.left,
\r
7624 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7625 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7629 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7630 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7631 and it doesn't work when you resize the dialog.
\r
7632 For now, just give it a default position.
\r
7634 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7636 errorDialog = hDlg;
\r
7637 SetWindowText(hDlg, errorTitle);
\r
7638 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7639 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7643 switch (LOWORD(wParam)) {
\r
7646 if (errorDialog == hDlg) errorDialog = NULL;
\r
7647 DestroyWindow(hDlg);
\r
7659 HWND gothicDialog = NULL;
\r
7662 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7666 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7668 switch (message) {
\r
7669 case WM_INITDIALOG:
\r
7670 GetWindowRect(hDlg, &rChild);
\r
7672 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7676 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7677 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7678 and it doesn't work when you resize the dialog.
\r
7679 For now, just give it a default position.
\r
7681 gothicDialog = hDlg;
\r
7682 SetWindowText(hDlg, errorTitle);
\r
7683 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7684 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7688 switch (LOWORD(wParam)) {
\r
7691 if (errorDialog == hDlg) errorDialog = NULL;
\r
7692 DestroyWindow(hDlg);
\r
7704 GothicPopUp(char *title, VariantClass variant)
\r
7707 static char *lastTitle;
\r
7709 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7710 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7712 if(lastTitle != title && gothicDialog != NULL) {
\r
7713 DestroyWindow(gothicDialog);
\r
7714 gothicDialog = NULL;
\r
7716 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7717 title = lastTitle;
\r
7718 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7719 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7720 hwndMain, (DLGPROC)lpProc);
\r
7721 FreeProcInstance(lpProc);
\r
7726 /*---------------------------------------------------------------------------*\
\r
7728 * Ics Interaction console functions
\r
7730 \*---------------------------------------------------------------------------*/
\r
7732 #define HISTORY_SIZE 64
\r
7733 static char *history[HISTORY_SIZE];
\r
7734 int histIn = 0, histP = 0;
\r
7737 SaveInHistory(char *cmd)
\r
7739 if (history[histIn] != NULL) {
\r
7740 free(history[histIn]);
\r
7741 history[histIn] = NULL;
\r
7743 if (*cmd == NULLCHAR) return;
\r
7744 history[histIn] = StrSave(cmd);
\r
7745 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7746 if (history[histIn] != NULL) {
\r
7747 free(history[histIn]);
\r
7748 history[histIn] = NULL;
\r
7754 PrevInHistory(char *cmd)
\r
7757 if (histP == histIn) {
\r
7758 if (history[histIn] != NULL) free(history[histIn]);
\r
7759 history[histIn] = StrSave(cmd);
\r
7761 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7762 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7764 return history[histP];
\r
7770 if (histP == histIn) return NULL;
\r
7771 histP = (histP + 1) % HISTORY_SIZE;
\r
7772 return history[histP];
\r
7779 BOOLEAN immediate;
\r
7780 } IcsTextMenuEntry;
\r
7781 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7782 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7785 ParseIcsTextMenu(char *icsTextMenuString)
\r
7788 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7789 char *p = icsTextMenuString;
\r
7790 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7793 if (e->command != NULL) {
\r
7795 e->command = NULL;
\r
7799 e = icsTextMenuEntry;
\r
7800 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7801 if (*p == ';' || *p == '\n') {
\r
7802 e->item = strdup("-");
\r
7803 e->command = NULL;
\r
7805 } else if (*p == '-') {
\r
7806 e->item = strdup("-");
\r
7807 e->command = NULL;
\r
7811 char *q, *r, *s, *t;
\r
7813 q = strchr(p, ',');
\r
7814 if (q == NULL) break;
\r
7816 r = strchr(q + 1, ',');
\r
7817 if (r == NULL) break;
\r
7819 s = strchr(r + 1, ',');
\r
7820 if (s == NULL) break;
\r
7823 t = strchr(s + 1, c);
\r
7826 t = strchr(s + 1, c);
\r
7828 if (t != NULL) *t = NULLCHAR;
\r
7829 e->item = strdup(p);
\r
7830 e->command = strdup(q + 1);
\r
7831 e->getname = *(r + 1) != '0';
\r
7832 e->immediate = *(s + 1) != '0';
\r
7836 if (t == NULL) break;
\r
7845 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7849 hmenu = LoadMenu(hInst, "TextMenu");
\r
7850 h = GetSubMenu(hmenu, 0);
\r
7852 if (strcmp(e->item, "-") == 0) {
\r
7853 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7855 if (e->item[0] == '|') {
\r
7856 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7857 IDM_CommandX + i, &e->item[1]);
\r
7859 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7868 WNDPROC consoleTextWindowProc;
\r
7871 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7873 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7874 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7878 SetWindowText(hInput, command);
\r
7880 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7882 sel.cpMin = 999999;
\r
7883 sel.cpMax = 999999;
\r
7884 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7889 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7890 if (sel.cpMin == sel.cpMax) {
\r
7891 /* Expand to surrounding word */
\r
7894 tr.chrg.cpMax = sel.cpMin;
\r
7895 tr.chrg.cpMin = --sel.cpMin;
\r
7896 if (sel.cpMin < 0) break;
\r
7897 tr.lpstrText = name;
\r
7898 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7899 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7903 tr.chrg.cpMin = sel.cpMax;
\r
7904 tr.chrg.cpMax = ++sel.cpMax;
\r
7905 tr.lpstrText = name;
\r
7906 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7907 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7910 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7911 MessageBeep(MB_ICONEXCLAMATION);
\r
7915 tr.lpstrText = name;
\r
7916 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7918 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7919 MessageBeep(MB_ICONEXCLAMATION);
\r
7922 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7925 sprintf(buf, "%s %s", command, name);
\r
7926 SetWindowText(hInput, buf);
\r
7927 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7929 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7930 SetWindowText(hInput, buf);
\r
7931 sel.cpMin = 999999;
\r
7932 sel.cpMax = 999999;
\r
7933 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7939 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7944 switch (message) {
\r
7946 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7949 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7952 sel.cpMin = 999999;
\r
7953 sel.cpMax = 999999;
\r
7954 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7955 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7960 if(wParam != '\022') {
\r
7961 if (wParam == '\t') {
\r
7962 if (GetKeyState(VK_SHIFT) < 0) {
\r
7964 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7965 if (buttonDesc[0].hwnd) {
\r
7966 SetFocus(buttonDesc[0].hwnd);
\r
7968 SetFocus(hwndMain);
\r
7972 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7975 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7976 JAWS_DELETE( SetFocus(hInput); )
\r
7977 SendMessage(hInput, message, wParam, lParam);
\r
7980 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7981 case WM_RBUTTONUP:
\r
7982 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7983 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7984 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7987 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7988 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7989 if (sel.cpMin == sel.cpMax) {
\r
7990 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7991 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7993 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7994 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7996 pt.x = LOWORD(lParam);
\r
7997 pt.y = HIWORD(lParam);
\r
7998 MenuPopup(hwnd, pt, hmenu, -1);
\r
8002 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8004 return SendMessage(hInput, message, wParam, lParam);
\r
8005 case WM_MBUTTONDOWN:
\r
8006 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8007 case WM_RBUTTONDOWN:
\r
8008 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
8009 /* Move selection here if it was empty */
\r
8011 pt.x = LOWORD(lParam);
\r
8012 pt.y = HIWORD(lParam);
\r
8013 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8014 if (sel.cpMin == sel.cpMax) {
\r
8015 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
8016 sel.cpMax = sel.cpMin;
\r
8017 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8019 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
8023 switch (LOWORD(wParam)) {
\r
8024 case IDM_QuickPaste:
\r
8026 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8027 if (sel.cpMin == sel.cpMax) {
\r
8028 MessageBeep(MB_ICONEXCLAMATION);
\r
8031 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8032 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8033 SendMessage(hInput, WM_PASTE, 0, 0);
\r
8038 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8041 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8044 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8048 int i = LOWORD(wParam) - IDM_CommandX;
\r
8049 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8050 icsTextMenuEntry[i].command != NULL) {
\r
8051 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8052 icsTextMenuEntry[i].getname,
\r
8053 icsTextMenuEntry[i].immediate);
\r
8061 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8064 WNDPROC consoleInputWindowProc;
\r
8067 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8069 char buf[MSG_SIZ];
\r
8071 static BOOL sendNextChar = FALSE;
\r
8072 static BOOL quoteNextChar = FALSE;
\r
8073 InputSource *is = consoleInputSource;
\r
8077 switch (message) {
\r
8079 if (!appData.localLineEditing || sendNextChar) {
\r
8080 is->buf[0] = (CHAR) wParam;
\r
8082 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8083 sendNextChar = FALSE;
\r
8086 if (quoteNextChar) {
\r
8087 buf[0] = (char) wParam;
\r
8088 buf[1] = NULLCHAR;
\r
8089 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8090 quoteNextChar = FALSE;
\r
8094 case '\r': /* Enter key */
\r
8095 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8096 if (consoleEcho) SaveInHistory(is->buf);
\r
8097 is->buf[is->count++] = '\n';
\r
8098 is->buf[is->count] = NULLCHAR;
\r
8099 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8100 if (consoleEcho) {
\r
8101 ConsoleOutput(is->buf, is->count, TRUE);
\r
8102 } else if (appData.localLineEditing) {
\r
8103 ConsoleOutput("\n", 1, TRUE);
\r
8106 case '\033': /* Escape key */
\r
8107 SetWindowText(hwnd, "");
\r
8108 cf.cbSize = sizeof(CHARFORMAT);
\r
8109 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8110 if (consoleEcho) {
\r
8111 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8113 cf.crTextColor = COLOR_ECHOOFF;
\r
8115 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8116 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8118 case '\t': /* Tab key */
\r
8119 if (GetKeyState(VK_SHIFT) < 0) {
\r
8121 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8124 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8125 if (buttonDesc[0].hwnd) {
\r
8126 SetFocus(buttonDesc[0].hwnd);
\r
8128 SetFocus(hwndMain);
\r
8132 case '\023': /* Ctrl+S */
\r
8133 sendNextChar = TRUE;
\r
8135 case '\021': /* Ctrl+Q */
\r
8136 quoteNextChar = TRUE;
\r
8146 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8147 p = PrevInHistory(buf);
\r
8149 SetWindowText(hwnd, p);
\r
8150 sel.cpMin = 999999;
\r
8151 sel.cpMax = 999999;
\r
8152 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8157 p = NextInHistory();
\r
8159 SetWindowText(hwnd, p);
\r
8160 sel.cpMin = 999999;
\r
8161 sel.cpMax = 999999;
\r
8162 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8168 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8172 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8176 case WM_MBUTTONDOWN:
\r
8177 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8178 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8180 case WM_RBUTTONUP:
\r
8181 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8182 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8183 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8187 hmenu = LoadMenu(hInst, "InputMenu");
\r
8188 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8189 if (sel.cpMin == sel.cpMax) {
\r
8190 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8191 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8193 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8194 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8196 pt.x = LOWORD(lParam);
\r
8197 pt.y = HIWORD(lParam);
\r
8198 MenuPopup(hwnd, pt, hmenu, -1);
\r
8202 switch (LOWORD(wParam)) {
\r
8204 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8206 case IDM_SelectAll:
\r
8208 sel.cpMax = -1; /*999999?*/
\r
8209 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8212 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8215 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8218 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8223 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8226 #define CO_MAX 100000
\r
8227 #define CO_TRIM 1000
\r
8230 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8232 static SnapData sd;
\r
8233 static HWND hText, hInput /*, hFocus*/;
\r
8234 // InputSource *is = consoleInputSource;
\r
8236 static int sizeX, sizeY;
\r
8237 int newSizeX, newSizeY;
\r
8240 switch (message) {
\r
8241 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8242 hwndConsole = hDlg;
\r
8243 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8244 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8246 consoleTextWindowProc = (WNDPROC)
\r
8247 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8248 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8249 consoleInputWindowProc = (WNDPROC)
\r
8250 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8251 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8252 Colorize(ColorNormal, TRUE);
\r
8253 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8254 ChangedConsoleFont();
\r
8255 GetClientRect(hDlg, &rect);
\r
8256 sizeX = rect.right;
\r
8257 sizeY = rect.bottom;
\r
8258 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8259 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8260 WINDOWPLACEMENT wp;
\r
8261 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8262 wp.length = sizeof(WINDOWPLACEMENT);
\r
8264 wp.showCmd = SW_SHOW;
\r
8265 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8266 wp.rcNormalPosition.left = wpConsole.x;
\r
8267 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8268 wp.rcNormalPosition.top = wpConsole.y;
\r
8269 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8270 SetWindowPlacement(hDlg, &wp);
\r
8273 // [HGM] Chessknight's change 2004-07-13
\r
8274 else { /* Determine Defaults */
\r
8275 WINDOWPLACEMENT wp;
\r
8276 wpConsole.x = winWidth + 1;
\r
8277 wpConsole.y = boardY;
\r
8278 wpConsole.width = screenWidth - winWidth;
\r
8279 wpConsole.height = winHeight;
\r
8280 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8281 wp.length = sizeof(WINDOWPLACEMENT);
\r
8283 wp.showCmd = SW_SHOW;
\r
8284 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8285 wp.rcNormalPosition.left = wpConsole.x;
\r
8286 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8287 wp.rcNormalPosition.top = wpConsole.y;
\r
8288 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8289 SetWindowPlacement(hDlg, &wp);
\r
8304 if (IsIconic(hDlg)) break;
\r
8305 newSizeX = LOWORD(lParam);
\r
8306 newSizeY = HIWORD(lParam);
\r
8307 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8308 RECT rectText, rectInput;
\r
8310 int newTextHeight, newTextWidth;
\r
8311 GetWindowRect(hText, &rectText);
\r
8312 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8313 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8314 if (newTextHeight < 0) {
\r
8315 newSizeY += -newTextHeight;
\r
8316 newTextHeight = 0;
\r
8318 SetWindowPos(hText, NULL, 0, 0,
\r
8319 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8320 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8321 pt.x = rectInput.left;
\r
8322 pt.y = rectInput.top + newSizeY - sizeY;
\r
8323 ScreenToClient(hDlg, &pt);
\r
8324 SetWindowPos(hInput, NULL,
\r
8325 pt.x, pt.y, /* needs client coords */
\r
8326 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8327 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8333 case WM_GETMINMAXINFO:
\r
8334 /* Prevent resizing window too small */
\r
8335 mmi = (MINMAXINFO *) lParam;
\r
8336 mmi->ptMinTrackSize.x = 100;
\r
8337 mmi->ptMinTrackSize.y = 100;
\r
8340 /* [AS] Snapping */
\r
8341 case WM_ENTERSIZEMOVE:
\r
8342 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8345 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8348 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8350 case WM_EXITSIZEMOVE:
\r
8351 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8354 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8362 if (hwndConsole) return;
\r
8363 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8364 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8369 ConsoleOutput(char* data, int length, int forceVisible)
\r
8374 char buf[CO_MAX+1];
\r
8377 static int delayLF = 0;
\r
8378 CHARRANGE savesel, sel;
\r
8380 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8388 while (length--) {
\r
8396 } else if (*p == '\007') {
\r
8397 MyPlaySound(&sounds[(int)SoundBell]);
\r
8404 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8405 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8406 /* Save current selection */
\r
8407 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8408 exlen = GetWindowTextLength(hText);
\r
8409 /* Find out whether current end of text is visible */
\r
8410 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8411 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8412 /* Trim existing text if it's too long */
\r
8413 if (exlen + (q - buf) > CO_MAX) {
\r
8414 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8417 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8418 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8420 savesel.cpMin -= trim;
\r
8421 savesel.cpMax -= trim;
\r
8422 if (exlen < 0) exlen = 0;
\r
8423 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8424 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8426 /* Append the new text */
\r
8427 sel.cpMin = exlen;
\r
8428 sel.cpMax = exlen;
\r
8429 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8430 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8431 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8432 if (forceVisible || exlen == 0 ||
\r
8433 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8434 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8435 /* Scroll to make new end of text visible if old end of text
\r
8436 was visible or new text is an echo of user typein */
\r
8437 sel.cpMin = 9999999;
\r
8438 sel.cpMax = 9999999;
\r
8439 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8440 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8441 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8442 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8444 if (savesel.cpMax == exlen || forceVisible) {
\r
8445 /* Move insert point to new end of text if it was at the old
\r
8446 end of text or if the new text is an echo of user typein */
\r
8447 sel.cpMin = 9999999;
\r
8448 sel.cpMax = 9999999;
\r
8449 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8451 /* Restore previous selection */
\r
8452 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8454 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8461 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8465 COLORREF oldFg, oldBg;
\r
8469 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8471 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8472 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8473 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8476 rect.right = x + squareSize;
\r
8478 rect.bottom = y + squareSize;
\r
8481 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8482 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8483 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8484 &rect, str, strlen(str), NULL);
\r
8486 (void) SetTextColor(hdc, oldFg);
\r
8487 (void) SetBkColor(hdc, oldBg);
\r
8488 (void) SelectObject(hdc, oldFont);
\r
8492 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8493 RECT *rect, char *color, char *flagFell)
\r
8497 COLORREF oldFg, oldBg;
\r
8500 if (appData.clockMode) {
\r
8502 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8504 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8511 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8512 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8514 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8515 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8517 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8521 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8522 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8523 rect, str, strlen(str), NULL);
\r
8524 if(logoHeight > 0 && appData.clockMode) {
\r
8526 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8527 r.top = rect->top + logoHeight/2;
\r
8528 r.left = rect->left;
\r
8529 r.right = rect->right;
\r
8530 r.bottom = rect->bottom;
\r
8531 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8532 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8533 &r, str, strlen(str), NULL);
\r
8535 (void) SetTextColor(hdc, oldFg);
\r
8536 (void) SetBkColor(hdc, oldBg);
\r
8537 (void) SelectObject(hdc, oldFont);
\r
8542 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8548 if( count <= 0 ) {
\r
8549 if (appData.debugMode) {
\r
8550 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8553 return ERROR_INVALID_USER_BUFFER;
\r
8556 ResetEvent(ovl->hEvent);
\r
8557 ovl->Offset = ovl->OffsetHigh = 0;
\r
8558 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8562 err = GetLastError();
\r
8563 if (err == ERROR_IO_PENDING) {
\r
8564 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8568 err = GetLastError();
\r
8575 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8580 ResetEvent(ovl->hEvent);
\r
8581 ovl->Offset = ovl->OffsetHigh = 0;
\r
8582 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8586 err = GetLastError();
\r
8587 if (err == ERROR_IO_PENDING) {
\r
8588 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8592 err = GetLastError();
\r
8598 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8599 void CheckForInputBufferFull( InputSource * is )
\r
8601 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8602 /* Look for end of line */
\r
8603 char * p = is->buf;
\r
8605 while( p < is->next && *p != '\n' ) {
\r
8609 if( p >= is->next ) {
\r
8610 if (appData.debugMode) {
\r
8611 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8614 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8615 is->count = (DWORD) -1;
\r
8616 is->next = is->buf;
\r
8622 InputThread(LPVOID arg)
\r
8627 is = (InputSource *) arg;
\r
8628 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8629 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8630 while (is->hThread != NULL) {
\r
8631 is->error = DoReadFile(is->hFile, is->next,
\r
8632 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8633 &is->count, &ovl);
\r
8634 if (is->error == NO_ERROR) {
\r
8635 is->next += is->count;
\r
8637 if (is->error == ERROR_BROKEN_PIPE) {
\r
8638 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8641 is->count = (DWORD) -1;
\r
8642 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8647 CheckForInputBufferFull( is );
\r
8649 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8651 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8653 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8656 CloseHandle(ovl.hEvent);
\r
8657 CloseHandle(is->hFile);
\r
8659 if (appData.debugMode) {
\r
8660 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8667 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8669 NonOvlInputThread(LPVOID arg)
\r
8676 is = (InputSource *) arg;
\r
8677 while (is->hThread != NULL) {
\r
8678 is->error = ReadFile(is->hFile, is->next,
\r
8679 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8680 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8681 if (is->error == NO_ERROR) {
\r
8682 /* Change CRLF to LF */
\r
8683 if (is->next > is->buf) {
\r
8685 i = is->count + 1;
\r
8693 if (prev == '\r' && *p == '\n') {
\r
8705 if (is->error == ERROR_BROKEN_PIPE) {
\r
8706 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8709 is->count = (DWORD) -1;
\r
8713 CheckForInputBufferFull( is );
\r
8715 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8717 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8719 if (is->count < 0) break; /* Quit on error */
\r
8721 CloseHandle(is->hFile);
\r
8726 SocketInputThread(LPVOID arg)
\r
8730 is = (InputSource *) arg;
\r
8731 while (is->hThread != NULL) {
\r
8732 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8733 if ((int)is->count == SOCKET_ERROR) {
\r
8734 is->count = (DWORD) -1;
\r
8735 is->error = WSAGetLastError();
\r
8737 is->error = NO_ERROR;
\r
8738 is->next += is->count;
\r
8739 if (is->count == 0 && is->second == is) {
\r
8740 /* End of file on stderr; quit with no message */
\r
8744 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8746 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8748 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8754 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8758 is = (InputSource *) lParam;
\r
8759 if (is->lineByLine) {
\r
8760 /* Feed in lines one by one */
\r
8761 char *p = is->buf;
\r
8763 while (q < is->next) {
\r
8764 if (*q++ == '\n') {
\r
8765 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8770 /* Move any partial line to the start of the buffer */
\r
8772 while (p < is->next) {
\r
8777 if (is->error != NO_ERROR || is->count == 0) {
\r
8778 /* Notify backend of the error. Note: If there was a partial
\r
8779 line at the end, it is not flushed through. */
\r
8780 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8783 /* Feed in the whole chunk of input at once */
\r
8784 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8785 is->next = is->buf;
\r
8789 /*---------------------------------------------------------------------------*\
\r
8791 * Menu enables. Used when setting various modes.
\r
8793 \*---------------------------------------------------------------------------*/
\r
8801 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8803 while (enab->item > 0) {
\r
8804 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8809 Enables gnuEnables[] = {
\r
8810 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8811 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8812 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8813 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8814 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8815 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8816 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8817 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8818 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8819 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8823 Enables icsEnables[] = {
\r
8824 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8825 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8826 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8827 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8828 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8829 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8830 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8831 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8832 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8833 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8834 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8835 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8840 Enables zippyEnables[] = {
\r
8841 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8842 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8843 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8848 Enables ncpEnables[] = {
\r
8849 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8850 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8851 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8852 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8853 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8854 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8855 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8856 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8857 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8858 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8859 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8860 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8861 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8862 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8863 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8867 Enables trainingOnEnables[] = {
\r
8868 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8869 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8870 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8871 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8872 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8873 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8874 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8875 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8879 Enables trainingOffEnables[] = {
\r
8880 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8881 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8882 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8883 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8884 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8885 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8886 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8887 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8891 /* These modify either ncpEnables or gnuEnables */
\r
8892 Enables cmailEnables[] = {
\r
8893 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8894 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8895 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8896 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8897 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8898 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8899 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8903 Enables machineThinkingEnables[] = {
\r
8904 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8905 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8906 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8907 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8908 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8909 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8910 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8911 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8912 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8913 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8914 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8915 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8916 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8917 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8918 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8922 Enables userThinkingEnables[] = {
\r
8923 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8924 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8925 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8926 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8927 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8928 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8929 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8930 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8931 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8932 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8933 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8934 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8935 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8936 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8937 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8941 /*---------------------------------------------------------------------------*\
\r
8943 * Front-end interface functions exported by XBoard.
\r
8944 * Functions appear in same order as prototypes in frontend.h.
\r
8946 \*---------------------------------------------------------------------------*/
\r
8950 static UINT prevChecked = 0;
\r
8951 static int prevPausing = 0;
\r
8954 if (pausing != prevPausing) {
\r
8955 prevPausing = pausing;
\r
8956 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8957 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8958 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8961 switch (gameMode) {
\r
8962 case BeginningOfGame:
\r
8963 if (appData.icsActive)
\r
8964 nowChecked = IDM_IcsClient;
\r
8965 else if (appData.noChessProgram)
\r
8966 nowChecked = IDM_EditGame;
\r
8968 nowChecked = IDM_MachineBlack;
\r
8970 case MachinePlaysBlack:
\r
8971 nowChecked = IDM_MachineBlack;
\r
8973 case MachinePlaysWhite:
\r
8974 nowChecked = IDM_MachineWhite;
\r
8976 case TwoMachinesPlay:
\r
8977 nowChecked = IDM_TwoMachines;
\r
8980 nowChecked = IDM_AnalysisMode;
\r
8983 nowChecked = IDM_AnalyzeFile;
\r
8986 nowChecked = IDM_EditGame;
\r
8988 case PlayFromGameFile:
\r
8989 nowChecked = IDM_LoadGame;
\r
8991 case EditPosition:
\r
8992 nowChecked = IDM_EditPosition;
\r
8995 nowChecked = IDM_Training;
\r
8997 case IcsPlayingWhite:
\r
8998 case IcsPlayingBlack:
\r
8999 case IcsObserving:
\r
9001 nowChecked = IDM_IcsClient;
\r
9008 if (prevChecked != 0)
\r
9009 (void) CheckMenuItem(GetMenu(hwndMain),
\r
9010 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
9011 if (nowChecked != 0)
\r
9012 (void) CheckMenuItem(GetMenu(hwndMain),
\r
9013 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
9015 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
9016 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
9017 MF_BYCOMMAND|MF_ENABLED);
\r
9019 (void) EnableMenuItem(GetMenu(hwndMain),
\r
9020 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
9023 prevChecked = nowChecked;
\r
9025 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
9026 if (appData.icsActive) {
\r
9027 if (appData.icsEngineAnalyze) {
\r
9028 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9029 MF_BYCOMMAND|MF_CHECKED);
\r
9031 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9032 MF_BYCOMMAND|MF_UNCHECKED);
\r
9040 HMENU hmenu = GetMenu(hwndMain);
\r
9041 SetMenuEnables(hmenu, icsEnables);
\r
9042 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9043 MF_BYPOSITION|MF_ENABLED);
\r
9045 if (appData.zippyPlay) {
\r
9046 SetMenuEnables(hmenu, zippyEnables);
\r
9047 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9048 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9049 MF_BYCOMMAND|MF_ENABLED);
\r
9057 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9063 HMENU hmenu = GetMenu(hwndMain);
\r
9064 SetMenuEnables(hmenu, ncpEnables);
\r
9065 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9066 MF_BYPOSITION|MF_GRAYED);
\r
9067 DrawMenuBar(hwndMain);
\r
9073 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9077 SetTrainingModeOn()
\r
9080 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9081 for (i = 0; i < N_BUTTONS; i++) {
\r
9082 if (buttonDesc[i].hwnd != NULL)
\r
9083 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9088 VOID SetTrainingModeOff()
\r
9091 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9092 for (i = 0; i < N_BUTTONS; i++) {
\r
9093 if (buttonDesc[i].hwnd != NULL)
\r
9094 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9100 SetUserThinkingEnables()
\r
9102 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9106 SetMachineThinkingEnables()
\r
9108 HMENU hMenu = GetMenu(hwndMain);
\r
9109 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9111 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9113 if (gameMode == MachinePlaysBlack) {
\r
9114 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9115 } else if (gameMode == MachinePlaysWhite) {
\r
9116 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9117 } else if (gameMode == TwoMachinesPlay) {
\r
9118 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9124 DisplayTitle(char *str)
\r
9126 char title[MSG_SIZ], *host;
\r
9127 if (str[0] != NULLCHAR) {
\r
9128 strcpy(title, str);
\r
9129 } else if (appData.icsActive) {
\r
9130 if (appData.icsCommPort[0] != NULLCHAR)
\r
9133 host = appData.icsHost;
\r
9134 sprintf(title, "%s: %s", szTitle, host);
\r
9135 } else if (appData.noChessProgram) {
\r
9136 strcpy(title, szTitle);
\r
9138 strcpy(title, szTitle);
\r
9139 strcat(title, ": ");
\r
9140 strcat(title, first.tidy);
\r
9142 SetWindowText(hwndMain, title);
\r
9147 DisplayMessage(char *str1, char *str2)
\r
9151 int remain = MESSAGE_TEXT_MAX - 1;
\r
9154 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9155 messageText[0] = NULLCHAR;
\r
9157 len = strlen(str1);
\r
9158 if (len > remain) len = remain;
\r
9159 strncpy(messageText, str1, len);
\r
9160 messageText[len] = NULLCHAR;
\r
9163 if (*str2 && remain >= 2) {
\r
9165 strcat(messageText, " ");
\r
9168 len = strlen(str2);
\r
9169 if (len > remain) len = remain;
\r
9170 strncat(messageText, str2, len);
\r
9172 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9174 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9178 hdc = GetDC(hwndMain);
\r
9179 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9180 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9181 &messageRect, messageText, strlen(messageText), NULL);
\r
9182 (void) SelectObject(hdc, oldFont);
\r
9183 (void) ReleaseDC(hwndMain, hdc);
\r
9187 DisplayError(char *str, int error)
\r
9189 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9195 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9196 NULL, error, LANG_NEUTRAL,
\r
9197 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9199 sprintf(buf, "%s:\n%s", str, buf2);
\r
9201 ErrorMap *em = errmap;
\r
9202 while (em->err != 0 && em->err != error) em++;
\r
9203 if (em->err != 0) {
\r
9204 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9206 sprintf(buf, "%s:\nError code %d", str, error);
\r
9211 ErrorPopUp("Error", buf);
\r
9216 DisplayMoveError(char *str)
\r
9218 fromX = fromY = -1;
\r
9219 ClearHighlights();
\r
9220 DrawPosition(FALSE, NULL);
\r
9221 if (appData.popupMoveErrors) {
\r
9222 ErrorPopUp("Error", str);
\r
9224 DisplayMessage(str, "");
\r
9225 moveErrorMessageUp = TRUE;
\r
9230 DisplayFatalError(char *str, int error, int exitStatus)
\r
9232 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9234 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9237 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9238 NULL, error, LANG_NEUTRAL,
\r
9239 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9241 sprintf(buf, "%s:\n%s", str, buf2);
\r
9243 ErrorMap *em = errmap;
\r
9244 while (em->err != 0 && em->err != error) em++;
\r
9245 if (em->err != 0) {
\r
9246 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9248 sprintf(buf, "%s:\nError code %d", str, error);
\r
9253 if (appData.debugMode) {
\r
9254 fprintf(debugFP, "%s: %s\n", label, str);
\r
9256 if (appData.popupExitMessage) {
\r
9257 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9258 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9260 ExitEvent(exitStatus);
\r
9265 DisplayInformation(char *str)
\r
9267 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9272 DisplayNote(char *str)
\r
9274 ErrorPopUp("Note", str);
\r
9279 char *title, *question, *replyPrefix;
\r
9284 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9286 static QuestionParams *qp;
\r
9287 char reply[MSG_SIZ];
\r
9290 switch (message) {
\r
9291 case WM_INITDIALOG:
\r
9292 qp = (QuestionParams *) lParam;
\r
9293 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9294 SetWindowText(hDlg, qp->title);
\r
9295 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9296 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9300 switch (LOWORD(wParam)) {
\r
9302 strcpy(reply, qp->replyPrefix);
\r
9303 if (*reply) strcat(reply, " ");
\r
9304 len = strlen(reply);
\r
9305 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9306 strcat(reply, "\n");
\r
9307 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9308 EndDialog(hDlg, TRUE);
\r
9309 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9312 EndDialog(hDlg, FALSE);
\r
9323 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9325 QuestionParams qp;
\r
9329 qp.question = question;
\r
9330 qp.replyPrefix = replyPrefix;
\r
9332 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9333 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9334 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9335 FreeProcInstance(lpProc);
\r
9338 /* [AS] Pick FRC position */
\r
9339 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9341 static int * lpIndexFRC;
\r
9347 case WM_INITDIALOG:
\r
9348 lpIndexFRC = (int *) lParam;
\r
9350 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9352 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9353 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9354 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9355 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9360 switch( LOWORD(wParam) ) {
\r
9362 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9363 EndDialog( hDlg, 0 );
\r
9364 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9367 EndDialog( hDlg, 1 );
\r
9369 case IDC_NFG_Edit:
\r
9370 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9371 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9373 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9376 case IDC_NFG_Random:
\r
9377 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9378 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9391 int index = appData.defaultFrcPosition;
\r
9392 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9394 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9396 if( result == 0 ) {
\r
9397 appData.defaultFrcPosition = index;
\r
9403 /* [AS] Game list options */
\r
9409 static GLT_Item GLT_ItemInfo[] = {
\r
9410 { GLT_EVENT, "Event" },
\r
9411 { GLT_SITE, "Site" },
\r
9412 { GLT_DATE, "Date" },
\r
9413 { GLT_ROUND, "Round" },
\r
9414 { GLT_PLAYERS, "Players" },
\r
9415 { GLT_RESULT, "Result" },
\r
9416 { GLT_WHITE_ELO, "White Rating" },
\r
9417 { GLT_BLACK_ELO, "Black Rating" },
\r
9418 { GLT_TIME_CONTROL,"Time Control" },
\r
9419 { GLT_VARIANT, "Variant" },
\r
9420 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9421 { GLT_RESULT_COMMENT, "Result Comment" }, // [HGM] rescom
\r
9425 const char * GLT_FindItem( char id )
\r
9427 const char * result = 0;
\r
9429 GLT_Item * list = GLT_ItemInfo;
\r
9431 while( list->id != 0 ) {
\r
9432 if( list->id == id ) {
\r
9433 result = list->name;
\r
9443 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9445 const char * name = GLT_FindItem( id );
\r
9448 if( index >= 0 ) {
\r
9449 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9452 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9457 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9461 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9464 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9468 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9470 pc = GLT_ALL_TAGS;
\r
9473 if( strchr( tags, *pc ) == 0 ) {
\r
9474 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9479 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9482 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9484 char result = '\0';
\r
9487 GLT_Item * list = GLT_ItemInfo;
\r
9489 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9490 while( list->id != 0 ) {
\r
9491 if( strcmp( list->name, name ) == 0 ) {
\r
9492 result = list->id;
\r
9503 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9505 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9506 int idx2 = idx1 + delta;
\r
9507 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9509 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9512 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9513 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9514 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9515 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9519 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9521 static char glt[64];
\r
9522 static char * lpUserGLT;
\r
9526 case WM_INITDIALOG:
\r
9527 lpUserGLT = (char *) lParam;
\r
9529 strcpy( glt, lpUserGLT );
\r
9531 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9533 /* Initialize list */
\r
9534 GLT_TagsToList( hDlg, glt );
\r
9536 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9541 switch( LOWORD(wParam) ) {
\r
9544 char * pc = lpUserGLT;
\r
9546 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9550 id = GLT_ListItemToTag( hDlg, idx );
\r
9554 } while( id != '\0' );
\r
9556 EndDialog( hDlg, 0 );
\r
9559 EndDialog( hDlg, 1 );
\r
9562 case IDC_GLT_Default:
\r
9563 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9564 GLT_TagsToList( hDlg, glt );
\r
9567 case IDC_GLT_Restore:
\r
9568 strcpy( glt, lpUserGLT );
\r
9569 GLT_TagsToList( hDlg, glt );
\r
9573 GLT_MoveSelection( hDlg, -1 );
\r
9576 case IDC_GLT_Down:
\r
9577 GLT_MoveSelection( hDlg, +1 );
\r
9587 int GameListOptions()
\r
9591 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9593 strcpy( glt, appData.gameListTags );
\r
9595 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9597 if( result == 0 ) {
\r
9598 /* [AS] Memory leak here! */
\r
9599 appData.gameListTags = strdup( glt );
\r
9607 DisplayIcsInteractionTitle(char *str)
\r
9609 char consoleTitle[MSG_SIZ];
\r
9611 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9612 SetWindowText(hwndConsole, consoleTitle);
\r
9616 DrawPosition(int fullRedraw, Board board)
\r
9618 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9625 fromX = fromY = -1;
\r
9626 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9627 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9628 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9629 dragInfo.lastpos = dragInfo.pos;
\r
9630 dragInfo.start.x = dragInfo.start.y = -1;
\r
9631 dragInfo.from = dragInfo.start;
\r
9633 DrawPosition(TRUE, NULL);
\r
9639 CommentPopUp(char *title, char *str)
\r
9641 HWND hwnd = GetActiveWindow();
\r
9642 EitherCommentPopUp(0, title, str, FALSE);
\r
9643 SetActiveWindow(hwnd);
\r
9647 CommentPopDown(void)
\r
9649 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9650 if (commentDialog) {
\r
9651 ShowWindow(commentDialog, SW_HIDE);
\r
9653 commentDialogUp = FALSE;
\r
9657 EditCommentPopUp(int index, char *title, char *str)
\r
9659 EitherCommentPopUp(index, title, str, TRUE);
\r
9666 MyPlaySound(&sounds[(int)SoundMove]);
\r
9669 VOID PlayIcsWinSound()
\r
9671 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9674 VOID PlayIcsLossSound()
\r
9676 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9679 VOID PlayIcsDrawSound()
\r
9681 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9684 VOID PlayIcsUnfinishedSound()
\r
9686 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9692 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9700 consoleEcho = TRUE;
\r
9701 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9702 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9703 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9712 consoleEcho = FALSE;
\r
9713 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9714 /* This works OK: set text and background both to the same color */
\r
9716 cf.crTextColor = COLOR_ECHOOFF;
\r
9717 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9718 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9721 /* No Raw()...? */
\r
9723 void Colorize(ColorClass cc, int continuation)
\r
9725 currentColorClass = cc;
\r
9726 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9727 consoleCF.crTextColor = textAttribs[cc].color;
\r
9728 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9729 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9735 static char buf[MSG_SIZ];
\r
9736 DWORD bufsiz = MSG_SIZ;
\r
9738 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9739 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9741 if (!GetUserName(buf, &bufsiz)) {
\r
9742 /*DisplayError("Error getting user name", GetLastError());*/
\r
9743 strcpy(buf, "User");
\r
9751 static char buf[MSG_SIZ];
\r
9752 DWORD bufsiz = MSG_SIZ;
\r
9754 if (!GetComputerName(buf, &bufsiz)) {
\r
9755 /*DisplayError("Error getting host name", GetLastError());*/
\r
9756 strcpy(buf, "Unknown");
\r
9763 ClockTimerRunning()
\r
9765 return clockTimerEvent != 0;
\r
9771 if (clockTimerEvent == 0) return FALSE;
\r
9772 KillTimer(hwndMain, clockTimerEvent);
\r
9773 clockTimerEvent = 0;
\r
9778 StartClockTimer(long millisec)
\r
9780 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9781 (UINT) millisec, NULL);
\r
9785 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9788 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9790 if(appData.noGUI) return;
\r
9791 hdc = GetDC(hwndMain);
\r
9792 if (!IsIconic(hwndMain)) {
\r
9793 DisplayAClock(hdc, timeRemaining, highlight,
\r
9794 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9796 if (highlight && iconCurrent == iconBlack) {
\r
9797 iconCurrent = iconWhite;
\r
9798 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9799 if (IsIconic(hwndMain)) {
\r
9800 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9803 (void) ReleaseDC(hwndMain, hdc);
\r
9805 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9809 DisplayBlackClock(long timeRemaining, int highlight)
\r
9812 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9814 if(appData.noGUI) return;
\r
9815 hdc = GetDC(hwndMain);
\r
9816 if (!IsIconic(hwndMain)) {
\r
9817 DisplayAClock(hdc, timeRemaining, highlight,
\r
9818 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9820 if (highlight && iconCurrent == iconWhite) {
\r
9821 iconCurrent = iconBlack;
\r
9822 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9823 if (IsIconic(hwndMain)) {
\r
9824 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9827 (void) ReleaseDC(hwndMain, hdc);
\r
9829 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9834 LoadGameTimerRunning()
\r
9836 return loadGameTimerEvent != 0;
\r
9840 StopLoadGameTimer()
\r
9842 if (loadGameTimerEvent == 0) return FALSE;
\r
9843 KillTimer(hwndMain, loadGameTimerEvent);
\r
9844 loadGameTimerEvent = 0;
\r
9849 StartLoadGameTimer(long millisec)
\r
9851 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9852 (UINT) millisec, NULL);
\r
9860 char fileTitle[MSG_SIZ];
\r
9862 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9863 f = OpenFileDialog(hwndMain, "a", defName,
\r
9864 appData.oldSaveStyle ? "gam" : "pgn",
\r
9866 "Save Game to File", NULL, fileTitle, NULL);
\r
9868 SaveGame(f, 0, "");
\r
9875 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9877 if (delayedTimerEvent != 0) {
\r
9878 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9879 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9881 KillTimer(hwndMain, delayedTimerEvent);
\r
9882 delayedTimerEvent = 0;
\r
9883 if(delayedTimerCallback != cb) // [HGM] alive: do not "flush" same event, just postpone it
\r
9884 delayedTimerCallback();
\r
9886 delayedTimerCallback = cb;
\r
9887 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9888 (UINT) millisec, NULL);
\r
9891 DelayedEventCallback
\r
9894 if (delayedTimerEvent) {
\r
9895 return delayedTimerCallback;
\r
9902 CancelDelayedEvent()
\r
9904 if (delayedTimerEvent) {
\r
9905 KillTimer(hwndMain, delayedTimerEvent);
\r
9906 delayedTimerEvent = 0;
\r
9910 DWORD GetWin32Priority(int nice)
\r
9911 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9913 REALTIME_PRIORITY_CLASS 0x00000100
\r
9914 HIGH_PRIORITY_CLASS 0x00000080
\r
9915 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9916 NORMAL_PRIORITY_CLASS 0x00000020
\r
9917 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9918 IDLE_PRIORITY_CLASS 0x00000040
\r
9920 if (nice < -15) return 0x00000080;
\r
9921 if (nice < 0) return 0x00008000;
\r
9922 if (nice == 0) return 0x00000020;
\r
9923 if (nice < 15) return 0x00004000;
\r
9924 return 0x00000040;
\r
9927 /* Start a child process running the given program.
\r
9928 The process's standard output can be read from "from", and its
\r
9929 standard input can be written to "to".
\r
9930 Exit with fatal error if anything goes wrong.
\r
9931 Returns an opaque pointer that can be used to destroy the process
\r
9935 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9937 #define BUFSIZE 4096
\r
9939 HANDLE hChildStdinRd, hChildStdinWr,
\r
9940 hChildStdoutRd, hChildStdoutWr;
\r
9941 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9942 SECURITY_ATTRIBUTES saAttr;
\r
9944 PROCESS_INFORMATION piProcInfo;
\r
9945 STARTUPINFO siStartInfo;
\r
9947 char buf[MSG_SIZ];
\r
9950 if (appData.debugMode) {
\r
9951 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9956 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9957 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9958 saAttr.bInheritHandle = TRUE;
\r
9959 saAttr.lpSecurityDescriptor = NULL;
\r
9962 * The steps for redirecting child's STDOUT:
\r
9963 * 1. Create anonymous pipe to be STDOUT for child.
\r
9964 * 2. Create a noninheritable duplicate of read handle,
\r
9965 * and close the inheritable read handle.
\r
9968 /* Create a pipe for the child's STDOUT. */
\r
9969 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9970 return GetLastError();
\r
9973 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9974 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9975 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9976 FALSE, /* not inherited */
\r
9977 DUPLICATE_SAME_ACCESS);
\r
9979 return GetLastError();
\r
9981 CloseHandle(hChildStdoutRd);
\r
9984 * The steps for redirecting child's STDIN:
\r
9985 * 1. Create anonymous pipe to be STDIN for child.
\r
9986 * 2. Create a noninheritable duplicate of write handle,
\r
9987 * and close the inheritable write handle.
\r
9990 /* Create a pipe for the child's STDIN. */
\r
9991 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9992 return GetLastError();
\r
9995 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9996 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9997 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9998 FALSE, /* not inherited */
\r
9999 DUPLICATE_SAME_ACCESS);
\r
10000 if (! fSuccess) {
\r
10001 return GetLastError();
\r
10003 CloseHandle(hChildStdinWr);
\r
10005 /* Arrange to (1) look in dir for the child .exe file, and
\r
10006 * (2) have dir be the child's working directory. Interpret
\r
10007 * dir relative to the directory WinBoard loaded from. */
\r
10008 GetCurrentDirectory(MSG_SIZ, buf);
\r
10009 SetCurrentDirectory(installDir);
\r
10010 SetCurrentDirectory(dir);
\r
10012 /* Now create the child process. */
\r
10014 siStartInfo.cb = sizeof(STARTUPINFO);
\r
10015 siStartInfo.lpReserved = NULL;
\r
10016 siStartInfo.lpDesktop = NULL;
\r
10017 siStartInfo.lpTitle = NULL;
\r
10018 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
10019 siStartInfo.cbReserved2 = 0;
\r
10020 siStartInfo.lpReserved2 = NULL;
\r
10021 siStartInfo.hStdInput = hChildStdinRd;
\r
10022 siStartInfo.hStdOutput = hChildStdoutWr;
\r
10023 siStartInfo.hStdError = hChildStdoutWr;
\r
10025 fSuccess = CreateProcess(NULL,
\r
10026 cmdLine, /* command line */
\r
10027 NULL, /* process security attributes */
\r
10028 NULL, /* primary thread security attrs */
\r
10029 TRUE, /* handles are inherited */
\r
10030 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
10031 NULL, /* use parent's environment */
\r
10033 &siStartInfo, /* STARTUPINFO pointer */
\r
10034 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
10036 err = GetLastError();
\r
10037 SetCurrentDirectory(buf); /* return to prev directory */
\r
10038 if (! fSuccess) {
\r
10042 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10043 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10044 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10047 /* Close the handles we don't need in the parent */
\r
10048 CloseHandle(piProcInfo.hThread);
\r
10049 CloseHandle(hChildStdinRd);
\r
10050 CloseHandle(hChildStdoutWr);
\r
10052 /* Prepare return value */
\r
10053 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10054 cp->kind = CPReal;
\r
10055 cp->hProcess = piProcInfo.hProcess;
\r
10056 cp->pid = piProcInfo.dwProcessId;
\r
10057 cp->hFrom = hChildStdoutRdDup;
\r
10058 cp->hTo = hChildStdinWrDup;
\r
10060 *pr = (void *) cp;
\r
10062 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10063 2000 where engines sometimes don't see the initial command(s)
\r
10064 from WinBoard and hang. I don't understand how that can happen,
\r
10065 but the Sleep is harmless, so I've put it in. Others have also
\r
10066 reported what may be the same problem, so hopefully this will fix
\r
10067 it for them too. */
\r
10075 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10077 ChildProc *cp; int result;
\r
10079 cp = (ChildProc *) pr;
\r
10080 if (cp == NULL) return;
\r
10082 switch (cp->kind) {
\r
10084 /* TerminateProcess is considered harmful, so... */
\r
10085 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10086 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10087 /* The following doesn't work because the chess program
\r
10088 doesn't "have the same console" as WinBoard. Maybe
\r
10089 we could arrange for this even though neither WinBoard
\r
10090 nor the chess program uses a console for stdio? */
\r
10091 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10093 /* [AS] Special termination modes for misbehaving programs... */
\r
10094 if( signal == 9 ) {
\r
10095 result = TerminateProcess( cp->hProcess, 0 );
\r
10097 if ( appData.debugMode) {
\r
10098 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10101 else if( signal == 10 ) {
\r
10102 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10104 if( dw != WAIT_OBJECT_0 ) {
\r
10105 result = TerminateProcess( cp->hProcess, 0 );
\r
10107 if ( appData.debugMode) {
\r
10108 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10114 CloseHandle(cp->hProcess);
\r
10118 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10122 closesocket(cp->sock);
\r
10127 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10128 closesocket(cp->sock);
\r
10129 closesocket(cp->sock2);
\r
10137 InterruptChildProcess(ProcRef pr)
\r
10141 cp = (ChildProc *) pr;
\r
10142 if (cp == NULL) return;
\r
10143 switch (cp->kind) {
\r
10145 /* The following doesn't work because the chess program
\r
10146 doesn't "have the same console" as WinBoard. Maybe
\r
10147 we could arrange for this even though neither WinBoard
\r
10148 nor the chess program uses a console for stdio */
\r
10149 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10154 /* Can't interrupt */
\r
10158 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10165 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10167 char cmdLine[MSG_SIZ];
\r
10169 if (port[0] == NULLCHAR) {
\r
10170 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10172 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10174 return StartChildProcess(cmdLine, "", pr);
\r
10178 /* Code to open TCP sockets */
\r
10181 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10186 struct sockaddr_in sa, mysa;
\r
10187 struct hostent FAR *hp;
\r
10188 unsigned short uport;
\r
10189 WORD wVersionRequested;
\r
10192 /* Initialize socket DLL */
\r
10193 wVersionRequested = MAKEWORD(1, 1);
\r
10194 err = WSAStartup(wVersionRequested, &wsaData);
\r
10195 if (err != 0) return err;
\r
10197 /* Make socket */
\r
10198 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10199 err = WSAGetLastError();
\r
10204 /* Bind local address using (mostly) don't-care values.
\r
10206 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10207 mysa.sin_family = AF_INET;
\r
10208 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10209 uport = (unsigned short) 0;
\r
10210 mysa.sin_port = htons(uport);
\r
10211 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10212 == SOCKET_ERROR) {
\r
10213 err = WSAGetLastError();
\r
10218 /* Resolve remote host name */
\r
10219 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10220 if (!(hp = gethostbyname(host))) {
\r
10221 unsigned int b0, b1, b2, b3;
\r
10223 err = WSAGetLastError();
\r
10225 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10226 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10227 hp->h_addrtype = AF_INET;
\r
10228 hp->h_length = 4;
\r
10229 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10230 hp->h_addr_list[0] = (char *) malloc(4);
\r
10231 hp->h_addr_list[0][0] = (char) b0;
\r
10232 hp->h_addr_list[0][1] = (char) b1;
\r
10233 hp->h_addr_list[0][2] = (char) b2;
\r
10234 hp->h_addr_list[0][3] = (char) b3;
\r
10240 sa.sin_family = hp->h_addrtype;
\r
10241 uport = (unsigned short) atoi(port);
\r
10242 sa.sin_port = htons(uport);
\r
10243 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10245 /* Make connection */
\r
10246 if (connect(s, (struct sockaddr *) &sa,
\r
10247 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10248 err = WSAGetLastError();
\r
10253 /* Prepare return value */
\r
10254 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10255 cp->kind = CPSock;
\r
10257 *pr = (ProcRef *) cp;
\r
10263 OpenCommPort(char *name, ProcRef *pr)
\r
10268 char fullname[MSG_SIZ];
\r
10270 if (*name != '\\')
\r
10271 sprintf(fullname, "\\\\.\\%s", name);
\r
10273 strcpy(fullname, name);
\r
10275 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10276 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10277 if (h == (HANDLE) -1) {
\r
10278 return GetLastError();
\r
10282 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10284 /* Accumulate characters until a 100ms pause, then parse */
\r
10285 ct.ReadIntervalTimeout = 100;
\r
10286 ct.ReadTotalTimeoutMultiplier = 0;
\r
10287 ct.ReadTotalTimeoutConstant = 0;
\r
10288 ct.WriteTotalTimeoutMultiplier = 0;
\r
10289 ct.WriteTotalTimeoutConstant = 0;
\r
10290 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10292 /* Prepare return value */
\r
10293 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10294 cp->kind = CPComm;
\r
10297 *pr = (ProcRef *) cp;
\r
10303 OpenLoopback(ProcRef *pr)
\r
10305 DisplayFatalError("Not implemented", 0, 1);
\r
10311 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10315 SOCKET s, s2, s3;
\r
10316 struct sockaddr_in sa, mysa;
\r
10317 struct hostent FAR *hp;
\r
10318 unsigned short uport;
\r
10319 WORD wVersionRequested;
\r
10322 char stderrPortStr[MSG_SIZ];
\r
10324 /* Initialize socket DLL */
\r
10325 wVersionRequested = MAKEWORD(1, 1);
\r
10326 err = WSAStartup(wVersionRequested, &wsaData);
\r
10327 if (err != 0) return err;
\r
10329 /* Resolve remote host name */
\r
10330 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10331 if (!(hp = gethostbyname(host))) {
\r
10332 unsigned int b0, b1, b2, b3;
\r
10334 err = WSAGetLastError();
\r
10336 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10337 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10338 hp->h_addrtype = AF_INET;
\r
10339 hp->h_length = 4;
\r
10340 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10341 hp->h_addr_list[0] = (char *) malloc(4);
\r
10342 hp->h_addr_list[0][0] = (char) b0;
\r
10343 hp->h_addr_list[0][1] = (char) b1;
\r
10344 hp->h_addr_list[0][2] = (char) b2;
\r
10345 hp->h_addr_list[0][3] = (char) b3;
\r
10351 sa.sin_family = hp->h_addrtype;
\r
10352 uport = (unsigned short) 514;
\r
10353 sa.sin_port = htons(uport);
\r
10354 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10356 /* Bind local socket to unused "privileged" port address
\r
10358 s = INVALID_SOCKET;
\r
10359 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10360 mysa.sin_family = AF_INET;
\r
10361 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10362 for (fromPort = 1023;; fromPort--) {
\r
10363 if (fromPort < 0) {
\r
10365 return WSAEADDRINUSE;
\r
10367 if (s == INVALID_SOCKET) {
\r
10368 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10369 err = WSAGetLastError();
\r
10374 uport = (unsigned short) fromPort;
\r
10375 mysa.sin_port = htons(uport);
\r
10376 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10377 == SOCKET_ERROR) {
\r
10378 err = WSAGetLastError();
\r
10379 if (err == WSAEADDRINUSE) continue;
\r
10383 if (connect(s, (struct sockaddr *) &sa,
\r
10384 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10385 err = WSAGetLastError();
\r
10386 if (err == WSAEADDRINUSE) {
\r
10397 /* Bind stderr local socket to unused "privileged" port address
\r
10399 s2 = INVALID_SOCKET;
\r
10400 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10401 mysa.sin_family = AF_INET;
\r
10402 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10403 for (fromPort = 1023;; fromPort--) {
\r
10404 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10405 if (fromPort < 0) {
\r
10406 (void) closesocket(s);
\r
10408 return WSAEADDRINUSE;
\r
10410 if (s2 == INVALID_SOCKET) {
\r
10411 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10412 err = WSAGetLastError();
\r
10418 uport = (unsigned short) fromPort;
\r
10419 mysa.sin_port = htons(uport);
\r
10420 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10421 == SOCKET_ERROR) {
\r
10422 err = WSAGetLastError();
\r
10423 if (err == WSAEADDRINUSE) continue;
\r
10424 (void) closesocket(s);
\r
10428 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10429 err = WSAGetLastError();
\r
10430 if (err == WSAEADDRINUSE) {
\r
10432 s2 = INVALID_SOCKET;
\r
10435 (void) closesocket(s);
\r
10436 (void) closesocket(s2);
\r
10442 prevStderrPort = fromPort; // remember port used
\r
10443 sprintf(stderrPortStr, "%d", fromPort);
\r
10445 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10446 err = WSAGetLastError();
\r
10447 (void) closesocket(s);
\r
10448 (void) closesocket(s2);
\r
10453 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10454 err = WSAGetLastError();
\r
10455 (void) closesocket(s);
\r
10456 (void) closesocket(s2);
\r
10460 if (*user == NULLCHAR) user = UserName();
\r
10461 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10462 err = WSAGetLastError();
\r
10463 (void) closesocket(s);
\r
10464 (void) closesocket(s2);
\r
10468 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10469 err = WSAGetLastError();
\r
10470 (void) closesocket(s);
\r
10471 (void) closesocket(s2);
\r
10476 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10477 err = WSAGetLastError();
\r
10478 (void) closesocket(s);
\r
10479 (void) closesocket(s2);
\r
10483 (void) closesocket(s2); /* Stop listening */
\r
10485 /* Prepare return value */
\r
10486 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10487 cp->kind = CPRcmd;
\r
10490 *pr = (ProcRef *) cp;
\r
10497 AddInputSource(ProcRef pr, int lineByLine,
\r
10498 InputCallback func, VOIDSTAR closure)
\r
10500 InputSource *is, *is2 = NULL;
\r
10501 ChildProc *cp = (ChildProc *) pr;
\r
10503 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10504 is->lineByLine = lineByLine;
\r
10506 is->closure = closure;
\r
10507 is->second = NULL;
\r
10508 is->next = is->buf;
\r
10509 if (pr == NoProc) {
\r
10510 is->kind = CPReal;
\r
10511 consoleInputSource = is;
\r
10513 is->kind = cp->kind;
\r
10515 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10516 we create all threads suspended so that the is->hThread variable can be
\r
10517 safely assigned, then let the threads start with ResumeThread.
\r
10519 switch (cp->kind) {
\r
10521 is->hFile = cp->hFrom;
\r
10522 cp->hFrom = NULL; /* now owned by InputThread */
\r
10524 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10525 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10529 is->hFile = cp->hFrom;
\r
10530 cp->hFrom = NULL; /* now owned by InputThread */
\r
10532 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10533 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10537 is->sock = cp->sock;
\r
10539 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10540 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10544 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10546 is->sock = cp->sock;
\r
10547 is->second = is2;
\r
10548 is2->sock = cp->sock2;
\r
10549 is2->second = is2;
\r
10551 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10552 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10554 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10555 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10559 if( is->hThread != NULL ) {
\r
10560 ResumeThread( is->hThread );
\r
10563 if( is2 != NULL && is2->hThread != NULL ) {
\r
10564 ResumeThread( is2->hThread );
\r
10568 return (InputSourceRef) is;
\r
10572 RemoveInputSource(InputSourceRef isr)
\r
10576 is = (InputSource *) isr;
\r
10577 is->hThread = NULL; /* tell thread to stop */
\r
10578 CloseHandle(is->hThread);
\r
10579 if (is->second != NULL) {
\r
10580 is->second->hThread = NULL;
\r
10581 CloseHandle(is->second->hThread);
\r
10587 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10590 int outCount = SOCKET_ERROR;
\r
10591 ChildProc *cp = (ChildProc *) pr;
\r
10592 static OVERLAPPED ovl;
\r
10594 if (pr == NoProc) {
\r
10595 ConsoleOutput(message, count, FALSE);
\r
10599 if (ovl.hEvent == NULL) {
\r
10600 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10602 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10604 switch (cp->kind) {
\r
10607 outCount = send(cp->sock, message, count, 0);
\r
10608 if (outCount == SOCKET_ERROR) {
\r
10609 *outError = WSAGetLastError();
\r
10611 *outError = NO_ERROR;
\r
10616 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10617 &dOutCount, NULL)) {
\r
10618 *outError = NO_ERROR;
\r
10619 outCount = (int) dOutCount;
\r
10621 *outError = GetLastError();
\r
10626 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10627 &dOutCount, &ovl);
\r
10628 if (*outError == NO_ERROR) {
\r
10629 outCount = (int) dOutCount;
\r
10637 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10640 /* Ignore delay, not implemented for WinBoard */
\r
10641 return OutputToProcess(pr, message, count, outError);
\r
10646 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10647 char *buf, int count, int error)
\r
10649 DisplayFatalError("Not implemented", 0, 1);
\r
10652 /* see wgamelist.c for Game List functions */
\r
10653 /* see wedittags.c for Edit Tags functions */
\r
10660 char buf[MSG_SIZ];
\r
10663 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10664 f = fopen(buf, "r");
\r
10666 ProcessICSInitScript(f);
\r
10674 StartAnalysisClock()
\r
10676 if (analysisTimerEvent) return;
\r
10677 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10678 (UINT) 2000, NULL);
\r
10682 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10684 static HANDLE hwndText;
\r
10686 static int sizeX, sizeY;
\r
10687 int newSizeX, newSizeY, flags;
\r
10690 switch (message) {
\r
10691 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10692 /* Initialize the dialog items */
\r
10693 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10694 SetWindowText(hDlg, analysisTitle);
\r
10695 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10696 /* Size and position the dialog */
\r
10697 if (!analysisDialog) {
\r
10698 analysisDialog = hDlg;
\r
10699 flags = SWP_NOZORDER;
\r
10700 GetClientRect(hDlg, &rect);
\r
10701 sizeX = rect.right;
\r
10702 sizeY = rect.bottom;
\r
10703 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10704 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10705 WINDOWPLACEMENT wp;
\r
10706 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10707 wp.length = sizeof(WINDOWPLACEMENT);
\r
10709 wp.showCmd = SW_SHOW;
\r
10710 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10711 wp.rcNormalPosition.left = analysisX;
\r
10712 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10713 wp.rcNormalPosition.top = analysisY;
\r
10714 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10715 SetWindowPlacement(hDlg, &wp);
\r
10717 GetClientRect(hDlg, &rect);
\r
10718 newSizeX = rect.right;
\r
10719 newSizeY = rect.bottom;
\r
10720 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10721 newSizeX, newSizeY);
\r
10722 sizeX = newSizeX;
\r
10723 sizeY = newSizeY;
\r
10728 case WM_COMMAND: /* message: received a command */
\r
10729 switch (LOWORD(wParam)) {
\r
10731 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10732 ExitAnalyzeMode();
\r
10744 newSizeX = LOWORD(lParam);
\r
10745 newSizeY = HIWORD(lParam);
\r
10746 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10747 sizeX = newSizeX;
\r
10748 sizeY = newSizeY;
\r
10751 case WM_GETMINMAXINFO:
\r
10752 /* Prevent resizing window too small */
\r
10753 mmi = (MINMAXINFO *) lParam;
\r
10754 mmi->ptMinTrackSize.x = 100;
\r
10755 mmi->ptMinTrackSize.y = 100;
\r
10762 AnalysisPopUp(char* title, char* str)
\r
10768 EngineOutputPopUp();
\r
10771 if (str == NULL) str = "";
\r
10772 p = (char *) malloc(2 * strlen(str) + 2);
\r
10775 if (*str == '\n') *q++ = '\r';
\r
10779 if (analysisText != NULL) free(analysisText);
\r
10780 analysisText = p;
\r
10782 if (analysisDialog) {
\r
10783 SetWindowText(analysisDialog, title);
\r
10784 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10785 ShowWindow(analysisDialog, SW_SHOW);
\r
10787 analysisTitle = title;
\r
10788 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10789 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10790 hwndMain, (DLGPROC)lpProc);
\r
10791 FreeProcInstance(lpProc);
\r
10793 analysisDialogUp = TRUE;
\r
10797 AnalysisPopDown()
\r
10799 if (analysisDialog) {
\r
10800 ShowWindow(analysisDialog, SW_HIDE);
\r
10802 analysisDialogUp = FALSE;
\r
10807 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10809 highlightInfo.sq[0].x = fromX;
\r
10810 highlightInfo.sq[0].y = fromY;
\r
10811 highlightInfo.sq[1].x = toX;
\r
10812 highlightInfo.sq[1].y = toY;
\r
10816 ClearHighlights()
\r
10818 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10819 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10823 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10825 premoveHighlightInfo.sq[0].x = fromX;
\r
10826 premoveHighlightInfo.sq[0].y = fromY;
\r
10827 premoveHighlightInfo.sq[1].x = toX;
\r
10828 premoveHighlightInfo.sq[1].y = toY;
\r
10832 ClearPremoveHighlights()
\r
10834 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10835 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10839 ShutDownFrontEnd()
\r
10841 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10842 DeleteClipboardTempFiles();
\r
10848 if (IsIconic(hwndMain))
\r
10849 ShowWindow(hwndMain, SW_RESTORE);
\r
10851 SetActiveWindow(hwndMain);
\r
10855 * Prototypes for animation support routines
\r
10857 static void ScreenSquare(int column, int row, POINT * pt);
\r
10858 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10859 POINT frames[], int * nFrames);
\r
10863 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10864 { // [HGM] atomic: animate blast wave
\r
10866 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10867 explodeInfo.fromX = fromX;
\r
10868 explodeInfo.fromY = fromY;
\r
10869 explodeInfo.toX = toX;
\r
10870 explodeInfo.toY = toY;
\r
10871 for(i=1; i<nFrames; i++) {
\r
10872 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10873 DrawPosition(FALSE, NULL);
\r
10874 Sleep(appData.animSpeed);
\r
10876 explodeInfo.radius = 0;
\r
10877 DrawPosition(TRUE, NULL);
\r
10880 #define kFactor 4
\r
10883 AnimateMove(board, fromX, fromY, toX, toY)
\r
10890 ChessSquare piece;
\r
10891 POINT start, finish, mid;
\r
10892 POINT frames[kFactor * 2 + 1];
\r
10895 if (!appData.animate) return;
\r
10896 if (doingSizing) return;
\r
10897 if (fromY < 0 || fromX < 0) return;
\r
10898 piece = board[fromY][fromX];
\r
10899 if (piece >= EmptySquare) return;
\r
10901 ScreenSquare(fromX, fromY, &start);
\r
10902 ScreenSquare(toX, toY, &finish);
\r
10904 /* All pieces except knights move in straight line */
\r
10905 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10906 mid.x = start.x + (finish.x - start.x) / 2;
\r
10907 mid.y = start.y + (finish.y - start.y) / 2;
\r
10909 /* Knight: make diagonal movement then straight */
\r
10910 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10911 mid.x = start.x + (finish.x - start.x) / 2;
\r
10912 mid.y = finish.y;
\r
10914 mid.x = finish.x;
\r
10915 mid.y = start.y + (finish.y - start.y) / 2;
\r
10919 /* Don't use as many frames for very short moves */
\r
10920 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10921 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10923 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10925 animInfo.from.x = fromX;
\r
10926 animInfo.from.y = fromY;
\r
10927 animInfo.to.x = toX;
\r
10928 animInfo.to.y = toY;
\r
10929 animInfo.lastpos = start;
\r
10930 animInfo.piece = piece;
\r
10931 for (n = 0; n < nFrames; n++) {
\r
10932 animInfo.pos = frames[n];
\r
10933 DrawPosition(FALSE, NULL);
\r
10934 animInfo.lastpos = animInfo.pos;
\r
10935 Sleep(appData.animSpeed);
\r
10937 animInfo.pos = finish;
\r
10938 DrawPosition(FALSE, NULL);
\r
10939 animInfo.piece = EmptySquare;
\r
10940 if(gameInfo.variant == VariantAtomic &&
\r
10941 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10942 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10945 /* Convert board position to corner of screen rect and color */
\r
10948 ScreenSquare(column, row, pt)
\r
10949 int column; int row; POINT * pt;
\r
10952 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10953 pt->y = lineGap + row * (squareSize + lineGap);
\r
10955 pt->x = lineGap + column * (squareSize + lineGap);
\r
10956 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10960 /* Generate a series of frame coords from start->mid->finish.
\r
10961 The movement rate doubles until the half way point is
\r
10962 reached, then halves back down to the final destination,
\r
10963 which gives a nice slow in/out effect. The algorithmn
\r
10964 may seem to generate too many intermediates for short
\r
10965 moves, but remember that the purpose is to attract the
\r
10966 viewers attention to the piece about to be moved and
\r
10967 then to where it ends up. Too few frames would be less
\r
10971 Tween(start, mid, finish, factor, frames, nFrames)
\r
10972 POINT * start; POINT * mid;
\r
10973 POINT * finish; int factor;
\r
10974 POINT frames[]; int * nFrames;
\r
10976 int n, fraction = 1, count = 0;
\r
10978 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10979 for (n = 0; n < factor; n++)
\r
10981 for (n = 0; n < factor; n++) {
\r
10982 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10983 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10985 fraction = fraction / 2;
\r
10989 frames[count] = *mid;
\r
10992 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10994 for (n = 0; n < factor; n++) {
\r
10995 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10996 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10998 fraction = fraction * 2;
\r
11000 *nFrames = count;
\r
11004 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
11009 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
11010 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
11012 OutputDebugString( buf );
\r
11015 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
11017 EvalGraphSet( first, last, current, pvInfoList );
\r
11020 void SetProgramStats( FrontEndProgramStats * stats )
\r
11025 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
11026 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
11028 OutputDebugString( buf );
\r
11031 EngineOutputUpdate( stats );
\r