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
500 #define JAWS_ALT_INTERCEPT
\r
501 #define JAWS_KB_NAVIGATION
\r
502 #define JAWS_MENU_ITEMS
\r
503 #define JAWS_SILENCE
\r
504 #define JAWS_REPLAY
\r
506 #define JAWS_COPYRIGHT
\r
507 #define JAWS_DELETE(X) X
\r
508 #define SAYMACHINEMOVE()
\r
512 /*---------------------------------------------------------------------------*\
\r
516 \*---------------------------------------------------------------------------*/
\r
519 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
520 LPSTR lpCmdLine, int nCmdShow)
\r
523 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
524 // INITCOMMONCONTROLSEX ex;
\r
528 LoadLibrary("RICHED32.DLL");
\r
529 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
531 if (!InitApplication(hInstance)) {
\r
534 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
540 // InitCommonControlsEx(&ex);
\r
541 InitCommonControls();
\r
543 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
544 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
545 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
547 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
549 while (GetMessage(&msg, /* message structure */
\r
550 NULL, /* handle of window receiving the message */
\r
551 0, /* lowest message to examine */
\r
552 0)) /* highest message to examine */
\r
555 if(msg.message == WM_CHAR && msg.wParam == '\t') {
\r
556 // [HGM] navigate: switch between all windows with tab
\r
557 HWND e1 = NULL, e2 = NULL, mh = NULL, hInput = NULL, hText = NULL;
\r
558 int i, currentElement = 0;
\r
560 // first determine what element of the chain we come from (if any)
\r
561 if(appData.icsActive) {
\r
562 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
563 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
565 if(engineOutputDialog && EngineOutputIsUp()) {
\r
566 e1 = GetDlgItem(engineOutputDialog, IDC_EngineMemo1);
\r
567 e2 = GetDlgItem(engineOutputDialog, IDC_EngineMemo2);
\r
569 if(moveHistoryDialog && MoveHistoryIsUp()) {
\r
570 mh = GetDlgItem(moveHistoryDialog, IDC_MoveHistory);
\r
572 if(msg.hwnd == hwndMain) currentElement = 7 ; else
\r
573 if(msg.hwnd == engineOutputDialog) currentElement = 2; else
\r
574 if(msg.hwnd == e1) currentElement = 2; else
\r
575 if(msg.hwnd == e2) currentElement = 3; else
\r
576 if(msg.hwnd == moveHistoryDialog) currentElement = 4; else
\r
577 if(msg.hwnd == mh) currentElement = 4; else
\r
578 if(msg.hwnd == evalGraphDialog) currentElement = 6; else
\r
579 if(msg.hwnd == hText) currentElement = 5; else
\r
580 if(msg.hwnd == hInput) currentElement = 6; else
\r
581 for (i = 0; i < N_BUTTONS; i++) {
\r
582 if (buttonDesc[i].hwnd == msg.hwnd) { currentElement = 1; break; }
\r
585 // determine where to go to
\r
586 if(currentElement) { HWND h = NULL; int direction = GetKeyState(VK_SHIFT) < 0 ? -1 : 1;
\r
588 currentElement = (currentElement + direction) % 7;
\r
589 switch(currentElement) {
\r
591 h = hwndMain; break; // passing this case always makes the loop exit
\r
593 h = buttonDesc[0].hwnd; break; // could be NULL
\r
595 if(!EngineOutputIsUp()) continue; // skip closed auxiliary windows
\r
598 if(!EngineOutputIsUp()) continue;
\r
601 if(!MoveHistoryIsUp()) continue;
\r
603 // case 6: // input to eval graph does not seem to get here!
\r
604 // if(!EvalGraphIsUp()) continue;
\r
605 // h = evalGraphDialog; break;
\r
607 if(!appData.icsActive) continue;
\r
611 if(!appData.icsActive) continue;
\r
617 if(currentElement > 4 && IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
618 if(currentElement < 5 && IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE); // all open together
\r
621 continue; // this message now has been processed
\r
625 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
626 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
627 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
628 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
629 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
630 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
631 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
632 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) && JAWS_ACCEL
\r
633 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
634 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
635 int done = 0, i; // [HGM] chat: dispatch cat-box messages
\r
636 for(i=0; i<MAX_CHAT; i++)
\r
637 if(chatHandle[i] && IsDialogMessage(chatHandle[i], &msg)) {
\r
640 if(done) continue; // [HGM] chat: end patch
\r
641 TranslateMessage(&msg); /* Translates virtual key codes */
\r
642 DispatchMessage(&msg); /* Dispatches message to window */
\r
647 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
650 /*---------------------------------------------------------------------------*\
\r
652 * Initialization functions
\r
654 \*---------------------------------------------------------------------------*/
\r
658 { // update user logo if necessary
\r
659 static char oldUserName[MSG_SIZ], *curName;
\r
661 if(appData.autoLogo) {
\r
662 curName = UserName();
\r
663 if(strcmp(curName, oldUserName)) {
\r
664 sprintf(oldUserName, "logos\\%s.bmp", curName);
\r
665 userLogo = LoadImage( 0, oldUserName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
666 strcpy(oldUserName, curName);
\r
672 InitApplication(HINSTANCE hInstance)
\r
676 /* Fill in window class structure with parameters that describe the */
\r
679 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
680 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
681 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
682 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
683 wc.hInstance = hInstance; /* Owner of this class */
\r
684 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
685 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
686 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
687 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
688 wc.lpszClassName = szAppName; /* Name to register as */
\r
690 /* Register the window class and return success/failure code. */
\r
691 if (!RegisterClass(&wc)) return FALSE;
\r
693 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
694 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
696 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
697 wc.hInstance = hInstance;
\r
698 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
699 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
700 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
701 wc.lpszMenuName = NULL;
\r
702 wc.lpszClassName = szConsoleName;
\r
704 if (!RegisterClass(&wc)) return FALSE;
\r
709 /* Set by InitInstance, used by EnsureOnScreen */
\r
710 int screenHeight, screenWidth;
\r
713 EnsureOnScreen(int *x, int *y, int minX, int minY)
\r
715 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
716 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
717 if (*x > screenWidth - 32) *x = 0;
\r
718 if (*y > screenHeight - 32) *y = 0;
\r
719 if (*x < minX) *x = minX;
\r
720 if (*y < minY) *y = minY;
\r
724 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
726 HWND hwnd; /* Main window handle. */
\r
728 WINDOWPLACEMENT wp;
\r
731 hInst = hInstance; /* Store instance handle in our global variable */
\r
733 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
734 *filepart = NULLCHAR;
\r
736 GetCurrentDirectory(MSG_SIZ, installDir);
\r
738 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
739 screenWidth = screenHeight = 1000; // [HGM] placement: kludge to allow calling EnsureOnScreen from InitAppData
\r
740 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
741 if (appData.debugMode) {
\r
742 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
743 setbuf(debugFP, NULL);
\r
748 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
749 // InitEngineUCI( installDir, &second );
\r
751 /* Create a main window for this application instance. */
\r
752 hwnd = CreateWindow(szAppName, szTitle,
\r
753 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
754 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
755 NULL, NULL, hInstance, NULL);
\r
758 /* If window could not be created, return "failure" */
\r
763 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
764 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
765 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
767 if (first.programLogo == NULL && appData.debugMode) {
\r
768 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
770 } else if(appData.autoLogo) {
\r
771 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
773 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
774 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
778 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
779 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
781 if (second.programLogo == NULL && appData.debugMode) {
\r
782 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
784 } else if(appData.autoLogo) {
\r
786 if(appData.icsActive) { // [HGM] logo: in ICS mode second can be used for ICS
\r
787 sprintf(buf, "logos\\%s.bmp", appData.icsHost);
\r
788 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
790 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
791 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
792 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
798 iconWhite = LoadIcon(hInstance, "icon_white");
\r
799 iconBlack = LoadIcon(hInstance, "icon_black");
\r
800 iconCurrent = iconWhite;
\r
801 InitDrawingColors();
\r
802 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
803 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
804 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
805 /* Compute window size for each board size, and use the largest
\r
806 size that fits on this screen as the default. */
\r
807 InitDrawingSizes((BoardSize)(ibs+1000), 0);
\r
808 if (boardSize == (BoardSize)-1 &&
\r
809 winH <= screenHeight
\r
810 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
811 && winW <= screenWidth) {
\r
812 boardSize = (BoardSize)ibs;
\r
816 InitDrawingSizes(boardSize, 0);
\r
818 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
820 /* [AS] Load textures if specified */
\r
821 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
823 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
824 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
825 liteBackTextureMode = appData.liteBackTextureMode;
\r
827 if (liteBackTexture == NULL && appData.debugMode) {
\r
828 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
832 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
833 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
834 darkBackTextureMode = appData.darkBackTextureMode;
\r
836 if (darkBackTexture == NULL && appData.debugMode) {
\r
837 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
841 mysrandom( (unsigned) time(NULL) );
\r
843 /* [AS] Restore layout */
\r
844 if( wpMoveHistory.visible ) {
\r
845 MoveHistoryPopUp();
\r
848 if( wpEvalGraph.visible ) {
\r
852 if( wpEngineOutput.visible ) {
\r
853 EngineOutputPopUp();
\r
858 /* Make the window visible; update its client area; and return "success" */
\r
859 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
860 wp.length = sizeof(WINDOWPLACEMENT);
\r
862 wp.showCmd = nCmdShow;
\r
863 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
864 wp.rcNormalPosition.left = boardX;
\r
865 wp.rcNormalPosition.right = boardX + winWidth;
\r
866 wp.rcNormalPosition.top = boardY;
\r
867 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
868 SetWindowPlacement(hwndMain, &wp);
\r
870 if(!appData.noGUI) SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
871 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
875 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
876 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
878 ShowWindow(hwndConsole, nCmdShow);
\r
880 if(!appData.noGUI) UpdateWindow(hwnd); else ShowWindow(hwnd, SW_MINIMIZE);
\r
888 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
889 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
890 ArgSettingsFilename,
\r
891 ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
\r
899 String *pString; // ArgString
\r
900 int *pInt; // ArgInt
\r
901 float *pFloat; // ArgFloat
\r
902 Boolean *pBoolean; // ArgBoolean
\r
903 COLORREF *pColor; // ArgColor
\r
904 ColorClass cc; // ArgAttribs
\r
905 String *pFilename; // ArgFilename
\r
906 BoardSize *pBoardSize; // ArgBoardSize
\r
907 int whichFont; // ArgFont
\r
908 DCB *pDCB; // ArgCommSettings
\r
909 String *pFilename; // ArgSettingsFilename
\r
917 ArgDescriptor argDescriptors[] = {
\r
918 /* positional arguments */
\r
919 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
920 { "", ArgNone, NULL },
\r
921 /* keyword arguments */
\r
922 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
923 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
924 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
925 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
926 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
927 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
928 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
929 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
930 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
931 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
932 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
933 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
934 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
935 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
936 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
937 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
938 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
939 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
941 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
943 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
945 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
946 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
948 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
949 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
950 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
951 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
952 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
953 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
954 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
955 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
956 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
957 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
958 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
959 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
960 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
961 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
962 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
963 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
964 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
965 /*!!bitmapDirectory?*/
\r
966 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
967 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
968 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
969 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
970 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
971 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
972 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
973 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
974 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
975 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
976 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
977 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
978 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
979 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
980 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
981 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
982 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
983 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
984 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
985 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
986 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
987 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
988 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
989 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
990 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
991 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
992 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
993 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
994 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
995 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
996 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
997 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
998 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
999 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1000 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
1001 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
1002 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
1003 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
1004 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1005 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1006 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
1007 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1008 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
1009 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1010 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
1011 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1012 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
1013 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
1014 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
1015 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1016 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
1017 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1018 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
1019 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
1020 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
1021 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1022 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
1023 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
1024 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
1025 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1026 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
1027 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
1028 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
1029 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1030 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
1031 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1032 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
1033 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1034 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
1035 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
1036 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
1037 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1038 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
1039 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
1040 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
1041 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1042 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
1043 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
1044 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1045 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1046 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
1047 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
1048 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1049 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1050 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
1051 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
1052 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1053 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1054 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
1055 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
1056 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1057 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1058 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
1059 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
1060 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
1061 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
1062 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
1063 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
1064 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
1065 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
1066 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
1067 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
1068 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
1069 TRUE }, /* must come after all fonts */
\r
1070 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
1071 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
1072 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
1073 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
1074 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
1075 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1076 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
1077 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
1078 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1079 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1080 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
1081 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
1082 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
1083 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1084 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
1085 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
1086 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
1087 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1088 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
1089 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
1090 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
1091 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1092 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
1093 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
1094 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
1095 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1096 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
1097 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
1098 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1099 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1100 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
1102 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1103 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
1105 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
1106 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1107 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1108 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
1109 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
1110 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1111 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1112 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
1113 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
1114 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
1115 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1116 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
1117 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
1118 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
1119 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1120 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
1121 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
1122 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
1123 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1124 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1125 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1126 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1127 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1128 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1129 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1130 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1131 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1132 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1133 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1134 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1135 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1136 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1137 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1138 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1139 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1140 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1141 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1142 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1143 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1144 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1145 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1146 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1147 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1148 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1149 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1150 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1151 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1152 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1153 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1154 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1155 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1156 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1157 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1158 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1159 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1160 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1161 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1162 { "highlightLastMove", ArgBoolean,
\r
1163 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1164 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1165 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1166 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1167 { "highlightDragging", ArgBoolean,
\r
1168 (LPVOID) &appData.highlightDragging, TRUE },
\r
1169 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1170 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1171 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1172 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1173 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1174 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1175 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1176 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1177 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1178 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1179 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1180 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1181 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1182 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1183 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1184 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1185 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1186 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1187 { "soundShout", ArgFilename,
\r
1188 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1189 { "soundSShout", ArgFilename,
\r
1190 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1191 { "soundChannel1", ArgFilename,
\r
1192 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1193 { "soundChannel", ArgFilename,
\r
1194 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1195 { "soundKibitz", ArgFilename,
\r
1196 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1197 { "soundTell", ArgFilename,
\r
1198 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1199 { "soundChallenge", ArgFilename,
\r
1200 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1201 { "soundRequest", ArgFilename,
\r
1202 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1203 { "soundSeek", ArgFilename,
\r
1204 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1205 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1206 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1207 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1208 { "soundIcsLoss", ArgFilename,
\r
1209 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1210 { "soundIcsDraw", ArgFilename,
\r
1211 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1212 { "soundIcsUnfinished", ArgFilename,
\r
1213 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1214 { "soundIcsAlarm", ArgFilename,
\r
1215 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1216 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1217 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1218 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1219 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1220 { "reuseChessPrograms", ArgBoolean,
\r
1221 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1222 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1223 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1224 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1225 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1226 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1227 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1228 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1229 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1230 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1231 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1232 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1233 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1234 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1235 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1236 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1238 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1240 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1241 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1242 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1243 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1244 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1245 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1246 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1247 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1248 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1249 /* [AS] New features */
\r
1250 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1251 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1252 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1253 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1254 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1255 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1256 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1257 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1258 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1259 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1260 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1261 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1262 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1263 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1264 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1265 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1266 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1267 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1268 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1269 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1270 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1271 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1272 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1273 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1274 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1275 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1276 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1277 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1278 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1279 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1280 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1281 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1282 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1283 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1284 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1285 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1286 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1287 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1288 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1289 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1290 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1291 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1292 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1293 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1294 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1295 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1296 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1297 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1298 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1299 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1301 /* [HGM] board-size, adjudication and misc. options */
\r
1302 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1303 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1304 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1305 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1306 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1307 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1308 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1309 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1310 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1311 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1312 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1313 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1314 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1315 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1316 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1317 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1318 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1319 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1320 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1321 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1322 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1323 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1324 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1325 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1326 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1327 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1328 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1329 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1330 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1331 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1332 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1333 { "keepAlive", ArgInt, (LPVOID) &appData.keepAlive, FALSE },
\r
1334 { "icstype", ArgInt, (LPVOID) &ics_type, FALSE },
\r
1337 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1338 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1339 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1340 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1341 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1342 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1343 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1344 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1345 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1346 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1347 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1348 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1349 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1351 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1352 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1353 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1354 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1355 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1356 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1357 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1359 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1360 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1361 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1362 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1363 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1364 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1365 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1366 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1367 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1368 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1369 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1370 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1371 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1372 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1373 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1374 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1375 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1376 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1377 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1379 /* [HGM] options for broadcasting and time odds */
\r
1380 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1381 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1382 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1383 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1384 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1385 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1386 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1387 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1388 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1389 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1390 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1392 // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
\r
1393 { "minX", ArgZ, (LPVOID) &minX, FALSE }, // [HGM] placement: to make suer auxialary windows can be placed
\r
1394 { "minY", ArgZ, (LPVOID) &minY, FALSE },
\r
1395 { "winWidth", ArgInt, (LPVOID) &winWidth, TRUE }, // [HGM] placement: dummies to remember right & bottom
\r
1396 { "winHeight", ArgInt, (LPVOID) &winHeight, TRUE }, // for attaching auxiliary windows to them
\r
1397 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1398 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1399 { "icsX", ArgX, (LPVOID) &wpConsole.x, TRUE },
\r
1400 { "icsY", ArgY, (LPVOID) &wpConsole.y, TRUE },
\r
1401 { "icsW", ArgInt, (LPVOID) &wpConsole.width, TRUE },
\r
1402 { "icsH", ArgInt, (LPVOID) &wpConsole.height, TRUE },
\r
1403 { "analysisX", ArgX, (LPVOID) &analysisX, FALSE }, // [HGM] placement: analysis window no longer exists
\r
1404 { "analysisY", ArgY, (LPVOID) &analysisY, FALSE }, // provided for compatibility with old ini files
\r
1405 { "analysisW", ArgInt, (LPVOID) &analysisW, FALSE },
\r
1406 { "analysisH", ArgInt, (LPVOID) &analysisH, FALSE },
\r
1407 { "commentX", ArgX, (LPVOID) &commentX, TRUE },
\r
1408 { "commentY", ArgY, (LPVOID) &commentY, TRUE },
\r
1409 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1410 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1411 { "tagsX", ArgX, (LPVOID) &editTagsX, TRUE },
\r
1412 { "tagsY", ArgY, (LPVOID) &editTagsY, TRUE },
\r
1413 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1414 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1415 { "gameListX", ArgX, (LPVOID) &wpGameList.x, TRUE },
\r
1416 { "gameListY", ArgY, (LPVOID) &wpGameList.y, TRUE },
\r
1417 { "gameListW", ArgInt, (LPVOID) &wpGameList.width, TRUE },
\r
1418 { "gameListH", ArgInt, (LPVOID) &wpGameList.height, TRUE },
\r
1419 /* [AS] Layout stuff */
\r
1420 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1421 { "moveHistoryX", ArgX, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1422 { "moveHistoryY", ArgY, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1423 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1424 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1426 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1427 { "evalGraphX", ArgX, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1428 { "evalGraphY", ArgY, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1429 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1430 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1432 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1433 { "engineOutputX", ArgX, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1434 { "engineOutputY", ArgY, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1435 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1436 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1438 { NULL, ArgNone, NULL, FALSE }
\r
1442 /* Kludge for indirection files on command line */
\r
1443 char* lastIndirectionFilename;
\r
1444 ArgDescriptor argDescriptorIndirection =
\r
1445 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1449 ExitArgError(char *msg, char *badArg)
\r
1451 char buf[MSG_SIZ];
\r
1453 sprintf(buf, "%s %s", msg, badArg);
\r
1454 DisplayFatalError(buf, 0, 2);
\r
1458 /* Command line font name parser. NULL name means do nothing.
\r
1459 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1460 For backward compatibility, syntax without the colon is also
\r
1461 accepted, but font names with digits in them won't work in that case.
\r
1464 ParseFontName(char *name, MyFontParams *mfp)
\r
1467 if (name == NULL) return;
\r
1469 q = strchr(p, ':');
\r
1471 if (q - p >= sizeof(mfp->faceName))
\r
1472 ExitArgError("Font name too long:", name);
\r
1473 memcpy(mfp->faceName, p, q - p);
\r
1474 mfp->faceName[q - p] = NULLCHAR;
\r
1477 q = mfp->faceName;
\r
1478 while (*p && !isdigit(*p)) {
\r
1480 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1481 ExitArgError("Font name too long:", name);
\r
1483 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1486 if (!*p) ExitArgError("Font point size missing:", name);
\r
1487 mfp->pointSize = (float) atof(p);
\r
1488 mfp->bold = (strchr(p, 'b') != NULL);
\r
1489 mfp->italic = (strchr(p, 'i') != NULL);
\r
1490 mfp->underline = (strchr(p, 'u') != NULL);
\r
1491 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1494 /* Color name parser.
\r
1495 X version accepts X color names, but this one
\r
1496 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1498 ParseColorName(char *name)
\r
1500 int red, green, blue, count;
\r
1501 char buf[MSG_SIZ];
\r
1503 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1505 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1506 &red, &green, &blue);
\r
1509 sprintf(buf, "Can't parse color name %s", name);
\r
1510 DisplayError(buf, 0);
\r
1511 return RGB(0, 0, 0);
\r
1513 return PALETTERGB(red, green, blue);
\r
1517 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1519 char *e = argValue;
\r
1523 if (*e == 'b') eff |= CFE_BOLD;
\r
1524 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1525 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1526 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1527 else if (*e == '#' || isdigit(*e)) break;
\r
1531 *color = ParseColorName(e);
\r
1536 ParseBoardSize(char *name)
\r
1538 BoardSize bs = SizeTiny;
\r
1539 while (sizeInfo[bs].name != NULL) {
\r
1540 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1543 ExitArgError("Unrecognized board size value", name);
\r
1544 return bs; /* not reached */
\r
1549 StringGet(void *getClosure)
\r
1551 char **p = (char **) getClosure;
\r
1556 FileGet(void *getClosure)
\r
1559 FILE* f = (FILE*) getClosure;
\r
1562 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1569 /* Parse settings file named "name". If file found, return the
\r
1570 full name in fullname and return TRUE; else return FALSE */
\r
1572 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1576 int ok; char buf[MSG_SIZ];
\r
1578 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1579 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1580 sprintf(buf, "%s.ini", name);
\r
1581 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1584 f = fopen(fullname, "r");
\r
1586 ParseArgs(FileGet, f);
\r
1595 ParseArgs(GetFunc get, void *cl)
\r
1597 char argName[ARG_MAX];
\r
1598 char argValue[ARG_MAX];
\r
1599 ArgDescriptor *ad;
\r
1608 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1609 if (ch == NULLCHAR) break;
\r
1611 /* Comment to end of line */
\r
1613 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1615 } else if (ch == '/' || ch == '-') {
\r
1618 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1619 ch != '\n' && ch != '\t') {
\r
1625 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1626 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1628 if (ad->argName == NULL)
\r
1629 ExitArgError("Unrecognized argument", argName);
\r
1631 } else if (ch == '@') {
\r
1632 /* Indirection file */
\r
1633 ad = &argDescriptorIndirection;
\r
1636 /* Positional argument */
\r
1637 ad = &argDescriptors[posarg++];
\r
1638 strcpy(argName, ad->argName);
\r
1641 if (ad->argType == ArgTrue) {
\r
1642 *(Boolean *) ad->argLoc = TRUE;
\r
1645 if (ad->argType == ArgFalse) {
\r
1646 *(Boolean *) ad->argLoc = FALSE;
\r
1650 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1651 if (ch == NULLCHAR || ch == '\n') {
\r
1652 ExitArgError("No value provided for argument", argName);
\r
1656 // Quoting with { }. No characters have to (or can) be escaped.
\r
1657 // Thus the string cannot contain a '}' character.
\r
1677 } else if (ch == '\'' || ch == '"') {
\r
1678 // Quoting with ' ' or " ", with \ as escape character.
\r
1679 // Inconvenient for long strings that may contain Windows filenames.
\r
1696 if (ch == start) {
\r
1705 if (ad->argType == ArgFilename
\r
1706 || ad->argType == ArgSettingsFilename) {
\r
1712 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1736 for (i = 0; i < 3; i++) {
\r
1737 if (ch >= '0' && ch <= '7') {
\r
1738 octval = octval*8 + (ch - '0');
\r
1745 *q++ = (char) octval;
\r
1756 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1763 switch (ad->argType) {
\r
1765 *(int *) ad->argLoc = atoi(argValue);
\r
1769 *(int *) ad->argLoc = atoi(argValue) + boardX; // [HGM] placement: translate stored relative to absolute
\r
1773 *(int *) ad->argLoc = atoi(argValue) + boardY; // (this is really kludgey, it should be done where used...)
\r
1777 *(int *) ad->argLoc = atoi(argValue);
\r
1778 EnsureOnScreen(&boardX, &boardY, minX, minY);
\r
1782 *(float *) ad->argLoc = (float) atof(argValue);
\r
1787 *(char **) ad->argLoc = strdup(argValue);
\r
1790 case ArgSettingsFilename:
\r
1792 char fullname[MSG_SIZ];
\r
1793 if (ParseSettingsFile(argValue, fullname)) {
\r
1794 if (ad->argLoc != NULL) {
\r
1795 *(char **) ad->argLoc = strdup(fullname);
\r
1798 if (ad->argLoc != NULL) {
\r
1800 ExitArgError("Failed to open indirection file", argValue);
\r
1807 switch (argValue[0]) {
\r
1810 *(Boolean *) ad->argLoc = TRUE;
\r
1814 *(Boolean *) ad->argLoc = FALSE;
\r
1817 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1823 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1826 case ArgAttribs: {
\r
1827 ColorClass cc = (ColorClass)ad->argLoc;
\r
1828 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1832 case ArgBoardSize:
\r
1833 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1837 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1840 case ArgCommSettings:
\r
1841 ParseCommSettings(argValue, &dcb);
\r
1845 ExitArgError("Unrecognized argument", argValue);
\r
1854 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1856 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1857 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1860 lf->lfEscapement = 0;
\r
1861 lf->lfOrientation = 0;
\r
1862 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1863 lf->lfItalic = mfp->italic;
\r
1864 lf->lfUnderline = mfp->underline;
\r
1865 lf->lfStrikeOut = mfp->strikeout;
\r
1866 lf->lfCharSet = DEFAULT_CHARSET;
\r
1867 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1868 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1869 lf->lfQuality = DEFAULT_QUALITY;
\r
1870 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1871 strcpy(lf->lfFaceName, mfp->faceName);
\r
1875 CreateFontInMF(MyFont *mf)
\r
1877 LFfromMFP(&mf->lf, &mf->mfp);
\r
1878 if (mf->hf) DeleteObject(mf->hf);
\r
1879 mf->hf = CreateFontIndirect(&mf->lf);
\r
1883 SetDefaultTextAttribs()
\r
1886 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1887 ParseAttribs(&textAttribs[cc].color,
\r
1888 &textAttribs[cc].effects,
\r
1889 defaultTextAttribs[cc]);
\r
1894 SetDefaultSounds()
\r
1898 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1899 textAttribs[cc].sound.name = strdup("");
\r
1900 textAttribs[cc].sound.data = NULL;
\r
1902 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1903 sounds[sc].name = strdup("");
\r
1904 sounds[sc].data = NULL;
\r
1906 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1914 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1915 MyLoadSound(&textAttribs[cc].sound);
\r
1917 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1918 MyLoadSound(&sounds[sc]);
\r
1923 InitAppData(LPSTR lpCmdLine)
\r
1926 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1929 programName = szAppName;
\r
1931 /* Initialize to defaults */
\r
1932 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1933 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1934 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1935 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1936 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1937 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1938 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1939 SetDefaultTextAttribs();
\r
1940 SetDefaultSounds();
\r
1941 appData.movesPerSession = MOVES_PER_SESSION;
\r
1942 appData.initString = INIT_STRING;
\r
1943 appData.secondInitString = INIT_STRING;
\r
1944 appData.firstComputerString = COMPUTER_STRING;
\r
1945 appData.secondComputerString = COMPUTER_STRING;
\r
1946 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1947 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1948 appData.firstPlaysBlack = FALSE;
\r
1949 appData.noChessProgram = FALSE;
\r
1950 chessProgram = FALSE;
\r
1951 appData.firstHost = FIRST_HOST;
\r
1952 appData.secondHost = SECOND_HOST;
\r
1953 appData.firstDirectory = FIRST_DIRECTORY;
\r
1954 appData.secondDirectory = SECOND_DIRECTORY;
\r
1955 appData.bitmapDirectory = "";
\r
1956 appData.remoteShell = REMOTE_SHELL;
\r
1957 appData.remoteUser = "";
\r
1958 appData.timeDelay = TIME_DELAY;
\r
1959 appData.timeControl = TIME_CONTROL;
\r
1960 appData.timeIncrement = TIME_INCREMENT;
\r
1961 appData.icsActive = FALSE;
\r
1962 appData.icsHost = "";
\r
1963 appData.icsPort = ICS_PORT;
\r
1964 appData.icsCommPort = ICS_COMM_PORT;
\r
1965 appData.icsLogon = ICS_LOGON;
\r
1966 appData.icsHelper = "";
\r
1967 appData.useTelnet = FALSE;
\r
1968 appData.telnetProgram = TELNET_PROGRAM;
\r
1969 appData.gateway = "";
\r
1970 appData.loadGameFile = "";
\r
1971 appData.loadGameIndex = 0;
\r
1972 appData.saveGameFile = "";
\r
1973 appData.autoSaveGames = FALSE;
\r
1974 appData.loadPositionFile = "";
\r
1975 appData.loadPositionIndex = 1;
\r
1976 appData.savePositionFile = "";
\r
1977 appData.matchMode = FALSE;
\r
1978 appData.matchGames = 0;
\r
1979 appData.monoMode = FALSE;
\r
1980 appData.debugMode = FALSE;
\r
1981 appData.clockMode = TRUE;
\r
1982 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1983 appData.Iconic = FALSE; /*unused*/
\r
1984 appData.searchTime = "";
\r
1985 appData.searchDepth = 0;
\r
1986 appData.showCoords = FALSE;
\r
1987 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1988 appData.autoCallFlag = FALSE;
\r
1989 appData.flipView = FALSE;
\r
1990 appData.autoFlipView = TRUE;
\r
1991 appData.cmailGameName = "";
\r
1992 appData.alwaysPromoteToQueen = FALSE;
\r
1993 appData.oldSaveStyle = FALSE;
\r
1994 appData.quietPlay = FALSE;
\r
1995 appData.showThinking = FALSE;
\r
1996 appData.ponderNextMove = TRUE;
\r
1997 appData.periodicUpdates = TRUE;
\r
1998 appData.popupExitMessage = TRUE;
\r
1999 appData.popupMoveErrors = FALSE;
\r
2000 appData.autoObserve = FALSE;
\r
2001 appData.autoComment = FALSE;
\r
2002 appData.animate = TRUE;
\r
2003 appData.animSpeed = 10;
\r
2004 appData.animateDragging = TRUE;
\r
2005 appData.highlightLastMove = TRUE;
\r
2006 appData.getMoveList = TRUE;
\r
2007 appData.testLegality = TRUE;
\r
2008 appData.premove = TRUE;
\r
2009 appData.premoveWhite = FALSE;
\r
2010 appData.premoveWhiteText = "";
\r
2011 appData.premoveBlack = FALSE;
\r
2012 appData.premoveBlackText = "";
\r
2013 appData.icsAlarm = TRUE;
\r
2014 appData.icsAlarmTime = 5000;
\r
2015 appData.autoRaiseBoard = TRUE;
\r
2016 appData.localLineEditing = TRUE;
\r
2017 appData.colorize = TRUE;
\r
2018 appData.reuseFirst = TRUE;
\r
2019 appData.reuseSecond = TRUE;
\r
2020 appData.blindfold = FALSE;
\r
2021 appData.icsEngineAnalyze = FALSE;
\r
2022 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
2023 dcb.DCBlength = sizeof(DCB);
\r
2024 dcb.BaudRate = 9600;
\r
2025 dcb.fBinary = TRUE;
\r
2026 dcb.fParity = FALSE;
\r
2027 dcb.fOutxCtsFlow = FALSE;
\r
2028 dcb.fOutxDsrFlow = FALSE;
\r
2029 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
2030 dcb.fDsrSensitivity = FALSE;
\r
2031 dcb.fTXContinueOnXoff = TRUE;
\r
2032 dcb.fOutX = FALSE;
\r
2034 dcb.fNull = FALSE;
\r
2035 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
2036 dcb.fAbortOnError = FALSE;
\r
2038 dcb.Parity = SPACEPARITY;
\r
2039 dcb.StopBits = ONESTOPBIT;
\r
2040 settingsFileName = SETTINGS_FILE;
\r
2041 saveSettingsOnExit = TRUE;
\r
2042 boardX = CW_USEDEFAULT;
\r
2043 boardY = CW_USEDEFAULT;
\r
2044 analysisX = CW_USEDEFAULT;
\r
2045 analysisY = CW_USEDEFAULT;
\r
2046 analysisW = CW_USEDEFAULT;
\r
2047 analysisH = CW_USEDEFAULT;
\r
2048 commentX = CW_USEDEFAULT;
\r
2049 commentY = CW_USEDEFAULT;
\r
2050 commentW = CW_USEDEFAULT;
\r
2051 commentH = CW_USEDEFAULT;
\r
2052 editTagsX = CW_USEDEFAULT;
\r
2053 editTagsY = CW_USEDEFAULT;
\r
2054 editTagsW = CW_USEDEFAULT;
\r
2055 editTagsH = CW_USEDEFAULT;
\r
2056 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
2057 icsNames = ICS_NAMES;
\r
2058 firstChessProgramNames = FCP_NAMES;
\r
2059 secondChessProgramNames = SCP_NAMES;
\r
2060 appData.initialMode = "";
\r
2061 appData.variant = "normal";
\r
2062 appData.firstProtocolVersion = PROTOVER;
\r
2063 appData.secondProtocolVersion = PROTOVER;
\r
2064 appData.showButtonBar = TRUE;
\r
2066 /* [AS] New properties (see comments in header file) */
\r
2067 appData.firstScoreIsAbsolute = FALSE;
\r
2068 appData.secondScoreIsAbsolute = FALSE;
\r
2069 appData.saveExtendedInfoInPGN = FALSE;
\r
2070 appData.hideThinkingFromHuman = FALSE;
\r
2071 appData.liteBackTextureFile = "";
\r
2072 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2073 appData.darkBackTextureFile = "";
\r
2074 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
2075 appData.renderPiecesWithFont = "";
\r
2076 appData.fontToPieceTable = "";
\r
2077 appData.fontBackColorWhite = 0;
\r
2078 appData.fontForeColorWhite = 0;
\r
2079 appData.fontBackColorBlack = 0;
\r
2080 appData.fontForeColorBlack = 0;
\r
2081 appData.fontPieceSize = 80;
\r
2082 appData.overrideLineGap = 1;
\r
2083 appData.adjudicateLossThreshold = 0;
\r
2084 appData.delayBeforeQuit = 0;
\r
2085 appData.delayAfterQuit = 0;
\r
2086 appData.nameOfDebugFile = "winboard.debug";
\r
2087 appData.pgnEventHeader = "Computer Chess Game";
\r
2088 appData.defaultFrcPosition = -1;
\r
2089 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
2090 appData.saveOutOfBookInfo = TRUE;
\r
2091 appData.showEvalInMoveHistory = TRUE;
\r
2092 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
2093 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
2094 appData.highlightMoveWithArrow = FALSE;
\r
2095 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
2096 appData.useStickyWindows = TRUE;
\r
2097 appData.adjudicateDrawMoves = 0;
\r
2098 appData.autoDisplayComment = TRUE;
\r
2099 appData.autoDisplayTags = TRUE;
\r
2100 appData.firstIsUCI = FALSE;
\r
2101 appData.secondIsUCI = FALSE;
\r
2102 appData.firstHasOwnBookUCI = TRUE;
\r
2103 appData.secondHasOwnBookUCI = TRUE;
\r
2104 appData.polyglotDir = "";
\r
2105 appData.usePolyglotBook = FALSE;
\r
2106 appData.polyglotBook = "";
\r
2107 appData.defaultHashSize = 64;
\r
2108 appData.defaultCacheSizeEGTB = 4;
\r
2109 appData.defaultPathEGTB = "c:\\egtb";
\r
2110 appData.firstOptions = "";
\r
2111 appData.secondOptions = "";
\r
2113 InitWindowPlacement( &wpGameList );
\r
2114 InitWindowPlacement( &wpMoveHistory );
\r
2115 InitWindowPlacement( &wpEvalGraph );
\r
2116 InitWindowPlacement( &wpEngineOutput );
\r
2117 InitWindowPlacement( &wpConsole );
\r
2119 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
2120 appData.NrFiles = -1;
\r
2121 appData.NrRanks = -1;
\r
2122 appData.holdingsSize = -1;
\r
2123 appData.testClaims = FALSE;
\r
2124 appData.checkMates = FALSE;
\r
2125 appData.materialDraws= FALSE;
\r
2126 appData.trivialDraws = FALSE;
\r
2127 appData.ruleMoves = 51;
\r
2128 appData.drawRepeats = 6;
\r
2129 appData.matchPause = 10000;
\r
2130 appData.alphaRank = FALSE;
\r
2131 appData.allWhite = FALSE;
\r
2132 appData.upsideDown = FALSE;
\r
2133 appData.serverPause = 15;
\r
2134 appData.serverMovesName = NULL;
\r
2135 appData.suppressLoadMoves = FALSE;
\r
2136 appData.firstTimeOdds = 1;
\r
2137 appData.secondTimeOdds = 1;
\r
2138 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
2139 appData.secondAccumulateTC = 1;
\r
2140 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2141 appData.secondNPS = -1;
\r
2142 appData.engineComments = 1;
\r
2143 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2144 appData.egtFormats = "";
\r
2147 appData.zippyTalk = ZIPPY_TALK;
\r
2148 appData.zippyPlay = ZIPPY_PLAY;
\r
2149 appData.zippyLines = ZIPPY_LINES;
\r
2150 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2151 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2152 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2153 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2154 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2155 appData.zippyUseI = ZIPPY_USE_I;
\r
2156 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2157 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2158 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2159 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2160 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2161 appData.zippyAbort = ZIPPY_ABORT;
\r
2162 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2163 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2164 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2167 /* Point font array elements to structures and
\r
2168 parse default font names */
\r
2169 for (i=0; i<NUM_FONTS; i++) {
\r
2170 for (j=0; j<NUM_SIZES; j++) {
\r
2171 font[j][i] = &fontRec[j][i];
\r
2172 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2176 /* Parse default settings file if any */
\r
2177 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2178 settingsFileName = strdup(buf);
\r
2181 /* Parse command line */
\r
2182 ParseArgs(StringGet, &lpCmdLine);
\r
2184 /* [HGM] make sure board size is acceptable */
\r
2185 if(appData.NrFiles > BOARD_SIZE ||
\r
2186 appData.NrRanks > BOARD_SIZE )
\r
2187 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2189 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2190 * with options from the command line, we now make an even higher priority
\r
2191 * overrule by WB options attached to the engine command line. This so that
\r
2192 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2195 if(appData.firstChessProgram != NULL) {
\r
2196 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2197 static char *f = "first";
\r
2198 char buf[MSG_SIZ], *q = buf;
\r
2199 if(p != NULL) { // engine command line contains WinBoard options
\r
2200 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2201 ParseArgs(StringGet, &q);
\r
2202 p[-1] = 0; // cut them offengine command line
\r
2205 // now do same for second chess program
\r
2206 if(appData.secondChessProgram != NULL) {
\r
2207 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2208 static char *s = "second";
\r
2209 char buf[MSG_SIZ], *q = buf;
\r
2210 if(p != NULL) { // engine command line contains WinBoard options
\r
2211 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2212 ParseArgs(StringGet, &q);
\r
2213 p[-1] = 0; // cut them offengine command line
\r
2218 /* Propagate options that affect others */
\r
2219 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2220 if (appData.icsActive || appData.noChessProgram) {
\r
2221 chessProgram = FALSE; /* not local chess program mode */
\r
2224 /* Open startup dialog if needed */
\r
2225 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2226 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2227 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2228 *appData.secondChessProgram == NULLCHAR))) {
\r
2231 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2232 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2233 FreeProcInstance(lpProc);
\r
2236 /* Make sure save files land in the right (?) directory */
\r
2237 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2238 appData.saveGameFile = strdup(buf);
\r
2240 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2241 appData.savePositionFile = strdup(buf);
\r
2244 /* Finish initialization for fonts and sounds */
\r
2245 for (i=0; i<NUM_FONTS; i++) {
\r
2246 for (j=0; j<NUM_SIZES; j++) {
\r
2247 CreateFontInMF(font[j][i]);
\r
2250 /* xboard, and older WinBoards, controlled the move sound with the
\r
2251 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2252 always turn the option on (so that the backend will call us),
\r
2253 then let the user turn the sound off by setting it to silence if
\r
2254 desired. To accommodate old winboard.ini files saved by old
\r
2255 versions of WinBoard, we also turn off the sound if the option
\r
2256 was initially set to false. */
\r
2257 if (!appData.ringBellAfterMoves) {
\r
2258 sounds[(int)SoundMove].name = strdup("");
\r
2259 appData.ringBellAfterMoves = TRUE;
\r
2261 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2262 SetCurrentDirectory(installDir);
\r
2264 SetCurrentDirectory(currDir);
\r
2266 p = icsTextMenuString;
\r
2267 if (p[0] == '@') {
\r
2268 FILE* f = fopen(p + 1, "r");
\r
2270 DisplayFatalError(p + 1, errno, 2);
\r
2273 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2275 buf[i] = NULLCHAR;
\r
2278 ParseIcsTextMenu(strdup(p));
\r
2285 HMENU hmenu = GetMenu(hwndMain);
\r
2287 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2288 MF_BYCOMMAND|((appData.icsActive &&
\r
2289 *appData.icsCommPort != NULLCHAR) ?
\r
2290 MF_ENABLED : MF_GRAYED));
\r
2291 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2292 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2293 MF_CHECKED : MF_UNCHECKED));
\r
2298 SaveSettings(char* name)
\r
2301 ArgDescriptor *ad;
\r
2302 WINDOWPLACEMENT wp;
\r
2303 char dir[MSG_SIZ];
\r
2305 if (!hwndMain) return;
\r
2307 GetCurrentDirectory(MSG_SIZ, dir);
\r
2308 SetCurrentDirectory(installDir);
\r
2309 f = fopen(name, "w");
\r
2310 SetCurrentDirectory(dir);
\r
2312 DisplayError(name, errno);
\r
2315 fprintf(f, ";\n");
\r
2316 fprintf(f, "; %s Save Settings file\n", PACKAGE_STRING);
\r
2317 fprintf(f, ";\n");
\r
2318 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2319 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2320 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2321 fprintf(f, ";\n");
\r
2323 wp.length = sizeof(WINDOWPLACEMENT);
\r
2324 GetWindowPlacement(hwndMain, &wp);
\r
2325 boardX = wp.rcNormalPosition.left;
\r
2326 boardY = wp.rcNormalPosition.top;
\r
2328 if (hwndConsole) {
\r
2329 GetWindowPlacement(hwndConsole, &wp);
\r
2330 wpConsole.x = wp.rcNormalPosition.left;
\r
2331 wpConsole.y = wp.rcNormalPosition.top;
\r
2332 wpConsole.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2333 wpConsole.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2336 if (analysisDialog) {
\r
2337 GetWindowPlacement(analysisDialog, &wp);
\r
2338 analysisX = wp.rcNormalPosition.left;
\r
2339 analysisY = wp.rcNormalPosition.top;
\r
2340 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2341 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2344 if (commentDialog) {
\r
2345 GetWindowPlacement(commentDialog, &wp);
\r
2346 commentX = wp.rcNormalPosition.left;
\r
2347 commentY = wp.rcNormalPosition.top;
\r
2348 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2349 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2352 if (editTagsDialog) {
\r
2353 GetWindowPlacement(editTagsDialog, &wp);
\r
2354 editTagsX = wp.rcNormalPosition.left;
\r
2355 editTagsY = wp.rcNormalPosition.top;
\r
2356 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2357 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2360 if (gameListDialog) {
\r
2361 GetWindowPlacement(gameListDialog, &wp);
\r
2362 wpGameList.x = wp.rcNormalPosition.left;
\r
2363 wpGameList.y = wp.rcNormalPosition.top;
\r
2364 wpGameList.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2365 wpGameList.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2368 /* [AS] Move history */
\r
2369 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2371 if( moveHistoryDialog ) {
\r
2372 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2373 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2374 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2375 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2376 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2379 /* [AS] Eval graph */
\r
2380 wpEvalGraph.visible = EvalGraphIsUp();
\r
2382 if( evalGraphDialog ) {
\r
2383 GetWindowPlacement(evalGraphDialog, &wp);
\r
2384 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2385 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2386 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2387 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2390 /* [AS] Engine output */
\r
2391 wpEngineOutput.visible = EngineOutputIsUp();
\r
2393 if( engineOutputDialog ) {
\r
2394 GetWindowPlacement(engineOutputDialog, &wp);
\r
2395 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2396 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2397 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2398 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2401 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2402 if (!ad->save) continue;
\r
2403 switch (ad->argType) {
\r
2406 char *p = *(char **)ad->argLoc;
\r
2407 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2408 /* Quote multiline values or \-containing values
\r
2409 with { } if possible */
\r
2410 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2412 /* Else quote with " " */
\r
2413 fprintf(f, "/%s=\"", ad->argName);
\r
2415 if (*p == '\n') fprintf(f, "\n");
\r
2416 else if (*p == '\r') fprintf(f, "\\r");
\r
2417 else if (*p == '\t') fprintf(f, "\\t");
\r
2418 else if (*p == '\b') fprintf(f, "\\b");
\r
2419 else if (*p == '\f') fprintf(f, "\\f");
\r
2420 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2421 else if (*p == '\"') fprintf(f, "\\\"");
\r
2422 else if (*p == '\\') fprintf(f, "\\\\");
\r
2426 fprintf(f, "\"\n");
\r
2432 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2435 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardX); // [HGM] placement: stor relative value
\r
2438 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc - boardY);
\r
2441 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2444 fprintf(f, "/%s=%s\n", ad->argName,
\r
2445 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2448 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2451 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2455 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2456 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2457 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2462 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2463 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2464 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2465 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2466 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2467 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2468 (ta->effects) ? " " : "",
\r
2469 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2473 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2474 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2476 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2479 case ArgBoardSize:
\r
2480 fprintf(f, "/%s=%s\n", ad->argName,
\r
2481 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2486 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2487 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2488 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2489 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2490 ad->argName, mfp->faceName, mfp->pointSize,
\r
2491 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2492 mfp->bold ? "b" : "",
\r
2493 mfp->italic ? "i" : "",
\r
2494 mfp->underline ? "u" : "",
\r
2495 mfp->strikeout ? "s" : "");
\r
2499 case ArgCommSettings:
\r
2500 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2502 case ArgSettingsFilename: ;
\r
2510 /*---------------------------------------------------------------------------*\
\r
2512 * GDI board drawing routines
\r
2514 \*---------------------------------------------------------------------------*/
\r
2516 /* [AS] Draw square using background texture */
\r
2517 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2522 return; /* Should never happen! */
\r
2525 SetGraphicsMode( dst, GM_ADVANCED );
\r
2532 /* X reflection */
\r
2537 x.eDx = (FLOAT) dw + dx - 1;
\r
2540 SetWorldTransform( dst, &x );
\r
2543 /* Y reflection */
\r
2549 x.eDy = (FLOAT) dh + dy - 1;
\r
2551 SetWorldTransform( dst, &x );
\r
2559 x.eDx = (FLOAT) dx;
\r
2560 x.eDy = (FLOAT) dy;
\r
2563 SetWorldTransform( dst, &x );
\r
2567 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2575 SetWorldTransform( dst, &x );
\r
2577 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2580 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2582 PM_WP = (int) WhitePawn,
\r
2583 PM_WN = (int) WhiteKnight,
\r
2584 PM_WB = (int) WhiteBishop,
\r
2585 PM_WR = (int) WhiteRook,
\r
2586 PM_WQ = (int) WhiteQueen,
\r
2587 PM_WF = (int) WhiteFerz,
\r
2588 PM_WW = (int) WhiteWazir,
\r
2589 PM_WE = (int) WhiteAlfil,
\r
2590 PM_WM = (int) WhiteMan,
\r
2591 PM_WO = (int) WhiteCannon,
\r
2592 PM_WU = (int) WhiteUnicorn,
\r
2593 PM_WH = (int) WhiteNightrider,
\r
2594 PM_WA = (int) WhiteAngel,
\r
2595 PM_WC = (int) WhiteMarshall,
\r
2596 PM_WAB = (int) WhiteCardinal,
\r
2597 PM_WD = (int) WhiteDragon,
\r
2598 PM_WL = (int) WhiteLance,
\r
2599 PM_WS = (int) WhiteCobra,
\r
2600 PM_WV = (int) WhiteFalcon,
\r
2601 PM_WSG = (int) WhiteSilver,
\r
2602 PM_WG = (int) WhiteGrasshopper,
\r
2603 PM_WK = (int) WhiteKing,
\r
2604 PM_BP = (int) BlackPawn,
\r
2605 PM_BN = (int) BlackKnight,
\r
2606 PM_BB = (int) BlackBishop,
\r
2607 PM_BR = (int) BlackRook,
\r
2608 PM_BQ = (int) BlackQueen,
\r
2609 PM_BF = (int) BlackFerz,
\r
2610 PM_BW = (int) BlackWazir,
\r
2611 PM_BE = (int) BlackAlfil,
\r
2612 PM_BM = (int) BlackMan,
\r
2613 PM_BO = (int) BlackCannon,
\r
2614 PM_BU = (int) BlackUnicorn,
\r
2615 PM_BH = (int) BlackNightrider,
\r
2616 PM_BA = (int) BlackAngel,
\r
2617 PM_BC = (int) BlackMarshall,
\r
2618 PM_BG = (int) BlackGrasshopper,
\r
2619 PM_BAB = (int) BlackCardinal,
\r
2620 PM_BD = (int) BlackDragon,
\r
2621 PM_BL = (int) BlackLance,
\r
2622 PM_BS = (int) BlackCobra,
\r
2623 PM_BV = (int) BlackFalcon,
\r
2624 PM_BSG = (int) BlackSilver,
\r
2625 PM_BK = (int) BlackKing
\r
2628 static HFONT hPieceFont = NULL;
\r
2629 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2630 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2631 static int fontBitmapSquareSize = 0;
\r
2632 static char pieceToFontChar[(int) EmptySquare] =
\r
2633 { 'p', 'n', 'b', 'r', 'q',
\r
2634 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2635 'k', 'o', 'm', 'v', 't', 'w',
\r
2636 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2639 extern BOOL SetCharTable( char *table, const char * map );
\r
2640 /* [HGM] moved to backend.c */
\r
2642 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2645 BYTE r1 = GetRValue( color );
\r
2646 BYTE g1 = GetGValue( color );
\r
2647 BYTE b1 = GetBValue( color );
\r
2653 /* Create a uniform background first */
\r
2654 hbrush = CreateSolidBrush( color );
\r
2655 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2656 FillRect( hdc, &rc, hbrush );
\r
2657 DeleteObject( hbrush );
\r
2660 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2661 int steps = squareSize / 2;
\r
2664 for( i=0; i<steps; i++ ) {
\r
2665 BYTE r = r1 - (r1-r2) * i / steps;
\r
2666 BYTE g = g1 - (g1-g2) * i / steps;
\r
2667 BYTE b = b1 - (b1-b2) * i / steps;
\r
2669 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2670 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2671 FillRect( hdc, &rc, hbrush );
\r
2672 DeleteObject(hbrush);
\r
2675 else if( mode == 2 ) {
\r
2676 /* Diagonal gradient, good more or less for every piece */
\r
2677 POINT triangle[3];
\r
2678 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2679 HBRUSH hbrush_old;
\r
2680 int steps = squareSize;
\r
2683 triangle[0].x = squareSize - steps;
\r
2684 triangle[0].y = squareSize;
\r
2685 triangle[1].x = squareSize;
\r
2686 triangle[1].y = squareSize;
\r
2687 triangle[2].x = squareSize;
\r
2688 triangle[2].y = squareSize - steps;
\r
2690 for( i=0; i<steps; i++ ) {
\r
2691 BYTE r = r1 - (r1-r2) * i / steps;
\r
2692 BYTE g = g1 - (g1-g2) * i / steps;
\r
2693 BYTE b = b1 - (b1-b2) * i / steps;
\r
2695 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2696 hbrush_old = SelectObject( hdc, hbrush );
\r
2697 Polygon( hdc, triangle, 3 );
\r
2698 SelectObject( hdc, hbrush_old );
\r
2699 DeleteObject(hbrush);
\r
2704 SelectObject( hdc, hpen );
\r
2709 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2710 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2711 piece: follow the steps as explained below.
\r
2713 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2717 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2721 int backColor = whitePieceColor;
\r
2722 int foreColor = blackPieceColor;
\r
2724 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2725 backColor = appData.fontBackColorWhite;
\r
2726 foreColor = appData.fontForeColorWhite;
\r
2728 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2729 backColor = appData.fontBackColorBlack;
\r
2730 foreColor = appData.fontForeColorBlack;
\r
2734 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2736 hbm_old = SelectObject( hdc, hbm );
\r
2740 rc.right = squareSize;
\r
2741 rc.bottom = squareSize;
\r
2743 /* Step 1: background is now black */
\r
2744 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2746 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2748 pt.x = (squareSize - sz.cx) / 2;
\r
2749 pt.y = (squareSize - sz.cy) / 2;
\r
2751 SetBkMode( hdc, TRANSPARENT );
\r
2752 SetTextColor( hdc, chroma );
\r
2753 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2754 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2756 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2757 /* Step 3: the area outside the piece is filled with white */
\r
2758 // FloodFill( hdc, 0, 0, chroma );
\r
2759 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2760 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2761 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2762 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2763 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2765 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2766 but if the start point is not inside the piece we're lost!
\r
2767 There should be a better way to do this... if we could create a region or path
\r
2768 from the fill operation we would be fine for example.
\r
2770 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2771 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2773 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2774 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2775 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2777 SelectObject( dc2, bm2 );
\r
2778 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2779 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2780 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2781 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2782 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2785 DeleteObject( bm2 );
\r
2788 SetTextColor( hdc, 0 );
\r
2790 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2791 draw the piece again in black for safety.
\r
2793 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2795 SelectObject( hdc, hbm_old );
\r
2797 if( hPieceMask[index] != NULL ) {
\r
2798 DeleteObject( hPieceMask[index] );
\r
2801 hPieceMask[index] = hbm;
\r
2804 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2806 SelectObject( hdc, hbm );
\r
2809 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2810 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2811 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2813 SelectObject( dc1, hPieceMask[index] );
\r
2814 SelectObject( dc2, bm2 );
\r
2815 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2816 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2819 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2820 the piece background and deletes (makes transparent) the rest.
\r
2821 Thanks to that mask, we are free to paint the background with the greates
\r
2822 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2823 We use this, to make gradients and give the pieces a "roundish" look.
\r
2825 SetPieceBackground( hdc, backColor, 2 );
\r
2826 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2830 DeleteObject( bm2 );
\r
2833 SetTextColor( hdc, foreColor );
\r
2834 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2836 SelectObject( hdc, hbm_old );
\r
2838 if( hPieceFace[index] != NULL ) {
\r
2839 DeleteObject( hPieceFace[index] );
\r
2842 hPieceFace[index] = hbm;
\r
2845 static int TranslatePieceToFontPiece( int piece )
\r
2875 case BlackMarshall:
\r
2879 case BlackNightrider:
\r
2885 case BlackUnicorn:
\r
2889 case BlackGrasshopper:
\r
2901 case BlackCardinal:
\r
2908 case WhiteMarshall:
\r
2912 case WhiteNightrider:
\r
2918 case WhiteUnicorn:
\r
2922 case WhiteGrasshopper:
\r
2934 case WhiteCardinal:
\r
2943 void CreatePiecesFromFont()
\r
2946 HDC hdc_window = NULL;
\r
2952 if( fontBitmapSquareSize < 0 ) {
\r
2953 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2957 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2958 fontBitmapSquareSize = -1;
\r
2962 if( fontBitmapSquareSize != squareSize ) {
\r
2963 hdc_window = GetDC( hwndMain );
\r
2964 hdc = CreateCompatibleDC( hdc_window );
\r
2966 if( hPieceFont != NULL ) {
\r
2967 DeleteObject( hPieceFont );
\r
2970 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2971 hPieceMask[i] = NULL;
\r
2972 hPieceFace[i] = NULL;
\r
2978 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2979 fontHeight = appData.fontPieceSize;
\r
2982 fontHeight = (fontHeight * squareSize) / 100;
\r
2984 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2986 lf.lfEscapement = 0;
\r
2987 lf.lfOrientation = 0;
\r
2988 lf.lfWeight = FW_NORMAL;
\r
2990 lf.lfUnderline = 0;
\r
2991 lf.lfStrikeOut = 0;
\r
2992 lf.lfCharSet = DEFAULT_CHARSET;
\r
2993 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2994 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2995 lf.lfQuality = PROOF_QUALITY;
\r
2996 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2997 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2998 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
3000 hPieceFont = CreateFontIndirect( &lf );
\r
3002 if( hPieceFont == NULL ) {
\r
3003 fontBitmapSquareSize = -2;
\r
3006 /* Setup font-to-piece character table */
\r
3007 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
3008 /* No (or wrong) global settings, try to detect the font */
\r
3009 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
3011 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
3013 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
3014 /* DiagramTT* family */
\r
3015 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
3017 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
3018 /* Fairy symbols */
\r
3019 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
3021 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
3022 /* Good Companion (Some characters get warped as literal :-( */
\r
3023 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
3024 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
3025 SetCharTable(pieceToFontChar, s);
\r
3028 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
3029 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
3033 /* Create bitmaps */
\r
3034 hfont_old = SelectObject( hdc, hPieceFont );
\r
3036 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
3037 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
3038 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
3039 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
3040 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
3041 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
3042 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
3043 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
3044 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
3045 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
3046 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
3047 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
3049 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
3050 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
3051 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
3052 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
3053 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
3054 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
3055 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
3056 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
3057 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
3058 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
3059 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
3060 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
3061 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
3062 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
3063 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
3064 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
3065 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
3066 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
3067 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
3068 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
3069 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
3070 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
3071 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
3072 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
3073 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
3074 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
3075 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
3076 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
3077 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
3078 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
3079 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
3080 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
3082 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
3083 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
3084 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
3086 SelectObject( hdc, hfont_old );
\r
3088 fontBitmapSquareSize = squareSize;
\r
3092 if( hdc != NULL ) {
\r
3096 if( hdc_window != NULL ) {
\r
3097 ReleaseDC( hwndMain, hdc_window );
\r
3102 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
3106 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
3107 if (gameInfo.event &&
\r
3108 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
3109 strcmp(name, "k80s") == 0) {
\r
3110 strcpy(name, "tim");
\r
3112 return LoadBitmap(hinst, name);
\r
3116 /* Insert a color into the program's logical palette
\r
3117 structure. This code assumes the given color is
\r
3118 the result of the RGB or PALETTERGB macro, and it
\r
3119 knows how those macros work (which is documented).
\r
3122 InsertInPalette(COLORREF color)
\r
3124 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
3126 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
3127 DisplayFatalError("Too many colors", 0, 1);
\r
3128 pLogPal->palNumEntries--;
\r
3132 pe->peFlags = (char) 0;
\r
3133 pe->peRed = (char) (0xFF & color);
\r
3134 pe->peGreen = (char) (0xFF & (color >> 8));
\r
3135 pe->peBlue = (char) (0xFF & (color >> 16));
\r
3141 InitDrawingColors()
\r
3143 if (pLogPal == NULL) {
\r
3144 /* Allocate enough memory for a logical palette with
\r
3145 * PALETTESIZE entries and set the size and version fields
\r
3146 * of the logical palette structure.
\r
3148 pLogPal = (NPLOGPALETTE)
\r
3149 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3150 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3151 pLogPal->palVersion = 0x300;
\r
3153 pLogPal->palNumEntries = 0;
\r
3155 InsertInPalette(lightSquareColor);
\r
3156 InsertInPalette(darkSquareColor);
\r
3157 InsertInPalette(whitePieceColor);
\r
3158 InsertInPalette(blackPieceColor);
\r
3159 InsertInPalette(highlightSquareColor);
\r
3160 InsertInPalette(premoveHighlightColor);
\r
3162 /* create a logical color palette according the information
\r
3163 * in the LOGPALETTE structure.
\r
3165 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3167 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3168 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3169 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3170 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3171 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3172 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3173 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3174 /* [AS] Force rendering of the font-based pieces */
\r
3175 if( fontBitmapSquareSize > 0 ) {
\r
3176 fontBitmapSquareSize = 0;
\r
3182 BoardWidth(int boardSize, int n)
\r
3183 { /* [HGM] argument n added to allow different width and height */
\r
3184 int lineGap = sizeInfo[boardSize].lineGap;
\r
3186 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3187 lineGap = appData.overrideLineGap;
\r
3190 return (n + 1) * lineGap +
\r
3191 n * sizeInfo[boardSize].squareSize;
\r
3194 /* Respond to board resize by dragging edge */
\r
3196 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3198 BoardSize newSize = NUM_SIZES - 1;
\r
3199 static int recurse = 0;
\r
3200 if (IsIconic(hwndMain)) return;
\r
3201 if (recurse > 0) return;
\r
3203 while (newSize > 0) {
\r
3204 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3205 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3206 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3209 boardSize = newSize;
\r
3210 InitDrawingSizes(boardSize, flags);
\r
3217 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3219 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3220 ChessSquare piece;
\r
3221 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3223 SIZE clockSize, messageSize;
\r
3225 char buf[MSG_SIZ];
\r
3227 HMENU hmenu = GetMenu(hwndMain);
\r
3228 RECT crect, wrect, oldRect;
\r
3230 LOGBRUSH logbrush;
\r
3232 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3233 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3235 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3236 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3238 oldRect.left = boardX; //[HGM] placement: remember previous window params
\r
3239 oldRect.top = boardY;
\r
3240 oldRect.right = boardX + winWidth;
\r
3241 oldRect.bottom = boardY + winHeight;
\r
3243 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3244 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3245 squareSize = sizeInfo[boardSize].squareSize;
\r
3246 lineGap = sizeInfo[boardSize].lineGap;
\r
3247 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3249 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3250 lineGap = appData.overrideLineGap;
\r
3253 if (tinyLayout != oldTinyLayout) {
\r
3254 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3256 style &= ~WS_SYSMENU;
\r
3257 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3258 "&Minimize\tCtrl+F4");
\r
3260 style |= WS_SYSMENU;
\r
3261 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3263 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3265 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3266 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3267 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3269 DrawMenuBar(hwndMain);
\r
3272 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3273 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3275 /* Get text area sizes */
\r
3276 hdc = GetDC(hwndMain);
\r
3277 if (appData.clockMode) {
\r
3278 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3280 sprintf(buf, "White");
\r
3282 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3283 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3284 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3285 str = "We only care about the height here";
\r
3286 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3287 SelectObject(hdc, oldFont);
\r
3288 ReleaseDC(hwndMain, hdc);
\r
3290 /* Compute where everything goes */
\r
3291 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3292 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3293 logoHeight = 2*clockSize.cy;
\r
3294 leftLogoRect.left = OUTER_MARGIN;
\r
3295 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3296 leftLogoRect.top = OUTER_MARGIN;
\r
3297 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3299 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3300 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3301 rightLogoRect.top = OUTER_MARGIN;
\r
3302 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3305 whiteRect.left = leftLogoRect.right;
\r
3306 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3307 whiteRect.top = OUTER_MARGIN;
\r
3308 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3310 blackRect.right = rightLogoRect.left;
\r
3311 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3312 blackRect.top = whiteRect.top;
\r
3313 blackRect.bottom = whiteRect.bottom;
\r
3315 whiteRect.left = OUTER_MARGIN;
\r
3316 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3317 whiteRect.top = OUTER_MARGIN;
\r
3318 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3320 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3321 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3322 blackRect.top = whiteRect.top;
\r
3323 blackRect.bottom = whiteRect.bottom;
\r
3326 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3327 if (appData.showButtonBar) {
\r
3328 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3329 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3331 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3333 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3334 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3336 boardRect.left = OUTER_MARGIN;
\r
3337 boardRect.right = boardRect.left + boardWidth;
\r
3338 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3339 boardRect.bottom = boardRect.top + boardHeight;
\r
3341 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3342 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3343 oldBoardSize = boardSize;
\r
3344 oldTinyLayout = tinyLayout;
\r
3345 winW = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3346 winH = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3347 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3348 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3349 winWidth = winW; // [HGM] placement: set through temporary which can used by initial sizing choice
\r
3350 winHeight = winH; // without disturbing window attachments
\r
3351 GetWindowRect(hwndMain, &wrect);
\r
3352 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3353 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3355 // [HGM] placement: let attached windows follow size change.
\r
3356 ReattachAfterSize( &oldRect, winWidth, winHeight, moveHistoryDialog, &wpMoveHistory );
\r
3357 ReattachAfterSize( &oldRect, winWidth, winHeight, evalGraphDialog, &wpEvalGraph );
\r
3358 ReattachAfterSize( &oldRect, winWidth, winHeight, engineOutputDialog, &wpEngineOutput );
\r
3359 ReattachAfterSize( &oldRect, winWidth, winHeight, gameListDialog, &wpGameList );
\r
3360 ReattachAfterSize( &oldRect, winWidth, winHeight, hwndConsole, &wpConsole );
\r
3362 /* compensate if menu bar wrapped */
\r
3363 GetClientRect(hwndMain, &crect);
\r
3364 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3365 winHeight += offby;
\r
3367 case WMSZ_TOPLEFT:
\r
3368 SetWindowPos(hwndMain, NULL,
\r
3369 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3370 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3373 case WMSZ_TOPRIGHT:
\r
3375 SetWindowPos(hwndMain, NULL,
\r
3376 wrect.left, wrect.bottom - winHeight,
\r
3377 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3380 case WMSZ_BOTTOMLEFT:
\r
3382 SetWindowPos(hwndMain, NULL,
\r
3383 wrect.right - winWidth, wrect.top,
\r
3384 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3387 case WMSZ_BOTTOMRIGHT:
\r
3391 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3392 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3397 for (i = 0; i < N_BUTTONS; i++) {
\r
3398 if (buttonDesc[i].hwnd != NULL) {
\r
3399 DestroyWindow(buttonDesc[i].hwnd);
\r
3400 buttonDesc[i].hwnd = NULL;
\r
3402 if (appData.showButtonBar) {
\r
3403 buttonDesc[i].hwnd =
\r
3404 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3405 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3406 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3407 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3408 (HMENU) buttonDesc[i].id,
\r
3409 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3411 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3412 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3413 MAKELPARAM(FALSE, 0));
\r
3415 if (buttonDesc[i].id == IDM_Pause)
\r
3416 hwndPause = buttonDesc[i].hwnd;
\r
3417 buttonDesc[i].wndproc = (WNDPROC)
\r
3418 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3421 if (gridPen != NULL) DeleteObject(gridPen);
\r
3422 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3423 if (premovePen != NULL) DeleteObject(premovePen);
\r
3424 if (lineGap != 0) {
\r
3425 logbrush.lbStyle = BS_SOLID;
\r
3426 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3428 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3429 lineGap, &logbrush, 0, NULL);
\r
3430 logbrush.lbColor = highlightSquareColor;
\r
3432 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3433 lineGap, &logbrush, 0, NULL);
\r
3435 logbrush.lbColor = premoveHighlightColor;
\r
3437 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3438 lineGap, &logbrush, 0, NULL);
\r
3440 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3441 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3442 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3443 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3444 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3445 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3446 BOARD_WIDTH * (squareSize + lineGap);
\r
3447 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3449 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3450 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3451 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3452 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3453 lineGap / 2 + (i * (squareSize + lineGap));
\r
3454 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3455 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3456 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3460 /* [HGM] Licensing requirement */
\r
3462 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3465 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3467 GothicPopUp( "", VariantNormal);
\r
3470 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3472 /* Load piece bitmaps for this board size */
\r
3473 for (i=0; i<=2; i++) {
\r
3474 for (piece = WhitePawn;
\r
3475 (int) piece < (int) BlackPawn;
\r
3476 piece = (ChessSquare) ((int) piece + 1)) {
\r
3477 if (pieceBitmap[i][piece] != NULL)
\r
3478 DeleteObject(pieceBitmap[i][piece]);
\r
3482 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3483 // Orthodox Chess pieces
\r
3484 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3485 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3486 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3487 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3488 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3489 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3490 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3491 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3492 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3493 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3494 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3495 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3496 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3497 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3498 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3499 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3500 // in Shogi, Hijack the unused Queen for Lance
\r
3501 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3502 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3503 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3505 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3506 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3507 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3510 if(squareSize <= 72 && squareSize >= 33) {
\r
3511 /* A & C are available in most sizes now */
\r
3512 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3513 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3514 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3515 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3516 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3517 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3518 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3519 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3520 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3521 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3522 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3523 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3524 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3525 } else { // Smirf-like
\r
3526 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3527 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3528 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3530 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3531 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3532 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3533 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3534 } else { // WinBoard standard
\r
3535 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3536 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3537 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3542 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3543 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3544 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3545 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3546 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3547 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3548 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3549 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3550 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3551 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3552 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3553 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3554 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3555 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3556 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3557 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3558 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3559 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3560 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3561 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3562 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3563 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3564 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3565 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3566 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3567 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3568 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3569 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3570 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3571 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3572 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3574 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3575 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3576 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3577 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3578 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3579 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3580 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3581 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3582 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3583 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3584 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3585 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3586 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3588 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3589 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3590 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3591 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3592 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3593 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3594 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3595 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3596 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3597 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3598 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3599 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3602 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3603 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3604 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3605 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3606 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3607 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3608 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3609 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3610 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3611 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3612 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3613 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3614 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3615 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3616 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3620 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3621 /* special Shogi support in this size */
\r
3622 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3623 for (piece = WhitePawn;
\r
3624 (int) piece < (int) BlackPawn;
\r
3625 piece = (ChessSquare) ((int) piece + 1)) {
\r
3626 if (pieceBitmap[i][piece] != NULL)
\r
3627 DeleteObject(pieceBitmap[i][piece]);
\r
3630 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3631 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3632 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3633 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3634 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3635 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3636 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3637 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3638 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3639 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3640 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3641 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3642 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3643 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3644 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3645 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3646 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3647 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3648 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3649 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3650 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3651 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3652 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3653 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3654 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3655 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3656 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3657 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3658 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3659 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3660 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3661 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3662 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3663 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3664 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3665 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3666 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3667 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3668 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3669 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3670 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3671 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3677 PieceBitmap(ChessSquare p, int kind)
\r
3679 if ((int) p >= (int) BlackPawn)
\r
3680 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3682 return pieceBitmap[kind][(int) p];
\r
3685 /***************************************************************/
\r
3687 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3688 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3690 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3691 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3695 SquareToPos(int row, int column, int * x, int * y)
\r
3698 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3699 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3701 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3702 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3707 DrawCoordsOnDC(HDC hdc)
\r
3709 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
3710 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
3711 char str[2] = { NULLCHAR, NULLCHAR };
\r
3712 int oldMode, oldAlign, x, y, start, i;
\r
3716 if (!appData.showCoords)
\r
3719 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3721 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3722 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3723 oldAlign = GetTextAlign(hdc);
\r
3724 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3726 y = boardRect.top + lineGap;
\r
3727 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3729 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3730 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3731 str[0] = files[start + i];
\r
3732 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3733 y += squareSize + lineGap;
\r
3736 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3738 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3739 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3740 str[0] = ranks[start + i];
\r
3741 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3742 x += squareSize + lineGap;
\r
3745 SelectObject(hdc, oldBrush);
\r
3746 SetBkMode(hdc, oldMode);
\r
3747 SetTextAlign(hdc, oldAlign);
\r
3748 SelectObject(hdc, oldFont);
\r
3752 DrawGridOnDC(HDC hdc)
\r
3756 if (lineGap != 0) {
\r
3757 oldPen = SelectObject(hdc, gridPen);
\r
3758 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3759 SelectObject(hdc, oldPen);
\r
3763 #define HIGHLIGHT_PEN 0
\r
3764 #define PREMOVE_PEN 1
\r
3767 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3770 HPEN oldPen, hPen;
\r
3771 if (lineGap == 0) return;
\r
3773 x1 = boardRect.left +
\r
3774 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3775 y1 = boardRect.top +
\r
3776 lineGap/2 + y * (squareSize + lineGap);
\r
3778 x1 = boardRect.left +
\r
3779 lineGap/2 + x * (squareSize + lineGap);
\r
3780 y1 = boardRect.top +
\r
3781 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3783 hPen = pen ? premovePen : highlightPen;
\r
3784 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3785 MoveToEx(hdc, x1, y1, NULL);
\r
3786 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3787 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3788 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3789 LineTo(hdc, x1, y1);
\r
3790 SelectObject(hdc, oldPen);
\r
3794 DrawHighlightsOnDC(HDC hdc)
\r
3797 for (i=0; i<2; i++) {
\r
3798 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3799 DrawHighlightOnDC(hdc, TRUE,
\r
3800 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3803 for (i=0; i<2; i++) {
\r
3804 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3805 premoveHighlightInfo.sq[i].y >= 0) {
\r
3806 DrawHighlightOnDC(hdc, TRUE,
\r
3807 premoveHighlightInfo.sq[i].x,
\r
3808 premoveHighlightInfo.sq[i].y,
\r
3814 /* Note: sqcolor is used only in monoMode */
\r
3815 /* Note that this code is largely duplicated in woptions.c,
\r
3816 function DrawSampleSquare, so that needs to be updated too */
\r
3818 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3820 HBITMAP oldBitmap;
\r
3824 if (appData.blindfold) return;
\r
3826 /* [AS] Use font-based pieces if needed */
\r
3827 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3828 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3829 CreatePiecesFromFont();
\r
3831 if( fontBitmapSquareSize == squareSize ) {
\r
3832 int index = TranslatePieceToFontPiece(piece);
\r
3834 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3838 squareSize, squareSize,
\r
3843 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3847 squareSize, squareSize,
\r
3856 if (appData.monoMode) {
\r
3857 SelectObject(tmphdc, PieceBitmap(piece,
\r
3858 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3859 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3860 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3862 tmpSize = squareSize;
\r
3864 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3865 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3866 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3867 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3868 x += (squareSize - minorSize)>>1;
\r
3869 y += squareSize - minorSize - 2;
\r
3870 tmpSize = minorSize;
\r
3872 if (color || appData.allWhite ) {
\r
3873 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3875 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3876 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3877 if(appData.upsideDown && color==flipView)
\r
3878 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3880 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3882 /* Use black piece color for outline of white pieces */
\r
3883 /* Not sure this looks really good (though xboard does it).
\r
3884 Maybe better to have another selectable color, default black */
\r
3885 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3886 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3887 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3889 /* Use black for outline of white pieces */
\r
3890 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3891 if(appData.upsideDown && color==flipView)
\r
3892 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3894 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3898 /* Use white piece color for details of black pieces */
\r
3899 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3900 WHITE_PIECE ones aren't always the right shape. */
\r
3901 /* Not sure this looks really good (though xboard does it).
\r
3902 Maybe better to have another selectable color, default medium gray? */
\r
3903 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3904 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3905 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3906 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3907 SelectObject(hdc, blackPieceBrush);
\r
3908 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3910 /* Use square color for details of black pieces */
\r
3911 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3912 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3913 if(appData.upsideDown && !flipView)
\r
3914 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3916 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3919 SelectObject(hdc, oldBrush);
\r
3920 SelectObject(tmphdc, oldBitmap);
\r
3924 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3925 int GetBackTextureMode( int algo )
\r
3927 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3931 case BACK_TEXTURE_MODE_PLAIN:
\r
3932 result = 1; /* Always use identity map */
\r
3934 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3935 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3943 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3944 to handle redraws cleanly (as random numbers would always be different).
\r
3946 VOID RebuildTextureSquareInfo()
\r
3956 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3958 if( liteBackTexture != NULL ) {
\r
3959 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3960 lite_w = bi.bmWidth;
\r
3961 lite_h = bi.bmHeight;
\r
3965 if( darkBackTexture != NULL ) {
\r
3966 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3967 dark_w = bi.bmWidth;
\r
3968 dark_h = bi.bmHeight;
\r
3972 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3973 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3974 if( (col + row) & 1 ) {
\r
3976 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3977 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3978 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3979 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3984 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3985 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3986 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3987 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3994 /* [AS] Arrow highlighting support */
\r
3996 static int A_WIDTH = 5; /* Width of arrow body */
\r
3998 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3999 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
4001 static double Sqr( double x )
\r
4006 static int Round( double x )
\r
4008 return (int) (x + 0.5);
\r
4011 /* Draw an arrow between two points using current settings */
\r
4012 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
4015 double dx, dy, j, k, x, y;
\r
4017 if( d_x == s_x ) {
\r
4018 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4020 arrow[0].x = s_x + A_WIDTH;
\r
4023 arrow[1].x = s_x + A_WIDTH;
\r
4024 arrow[1].y = d_y - h;
\r
4026 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
4027 arrow[2].y = d_y - h;
\r
4032 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
4033 arrow[4].y = d_y - h;
\r
4035 arrow[5].x = s_x - A_WIDTH;
\r
4036 arrow[5].y = d_y - h;
\r
4038 arrow[6].x = s_x - A_WIDTH;
\r
4041 else if( d_y == s_y ) {
\r
4042 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
4045 arrow[0].y = s_y + A_WIDTH;
\r
4047 arrow[1].x = d_x - w;
\r
4048 arrow[1].y = s_y + A_WIDTH;
\r
4050 arrow[2].x = d_x - w;
\r
4051 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
4056 arrow[4].x = d_x - w;
\r
4057 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
4059 arrow[5].x = d_x - w;
\r
4060 arrow[5].y = s_y - A_WIDTH;
\r
4063 arrow[6].y = s_y - A_WIDTH;
\r
4066 /* [AS] Needed a lot of paper for this! :-) */
\r
4067 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
4068 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
4070 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
4072 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
4077 arrow[0].x = Round(x - j);
\r
4078 arrow[0].y = Round(y + j*dx);
\r
4080 arrow[1].x = Round(x + j);
\r
4081 arrow[1].y = Round(y - j*dx);
\r
4084 x = (double) d_x - k;
\r
4085 y = (double) d_y - k*dy;
\r
4088 x = (double) d_x + k;
\r
4089 y = (double) d_y + k*dy;
\r
4092 arrow[2].x = Round(x + j);
\r
4093 arrow[2].y = Round(y - j*dx);
\r
4095 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
4096 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
4101 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
4102 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
4104 arrow[6].x = Round(x - j);
\r
4105 arrow[6].y = Round(y + j*dx);
\r
4108 Polygon( hdc, arrow, 7 );
\r
4111 /* [AS] Draw an arrow between two squares */
\r
4112 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
4114 int s_x, s_y, d_x, d_y;
\r
4121 if( s_col == d_col && s_row == d_row ) {
\r
4125 /* Get source and destination points */
\r
4126 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
4127 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
4130 d_y += squareSize / 4;
\r
4132 else if( d_y < s_y ) {
\r
4133 d_y += 3 * squareSize / 4;
\r
4136 d_y += squareSize / 2;
\r
4140 d_x += squareSize / 4;
\r
4142 else if( d_x < s_x ) {
\r
4143 d_x += 3 * squareSize / 4;
\r
4146 d_x += squareSize / 2;
\r
4149 s_x += squareSize / 2;
\r
4150 s_y += squareSize / 2;
\r
4152 /* Adjust width */
\r
4153 A_WIDTH = squareSize / 14;
\r
4156 stLB.lbStyle = BS_SOLID;
\r
4157 stLB.lbColor = appData.highlightArrowColor;
\r
4160 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
4161 holdpen = SelectObject( hdc, hpen );
\r
4162 hbrush = CreateBrushIndirect( &stLB );
\r
4163 holdbrush = SelectObject( hdc, hbrush );
\r
4165 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4167 SelectObject( hdc, holdpen );
\r
4168 SelectObject( hdc, holdbrush );
\r
4169 DeleteObject( hpen );
\r
4170 DeleteObject( hbrush );
\r
4173 BOOL HasHighlightInfo()
\r
4175 BOOL result = FALSE;
\r
4177 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4178 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4186 BOOL IsDrawArrowEnabled()
\r
4188 BOOL result = FALSE;
\r
4190 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4197 VOID DrawArrowHighlight( HDC hdc )
\r
4199 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4200 DrawArrowBetweenSquares( hdc,
\r
4201 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4202 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4206 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4208 HRGN result = NULL;
\r
4210 if( HasHighlightInfo() ) {
\r
4211 int x1, y1, x2, y2;
\r
4212 int sx, sy, dx, dy;
\r
4214 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4215 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4217 sx = MIN( x1, x2 );
\r
4218 sy = MIN( y1, y2 );
\r
4219 dx = MAX( x1, x2 ) + squareSize;
\r
4220 dy = MAX( y1, y2 ) + squareSize;
\r
4222 result = CreateRectRgn( sx, sy, dx, dy );
\r
4229 Warning: this function modifies the behavior of several other functions.
\r
4231 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4232 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4233 repaint is scattered all over the place, which is not good for features such as
\r
4234 "arrow highlighting" that require a full repaint of the board.
\r
4236 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4237 user interaction, when speed is not so important) but especially to avoid errors
\r
4238 in the displayed graphics.
\r
4240 In such patched places, I always try refer to this function so there is a single
\r
4241 place to maintain knowledge.
\r
4243 To restore the original behavior, just return FALSE unconditionally.
\r
4245 BOOL IsFullRepaintPreferrable()
\r
4247 BOOL result = FALSE;
\r
4249 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4250 /* Arrow may appear on the board */
\r
4258 This function is called by DrawPosition to know whether a full repaint must
\r
4261 Only DrawPosition may directly call this function, which makes use of
\r
4262 some state information. Other function should call DrawPosition specifying
\r
4263 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4265 BOOL DrawPositionNeedsFullRepaint()
\r
4267 BOOL result = FALSE;
\r
4270 Probably a slightly better policy would be to trigger a full repaint
\r
4271 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4272 but animation is fast enough that it's difficult to notice.
\r
4274 if( animInfo.piece == EmptySquare ) {
\r
4275 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4284 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4286 int row, column, x, y, square_color, piece_color;
\r
4287 ChessSquare piece;
\r
4289 HDC texture_hdc = NULL;
\r
4291 /* [AS] Initialize background textures if needed */
\r
4292 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4293 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4294 if( backTextureSquareSize != squareSize
\r
4295 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4296 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4297 backTextureSquareSize = squareSize;
\r
4298 RebuildTextureSquareInfo();
\r
4301 texture_hdc = CreateCompatibleDC( hdc );
\r
4304 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4305 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4307 SquareToPos(row, column, &x, &y);
\r
4309 piece = board[row][column];
\r
4311 square_color = ((column + row) % 2) == 1;
\r
4312 if( gameInfo.variant == VariantXiangqi ) {
\r
4313 square_color = !InPalace(row, column);
\r
4314 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4315 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4317 piece_color = (int) piece < (int) BlackPawn;
\r
4320 /* [HGM] holdings file: light square or black */
\r
4321 if(column == BOARD_LEFT-2) {
\r
4322 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4325 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4329 if(column == BOARD_RGHT + 1 ) {
\r
4330 if( row < gameInfo.holdingsSize )
\r
4333 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4337 if(column == BOARD_LEFT-1 ) /* left align */
\r
4338 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4339 else if( column == BOARD_RGHT) /* right align */
\r
4340 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4342 if (appData.monoMode) {
\r
4343 if (piece == EmptySquare) {
\r
4344 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4345 square_color ? WHITENESS : BLACKNESS);
\r
4347 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4350 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4351 /* [AS] Draw the square using a texture bitmap */
\r
4352 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4353 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4354 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4357 squareSize, squareSize,
\r
4360 backTextureSquareInfo[r][c].mode,
\r
4361 backTextureSquareInfo[r][c].x,
\r
4362 backTextureSquareInfo[r][c].y );
\r
4364 SelectObject( texture_hdc, hbm );
\r
4366 if (piece != EmptySquare) {
\r
4367 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4371 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4373 oldBrush = SelectObject(hdc, brush );
\r
4374 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4375 SelectObject(hdc, oldBrush);
\r
4376 if (piece != EmptySquare)
\r
4377 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4382 if( texture_hdc != NULL ) {
\r
4383 DeleteDC( texture_hdc );
\r
4387 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4388 void fputDW(FILE *f, int x)
\r
4390 fputc(x & 255, f);
\r
4391 fputc(x>>8 & 255, f);
\r
4392 fputc(x>>16 & 255, f);
\r
4393 fputc(x>>24 & 255, f);
\r
4396 #define MAX_CLIPS 200 /* more than enough */
\r
4399 DrawLogoOnDC(HDC hdc, RECT logoRect, HBITMAP logo)
\r
4401 // HBITMAP bufferBitmap;
\r
4406 int w = 100, h = 50;
\r
4408 if(logo == NULL) return;
\r
4409 // GetClientRect(hwndMain, &Rect);
\r
4410 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4411 // Rect.bottom-Rect.top+1);
\r
4412 tmphdc = CreateCompatibleDC(hdc);
\r
4413 hbm = SelectObject(tmphdc, logo);
\r
4414 if( GetObject( logo, sizeof(bi), &bi ) > 0 ) {
\r
4418 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4419 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4420 SelectObject(tmphdc, hbm);
\r
4425 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4427 static Board lastReq, lastDrawn;
\r
4428 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4429 static int lastDrawnFlipView = 0;
\r
4430 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4431 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4434 HBITMAP bufferBitmap;
\r
4435 HBITMAP oldBitmap;
\r
4437 HRGN clips[MAX_CLIPS];
\r
4438 ChessSquare dragged_piece = EmptySquare;
\r
4440 /* I'm undecided on this - this function figures out whether a full
\r
4441 * repaint is necessary on its own, so there's no real reason to have the
\r
4442 * caller tell it that. I think this can safely be set to FALSE - but
\r
4443 * if we trust the callers not to request full repaints unnessesarily, then
\r
4444 * we could skip some clipping work. In other words, only request a full
\r
4445 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4446 * gamestart and similar) --Hawk
\r
4448 Boolean fullrepaint = repaint;
\r
4450 if( DrawPositionNeedsFullRepaint() ) {
\r
4451 fullrepaint = TRUE;
\r
4455 if( fullrepaint ) {
\r
4456 static int repaint_count = 0;
\r
4460 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4461 OutputDebugString( buf );
\r
4465 if (board == NULL) {
\r
4466 if (!lastReqValid) {
\r
4471 CopyBoard(lastReq, board);
\r
4475 if (doingSizing) {
\r
4479 if (IsIconic(hwndMain)) {
\r
4483 if (hdc == NULL) {
\r
4484 hdc = GetDC(hwndMain);
\r
4485 if (!appData.monoMode) {
\r
4486 SelectPalette(hdc, hPal, FALSE);
\r
4487 RealizePalette(hdc);
\r
4491 releaseDC = FALSE;
\r
4495 fprintf(debugFP, "*******************************\n"
\r
4497 "dragInfo.from (%d,%d)\n"
\r
4498 "dragInfo.start (%d,%d)\n"
\r
4499 "dragInfo.pos (%d,%d)\n"
\r
4500 "dragInfo.lastpos (%d,%d)\n",
\r
4501 repaint ? "TRUE" : "FALSE",
\r
4502 dragInfo.from.x, dragInfo.from.y,
\r
4503 dragInfo.start.x, dragInfo.start.y,
\r
4504 dragInfo.pos.x, dragInfo.pos.y,
\r
4505 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4506 fprintf(debugFP, "prev: ");
\r
4507 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4508 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4509 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4512 fprintf(debugFP, "\n");
\r
4513 fprintf(debugFP, "board: ");
\r
4514 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4515 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4516 fprintf(debugFP, "%d ", board[row][column]);
\r
4519 fprintf(debugFP, "\n");
\r
4523 /* Create some work-DCs */
\r
4524 hdcmem = CreateCompatibleDC(hdc);
\r
4525 tmphdc = CreateCompatibleDC(hdc);
\r
4527 /* If dragging is in progress, we temporarely remove the piece */
\r
4528 /* [HGM] or temporarily decrease count if stacked */
\r
4529 /* !! Moved to before board compare !! */
\r
4530 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4531 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4532 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4533 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4534 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4536 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4537 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4538 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4540 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4543 /* Figure out which squares need updating by comparing the
\r
4544 * newest board with the last drawn board and checking if
\r
4545 * flipping has changed.
\r
4547 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4548 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4549 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4550 if (lastDrawn[row][column] != board[row][column]) {
\r
4551 SquareToPos(row, column, &x, &y);
\r
4552 clips[num_clips++] =
\r
4553 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4557 for (i=0; i<2; i++) {
\r
4558 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4559 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4560 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4561 lastDrawnHighlight.sq[i].y >= 0) {
\r
4562 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4563 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4564 clips[num_clips++] =
\r
4565 CreateRectRgn(x - lineGap, y - lineGap,
\r
4566 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4568 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4569 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4570 clips[num_clips++] =
\r
4571 CreateRectRgn(x - lineGap, y - lineGap,
\r
4572 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4576 for (i=0; i<2; i++) {
\r
4577 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4578 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4579 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4580 lastDrawnPremove.sq[i].y >= 0) {
\r
4581 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4582 lastDrawnPremove.sq[i].x, &x, &y);
\r
4583 clips[num_clips++] =
\r
4584 CreateRectRgn(x - lineGap, y - lineGap,
\r
4585 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4587 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4588 premoveHighlightInfo.sq[i].y >= 0) {
\r
4589 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4590 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4591 clips[num_clips++] =
\r
4592 CreateRectRgn(x - lineGap, y - lineGap,
\r
4593 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4598 fullrepaint = TRUE;
\r
4601 /* Create a buffer bitmap - this is the actual bitmap
\r
4602 * being written to. When all the work is done, we can
\r
4603 * copy it to the real DC (the screen). This avoids
\r
4604 * the problems with flickering.
\r
4606 GetClientRect(hwndMain, &Rect);
\r
4607 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4608 Rect.bottom-Rect.top+1);
\r
4609 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4610 if (!appData.monoMode) {
\r
4611 SelectPalette(hdcmem, hPal, FALSE);
\r
4614 /* Create clips for dragging */
\r
4615 if (!fullrepaint) {
\r
4616 if (dragInfo.from.x >= 0) {
\r
4617 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4618 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4620 if (dragInfo.start.x >= 0) {
\r
4621 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4622 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4624 if (dragInfo.pos.x >= 0) {
\r
4625 x = dragInfo.pos.x - squareSize / 2;
\r
4626 y = dragInfo.pos.y - squareSize / 2;
\r
4627 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4629 if (dragInfo.lastpos.x >= 0) {
\r
4630 x = dragInfo.lastpos.x - squareSize / 2;
\r
4631 y = dragInfo.lastpos.y - squareSize / 2;
\r
4632 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4636 /* Are we animating a move?
\r
4638 * - remove the piece from the board (temporarely)
\r
4639 * - calculate the clipping region
\r
4641 if (!fullrepaint) {
\r
4642 if (animInfo.piece != EmptySquare) {
\r
4643 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4644 x = boardRect.left + animInfo.lastpos.x;
\r
4645 y = boardRect.top + animInfo.lastpos.y;
\r
4646 x2 = boardRect.left + animInfo.pos.x;
\r
4647 y2 = boardRect.top + animInfo.pos.y;
\r
4648 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4649 /* Slight kludge. The real problem is that after AnimateMove is
\r
4650 done, the position on the screen does not match lastDrawn.
\r
4651 This currently causes trouble only on e.p. captures in
\r
4652 atomic, where the piece moves to an empty square and then
\r
4653 explodes. The old and new positions both had an empty square
\r
4654 at the destination, but animation has drawn a piece there and
\r
4655 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4656 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4660 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4661 if (num_clips == 0)
\r
4662 fullrepaint = TRUE;
\r
4664 /* Set clipping on the memory DC */
\r
4665 if (!fullrepaint) {
\r
4666 SelectClipRgn(hdcmem, clips[0]);
\r
4667 for (x = 1; x < num_clips; x++) {
\r
4668 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4669 abort(); // this should never ever happen!
\r
4673 /* Do all the drawing to the memory DC */
\r
4674 if(explodeInfo.radius) { // [HGM] atomic
\r
4676 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4677 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4678 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4679 x += squareSize/2;
\r
4680 y += squareSize/2;
\r
4681 if(!fullrepaint) {
\r
4682 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4683 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4685 DrawGridOnDC(hdcmem);
\r
4686 DrawHighlightsOnDC(hdcmem);
\r
4687 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4688 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4689 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4690 SelectObject(hdcmem, oldBrush);
\r
4692 DrawGridOnDC(hdcmem);
\r
4693 DrawHighlightsOnDC(hdcmem);
\r
4694 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4697 HBITMAP whiteLogo = (HBITMAP) first.programLogo, blackLogo = (HBITMAP) second.programLogo;
\r
4698 if(appData.autoLogo) {
\r
4700 switch(gameMode) { // pick logos based on game mode
\r
4701 case IcsObserving:
\r
4702 whiteLogo = second.programLogo; // ICS logo
\r
4703 blackLogo = second.programLogo;
\r
4706 case IcsPlayingWhite:
\r
4707 if(!appData.zippyPlay) whiteLogo = userLogo;
\r
4708 blackLogo = second.programLogo; // ICS logo
\r
4710 case IcsPlayingBlack:
\r
4711 whiteLogo = second.programLogo; // ICS logo
\r
4712 blackLogo = appData.zippyPlay ? first.programLogo : userLogo;
\r
4714 case TwoMachinesPlay:
\r
4715 if(first.twoMachinesColor[0] == 'b') {
\r
4716 whiteLogo = second.programLogo;
\r
4717 blackLogo = first.programLogo;
\r
4720 case MachinePlaysWhite:
\r
4721 blackLogo = userLogo;
\r
4723 case MachinePlaysBlack:
\r
4724 whiteLogo = userLogo;
\r
4725 blackLogo = first.programLogo;
\r
4728 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? blackLogo : whiteLogo);
\r
4729 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? whiteLogo : blackLogo);
\r
4732 if( appData.highlightMoveWithArrow ) {
\r
4733 DrawArrowHighlight(hdcmem);
\r
4736 DrawCoordsOnDC(hdcmem);
\r
4738 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4739 /* to make sure lastDrawn contains what is actually drawn */
\r
4741 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4742 if (dragged_piece != EmptySquare) {
\r
4743 /* [HGM] or restack */
\r
4744 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4745 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4747 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4748 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4749 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4750 x = dragInfo.pos.x - squareSize / 2;
\r
4751 y = dragInfo.pos.y - squareSize / 2;
\r
4752 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4753 ((int) dragged_piece < (int) BlackPawn),
\r
4754 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4757 /* Put the animated piece back into place and draw it */
\r
4758 if (animInfo.piece != EmptySquare) {
\r
4759 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4760 x = boardRect.left + animInfo.pos.x;
\r
4761 y = boardRect.top + animInfo.pos.y;
\r
4762 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4763 ((int) animInfo.piece < (int) BlackPawn),
\r
4764 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4767 /* Release the bufferBitmap by selecting in the old bitmap
\r
4768 * and delete the memory DC
\r
4770 SelectObject(hdcmem, oldBitmap);
\r
4773 /* Set clipping on the target DC */
\r
4774 if (!fullrepaint) {
\r
4775 SelectClipRgn(hdc, clips[0]);
\r
4776 for (x = 1; x < num_clips; x++) {
\r
4777 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4778 abort(); // this should never ever happen!
\r
4782 /* Copy the new bitmap onto the screen in one go.
\r
4783 * This way we avoid any flickering
\r
4785 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4786 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4787 boardRect.right - boardRect.left,
\r
4788 boardRect.bottom - boardRect.top,
\r
4789 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4790 if(saveDiagFlag) {
\r
4791 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4792 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4794 GetObject(bufferBitmap, sizeof(b), &b);
\r
4795 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4796 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4797 bih.biWidth = b.bmWidth;
\r
4798 bih.biHeight = b.bmHeight;
\r
4800 bih.biBitCount = b.bmBitsPixel;
\r
4801 bih.biCompression = 0;
\r
4802 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4803 bih.biXPelsPerMeter = 0;
\r
4804 bih.biYPelsPerMeter = 0;
\r
4805 bih.biClrUsed = 0;
\r
4806 bih.biClrImportant = 0;
\r
4807 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4808 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4809 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4810 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4813 wb = b.bmWidthBytes;
\r
4815 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4816 int k = ((int*) pData)[i];
\r
4817 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4818 if(j >= 16) break;
\r
4820 if(j >= nrColors) nrColors = j+1;
\r
4822 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4824 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4825 for(w=0; w<(wb>>2); w+=2) {
\r
4826 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4827 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4828 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4829 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4830 pData[p++] = m | j<<4;
\r
4832 while(p&3) pData[p++] = 0;
\r
4835 wb = ((wb+31)>>5)<<2;
\r
4837 // write BITMAPFILEHEADER
\r
4838 fprintf(diagFile, "BM");
\r
4839 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4840 fputDW(diagFile, 0);
\r
4841 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4842 // write BITMAPINFOHEADER
\r
4843 fputDW(diagFile, 40);
\r
4844 fputDW(diagFile, b.bmWidth);
\r
4845 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4846 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4847 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4848 fputDW(diagFile, 0);
\r
4849 fputDW(diagFile, 0);
\r
4850 fputDW(diagFile, 0);
\r
4851 fputDW(diagFile, 0);
\r
4852 fputDW(diagFile, 0);
\r
4853 fputDW(diagFile, 0);
\r
4854 // write color table
\r
4856 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4857 // write bitmap data
\r
4858 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4859 fputc(pData[i], diagFile);
\r
4864 SelectObject(tmphdc, oldBitmap);
\r
4866 /* Massive cleanup */
\r
4867 for (x = 0; x < num_clips; x++)
\r
4868 DeleteObject(clips[x]);
\r
4871 DeleteObject(bufferBitmap);
\r
4874 ReleaseDC(hwndMain, hdc);
\r
4876 if (lastDrawnFlipView != flipView) {
\r
4878 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4880 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4883 /* CopyBoard(lastDrawn, board);*/
\r
4884 lastDrawnHighlight = highlightInfo;
\r
4885 lastDrawnPremove = premoveHighlightInfo;
\r
4886 lastDrawnFlipView = flipView;
\r
4887 lastDrawnValid = 1;
\r
4890 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4895 saveDiagFlag = 1; diagFile = f;
\r
4896 HDCDrawPosition(NULL, TRUE, NULL);
\r
4900 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4907 /*---------------------------------------------------------------------------*\
\r
4908 | CLIENT PAINT PROCEDURE
\r
4909 | This is the main event-handler for the WM_PAINT message.
\r
4911 \*---------------------------------------------------------------------------*/
\r
4913 PaintProc(HWND hwnd)
\r
4919 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4920 if (IsIconic(hwnd)) {
\r
4921 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4923 if (!appData.monoMode) {
\r
4924 SelectPalette(hdc, hPal, FALSE);
\r
4925 RealizePalette(hdc);
\r
4927 HDCDrawPosition(hdc, 1, NULL);
\r
4929 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4930 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4931 ETO_CLIPPED|ETO_OPAQUE,
\r
4932 &messageRect, messageText, strlen(messageText), NULL);
\r
4933 SelectObject(hdc, oldFont);
\r
4934 DisplayBothClocks();
\r
4936 EndPaint(hwnd,&ps);
\r
4944 * If the user selects on a border boundary, return -1; if off the board,
\r
4945 * return -2. Otherwise map the event coordinate to the square.
\r
4946 * The offset boardRect.left or boardRect.top must already have been
\r
4947 * subtracted from x.
\r
4950 EventToSquare(int x)
\r
4957 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4959 x /= (squareSize + lineGap);
\r
4960 if (x >= BOARD_SIZE)
\r
4971 DropEnable dropEnables[] = {
\r
4972 { 'P', DP_Pawn, "Pawn" },
\r
4973 { 'N', DP_Knight, "Knight" },
\r
4974 { 'B', DP_Bishop, "Bishop" },
\r
4975 { 'R', DP_Rook, "Rook" },
\r
4976 { 'Q', DP_Queen, "Queen" },
\r
4980 SetupDropMenu(HMENU hmenu)
\r
4982 int i, count, enable;
\r
4984 extern char white_holding[], black_holding[];
\r
4985 char item[MSG_SIZ];
\r
4987 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4988 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4989 dropEnables[i].piece);
\r
4991 while (p && *p++ == dropEnables[i].piece) count++;
\r
4992 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4993 enable = count > 0 || !appData.testLegality
\r
4994 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4995 && !appData.icsActive);
\r
4996 ModifyMenu(hmenu, dropEnables[i].command,
\r
4997 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4998 dropEnables[i].command, item);
\r
5002 /* Event handler for mouse messages */
\r
5004 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5008 static int recursive = 0;
\r
5010 // BOOLEAN needsRedraw = FALSE;
\r
5011 BOOLEAN saveAnimate;
\r
5012 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
5013 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
5014 ChessMove moveType;
\r
5017 if (message == WM_MBUTTONUP) {
\r
5018 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
5019 to the middle button: we simulate pressing the left button too!
\r
5021 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
5022 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
5028 pt.x = LOWORD(lParam);
\r
5029 pt.y = HIWORD(lParam);
\r
5030 x = EventToSquare(pt.x - boardRect.left);
\r
5031 y = EventToSquare(pt.y - boardRect.top);
\r
5032 if (!flipView && y >= 0) {
\r
5033 y = BOARD_HEIGHT - 1 - y;
\r
5035 if (flipView && x >= 0) {
\r
5036 x = BOARD_WIDTH - 1 - x;
\r
5039 switch (message) {
\r
5040 case WM_LBUTTONDOWN:
\r
5041 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
5042 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
5043 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
5044 if(gameInfo.holdingsWidth &&
\r
5045 (WhiteOnMove(currentMove)
\r
5046 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
5047 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
5048 // click in right holdings, for determining promotion piece
\r
5049 ChessSquare p = boards[currentMove][y][x];
\r
5050 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
5051 if(p != EmptySquare) {
\r
5052 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
5053 fromX = fromY = -1;
\r
5057 DrawPosition(FALSE, boards[currentMove]);
\r
5061 sameAgain = FALSE;
\r
5063 /* Downclick vertically off board; check if on clock */
\r
5064 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5065 if (gameMode == EditPosition) {
\r
5066 SetWhiteToPlayEvent();
\r
5067 } else if (gameMode == IcsPlayingBlack ||
\r
5068 gameMode == MachinePlaysWhite) {
\r
5070 } else if (gameMode == EditGame) {
\r
5071 AdjustClock(flipClock, -1);
\r
5073 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5074 if (gameMode == EditPosition) {
\r
5075 SetBlackToPlayEvent();
\r
5076 } else if (gameMode == IcsPlayingWhite ||
\r
5077 gameMode == MachinePlaysBlack) {
\r
5079 } else if (gameMode == EditGame) {
\r
5080 AdjustClock(!flipClock, -1);
\r
5083 if (!appData.highlightLastMove) {
\r
5084 ClearHighlights();
\r
5085 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
5087 fromX = fromY = -1;
\r
5088 dragInfo.start.x = dragInfo.start.y = -1;
\r
5089 dragInfo.from = dragInfo.start;
\r
5091 } else if (x < 0 || y < 0
\r
5092 /* [HGM] block clicks between board and holdings */
\r
5093 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
5094 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
5095 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
5096 /* EditPosition, empty square, or different color piece;
\r
5097 click-click move is possible */
\r
5100 } else if (fromX == x && fromY == y) {
\r
5101 /* Downclick on same square again */
\r
5102 ClearHighlights();
\r
5103 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5104 sameAgain = TRUE;
\r
5105 } else if (fromX != -1 &&
\r
5106 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
5108 /* Downclick on different square. */
\r
5109 /* [HGM] if on holdings file, should count as new first click ! */
\r
5110 /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
5113 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
5114 to make sure move is legal before showing promotion popup */
\r
5115 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5116 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5117 fromX = fromY = -1;
\r
5118 ClearHighlights();
\r
5119 DrawPosition(FALSE, boards[currentMove]);
\r
5122 if(moveType != ImpossibleMove) {
\r
5123 if(moveType == IllegalMove) {
\r
5126 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
5127 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5128 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5129 appData.alwaysPromoteToQueen)) {
\r
5130 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5131 if (!appData.highlightLastMove) {
\r
5132 ClearHighlights();
\r
5133 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5136 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5137 SetHighlights(fromX, fromY, toX, toY);
\r
5138 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5139 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
5140 If promotion to Q is legal, all are legal! */
\r
5141 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5142 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5143 // kludge to temporarily execute move on display, without promoting yet
\r
5144 promotionChoice = TRUE;
\r
5145 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5146 boards[currentMove][toY][toX] = p;
\r
5147 DrawPosition(FALSE, boards[currentMove]);
\r
5148 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5149 boards[currentMove][toY][toX] = q;
\r
5151 PromotionPopup(hwnd);
\r
5152 } else { /* not a promotion */
\r
5153 if (appData.animate || appData.highlightLastMove) {
\r
5154 SetHighlights(fromX, fromY, toX, toY);
\r
5156 ClearHighlights();
\r
5158 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5159 if (appData.animate && !appData.highlightLastMove) {
\r
5160 ClearHighlights();
\r
5161 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5164 fromX = fromY = -1;
\r
5168 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5169 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5170 } else ClearHighlights();
\r
5171 fromX = fromY = -1;
\r
5172 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5174 /* First downclick, or restart on a square with same color piece */
\r
5175 if (!frozen && OKToStartUserMove(x, y)) {
\r
5178 dragInfo.lastpos = pt;
\r
5179 dragInfo.from.x = fromX;
\r
5180 dragInfo.from.y = fromY;
\r
5181 dragInfo.start = dragInfo.from;
\r
5182 SetCapture(hwndMain);
\r
5184 fromX = fromY = -1;
\r
5185 dragInfo.start.x = dragInfo.start.y = -1;
\r
5186 dragInfo.from = dragInfo.start;
\r
5187 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5191 case WM_LBUTTONUP:
\r
5193 if (fromX == -1) break;
\r
5194 if (x == fromX && y == fromY) {
\r
5195 dragInfo.from.x = dragInfo.from.y = -1;
\r
5196 /* Upclick on same square */
\r
5198 /* Clicked same square twice: abort click-click move */
\r
5199 fromX = fromY = -1;
\r
5201 ClearPremoveHighlights();
\r
5203 /* First square clicked: start click-click move */
\r
5204 SetHighlights(fromX, fromY, -1, -1);
\r
5206 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5207 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5208 /* Errant click; ignore */
\r
5211 /* Finish drag move. */
\r
5212 if (appData.debugMode) {
\r
5213 fprintf(debugFP, "release\n");
\r
5215 dragInfo.from.x = dragInfo.from.y = -1;
\r
5218 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5219 appData.animate = appData.animate && !appData.animateDragging;
\r
5220 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5221 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5222 fromX = fromY = -1;
\r
5223 ClearHighlights();
\r
5224 DrawPosition(FALSE, boards[currentMove]);
\r
5225 appData.animate = saveAnimate;
\r
5228 if(moveType != ImpossibleMove) {
\r
5229 /* [HGM] use move type to determine if move is promotion.
\r
5230 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5231 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5232 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5233 appData.alwaysPromoteToQueen))
\r
5234 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5236 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5237 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5238 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5239 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5240 // kludge to temporarily execute move on display, wthout promotng yet
\r
5241 promotionChoice = TRUE;
\r
5242 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5243 boards[currentMove][toY][toX] = p;
\r
5244 DrawPosition(FALSE, boards[currentMove]);
\r
5245 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5246 boards[currentMove][toY][toX] = q;
\r
5247 appData.animate = saveAnimate;
\r
5250 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5252 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5253 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5254 moveType == WhiteCapturesEnPassant ||
\r
5255 moveType == BlackCapturesEnPassant ) )
\r
5256 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5257 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5260 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5261 appData.animate = saveAnimate;
\r
5262 fromX = fromY = -1;
\r
5263 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5264 ClearHighlights();
\r
5266 if (appData.animate || appData.animateDragging ||
\r
5267 appData.highlightDragging || gotPremove) {
\r
5268 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5271 dragInfo.start.x = dragInfo.start.y = -1;
\r
5272 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5275 case WM_MOUSEMOVE:
\r
5276 if ((appData.animateDragging || appData.highlightDragging)
\r
5277 && (wParam & MK_LBUTTON)
\r
5278 && dragInfo.from.x >= 0)
\r
5280 BOOL full_repaint = FALSE;
\r
5282 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5283 if (appData.animateDragging) {
\r
5284 dragInfo.pos = pt;
\r
5286 if (appData.highlightDragging) {
\r
5287 SetHighlights(fromX, fromY, x, y);
\r
5288 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5289 full_repaint = TRUE;
\r
5293 DrawPosition( full_repaint, NULL);
\r
5295 dragInfo.lastpos = dragInfo.pos;
\r
5299 case WM_MOUSEWHEEL: // [DM]
\r
5300 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5301 /* Mouse Wheel is being rolled forward
\r
5302 * Play moves forward
\r
5304 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5305 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5306 /* Mouse Wheel is being rolled backward
\r
5307 * Play moves backward
\r
5309 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5310 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5314 case WM_MBUTTONDOWN:
\r
5315 case WM_RBUTTONDOWN:
\r
5318 fromX = fromY = -1;
\r
5319 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5320 dragInfo.start.x = dragInfo.start.y = -1;
\r
5321 dragInfo.from = dragInfo.start;
\r
5322 dragInfo.lastpos = dragInfo.pos;
\r
5323 if (appData.highlightDragging) {
\r
5324 ClearHighlights();
\r
5327 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5328 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5329 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5330 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5331 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5334 DrawPosition(TRUE, NULL);
\r
5336 switch (gameMode) {
\r
5337 case EditPosition:
\r
5338 case IcsExamining:
\r
5339 if (x < 0 || y < 0) break;
\r
5342 if (message == WM_MBUTTONDOWN) {
\r
5343 buttonCount = 3; /* even if system didn't think so */
\r
5344 if (wParam & MK_SHIFT)
\r
5345 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5347 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5348 } else { /* message == WM_RBUTTONDOWN */
\r
5350 if (buttonCount == 3) {
\r
5351 if (wParam & MK_SHIFT)
\r
5352 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5354 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5356 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5359 /* Just have one menu, on the right button. Windows users don't
\r
5360 think to try the middle one, and sometimes other software steals
\r
5361 it, or it doesn't really exist. */
\r
5362 if(gameInfo.variant != VariantShogi)
\r
5363 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5365 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5369 case IcsPlayingWhite:
\r
5370 case IcsPlayingBlack:
\r
5372 case MachinePlaysWhite:
\r
5373 case MachinePlaysBlack:
\r
5374 if (appData.testLegality &&
\r
5375 gameInfo.variant != VariantBughouse &&
\r
5376 gameInfo.variant != VariantCrazyhouse) break;
\r
5377 if (x < 0 || y < 0) break;
\r
5380 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5381 SetupDropMenu(hmenu);
\r
5382 MenuPopup(hwnd, pt, hmenu, -1);
\r
5393 /* Preprocess messages for buttons in main window */
\r
5395 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5397 int id = GetWindowLong(hwnd, GWL_ID);
\r
5400 for (i=0; i<N_BUTTONS; i++) {
\r
5401 if (buttonDesc[i].id == id) break;
\r
5403 if (i == N_BUTTONS) return 0;
\r
5404 switch (message) {
\r
5409 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5410 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5417 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5420 if (appData.icsActive && (isalpha((char)wParam) || wParam == '0')) {
\r
5421 // [HGM] movenum: only letters or leading zero should go to ICS input
\r
5422 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5423 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5425 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5427 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5428 PopUpMoveDialog((char)wParam);
\r
5434 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5437 /* Process messages for Promotion dialog box */
\r
5439 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5443 switch (message) {
\r
5444 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5445 /* Center the dialog over the application window */
\r
5446 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5447 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5448 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5449 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5450 SW_SHOW : SW_HIDE);
\r
5451 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5452 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5453 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5454 PieceToChar(WhiteAngel) != '~') ||
\r
5455 (PieceToChar(BlackAngel) >= 'A' &&
\r
5456 PieceToChar(BlackAngel) != '~') ) ?
\r
5457 SW_SHOW : SW_HIDE);
\r
5458 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5459 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5460 PieceToChar(WhiteMarshall) != '~') ||
\r
5461 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5462 PieceToChar(BlackMarshall) != '~') ) ?
\r
5463 SW_SHOW : SW_HIDE);
\r
5464 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5465 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5466 gameInfo.variant != VariantShogi ?
\r
5467 SW_SHOW : SW_HIDE);
\r
5468 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5469 gameInfo.variant != VariantShogi ?
\r
5470 SW_SHOW : SW_HIDE);
\r
5471 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5472 gameInfo.variant == VariantShogi ?
\r
5473 SW_SHOW : SW_HIDE);
\r
5474 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5475 gameInfo.variant == VariantShogi ?
\r
5476 SW_SHOW : SW_HIDE);
\r
5477 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5478 gameInfo.variant == VariantSuper ?
\r
5479 SW_SHOW : SW_HIDE);
\r
5482 case WM_COMMAND: /* message: received a command */
\r
5483 switch (LOWORD(wParam)) {
\r
5485 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5486 ClearHighlights();
\r
5487 DrawPosition(FALSE, NULL);
\r
5490 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5493 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5496 promoChar = PieceToChar(BlackRook);
\r
5499 promoChar = PieceToChar(BlackBishop);
\r
5501 case PB_Chancellor:
\r
5502 promoChar = PieceToChar(BlackMarshall);
\r
5504 case PB_Archbishop:
\r
5505 promoChar = PieceToChar(BlackAngel);
\r
5508 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5513 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5514 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5515 only show the popup when we are already sure the move is valid or
\r
5516 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5517 will figure out it is a promotion from the promoChar. */
\r
5518 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5519 if (!appData.highlightLastMove) {
\r
5520 ClearHighlights();
\r
5521 DrawPosition(FALSE, NULL);
\r
5528 /* Pop up promotion dialog */
\r
5530 PromotionPopup(HWND hwnd)
\r
5534 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5535 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5536 hwnd, (DLGPROC)lpProc);
\r
5537 FreeProcInstance(lpProc);
\r
5540 /* Toggle ShowThinking */
\r
5542 ToggleShowThinking()
\r
5544 appData.showThinking = !appData.showThinking;
\r
5545 ShowThinkingEvent();
\r
5549 LoadGameDialog(HWND hwnd, char* title)
\r
5553 char fileTitle[MSG_SIZ];
\r
5554 f = OpenFileDialog(hwnd, "rb", "",
\r
5555 appData.oldSaveStyle ? "gam" : "pgn",
\r
5557 title, &number, fileTitle, NULL);
\r
5559 cmailMsgLoaded = FALSE;
\r
5560 if (number == 0) {
\r
5561 int error = GameListBuild(f);
\r
5563 DisplayError("Cannot build game list", error);
\r
5564 } else if (!ListEmpty(&gameList) &&
\r
5565 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5566 GameListPopUp(f, fileTitle);
\r
5569 GameListDestroy();
\r
5572 LoadGame(f, number, fileTitle, FALSE);
\r
5577 ChangedConsoleFont()
\r
5580 CHARRANGE tmpsel, sel;
\r
5581 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5582 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5583 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5586 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5587 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5588 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5589 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5590 * size. This was undocumented in the version of MSVC++ that I had
\r
5591 * when I wrote the code, but is apparently documented now.
\r
5593 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5594 cfmt.bCharSet = f->lf.lfCharSet;
\r
5595 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5596 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5597 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5598 /* Why are the following seemingly needed too? */
\r
5599 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5600 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5601 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5603 tmpsel.cpMax = -1; /*999999?*/
\r
5604 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5605 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5606 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5607 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5609 paraf.cbSize = sizeof(paraf);
\r
5610 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5611 paraf.dxStartIndent = 0;
\r
5612 paraf.dxOffset = WRAP_INDENT;
\r
5613 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5614 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5617 /*---------------------------------------------------------------------------*\
\r
5619 * Window Proc for main window
\r
5621 \*---------------------------------------------------------------------------*/
\r
5623 /* Process messages for main window, etc. */
\r
5625 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5628 int wmId, wmEvent;
\r
5632 char fileTitle[MSG_SIZ];
\r
5633 char buf[MSG_SIZ];
\r
5634 static SnapData sd;
\r
5636 switch (message) {
\r
5638 case WM_PAINT: /* message: repaint portion of window */
\r
5642 case WM_ERASEBKGND:
\r
5643 if (IsIconic(hwnd)) {
\r
5644 /* Cheat; change the message */
\r
5645 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5647 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5651 case WM_LBUTTONDOWN:
\r
5652 case WM_MBUTTONDOWN:
\r
5653 case WM_RBUTTONDOWN:
\r
5654 case WM_LBUTTONUP:
\r
5655 case WM_MBUTTONUP:
\r
5656 case WM_RBUTTONUP:
\r
5657 case WM_MOUSEMOVE:
\r
5658 case WM_MOUSEWHEEL:
\r
5659 MouseEvent(hwnd, message, wParam, lParam);
\r
5662 JAWS_KB_NAVIGATION
\r
5666 JAWS_ALT_INTERCEPT
\r
5668 if (appData.icsActive && (char)wParam > ' ' && !((char)wParam >= '1' && (char)wParam <= '9')) {
\r
5669 // [HGM] movenum: for non-zero digits we always do type-in dialog
\r
5670 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5671 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5673 SendMessage(h, message, wParam, lParam);
\r
5674 } else if(lParam != KF_REPEAT) {
\r
5675 if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5676 PopUpMoveDialog((char)wParam);
\r
5677 } else if((char)wParam == 003) CopyGameToClipboard();
\r
5678 else if((char)wParam == 026) PasteGameOrFENFromClipboard();
\r
5683 case WM_PALETTECHANGED:
\r
5684 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5686 HDC hdc = GetDC(hwndMain);
\r
5687 SelectPalette(hdc, hPal, TRUE);
\r
5688 nnew = RealizePalette(hdc);
\r
5690 paletteChanged = TRUE;
\r
5692 UpdateColors(hdc);
\r
5694 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5697 ReleaseDC(hwnd, hdc);
\r
5701 case WM_QUERYNEWPALETTE:
\r
5702 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5704 HDC hdc = GetDC(hwndMain);
\r
5705 paletteChanged = FALSE;
\r
5706 SelectPalette(hdc, hPal, FALSE);
\r
5707 nnew = RealizePalette(hdc);
\r
5709 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5711 ReleaseDC(hwnd, hdc);
\r
5716 case WM_COMMAND: /* message: command from application menu */
\r
5717 wmId = LOWORD(wParam);
\r
5718 wmEvent = HIWORD(wParam);
\r
5723 AnalysisPopDown();
\r
5724 SAY("new game enter a move to play against the computer with white");
\r
5727 case IDM_NewGameFRC:
\r
5728 if( NewGameFRC() == 0 ) {
\r
5730 AnalysisPopDown();
\r
5734 case IDM_NewVariant:
\r
5735 NewVariantPopup(hwnd);
\r
5738 case IDM_LoadGame:
\r
5739 LoadGameDialog(hwnd, "Load Game from File");
\r
5742 case IDM_LoadNextGame:
\r
5746 case IDM_LoadPrevGame:
\r
5750 case IDM_ReloadGame:
\r
5754 case IDM_LoadPosition:
\r
5755 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5756 Reset(FALSE, TRUE);
\r
5759 f = OpenFileDialog(hwnd, "rb", "",
\r
5760 appData.oldSaveStyle ? "pos" : "fen",
\r
5762 "Load Position from File", &number, fileTitle, NULL);
\r
5764 LoadPosition(f, number, fileTitle);
\r
5768 case IDM_LoadNextPosition:
\r
5769 ReloadPosition(1);
\r
5772 case IDM_LoadPrevPosition:
\r
5773 ReloadPosition(-1);
\r
5776 case IDM_ReloadPosition:
\r
5777 ReloadPosition(0);
\r
5780 case IDM_SaveGame:
\r
5781 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5782 f = OpenFileDialog(hwnd, "a", defName,
\r
5783 appData.oldSaveStyle ? "gam" : "pgn",
\r
5785 "Save Game to File", NULL, fileTitle, NULL);
\r
5787 SaveGame(f, 0, "");
\r
5791 case IDM_SavePosition:
\r
5792 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5793 f = OpenFileDialog(hwnd, "a", defName,
\r
5794 appData.oldSaveStyle ? "pos" : "fen",
\r
5796 "Save Position to File", NULL, fileTitle, NULL);
\r
5798 SavePosition(f, 0, "");
\r
5802 case IDM_SaveDiagram:
\r
5803 defName = "diagram";
\r
5804 f = OpenFileDialog(hwnd, "wb", defName,
\r
5807 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5813 case IDM_CopyGame:
\r
5814 CopyGameToClipboard();
\r
5817 case IDM_PasteGame:
\r
5818 PasteGameFromClipboard();
\r
5821 case IDM_CopyGameListToClipboard:
\r
5822 CopyGameListToClipboard();
\r
5825 /* [AS] Autodetect FEN or PGN data */
\r
5826 case IDM_PasteAny:
\r
5827 PasteGameOrFENFromClipboard();
\r
5830 /* [AS] Move history */
\r
5831 case IDM_ShowMoveHistory:
\r
5832 if( MoveHistoryIsUp() ) {
\r
5833 MoveHistoryPopDown();
\r
5836 MoveHistoryPopUp();
\r
5840 /* [AS] Eval graph */
\r
5841 case IDM_ShowEvalGraph:
\r
5842 if( EvalGraphIsUp() ) {
\r
5843 EvalGraphPopDown();
\r
5847 SetFocus(hwndMain);
\r
5851 /* [AS] Engine output */
\r
5852 case IDM_ShowEngineOutput:
\r
5853 if( EngineOutputIsUp() ) {
\r
5854 EngineOutputPopDown();
\r
5857 EngineOutputPopUp();
\r
5861 /* [AS] User adjudication */
\r
5862 case IDM_UserAdjudication_White:
\r
5863 UserAdjudicationEvent( +1 );
\r
5866 case IDM_UserAdjudication_Black:
\r
5867 UserAdjudicationEvent( -1 );
\r
5870 case IDM_UserAdjudication_Draw:
\r
5871 UserAdjudicationEvent( 0 );
\r
5874 /* [AS] Game list options dialog */
\r
5875 case IDM_GameListOptions:
\r
5876 GameListOptions();
\r
5883 case IDM_CopyPosition:
\r
5884 CopyFENToClipboard();
\r
5887 case IDM_PastePosition:
\r
5888 PasteFENFromClipboard();
\r
5891 case IDM_MailMove:
\r
5895 case IDM_ReloadCMailMsg:
\r
5896 Reset(TRUE, TRUE);
\r
5897 ReloadCmailMsgEvent(FALSE);
\r
5900 case IDM_Minimize:
\r
5901 ShowWindow(hwnd, SW_MINIMIZE);
\r
5908 case IDM_MachineWhite:
\r
5909 MachineWhiteEvent();
\r
5911 * refresh the tags dialog only if it's visible
\r
5913 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5915 tags = PGNTags(&gameInfo);
\r
5916 TagsPopUp(tags, CmailMsg());
\r
5919 SAY("computer starts playing white");
\r
5922 case IDM_MachineBlack:
\r
5923 MachineBlackEvent();
\r
5925 * refresh the tags dialog only if it's visible
\r
5927 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5929 tags = PGNTags(&gameInfo);
\r
5930 TagsPopUp(tags, CmailMsg());
\r
5933 SAY("computer starts playing black");
\r
5936 case IDM_TwoMachines:
\r
5937 TwoMachinesEvent();
\r
5939 * refresh the tags dialog only if it's visible
\r
5941 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5943 tags = PGNTags(&gameInfo);
\r
5944 TagsPopUp(tags, CmailMsg());
\r
5947 SAY("programs start playing each other");
\r
5950 case IDM_AnalysisMode:
\r
5951 if (!first.analysisSupport) {
\r
5952 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5953 DisplayError(buf, 0);
\r
5955 SAY("analyzing current position");
\r
5956 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5957 if (appData.icsActive) {
\r
5958 if (gameMode != IcsObserving) {
\r
5959 sprintf(buf, "You are not observing a game");
\r
5960 DisplayError(buf, 0);
\r
5961 /* secure check */
\r
5962 if (appData.icsEngineAnalyze) {
\r
5963 if (appData.debugMode)
\r
5964 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5965 ExitAnalyzeMode();
\r
5971 /* if enable, user want disable icsEngineAnalyze */
\r
5972 if (appData.icsEngineAnalyze) {
\r
5973 ExitAnalyzeMode();
\r
5977 appData.icsEngineAnalyze = TRUE;
\r
5978 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5981 if (!appData.showThinking) ToggleShowThinking();
\r
5982 AnalyzeModeEvent();
\r
5986 case IDM_AnalyzeFile:
\r
5987 if (!first.analysisSupport) {
\r
5988 char buf[MSG_SIZ];
\r
5989 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5990 DisplayError(buf, 0);
\r
5992 if (!appData.showThinking) ToggleShowThinking();
\r
5993 AnalyzeFileEvent();
\r
5994 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5995 AnalysisPeriodicEvent(1);
\r
5999 case IDM_IcsClient:
\r
6003 case IDM_EditGame:
\r
6008 case IDM_EditPosition:
\r
6009 EditPositionEvent();
\r
6010 SAY("to set up a position type a FEN");
\r
6013 case IDM_Training:
\r
6017 case IDM_ShowGameList:
\r
6018 ShowGameListProc();
\r
6021 case IDM_EditTags:
\r
6025 case IDM_EditComment:
\r
6026 if (commentDialogUp && editComment) {
\r
6029 EditCommentEvent();
\r
6049 case IDM_CallFlag:
\r
6069 case IDM_StopObserving:
\r
6070 StopObservingEvent();
\r
6073 case IDM_StopExamining:
\r
6074 StopExaminingEvent();
\r
6077 case IDM_TypeInMove:
\r
6078 PopUpMoveDialog('\000');
\r
6081 case IDM_TypeInName:
\r
6082 PopUpNameDialog('\000');
\r
6085 case IDM_Backward:
\r
6087 SetFocus(hwndMain);
\r
6094 SetFocus(hwndMain);
\r
6099 SetFocus(hwndMain);
\r
6104 SetFocus(hwndMain);
\r
6111 case IDM_TruncateGame:
\r
6112 TruncateGameEvent();
\r
6119 case IDM_RetractMove:
\r
6120 RetractMoveEvent();
\r
6123 case IDM_FlipView:
\r
6124 flipView = !flipView;
\r
6125 DrawPosition(FALSE, NULL);
\r
6128 case IDM_FlipClock:
\r
6129 flipClock = !flipClock;
\r
6130 DisplayBothClocks();
\r
6131 DrawPosition(FALSE, NULL);
\r
6134 case IDM_GeneralOptions:
\r
6135 GeneralOptionsPopup(hwnd);
\r
6136 DrawPosition(TRUE, NULL);
\r
6139 case IDM_BoardOptions:
\r
6140 BoardOptionsPopup(hwnd);
\r
6143 case IDM_EnginePlayOptions:
\r
6144 EnginePlayOptionsPopup(hwnd);
\r
6147 case IDM_Engine1Options:
\r
6148 EngineOptionsPopup(hwnd, &first);
\r
6151 case IDM_Engine2Options:
\r
6152 EngineOptionsPopup(hwnd, &second);
\r
6155 case IDM_OptionsUCI:
\r
6156 UciOptionsPopup(hwnd);
\r
6159 case IDM_IcsOptions:
\r
6160 IcsOptionsPopup(hwnd);
\r
6164 FontsOptionsPopup(hwnd);
\r
6168 SoundOptionsPopup(hwnd);
\r
6171 case IDM_CommPort:
\r
6172 CommPortOptionsPopup(hwnd);
\r
6175 case IDM_LoadOptions:
\r
6176 LoadOptionsPopup(hwnd);
\r
6179 case IDM_SaveOptions:
\r
6180 SaveOptionsPopup(hwnd);
\r
6183 case IDM_TimeControl:
\r
6184 TimeControlOptionsPopup(hwnd);
\r
6187 case IDM_SaveSettings:
\r
6188 SaveSettings(settingsFileName);
\r
6191 case IDM_SaveSettingsOnExit:
\r
6192 saveSettingsOnExit = !saveSettingsOnExit;
\r
6193 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
6194 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6195 MF_CHECKED : MF_UNCHECKED));
\r
6206 case IDM_AboutGame:
\r
6211 appData.debugMode = !appData.debugMode;
\r
6212 if (appData.debugMode) {
\r
6213 char dir[MSG_SIZ];
\r
6214 GetCurrentDirectory(MSG_SIZ, dir);
\r
6215 SetCurrentDirectory(installDir);
\r
6216 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6217 SetCurrentDirectory(dir);
\r
6218 setbuf(debugFP, NULL);
\r
6225 case IDM_HELPCONTENTS:
\r
6226 if (!MyHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS") &&
\r
6227 !HtmlHelp(hwnd, "winboard.chm", 0, 0) ) {
\r
6228 MessageBox (GetFocus(),
\r
6229 "Unable to activate help",
\r
6230 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6234 case IDM_HELPSEARCH:
\r
6235 if (!MyHelp (hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"") &&
\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_HELPHELP:
\r
6244 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6245 MessageBox (GetFocus(),
\r
6246 "Unable to activate help",
\r
6247 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6252 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6254 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6255 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6256 FreeProcInstance(lpProc);
\r
6259 case IDM_DirectCommand1:
\r
6260 AskQuestionEvent("Direct Command",
\r
6261 "Send to chess program:", "", "1");
\r
6263 case IDM_DirectCommand2:
\r
6264 AskQuestionEvent("Direct Command",
\r
6265 "Send to second chess program:", "", "2");
\r
6268 case EP_WhitePawn:
\r
6269 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6270 fromX = fromY = -1;
\r
6273 case EP_WhiteKnight:
\r
6274 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6275 fromX = fromY = -1;
\r
6278 case EP_WhiteBishop:
\r
6279 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6280 fromX = fromY = -1;
\r
6283 case EP_WhiteRook:
\r
6284 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6285 fromX = fromY = -1;
\r
6288 case EP_WhiteQueen:
\r
6289 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6290 fromX = fromY = -1;
\r
6293 case EP_WhiteFerz:
\r
6294 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6295 fromX = fromY = -1;
\r
6298 case EP_WhiteWazir:
\r
6299 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6300 fromX = fromY = -1;
\r
6303 case EP_WhiteAlfil:
\r
6304 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6305 fromX = fromY = -1;
\r
6308 case EP_WhiteCannon:
\r
6309 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6310 fromX = fromY = -1;
\r
6313 case EP_WhiteCardinal:
\r
6314 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6315 fromX = fromY = -1;
\r
6318 case EP_WhiteMarshall:
\r
6319 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6320 fromX = fromY = -1;
\r
6323 case EP_WhiteKing:
\r
6324 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6325 fromX = fromY = -1;
\r
6328 case EP_BlackPawn:
\r
6329 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6330 fromX = fromY = -1;
\r
6333 case EP_BlackKnight:
\r
6334 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6335 fromX = fromY = -1;
\r
6338 case EP_BlackBishop:
\r
6339 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6340 fromX = fromY = -1;
\r
6343 case EP_BlackRook:
\r
6344 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6345 fromX = fromY = -1;
\r
6348 case EP_BlackQueen:
\r
6349 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6350 fromX = fromY = -1;
\r
6353 case EP_BlackFerz:
\r
6354 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6355 fromX = fromY = -1;
\r
6358 case EP_BlackWazir:
\r
6359 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6360 fromX = fromY = -1;
\r
6363 case EP_BlackAlfil:
\r
6364 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6365 fromX = fromY = -1;
\r
6368 case EP_BlackCannon:
\r
6369 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6370 fromX = fromY = -1;
\r
6373 case EP_BlackCardinal:
\r
6374 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6375 fromX = fromY = -1;
\r
6378 case EP_BlackMarshall:
\r
6379 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6380 fromX = fromY = -1;
\r
6383 case EP_BlackKing:
\r
6384 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6385 fromX = fromY = -1;
\r
6388 case EP_EmptySquare:
\r
6389 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6390 fromX = fromY = -1;
\r
6393 case EP_ClearBoard:
\r
6394 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6395 fromX = fromY = -1;
\r
6399 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6400 fromX = fromY = -1;
\r
6404 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6405 fromX = fromY = -1;
\r
6409 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6410 fromX = fromY = -1;
\r
6414 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6415 fromX = fromY = -1;
\r
6419 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6420 fromX = fromY = -1;
\r
6424 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6425 fromX = fromY = -1;
\r
6429 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6430 fromX = fromY = -1;
\r
6434 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6435 fromX = fromY = -1;
\r
6439 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6440 fromX = fromY = -1;
\r
6444 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6450 case CLOCK_TIMER_ID:
\r
6451 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6452 clockTimerEvent = 0;
\r
6453 DecrementClocks(); /* call into back end */
\r
6455 case LOAD_GAME_TIMER_ID:
\r
6456 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6457 loadGameTimerEvent = 0;
\r
6458 AutoPlayGameLoop(); /* call into back end */
\r
6460 case ANALYSIS_TIMER_ID:
\r
6461 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6462 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6463 AnalysisPeriodicEvent(0);
\r
6465 KillTimer(hwnd, analysisTimerEvent);
\r
6466 analysisTimerEvent = 0;
\r
6469 case DELAYED_TIMER_ID:
\r
6470 KillTimer(hwnd, delayedTimerEvent);
\r
6471 delayedTimerEvent = 0;
\r
6472 delayedTimerCallback();
\r
6477 case WM_USER_Input:
\r
6478 InputEvent(hwnd, message, wParam, lParam);
\r
6481 /* [AS] Also move "attached" child windows */
\r
6482 case WM_WINDOWPOSCHANGING:
\r
6484 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6485 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6487 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6488 /* Window is moving */
\r
6491 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6492 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6493 rcMain.right = boardX + winWidth;
\r
6494 rcMain.top = boardY;
\r
6495 rcMain.bottom = boardY + winHeight;
\r
6497 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6498 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6499 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6500 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, gameListDialog, &wpGameList );
\r
6501 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, hwndConsole, &wpConsole );
\r
6508 /* [AS] Snapping */
\r
6509 case WM_ENTERSIZEMOVE:
\r
6510 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6511 if (hwnd == hwndMain) {
\r
6512 doingSizing = TRUE;
\r
6515 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6519 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6520 if (hwnd == hwndMain) {
\r
6521 lastSizing = wParam;
\r
6526 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6527 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6529 case WM_EXITSIZEMOVE:
\r
6530 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6531 if (hwnd == hwndMain) {
\r
6533 doingSizing = FALSE;
\r
6534 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6535 GetClientRect(hwnd, &client);
\r
6536 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6538 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6540 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6543 case WM_DESTROY: /* message: window being destroyed */
\r
6544 PostQuitMessage(0);
\r
6548 if (hwnd == hwndMain) {
\r
6553 default: /* Passes it on if unprocessed */
\r
6554 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6559 /*---------------------------------------------------------------------------*\
\r
6561 * Misc utility routines
\r
6563 \*---------------------------------------------------------------------------*/
\r
6566 * Decent random number generator, at least not as bad as Windows
\r
6567 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6569 unsigned int randstate;
\r
6574 randstate = randstate * 1664525 + 1013904223;
\r
6575 return (int) randstate & 0x7fffffff;
\r
6579 mysrandom(unsigned int seed)
\r
6586 * returns TRUE if user selects a different color, FALSE otherwise
\r
6590 ChangeColor(HWND hwnd, COLORREF *which)
\r
6592 static BOOL firstTime = TRUE;
\r
6593 static DWORD customColors[16];
\r
6595 COLORREF newcolor;
\r
6600 /* Make initial colors in use available as custom colors */
\r
6601 /* Should we put the compiled-in defaults here instead? */
\r
6603 customColors[i++] = lightSquareColor & 0xffffff;
\r
6604 customColors[i++] = darkSquareColor & 0xffffff;
\r
6605 customColors[i++] = whitePieceColor & 0xffffff;
\r
6606 customColors[i++] = blackPieceColor & 0xffffff;
\r
6607 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6608 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6610 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6611 customColors[i++] = textAttribs[ccl].color;
\r
6613 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6614 firstTime = FALSE;
\r
6617 cc.lStructSize = sizeof(cc);
\r
6618 cc.hwndOwner = hwnd;
\r
6619 cc.hInstance = NULL;
\r
6620 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6621 cc.lpCustColors = (LPDWORD) customColors;
\r
6622 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6624 if (!ChooseColor(&cc)) return FALSE;
\r
6626 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6627 if (newcolor == *which) return FALSE;
\r
6628 *which = newcolor;
\r
6632 InitDrawingColors();
\r
6633 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6638 MyLoadSound(MySound *ms)
\r
6644 if (ms->data) free(ms->data);
\r
6647 switch (ms->name[0]) {
\r
6653 /* System sound from Control Panel. Don't preload here. */
\r
6657 if (ms->name[1] == NULLCHAR) {
\r
6658 /* "!" alone = silence */
\r
6661 /* Builtin wave resource. Error if not found. */
\r
6662 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6663 if (h == NULL) break;
\r
6664 ms->data = (void *)LoadResource(hInst, h);
\r
6665 if (h == NULL) break;
\r
6670 /* .wav file. Error if not found. */
\r
6671 f = fopen(ms->name, "rb");
\r
6672 if (f == NULL) break;
\r
6673 if (fstat(fileno(f), &st) < 0) break;
\r
6674 ms->data = malloc(st.st_size);
\r
6675 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6681 char buf[MSG_SIZ];
\r
6682 sprintf(buf, "Error loading sound %s", ms->name);
\r
6683 DisplayError(buf, GetLastError());
\r
6689 MyPlaySound(MySound *ms)
\r
6691 BOOLEAN ok = FALSE;
\r
6693 switch (ms->name[0]) {
\r
6695 if(appData.debugMode) fprintf(debugFP, "silence\n");
\r
6700 /* System sound from Control Panel (deprecated feature).
\r
6701 "$" alone or an unset sound name gets default beep (still in use). */
\r
6702 if (ms->name[1]) {
\r
6703 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6705 if (!ok) ok = MessageBeep(MB_OK);
\r
6708 /* Builtin wave resource, or "!" alone for silence */
\r
6709 if (ms->name[1]) {
\r
6710 if (ms->data == NULL) return FALSE;
\r
6711 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6717 /* .wav file. Error if not found. */
\r
6718 if (ms->data == NULL) return FALSE;
\r
6719 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6722 /* Don't print an error: this can happen innocently if the sound driver
\r
6723 is busy; for instance, if another instance of WinBoard is playing
\r
6724 a sound at about the same time. */
\r
6727 char buf[MSG_SIZ];
\r
6728 sprintf(buf, "Error playing sound %s", ms->name);
\r
6729 DisplayError(buf, GetLastError());
\r
6737 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6740 OPENFILENAME *ofn;
\r
6741 static UINT *number; /* gross that this is static */
\r
6743 switch (message) {
\r
6744 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6745 /* Center the dialog over the application window */
\r
6746 ofn = (OPENFILENAME *) lParam;
\r
6747 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6748 number = (UINT *) ofn->lCustData;
\r
6749 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6753 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6754 return FALSE; /* Allow for further processing */
\r
6757 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6758 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6760 return FALSE; /* Allow for further processing */
\r
6766 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6768 static UINT *number;
\r
6769 OPENFILENAME *ofname;
\r
6772 case WM_INITDIALOG:
\r
6773 ofname = (OPENFILENAME *)lParam;
\r
6774 number = (UINT *)(ofname->lCustData);
\r
6777 ofnot = (OFNOTIFY *)lParam;
\r
6778 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6779 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6788 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6789 char *nameFilt, char *dlgTitle, UINT *number,
\r
6790 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6792 OPENFILENAME openFileName;
\r
6793 char buf1[MSG_SIZ];
\r
6796 if (fileName == NULL) fileName = buf1;
\r
6797 if (defName == NULL) {
\r
6798 strcpy(fileName, "*.");
\r
6799 strcat(fileName, defExt);
\r
6801 strcpy(fileName, defName);
\r
6803 if (fileTitle) strcpy(fileTitle, "");
\r
6804 if (number) *number = 0;
\r
6806 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6807 openFileName.hwndOwner = hwnd;
\r
6808 openFileName.hInstance = (HANDLE) hInst;
\r
6809 openFileName.lpstrFilter = nameFilt;
\r
6810 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6811 openFileName.nMaxCustFilter = 0L;
\r
6812 openFileName.nFilterIndex = 1L;
\r
6813 openFileName.lpstrFile = fileName;
\r
6814 openFileName.nMaxFile = MSG_SIZ;
\r
6815 openFileName.lpstrFileTitle = fileTitle;
\r
6816 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6817 openFileName.lpstrInitialDir = NULL;
\r
6818 openFileName.lpstrTitle = dlgTitle;
\r
6819 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6820 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6821 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6822 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6823 openFileName.nFileOffset = 0;
\r
6824 openFileName.nFileExtension = 0;
\r
6825 openFileName.lpstrDefExt = defExt;
\r
6826 openFileName.lCustData = (LONG) number;
\r
6827 openFileName.lpfnHook = oldDialog ?
\r
6828 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6829 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6831 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6832 GetOpenFileName(&openFileName)) {
\r
6833 /* open the file */
\r
6834 f = fopen(openFileName.lpstrFile, write);
\r
6836 MessageBox(hwnd, "File open failed", NULL,
\r
6837 MB_OK|MB_ICONEXCLAMATION);
\r
6841 int err = CommDlgExtendedError();
\r
6842 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6851 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6853 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6856 * Get the first pop-up menu in the menu template. This is the
\r
6857 * menu that TrackPopupMenu displays.
\r
6859 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6861 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6864 * TrackPopup uses screen coordinates, so convert the
\r
6865 * coordinates of the mouse click to screen coordinates.
\r
6867 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6869 /* Draw and track the floating pop-up menu. */
\r
6870 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6871 pt.x, pt.y, 0, hwnd, NULL);
\r
6873 /* Destroy the menu.*/
\r
6874 DestroyMenu(hmenu);
\r
6879 int sizeX, sizeY, newSizeX, newSizeY;
\r
6881 } ResizeEditPlusButtonsClosure;
\r
6884 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6886 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6890 if (hChild == cl->hText) return TRUE;
\r
6891 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6892 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6893 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6894 ScreenToClient(cl->hDlg, &pt);
\r
6895 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6896 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6900 /* Resize a dialog that has a (rich) edit field filling most of
\r
6901 the top, with a row of buttons below */
\r
6903 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6906 int newTextHeight, newTextWidth;
\r
6907 ResizeEditPlusButtonsClosure cl;
\r
6909 /*if (IsIconic(hDlg)) return;*/
\r
6910 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6912 cl.hdwp = BeginDeferWindowPos(8);
\r
6914 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6915 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6916 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6917 if (newTextHeight < 0) {
\r
6918 newSizeY += -newTextHeight;
\r
6919 newTextHeight = 0;
\r
6921 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6922 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6928 cl.newSizeX = newSizeX;
\r
6929 cl.newSizeY = newSizeY;
\r
6930 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6932 EndDeferWindowPos(cl.hdwp);
\r
6935 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6937 RECT rChild, rParent;
\r
6938 int wChild, hChild, wParent, hParent;
\r
6939 int wScreen, hScreen, xNew, yNew;
\r
6942 /* Get the Height and Width of the child window */
\r
6943 GetWindowRect (hwndChild, &rChild);
\r
6944 wChild = rChild.right - rChild.left;
\r
6945 hChild = rChild.bottom - rChild.top;
\r
6947 /* Get the Height and Width of the parent window */
\r
6948 GetWindowRect (hwndParent, &rParent);
\r
6949 wParent = rParent.right - rParent.left;
\r
6950 hParent = rParent.bottom - rParent.top;
\r
6952 /* Get the display limits */
\r
6953 hdc = GetDC (hwndChild);
\r
6954 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6955 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6956 ReleaseDC(hwndChild, hdc);
\r
6958 /* Calculate new X position, then adjust for screen */
\r
6959 xNew = rParent.left + ((wParent - wChild) /2);
\r
6962 } else if ((xNew+wChild) > wScreen) {
\r
6963 xNew = wScreen - wChild;
\r
6966 /* Calculate new Y position, then adjust for screen */
\r
6968 yNew = rParent.top + ((hParent - hChild) /2);
\r
6971 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6976 } else if ((yNew+hChild) > hScreen) {
\r
6977 yNew = hScreen - hChild;
\r
6980 /* Set it, and return */
\r
6981 return SetWindowPos (hwndChild, NULL,
\r
6982 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6985 /* Center one window over another */
\r
6986 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6988 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6991 /*---------------------------------------------------------------------------*\
\r
6993 * Startup Dialog functions
\r
6995 \*---------------------------------------------------------------------------*/
\r
6997 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6999 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7001 while (*cd != NULL) {
\r
7002 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
7008 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
7010 char buf1[ARG_MAX];
\r
7013 if (str[0] == '@') {
\r
7014 FILE* f = fopen(str + 1, "r");
\r
7016 DisplayFatalError(str + 1, errno, 2);
\r
7019 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
7021 buf1[len] = NULLCHAR;
\r
7025 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
7028 char buf[MSG_SIZ];
\r
7029 char *end = strchr(str, '\n');
\r
7030 if (end == NULL) return;
\r
7031 memcpy(buf, str, end - str);
\r
7032 buf[end - str] = NULLCHAR;
\r
7033 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
7039 SetStartupDialogEnables(HWND hDlg)
\r
7041 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7042 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7043 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
7044 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7045 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
7046 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
7047 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
7048 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
7049 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
7050 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
7051 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
7052 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
7053 IsDlgButtonChecked(hDlg, OPT_View));
\r
7057 QuoteForFilename(char *filename)
\r
7059 int dquote, space;
\r
7060 dquote = strchr(filename, '"') != NULL;
\r
7061 space = strchr(filename, ' ') != NULL;
\r
7062 if (dquote || space) {
\r
7074 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
7076 char buf[MSG_SIZ];
\r
7079 InitComboStringsFromOption(hwndCombo, nthnames);
\r
7080 q = QuoteForFilename(nthcp);
\r
7081 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
7082 if (*nthdir != NULLCHAR) {
\r
7083 q = QuoteForFilename(nthdir);
\r
7084 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
7086 if (*nthcp == NULLCHAR) {
\r
7087 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7088 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7089 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7090 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7095 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7097 char buf[MSG_SIZ];
\r
7101 switch (message) {
\r
7102 case WM_INITDIALOG:
\r
7103 /* Center the dialog */
\r
7104 CenterWindow (hDlg, GetDesktopWindow());
\r
7105 /* Initialize the dialog items */
\r
7106 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
7107 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
7108 firstChessProgramNames);
\r
7109 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
7110 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
7111 secondChessProgramNames);
\r
7112 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
7113 InitComboStringsFromOption(hwndCombo, icsNames);
\r
7114 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
7115 if (*appData.icsHelper != NULLCHAR) {
\r
7116 char *q = QuoteForFilename(appData.icsHelper);
\r
7117 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
7119 if (*appData.icsHost == NULLCHAR) {
\r
7120 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
7121 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
7122 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
7123 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
7124 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
7127 if (appData.icsActive) {
\r
7128 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
7130 else if (appData.noChessProgram) {
\r
7131 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
7134 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
7137 SetStartupDialogEnables(hDlg);
\r
7141 switch (LOWORD(wParam)) {
\r
7143 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
7144 strcpy(buf, "/fcp=");
\r
7145 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7147 ParseArgs(StringGet, &p);
\r
7148 strcpy(buf, "/scp=");
\r
7149 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7151 ParseArgs(StringGet, &p);
\r
7152 appData.noChessProgram = FALSE;
\r
7153 appData.icsActive = FALSE;
\r
7154 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
7155 strcpy(buf, "/ics /icshost=");
\r
7156 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7158 ParseArgs(StringGet, &p);
\r
7159 if (appData.zippyPlay) {
\r
7160 strcpy(buf, "/fcp=");
\r
7161 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
7163 ParseArgs(StringGet, &p);
\r
7165 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
7166 appData.noChessProgram = TRUE;
\r
7167 appData.icsActive = FALSE;
\r
7169 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
7170 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
7173 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
7174 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
7176 ParseArgs(StringGet, &p);
\r
7178 EndDialog(hDlg, TRUE);
\r
7185 case IDM_HELPCONTENTS:
\r
7186 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
7187 MessageBox (GetFocus(),
\r
7188 "Unable to activate help",
\r
7189 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
7194 SetStartupDialogEnables(hDlg);
\r
7202 /*---------------------------------------------------------------------------*\
\r
7204 * About box dialog functions
\r
7206 \*---------------------------------------------------------------------------*/
\r
7208 /* Process messages for "About" dialog box */
\r
7210 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7212 switch (message) {
\r
7213 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7214 /* Center the dialog over the application window */
\r
7215 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7216 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7220 case WM_COMMAND: /* message: received a command */
\r
7221 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7222 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7223 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7231 /*---------------------------------------------------------------------------*\
\r
7233 * Comment Dialog functions
\r
7235 \*---------------------------------------------------------------------------*/
\r
7238 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7240 static HANDLE hwndText = NULL;
\r
7241 int len, newSizeX, newSizeY, flags;
\r
7242 static int sizeX, sizeY;
\r
7247 switch (message) {
\r
7248 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7249 /* Initialize the dialog items */
\r
7250 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7251 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7252 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7253 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7254 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7255 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7256 SetWindowText(hDlg, commentTitle);
\r
7257 if (editComment) {
\r
7258 SetFocus(hwndText);
\r
7260 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7262 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7263 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7264 MAKELPARAM(FALSE, 0));
\r
7265 /* Size and position the dialog */
\r
7266 if (!commentDialog) {
\r
7267 commentDialog = hDlg;
\r
7268 flags = SWP_NOZORDER;
\r
7269 GetClientRect(hDlg, &rect);
\r
7270 sizeX = rect.right;
\r
7271 sizeY = rect.bottom;
\r
7272 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7273 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7274 WINDOWPLACEMENT wp;
\r
7275 EnsureOnScreen(&commentX, &commentY, 0, 0);
\r
7276 wp.length = sizeof(WINDOWPLACEMENT);
\r
7278 wp.showCmd = SW_SHOW;
\r
7279 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7280 wp.rcNormalPosition.left = commentX;
\r
7281 wp.rcNormalPosition.right = commentX + commentW;
\r
7282 wp.rcNormalPosition.top = commentY;
\r
7283 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7284 SetWindowPlacement(hDlg, &wp);
\r
7286 GetClientRect(hDlg, &rect);
\r
7287 newSizeX = rect.right;
\r
7288 newSizeY = rect.bottom;
\r
7289 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7290 newSizeX, newSizeY);
\r
7297 case WM_COMMAND: /* message: received a command */
\r
7298 switch (LOWORD(wParam)) {
\r
7300 if (editComment) {
\r
7302 /* Read changed options from the dialog box */
\r
7303 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7304 len = GetWindowTextLength(hwndText);
\r
7305 str = (char *) malloc(len + 1);
\r
7306 GetWindowText(hwndText, str, len + 1);
\r
7315 ReplaceComment(commentIndex, str);
\r
7322 case OPT_CancelComment:
\r
7326 case OPT_ClearComment:
\r
7327 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7330 case OPT_EditComment:
\r
7331 EditCommentEvent();
\r
7340 newSizeX = LOWORD(lParam);
\r
7341 newSizeY = HIWORD(lParam);
\r
7342 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7347 case WM_GETMINMAXINFO:
\r
7348 /* Prevent resizing window too small */
\r
7349 mmi = (MINMAXINFO *) lParam;
\r
7350 mmi->ptMinTrackSize.x = 100;
\r
7351 mmi->ptMinTrackSize.y = 100;
\r
7358 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7363 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7365 if (str == NULL) str = "";
\r
7366 p = (char *) malloc(2 * strlen(str) + 2);
\r
7369 if (*str == '\n') *q++ = '\r';
\r
7373 if (commentText != NULL) free(commentText);
\r
7375 commentIndex = index;
\r
7376 commentTitle = title;
\r
7378 editComment = edit;
\r
7380 if (commentDialog) {
\r
7381 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7382 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7384 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7385 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7386 hwndMain, (DLGPROC)lpProc);
\r
7387 FreeProcInstance(lpProc);
\r
7389 commentDialogUp = TRUE;
\r
7393 /*---------------------------------------------------------------------------*\
\r
7395 * Type-in move dialog functions
\r
7397 \*---------------------------------------------------------------------------*/
\r
7400 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7402 char move[MSG_SIZ];
\r
7404 ChessMove moveType;
\r
7405 int fromX, fromY, toX, toY;
\r
7408 switch (message) {
\r
7409 case WM_INITDIALOG:
\r
7410 move[0] = (char) lParam;
\r
7411 move[1] = NULLCHAR;
\r
7412 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7413 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7414 SetWindowText(hInput, move);
\r
7416 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7420 switch (LOWORD(wParam)) {
\r
7422 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7423 { int n; Board board;
\r
7425 if(gameMode == EditPosition && ParseFEN(board, &n, move) ) {
\r
7426 EditPositionPasteFEN(move);
\r
7427 EndDialog(hDlg, TRUE);
\r
7430 // [HGM] movenum: allow move number to be typed in any mode
\r
7431 if(sscanf(move, "%d", &n) == 1 && n != 0 ) {
\r
7432 currentMove = 2*n-1;
\r
7433 if(currentMove > forwardMostMove) currentMove = forwardMostMove;
\r
7434 if(currentMove < backwardMostMove) currentMove = backwardMostMove;
\r
7435 EndDialog(hDlg, TRUE);
\r
7436 DrawPosition(TRUE, boards[currentMove]);
\r
7437 if(currentMove > backwardMostMove) DisplayMove(currentMove - 1);
\r
7438 else DisplayMessage("", "");
\r
7442 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7443 gameMode != Training) {
\r
7444 DisplayMoveError("Displayed move is not current");
\r
7446 // GetDlgItemText(hDlg, OPT_Move, move, sizeof(move)); // moved upstream
\r
7447 int ok = ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7448 &moveType, &fromX, &fromY, &toX, &toY, &promoChar);
\r
7449 if(!ok && move[0] >= 'a') { move[0] += 'A' - 'a'; ok = 2; } // [HGM] try also capitalized
\r
7450 if (ok==1 || ok && ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7451 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7452 if (gameMode != Training)
\r
7453 forwardMostMove = currentMove;
\r
7454 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7456 DisplayMoveError("Could not parse move");
\r
7459 EndDialog(hDlg, TRUE);
\r
7462 EndDialog(hDlg, FALSE);
\r
7473 PopUpMoveDialog(char firstchar)
\r
7477 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7478 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7479 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7480 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7481 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7482 isdigit(firstchar) && // [HGM] movenum: allow typing in of move nr in 'passive' modes
\r
7483 ( gameMode == AnalyzeFile || gameMode == PlayFromGameFile ||
\r
7484 gameMode == IcsObserving || gameMode == TwoMachinesPlay ) ||
\r
7485 gameMode == Training) {
\r
7486 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7487 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7488 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7489 FreeProcInstance(lpProc);
\r
7493 /*---------------------------------------------------------------------------*\
\r
7495 * Type-in name dialog functions
\r
7497 \*---------------------------------------------------------------------------*/
\r
7500 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7502 char move[MSG_SIZ];
\r
7505 switch (message) {
\r
7506 case WM_INITDIALOG:
\r
7507 move[0] = (char) lParam;
\r
7508 move[1] = NULLCHAR;
\r
7509 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7510 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7511 SetWindowText(hInput, move);
\r
7513 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7517 switch (LOWORD(wParam)) {
\r
7519 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7520 appData.userName = strdup(move);
\r
7523 EndDialog(hDlg, TRUE);
\r
7526 EndDialog(hDlg, FALSE);
\r
7537 PopUpNameDialog(char firstchar)
\r
7541 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7542 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7543 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7544 FreeProcInstance(lpProc);
\r
7547 /*---------------------------------------------------------------------------*\
\r
7551 \*---------------------------------------------------------------------------*/
\r
7553 /* Nonmodal error box */
\r
7554 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7555 WPARAM wParam, LPARAM lParam);
\r
7558 ErrorPopUp(char *title, char *content)
\r
7562 BOOLEAN modal = hwndMain == NULL;
\r
7580 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7581 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7584 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7586 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7587 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7588 hwndMain, (DLGPROC)lpProc);
\r
7589 FreeProcInstance(lpProc);
\r
7596 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7597 if (errorDialog == NULL) return;
\r
7598 DestroyWindow(errorDialog);
\r
7599 errorDialog = NULL;
\r
7603 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7608 switch (message) {
\r
7609 case WM_INITDIALOG:
\r
7610 GetWindowRect(hDlg, &rChild);
\r
7613 SetWindowPos(hDlg, NULL, rChild.left,
\r
7614 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7615 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7619 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7620 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7621 and it doesn't work when you resize the dialog.
\r
7622 For now, just give it a default position.
\r
7624 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7626 errorDialog = hDlg;
\r
7627 SetWindowText(hDlg, errorTitle);
\r
7628 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7629 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7633 switch (LOWORD(wParam)) {
\r
7636 if (errorDialog == hDlg) errorDialog = NULL;
\r
7637 DestroyWindow(hDlg);
\r
7649 HWND gothicDialog = NULL;
\r
7652 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7656 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7658 switch (message) {
\r
7659 case WM_INITDIALOG:
\r
7660 GetWindowRect(hDlg, &rChild);
\r
7662 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7666 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7667 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7668 and it doesn't work when you resize the dialog.
\r
7669 For now, just give it a default position.
\r
7671 gothicDialog = hDlg;
\r
7672 SetWindowText(hDlg, errorTitle);
\r
7673 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7674 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7678 switch (LOWORD(wParam)) {
\r
7681 if (errorDialog == hDlg) errorDialog = NULL;
\r
7682 DestroyWindow(hDlg);
\r
7694 GothicPopUp(char *title, VariantClass variant)
\r
7697 static char *lastTitle;
\r
7699 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7700 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7702 if(lastTitle != title && gothicDialog != NULL) {
\r
7703 DestroyWindow(gothicDialog);
\r
7704 gothicDialog = NULL;
\r
7706 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7707 title = lastTitle;
\r
7708 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7709 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7710 hwndMain, (DLGPROC)lpProc);
\r
7711 FreeProcInstance(lpProc);
\r
7716 /*---------------------------------------------------------------------------*\
\r
7718 * Ics Interaction console functions
\r
7720 \*---------------------------------------------------------------------------*/
\r
7722 #define HISTORY_SIZE 64
\r
7723 static char *history[HISTORY_SIZE];
\r
7724 int histIn = 0, histP = 0;
\r
7727 SaveInHistory(char *cmd)
\r
7729 if (history[histIn] != NULL) {
\r
7730 free(history[histIn]);
\r
7731 history[histIn] = NULL;
\r
7733 if (*cmd == NULLCHAR) return;
\r
7734 history[histIn] = StrSave(cmd);
\r
7735 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7736 if (history[histIn] != NULL) {
\r
7737 free(history[histIn]);
\r
7738 history[histIn] = NULL;
\r
7744 PrevInHistory(char *cmd)
\r
7747 if (histP == histIn) {
\r
7748 if (history[histIn] != NULL) free(history[histIn]);
\r
7749 history[histIn] = StrSave(cmd);
\r
7751 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7752 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7754 return history[histP];
\r
7760 if (histP == histIn) return NULL;
\r
7761 histP = (histP + 1) % HISTORY_SIZE;
\r
7762 return history[histP];
\r
7769 BOOLEAN immediate;
\r
7770 } IcsTextMenuEntry;
\r
7771 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7772 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7775 ParseIcsTextMenu(char *icsTextMenuString)
\r
7778 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7779 char *p = icsTextMenuString;
\r
7780 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7783 if (e->command != NULL) {
\r
7785 e->command = NULL;
\r
7789 e = icsTextMenuEntry;
\r
7790 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7791 if (*p == ';' || *p == '\n') {
\r
7792 e->item = strdup("-");
\r
7793 e->command = NULL;
\r
7795 } else if (*p == '-') {
\r
7796 e->item = strdup("-");
\r
7797 e->command = NULL;
\r
7801 char *q, *r, *s, *t;
\r
7803 q = strchr(p, ',');
\r
7804 if (q == NULL) break;
\r
7806 r = strchr(q + 1, ',');
\r
7807 if (r == NULL) break;
\r
7809 s = strchr(r + 1, ',');
\r
7810 if (s == NULL) break;
\r
7813 t = strchr(s + 1, c);
\r
7816 t = strchr(s + 1, c);
\r
7818 if (t != NULL) *t = NULLCHAR;
\r
7819 e->item = strdup(p);
\r
7820 e->command = strdup(q + 1);
\r
7821 e->getname = *(r + 1) != '0';
\r
7822 e->immediate = *(s + 1) != '0';
\r
7826 if (t == NULL) break;
\r
7835 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7839 hmenu = LoadMenu(hInst, "TextMenu");
\r
7840 h = GetSubMenu(hmenu, 0);
\r
7842 if (strcmp(e->item, "-") == 0) {
\r
7843 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7845 if (e->item[0] == '|') {
\r
7846 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7847 IDM_CommandX + i, &e->item[1]);
\r
7849 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7858 WNDPROC consoleTextWindowProc;
\r
7861 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7863 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7864 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7868 SetWindowText(hInput, command);
\r
7870 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7872 sel.cpMin = 999999;
\r
7873 sel.cpMax = 999999;
\r
7874 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7879 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7880 if (sel.cpMin == sel.cpMax) {
\r
7881 /* Expand to surrounding word */
\r
7884 tr.chrg.cpMax = sel.cpMin;
\r
7885 tr.chrg.cpMin = --sel.cpMin;
\r
7886 if (sel.cpMin < 0) break;
\r
7887 tr.lpstrText = name;
\r
7888 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7889 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7893 tr.chrg.cpMin = sel.cpMax;
\r
7894 tr.chrg.cpMax = ++sel.cpMax;
\r
7895 tr.lpstrText = name;
\r
7896 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7897 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7900 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7901 MessageBeep(MB_ICONEXCLAMATION);
\r
7905 tr.lpstrText = name;
\r
7906 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7908 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7909 MessageBeep(MB_ICONEXCLAMATION);
\r
7912 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7915 sprintf(buf, "%s %s", command, name);
\r
7916 SetWindowText(hInput, buf);
\r
7917 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7919 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7920 SetWindowText(hInput, buf);
\r
7921 sel.cpMin = 999999;
\r
7922 sel.cpMax = 999999;
\r
7923 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7929 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7934 switch (message) {
\r
7936 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7939 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7942 sel.cpMin = 999999;
\r
7943 sel.cpMax = 999999;
\r
7944 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7945 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7950 if(wParam != '\022') {
\r
7951 if (wParam == '\t') {
\r
7952 if (GetKeyState(VK_SHIFT) < 0) {
\r
7954 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7955 if (buttonDesc[0].hwnd) {
\r
7956 SetFocus(buttonDesc[0].hwnd);
\r
7958 SetFocus(hwndMain);
\r
7962 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7965 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7966 JAWS_DELETE( SetFocus(hInput); )
\r
7967 SendMessage(hInput, message, wParam, lParam);
\r
7970 } // [HGM] navigate: for Ctrl+R, flow into nex case (moved up here) to summon up menu
\r
7971 case WM_RBUTTONUP:
\r
7972 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7973 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7974 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7977 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7978 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7979 if (sel.cpMin == sel.cpMax) {
\r
7980 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7981 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7983 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7984 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7986 pt.x = LOWORD(lParam);
\r
7987 pt.y = HIWORD(lParam);
\r
7988 MenuPopup(hwnd, pt, hmenu, -1);
\r
7992 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7994 return SendMessage(hInput, message, wParam, lParam);
\r
7995 case WM_MBUTTONDOWN:
\r
7996 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7997 case WM_RBUTTONDOWN:
\r
7998 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7999 /* Move selection here if it was empty */
\r
8001 pt.x = LOWORD(lParam);
\r
8002 pt.y = HIWORD(lParam);
\r
8003 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8004 if (sel.cpMin == sel.cpMax) {
\r
8005 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
8006 sel.cpMax = sel.cpMin;
\r
8007 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8009 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
8013 switch (LOWORD(wParam)) {
\r
8014 case IDM_QuickPaste:
\r
8016 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8017 if (sel.cpMin == sel.cpMax) {
\r
8018 MessageBeep(MB_ICONEXCLAMATION);
\r
8021 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8022 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8023 SendMessage(hInput, WM_PASTE, 0, 0);
\r
8028 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8031 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8034 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8038 int i = LOWORD(wParam) - IDM_CommandX;
\r
8039 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
8040 icsTextMenuEntry[i].command != NULL) {
\r
8041 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
8042 icsTextMenuEntry[i].getname,
\r
8043 icsTextMenuEntry[i].immediate);
\r
8051 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
8054 WNDPROC consoleInputWindowProc;
\r
8057 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8059 char buf[MSG_SIZ];
\r
8061 static BOOL sendNextChar = FALSE;
\r
8062 static BOOL quoteNextChar = FALSE;
\r
8063 InputSource *is = consoleInputSource;
\r
8067 switch (message) {
\r
8069 if (!appData.localLineEditing || sendNextChar) {
\r
8070 is->buf[0] = (CHAR) wParam;
\r
8072 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8073 sendNextChar = FALSE;
\r
8076 if (quoteNextChar) {
\r
8077 buf[0] = (char) wParam;
\r
8078 buf[1] = NULLCHAR;
\r
8079 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
8080 quoteNextChar = FALSE;
\r
8084 case '\r': /* Enter key */
\r
8085 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
8086 if (consoleEcho) SaveInHistory(is->buf);
\r
8087 is->buf[is->count++] = '\n';
\r
8088 is->buf[is->count] = NULLCHAR;
\r
8089 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8090 if (consoleEcho) {
\r
8091 ConsoleOutput(is->buf, is->count, TRUE);
\r
8092 } else if (appData.localLineEditing) {
\r
8093 ConsoleOutput("\n", 1, TRUE);
\r
8096 case '\033': /* Escape key */
\r
8097 SetWindowText(hwnd, "");
\r
8098 cf.cbSize = sizeof(CHARFORMAT);
\r
8099 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8100 if (consoleEcho) {
\r
8101 cf.crTextColor = textAttribs[ColorNormal].color;
\r
8103 cf.crTextColor = COLOR_ECHOOFF;
\r
8105 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
8106 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8108 case '\t': /* Tab key */
\r
8109 if (GetKeyState(VK_SHIFT) < 0) {
\r
8111 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
8114 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
8115 if (buttonDesc[0].hwnd) {
\r
8116 SetFocus(buttonDesc[0].hwnd);
\r
8118 SetFocus(hwndMain);
\r
8122 case '\023': /* Ctrl+S */
\r
8123 sendNextChar = TRUE;
\r
8125 case '\021': /* Ctrl+Q */
\r
8126 quoteNextChar = TRUE;
\r
8136 GetWindowText(hwnd, buf, MSG_SIZ);
\r
8137 p = PrevInHistory(buf);
\r
8139 SetWindowText(hwnd, p);
\r
8140 sel.cpMin = 999999;
\r
8141 sel.cpMax = 999999;
\r
8142 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8147 p = NextInHistory();
\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
8158 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
8162 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
8166 case WM_MBUTTONDOWN:
\r
8167 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8168 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8170 case WM_RBUTTONUP:
\r
8171 if (GetKeyState(VK_SHIFT) & ~1) {
\r
8172 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
8173 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
8177 hmenu = LoadMenu(hInst, "InputMenu");
\r
8178 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
8179 if (sel.cpMin == sel.cpMax) {
\r
8180 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
8181 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
8183 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
8184 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
8186 pt.x = LOWORD(lParam);
\r
8187 pt.y = HIWORD(lParam);
\r
8188 MenuPopup(hwnd, pt, hmenu, -1);
\r
8192 switch (LOWORD(wParam)) {
\r
8194 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
8196 case IDM_SelectAll:
\r
8198 sel.cpMax = -1; /*999999?*/
\r
8199 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8202 SendMessage(hwnd, WM_CUT, 0, 0);
\r
8205 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
8208 SendMessage(hwnd, WM_COPY, 0, 0);
\r
8213 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
8216 #define CO_MAX 100000
\r
8217 #define CO_TRIM 1000
\r
8220 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8222 static SnapData sd;
\r
8223 static HWND hText, hInput /*, hFocus*/;
\r
8224 // InputSource *is = consoleInputSource;
\r
8226 static int sizeX, sizeY;
\r
8227 int newSizeX, newSizeY;
\r
8230 switch (message) {
\r
8231 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8232 hwndConsole = hDlg;
\r
8233 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8234 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8236 consoleTextWindowProc = (WNDPROC)
\r
8237 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8238 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8239 consoleInputWindowProc = (WNDPROC)
\r
8240 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8241 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8242 Colorize(ColorNormal, TRUE);
\r
8243 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8244 ChangedConsoleFont();
\r
8245 GetClientRect(hDlg, &rect);
\r
8246 sizeX = rect.right;
\r
8247 sizeY = rect.bottom;
\r
8248 if (wpConsole.x != CW_USEDEFAULT && wpConsole.y != CW_USEDEFAULT &&
\r
8249 wpConsole.width != CW_USEDEFAULT && wpConsole.height != CW_USEDEFAULT) {
\r
8250 WINDOWPLACEMENT wp;
\r
8251 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8252 wp.length = sizeof(WINDOWPLACEMENT);
\r
8254 wp.showCmd = SW_SHOW;
\r
8255 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8256 wp.rcNormalPosition.left = wpConsole.x;
\r
8257 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8258 wp.rcNormalPosition.top = wpConsole.y;
\r
8259 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8260 SetWindowPlacement(hDlg, &wp);
\r
8263 // [HGM] Chessknight's change 2004-07-13
\r
8264 else { /* Determine Defaults */
\r
8265 WINDOWPLACEMENT wp;
\r
8266 wpConsole.x = winWidth + 1;
\r
8267 wpConsole.y = boardY;
\r
8268 wpConsole.width = screenWidth - winWidth;
\r
8269 wpConsole.height = winHeight;
\r
8270 EnsureOnScreen(&wpConsole.x, &wpConsole.y, 0, 0);
\r
8271 wp.length = sizeof(WINDOWPLACEMENT);
\r
8273 wp.showCmd = SW_SHOW;
\r
8274 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8275 wp.rcNormalPosition.left = wpConsole.x;
\r
8276 wp.rcNormalPosition.right = wpConsole.x + wpConsole.width;
\r
8277 wp.rcNormalPosition.top = wpConsole.y;
\r
8278 wp.rcNormalPosition.bottom = wpConsole.y + wpConsole.height;
\r
8279 SetWindowPlacement(hDlg, &wp);
\r
8294 if (IsIconic(hDlg)) break;
\r
8295 newSizeX = LOWORD(lParam);
\r
8296 newSizeY = HIWORD(lParam);
\r
8297 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8298 RECT rectText, rectInput;
\r
8300 int newTextHeight, newTextWidth;
\r
8301 GetWindowRect(hText, &rectText);
\r
8302 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8303 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8304 if (newTextHeight < 0) {
\r
8305 newSizeY += -newTextHeight;
\r
8306 newTextHeight = 0;
\r
8308 SetWindowPos(hText, NULL, 0, 0,
\r
8309 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8310 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8311 pt.x = rectInput.left;
\r
8312 pt.y = rectInput.top + newSizeY - sizeY;
\r
8313 ScreenToClient(hDlg, &pt);
\r
8314 SetWindowPos(hInput, NULL,
\r
8315 pt.x, pt.y, /* needs client coords */
\r
8316 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8317 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8323 case WM_GETMINMAXINFO:
\r
8324 /* Prevent resizing window too small */
\r
8325 mmi = (MINMAXINFO *) lParam;
\r
8326 mmi->ptMinTrackSize.x = 100;
\r
8327 mmi->ptMinTrackSize.y = 100;
\r
8330 /* [AS] Snapping */
\r
8331 case WM_ENTERSIZEMOVE:
\r
8332 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8335 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8338 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8340 case WM_EXITSIZEMOVE:
\r
8341 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8344 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8352 if (hwndConsole) return;
\r
8353 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8354 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8359 ConsoleOutput(char* data, int length, int forceVisible)
\r
8364 char buf[CO_MAX+1];
\r
8367 static int delayLF = 0;
\r
8368 CHARRANGE savesel, sel;
\r
8370 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8378 while (length--) {
\r
8386 } else if (*p == '\007') {
\r
8387 MyPlaySound(&sounds[(int)SoundBell]);
\r
8394 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8395 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8396 /* Save current selection */
\r
8397 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8398 exlen = GetWindowTextLength(hText);
\r
8399 /* Find out whether current end of text is visible */
\r
8400 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8401 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8402 /* Trim existing text if it's too long */
\r
8403 if (exlen + (q - buf) > CO_MAX) {
\r
8404 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8407 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8408 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8410 savesel.cpMin -= trim;
\r
8411 savesel.cpMax -= trim;
\r
8412 if (exlen < 0) exlen = 0;
\r
8413 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8414 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8416 /* Append the new text */
\r
8417 sel.cpMin = exlen;
\r
8418 sel.cpMax = exlen;
\r
8419 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8420 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8421 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8422 if (forceVisible || exlen == 0 ||
\r
8423 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8424 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8425 /* Scroll to make new end of text visible if old end of text
\r
8426 was visible or new text is an echo of user typein */
\r
8427 sel.cpMin = 9999999;
\r
8428 sel.cpMax = 9999999;
\r
8429 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8430 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8431 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8432 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8434 if (savesel.cpMax == exlen || forceVisible) {
\r
8435 /* Move insert point to new end of text if it was at the old
\r
8436 end of text or if the 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
8441 /* Restore previous selection */
\r
8442 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8444 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8451 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8455 COLORREF oldFg, oldBg;
\r
8459 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8461 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8462 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8463 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8466 rect.right = x + squareSize;
\r
8468 rect.bottom = y + squareSize;
\r
8471 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8472 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8473 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8474 &rect, str, strlen(str), NULL);
\r
8476 (void) SetTextColor(hdc, oldFg);
\r
8477 (void) SetBkColor(hdc, oldBg);
\r
8478 (void) SelectObject(hdc, oldFont);
\r
8482 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8483 RECT *rect, char *color, char *flagFell)
\r
8487 COLORREF oldFg, oldBg;
\r
8490 if (appData.clockMode) {
\r
8492 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8494 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8501 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8502 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8504 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8505 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8507 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8511 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8512 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8513 rect, str, strlen(str), NULL);
\r
8514 if(logoHeight > 0 && appData.clockMode) {
\r
8516 sprintf(buf, "%s %s", buf+7, flagFell);
\r
8517 r.top = rect->top + logoHeight/2;
\r
8518 r.left = rect->left;
\r
8519 r.right = rect->right;
\r
8520 r.bottom = rect->bottom;
\r
8521 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8522 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8523 &r, str, strlen(str), NULL);
\r
8525 (void) SetTextColor(hdc, oldFg);
\r
8526 (void) SetBkColor(hdc, oldBg);
\r
8527 (void) SelectObject(hdc, oldFont);
\r
8532 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8538 if( count <= 0 ) {
\r
8539 if (appData.debugMode) {
\r
8540 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8543 return ERROR_INVALID_USER_BUFFER;
\r
8546 ResetEvent(ovl->hEvent);
\r
8547 ovl->Offset = ovl->OffsetHigh = 0;
\r
8548 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8552 err = GetLastError();
\r
8553 if (err == ERROR_IO_PENDING) {
\r
8554 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8558 err = GetLastError();
\r
8565 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8570 ResetEvent(ovl->hEvent);
\r
8571 ovl->Offset = ovl->OffsetHigh = 0;
\r
8572 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8576 err = GetLastError();
\r
8577 if (err == ERROR_IO_PENDING) {
\r
8578 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8582 err = GetLastError();
\r
8588 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8589 void CheckForInputBufferFull( InputSource * is )
\r
8591 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8592 /* Look for end of line */
\r
8593 char * p = is->buf;
\r
8595 while( p < is->next && *p != '\n' ) {
\r
8599 if( p >= is->next ) {
\r
8600 if (appData.debugMode) {
\r
8601 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8604 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8605 is->count = (DWORD) -1;
\r
8606 is->next = is->buf;
\r
8612 InputThread(LPVOID arg)
\r
8617 is = (InputSource *) arg;
\r
8618 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8619 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8620 while (is->hThread != NULL) {
\r
8621 is->error = DoReadFile(is->hFile, is->next,
\r
8622 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8623 &is->count, &ovl);
\r
8624 if (is->error == NO_ERROR) {
\r
8625 is->next += is->count;
\r
8627 if (is->error == ERROR_BROKEN_PIPE) {
\r
8628 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8631 is->count = (DWORD) -1;
\r
8632 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8637 CheckForInputBufferFull( is );
\r
8639 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8641 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8643 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8646 CloseHandle(ovl.hEvent);
\r
8647 CloseHandle(is->hFile);
\r
8649 if (appData.debugMode) {
\r
8650 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8657 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8659 NonOvlInputThread(LPVOID arg)
\r
8666 is = (InputSource *) arg;
\r
8667 while (is->hThread != NULL) {
\r
8668 is->error = ReadFile(is->hFile, is->next,
\r
8669 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8670 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8671 if (is->error == NO_ERROR) {
\r
8672 /* Change CRLF to LF */
\r
8673 if (is->next > is->buf) {
\r
8675 i = is->count + 1;
\r
8683 if (prev == '\r' && *p == '\n') {
\r
8695 if (is->error == ERROR_BROKEN_PIPE) {
\r
8696 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8699 is->count = (DWORD) -1;
\r
8703 CheckForInputBufferFull( is );
\r
8705 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8707 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8709 if (is->count < 0) break; /* Quit on error */
\r
8711 CloseHandle(is->hFile);
\r
8716 SocketInputThread(LPVOID arg)
\r
8720 is = (InputSource *) arg;
\r
8721 while (is->hThread != NULL) {
\r
8722 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8723 if ((int)is->count == SOCKET_ERROR) {
\r
8724 is->count = (DWORD) -1;
\r
8725 is->error = WSAGetLastError();
\r
8727 is->error = NO_ERROR;
\r
8728 is->next += is->count;
\r
8729 if (is->count == 0 && is->second == is) {
\r
8730 /* End of file on stderr; quit with no message */
\r
8734 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8736 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8738 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8744 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8748 is = (InputSource *) lParam;
\r
8749 if (is->lineByLine) {
\r
8750 /* Feed in lines one by one */
\r
8751 char *p = is->buf;
\r
8753 while (q < is->next) {
\r
8754 if (*q++ == '\n') {
\r
8755 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8760 /* Move any partial line to the start of the buffer */
\r
8762 while (p < is->next) {
\r
8767 if (is->error != NO_ERROR || is->count == 0) {
\r
8768 /* Notify backend of the error. Note: If there was a partial
\r
8769 line at the end, it is not flushed through. */
\r
8770 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8773 /* Feed in the whole chunk of input at once */
\r
8774 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8775 is->next = is->buf;
\r
8779 /*---------------------------------------------------------------------------*\
\r
8781 * Menu enables. Used when setting various modes.
\r
8783 \*---------------------------------------------------------------------------*/
\r
8791 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8793 while (enab->item > 0) {
\r
8794 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8799 Enables gnuEnables[] = {
\r
8800 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8801 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8802 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8803 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8804 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8805 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8806 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8807 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8808 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8809 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8813 Enables icsEnables[] = {
\r
8814 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8815 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8816 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8817 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8818 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8819 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8820 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8821 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8822 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8823 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8824 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8825 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8830 Enables zippyEnables[] = {
\r
8831 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8832 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8833 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8838 Enables ncpEnables[] = {
\r
8839 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8840 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8841 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8842 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8843 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8844 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8845 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8846 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8847 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8848 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8849 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8850 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8851 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8852 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8853 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8857 Enables trainingOnEnables[] = {
\r
8858 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8859 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8860 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8861 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8862 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8863 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8864 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8865 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8869 Enables trainingOffEnables[] = {
\r
8870 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8871 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8872 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8873 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8874 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8875 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8876 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8877 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8881 /* These modify either ncpEnables or gnuEnables */
\r
8882 Enables cmailEnables[] = {
\r
8883 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8884 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8885 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8886 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8887 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8888 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8889 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8893 Enables machineThinkingEnables[] = {
\r
8894 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8895 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8896 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8897 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8898 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8899 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8900 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8901 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8902 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8903 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8904 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8905 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8906 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8907 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8908 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8912 Enables userThinkingEnables[] = {
\r
8913 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8914 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8915 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8916 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8917 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8918 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8919 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8920 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8921 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8922 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8923 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8924 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8925 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8926 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8927 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8931 /*---------------------------------------------------------------------------*\
\r
8933 * Front-end interface functions exported by XBoard.
\r
8934 * Functions appear in same order as prototypes in frontend.h.
\r
8936 \*---------------------------------------------------------------------------*/
\r
8940 static UINT prevChecked = 0;
\r
8941 static int prevPausing = 0;
\r
8944 if (pausing != prevPausing) {
\r
8945 prevPausing = pausing;
\r
8946 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8947 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8948 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8951 switch (gameMode) {
\r
8952 case BeginningOfGame:
\r
8953 if (appData.icsActive)
\r
8954 nowChecked = IDM_IcsClient;
\r
8955 else if (appData.noChessProgram)
\r
8956 nowChecked = IDM_EditGame;
\r
8958 nowChecked = IDM_MachineBlack;
\r
8960 case MachinePlaysBlack:
\r
8961 nowChecked = IDM_MachineBlack;
\r
8963 case MachinePlaysWhite:
\r
8964 nowChecked = IDM_MachineWhite;
\r
8966 case TwoMachinesPlay:
\r
8967 nowChecked = IDM_TwoMachines;
\r
8970 nowChecked = IDM_AnalysisMode;
\r
8973 nowChecked = IDM_AnalyzeFile;
\r
8976 nowChecked = IDM_EditGame;
\r
8978 case PlayFromGameFile:
\r
8979 nowChecked = IDM_LoadGame;
\r
8981 case EditPosition:
\r
8982 nowChecked = IDM_EditPosition;
\r
8985 nowChecked = IDM_Training;
\r
8987 case IcsPlayingWhite:
\r
8988 case IcsPlayingBlack:
\r
8989 case IcsObserving:
\r
8991 nowChecked = IDM_IcsClient;
\r
8998 if (prevChecked != 0)
\r
8999 (void) CheckMenuItem(GetMenu(hwndMain),
\r
9000 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
9001 if (nowChecked != 0)
\r
9002 (void) CheckMenuItem(GetMenu(hwndMain),
\r
9003 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
9005 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
9006 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
9007 MF_BYCOMMAND|MF_ENABLED);
\r
9009 (void) EnableMenuItem(GetMenu(hwndMain),
\r
9010 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
9013 prevChecked = nowChecked;
\r
9015 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
9016 if (appData.icsActive) {
\r
9017 if (appData.icsEngineAnalyze) {
\r
9018 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9019 MF_BYCOMMAND|MF_CHECKED);
\r
9021 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9022 MF_BYCOMMAND|MF_UNCHECKED);
\r
9030 HMENU hmenu = GetMenu(hwndMain);
\r
9031 SetMenuEnables(hmenu, icsEnables);
\r
9032 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
9033 MF_BYPOSITION|MF_ENABLED);
\r
9035 if (appData.zippyPlay) {
\r
9036 SetMenuEnables(hmenu, zippyEnables);
\r
9037 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
9038 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
9039 MF_BYCOMMAND|MF_ENABLED);
\r
9047 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
9053 HMENU hmenu = GetMenu(hwndMain);
\r
9054 SetMenuEnables(hmenu, ncpEnables);
\r
9055 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
9056 MF_BYPOSITION|MF_GRAYED);
\r
9057 DrawMenuBar(hwndMain);
\r
9063 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
9067 SetTrainingModeOn()
\r
9070 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
9071 for (i = 0; i < N_BUTTONS; i++) {
\r
9072 if (buttonDesc[i].hwnd != NULL)
\r
9073 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
9078 VOID SetTrainingModeOff()
\r
9081 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
9082 for (i = 0; i < N_BUTTONS; i++) {
\r
9083 if (buttonDesc[i].hwnd != NULL)
\r
9084 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
9090 SetUserThinkingEnables()
\r
9092 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
9096 SetMachineThinkingEnables()
\r
9098 HMENU hMenu = GetMenu(hwndMain);
\r
9099 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
9101 SetMenuEnables(hMenu, machineThinkingEnables);
\r
9103 if (gameMode == MachinePlaysBlack) {
\r
9104 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
9105 } else if (gameMode == MachinePlaysWhite) {
\r
9106 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
9107 } else if (gameMode == TwoMachinesPlay) {
\r
9108 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
9114 DisplayTitle(char *str)
\r
9116 char title[MSG_SIZ], *host;
\r
9117 if (str[0] != NULLCHAR) {
\r
9118 strcpy(title, str);
\r
9119 } else if (appData.icsActive) {
\r
9120 if (appData.icsCommPort[0] != NULLCHAR)
\r
9123 host = appData.icsHost;
\r
9124 sprintf(title, "%s: %s", szTitle, host);
\r
9125 } else if (appData.noChessProgram) {
\r
9126 strcpy(title, szTitle);
\r
9128 strcpy(title, szTitle);
\r
9129 strcat(title, ": ");
\r
9130 strcat(title, first.tidy);
\r
9132 SetWindowText(hwndMain, title);
\r
9137 DisplayMessage(char *str1, char *str2)
\r
9141 int remain = MESSAGE_TEXT_MAX - 1;
\r
9144 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
9145 messageText[0] = NULLCHAR;
\r
9147 len = strlen(str1);
\r
9148 if (len > remain) len = remain;
\r
9149 strncpy(messageText, str1, len);
\r
9150 messageText[len] = NULLCHAR;
\r
9153 if (*str2 && remain >= 2) {
\r
9155 strcat(messageText, " ");
\r
9158 len = strlen(str2);
\r
9159 if (len > remain) len = remain;
\r
9160 strncat(messageText, str2, len);
\r
9162 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
9164 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
9168 hdc = GetDC(hwndMain);
\r
9169 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
9170 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
9171 &messageRect, messageText, strlen(messageText), NULL);
\r
9172 (void) SelectObject(hdc, oldFont);
\r
9173 (void) ReleaseDC(hwndMain, hdc);
\r
9177 DisplayError(char *str, int error)
\r
9179 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
9185 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9186 NULL, error, LANG_NEUTRAL,
\r
9187 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9189 sprintf(buf, "%s:\n%s", str, buf2);
\r
9191 ErrorMap *em = errmap;
\r
9192 while (em->err != 0 && em->err != error) em++;
\r
9193 if (em->err != 0) {
\r
9194 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9196 sprintf(buf, "%s:\nError code %d", str, error);
\r
9201 ErrorPopUp("Error", buf);
\r
9206 DisplayMoveError(char *str)
\r
9208 fromX = fromY = -1;
\r
9209 ClearHighlights();
\r
9210 DrawPosition(FALSE, NULL);
\r
9211 if (appData.popupMoveErrors) {
\r
9212 ErrorPopUp("Error", str);
\r
9214 DisplayMessage(str, "");
\r
9215 moveErrorMessageUp = TRUE;
\r
9220 DisplayFatalError(char *str, int error, int exitStatus)
\r
9222 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
9224 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
9227 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
9228 NULL, error, LANG_NEUTRAL,
\r
9229 (LPSTR) buf2, MSG_SIZ, NULL);
\r
9231 sprintf(buf, "%s:\n%s", str, buf2);
\r
9233 ErrorMap *em = errmap;
\r
9234 while (em->err != 0 && em->err != error) em++;
\r
9235 if (em->err != 0) {
\r
9236 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9238 sprintf(buf, "%s:\nError code %d", str, error);
\r
9243 if (appData.debugMode) {
\r
9244 fprintf(debugFP, "%s: %s\n", label, str);
\r
9246 if (appData.popupExitMessage) {
\r
9247 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9248 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9250 ExitEvent(exitStatus);
\r
9255 DisplayInformation(char *str)
\r
9257 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9262 DisplayNote(char *str)
\r
9264 ErrorPopUp("Note", str);
\r
9269 char *title, *question, *replyPrefix;
\r
9274 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9276 static QuestionParams *qp;
\r
9277 char reply[MSG_SIZ];
\r
9280 switch (message) {
\r
9281 case WM_INITDIALOG:
\r
9282 qp = (QuestionParams *) lParam;
\r
9283 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9284 SetWindowText(hDlg, qp->title);
\r
9285 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9286 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9290 switch (LOWORD(wParam)) {
\r
9292 strcpy(reply, qp->replyPrefix);
\r
9293 if (*reply) strcat(reply, " ");
\r
9294 len = strlen(reply);
\r
9295 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9296 strcat(reply, "\n");
\r
9297 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9298 EndDialog(hDlg, TRUE);
\r
9299 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9302 EndDialog(hDlg, FALSE);
\r
9313 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9315 QuestionParams qp;
\r
9319 qp.question = question;
\r
9320 qp.replyPrefix = replyPrefix;
\r
9322 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9323 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9324 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9325 FreeProcInstance(lpProc);
\r
9328 /* [AS] Pick FRC position */
\r
9329 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9331 static int * lpIndexFRC;
\r
9337 case WM_INITDIALOG:
\r
9338 lpIndexFRC = (int *) lParam;
\r
9340 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9342 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9343 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9344 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9345 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9350 switch( LOWORD(wParam) ) {
\r
9352 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9353 EndDialog( hDlg, 0 );
\r
9354 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9357 EndDialog( hDlg, 1 );
\r
9359 case IDC_NFG_Edit:
\r
9360 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9361 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9363 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9366 case IDC_NFG_Random:
\r
9367 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9368 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9381 int index = appData.defaultFrcPosition;
\r
9382 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9384 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9386 if( result == 0 ) {
\r
9387 appData.defaultFrcPosition = index;
\r
9393 /* [AS] Game list options */
\r
9399 static GLT_Item GLT_ItemInfo[] = {
\r
9400 { GLT_EVENT, "Event" },
\r
9401 { GLT_SITE, "Site" },
\r
9402 { GLT_DATE, "Date" },
\r
9403 { GLT_ROUND, "Round" },
\r
9404 { GLT_PLAYERS, "Players" },
\r
9405 { GLT_RESULT, "Result" },
\r
9406 { GLT_WHITE_ELO, "White Rating" },
\r
9407 { GLT_BLACK_ELO, "Black Rating" },
\r
9408 { GLT_TIME_CONTROL,"Time Control" },
\r
9409 { GLT_VARIANT, "Variant" },
\r
9410 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9414 const char * GLT_FindItem( char id )
\r
9416 const char * result = 0;
\r
9418 GLT_Item * list = GLT_ItemInfo;
\r
9420 while( list->id != 0 ) {
\r
9421 if( list->id == id ) {
\r
9422 result = list->name;
\r
9432 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9434 const char * name = GLT_FindItem( id );
\r
9437 if( index >= 0 ) {
\r
9438 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9441 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9446 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9450 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9453 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9457 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9459 pc = GLT_ALL_TAGS;
\r
9462 if( strchr( tags, *pc ) == 0 ) {
\r
9463 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9468 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9471 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9473 char result = '\0';
\r
9476 GLT_Item * list = GLT_ItemInfo;
\r
9478 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9479 while( list->id != 0 ) {
\r
9480 if( strcmp( list->name, name ) == 0 ) {
\r
9481 result = list->id;
\r
9492 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9494 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9495 int idx2 = idx1 + delta;
\r
9496 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9498 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9501 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9502 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9503 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9504 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9508 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9510 static char glt[64];
\r
9511 static char * lpUserGLT;
\r
9515 case WM_INITDIALOG:
\r
9516 lpUserGLT = (char *) lParam;
\r
9518 strcpy( glt, lpUserGLT );
\r
9520 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9522 /* Initialize list */
\r
9523 GLT_TagsToList( hDlg, glt );
\r
9525 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9530 switch( LOWORD(wParam) ) {
\r
9533 char * pc = lpUserGLT;
\r
9535 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9539 id = GLT_ListItemToTag( hDlg, idx );
\r
9543 } while( id != '\0' );
\r
9545 EndDialog( hDlg, 0 );
\r
9548 EndDialog( hDlg, 1 );
\r
9551 case IDC_GLT_Default:
\r
9552 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9553 GLT_TagsToList( hDlg, glt );
\r
9556 case IDC_GLT_Restore:
\r
9557 strcpy( glt, lpUserGLT );
\r
9558 GLT_TagsToList( hDlg, glt );
\r
9562 GLT_MoveSelection( hDlg, -1 );
\r
9565 case IDC_GLT_Down:
\r
9566 GLT_MoveSelection( hDlg, +1 );
\r
9576 int GameListOptions()
\r
9580 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9582 strcpy( glt, appData.gameListTags );
\r
9584 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9586 if( result == 0 ) {
\r
9587 /* [AS] Memory leak here! */
\r
9588 appData.gameListTags = strdup( glt );
\r
9596 DisplayIcsInteractionTitle(char *str)
\r
9598 char consoleTitle[MSG_SIZ];
\r
9600 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9601 SetWindowText(hwndConsole, consoleTitle);
\r
9605 DrawPosition(int fullRedraw, Board board)
\r
9607 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9614 fromX = fromY = -1;
\r
9615 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9616 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9617 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9618 dragInfo.lastpos = dragInfo.pos;
\r
9619 dragInfo.start.x = dragInfo.start.y = -1;
\r
9620 dragInfo.from = dragInfo.start;
\r
9622 DrawPosition(TRUE, NULL);
\r
9628 CommentPopUp(char *title, char *str)
\r
9630 HWND hwnd = GetActiveWindow();
\r
9631 EitherCommentPopUp(0, title, str, FALSE);
\r
9632 SetActiveWindow(hwnd);
\r
9636 CommentPopDown(void)
\r
9638 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9639 if (commentDialog) {
\r
9640 ShowWindow(commentDialog, SW_HIDE);
\r
9642 commentDialogUp = FALSE;
\r
9646 EditCommentPopUp(int index, char *title, char *str)
\r
9648 EitherCommentPopUp(index, title, str, TRUE);
\r
9655 MyPlaySound(&sounds[(int)SoundMove]);
\r
9658 VOID PlayIcsWinSound()
\r
9660 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9663 VOID PlayIcsLossSound()
\r
9665 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9668 VOID PlayIcsDrawSound()
\r
9670 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9673 VOID PlayIcsUnfinishedSound()
\r
9675 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9681 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9689 consoleEcho = TRUE;
\r
9690 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9691 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9692 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9701 consoleEcho = FALSE;
\r
9702 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9703 /* This works OK: set text and background both to the same color */
\r
9705 cf.crTextColor = COLOR_ECHOOFF;
\r
9706 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9707 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9710 /* No Raw()...? */
\r
9712 void Colorize(ColorClass cc, int continuation)
\r
9714 currentColorClass = cc;
\r
9715 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9716 consoleCF.crTextColor = textAttribs[cc].color;
\r
9717 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9718 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9724 static char buf[MSG_SIZ];
\r
9725 DWORD bufsiz = MSG_SIZ;
\r
9727 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9728 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9730 if (!GetUserName(buf, &bufsiz)) {
\r
9731 /*DisplayError("Error getting user name", GetLastError());*/
\r
9732 strcpy(buf, "User");
\r
9740 static char buf[MSG_SIZ];
\r
9741 DWORD bufsiz = MSG_SIZ;
\r
9743 if (!GetComputerName(buf, &bufsiz)) {
\r
9744 /*DisplayError("Error getting host name", GetLastError());*/
\r
9745 strcpy(buf, "Unknown");
\r
9752 ClockTimerRunning()
\r
9754 return clockTimerEvent != 0;
\r
9760 if (clockTimerEvent == 0) return FALSE;
\r
9761 KillTimer(hwndMain, clockTimerEvent);
\r
9762 clockTimerEvent = 0;
\r
9767 StartClockTimer(long millisec)
\r
9769 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9770 (UINT) millisec, NULL);
\r
9774 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9777 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9779 if(appData.noGUI) return;
\r
9780 hdc = GetDC(hwndMain);
\r
9781 if (!IsIconic(hwndMain)) {
\r
9782 DisplayAClock(hdc, timeRemaining, highlight,
\r
9783 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9785 if (highlight && iconCurrent == iconBlack) {
\r
9786 iconCurrent = iconWhite;
\r
9787 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9788 if (IsIconic(hwndMain)) {
\r
9789 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9792 (void) ReleaseDC(hwndMain, hdc);
\r
9794 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9798 DisplayBlackClock(long timeRemaining, int highlight)
\r
9801 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9803 if(appData.noGUI) return;
\r
9804 hdc = GetDC(hwndMain);
\r
9805 if (!IsIconic(hwndMain)) {
\r
9806 DisplayAClock(hdc, timeRemaining, highlight,
\r
9807 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9809 if (highlight && iconCurrent == iconWhite) {
\r
9810 iconCurrent = iconBlack;
\r
9811 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9812 if (IsIconic(hwndMain)) {
\r
9813 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9816 (void) ReleaseDC(hwndMain, hdc);
\r
9818 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9823 LoadGameTimerRunning()
\r
9825 return loadGameTimerEvent != 0;
\r
9829 StopLoadGameTimer()
\r
9831 if (loadGameTimerEvent == 0) return FALSE;
\r
9832 KillTimer(hwndMain, loadGameTimerEvent);
\r
9833 loadGameTimerEvent = 0;
\r
9838 StartLoadGameTimer(long millisec)
\r
9840 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9841 (UINT) millisec, NULL);
\r
9849 char fileTitle[MSG_SIZ];
\r
9851 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9852 f = OpenFileDialog(hwndMain, "a", defName,
\r
9853 appData.oldSaveStyle ? "gam" : "pgn",
\r
9855 "Save Game to File", NULL, fileTitle, NULL);
\r
9857 SaveGame(f, 0, "");
\r
9864 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9866 if (delayedTimerEvent != 0) {
\r
9867 if (appData.debugMode && cb != delayedTimerCallback) { // [HGM] alive: not too much debug
\r
9868 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9870 KillTimer(hwndMain, delayedTimerEvent);
\r
9871 delayedTimerEvent = 0;
\r
9872 delayedTimerCallback();
\r
9874 delayedTimerCallback = cb;
\r
9875 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9876 (UINT) millisec, NULL);
\r
9879 DelayedEventCallback
\r
9882 if (delayedTimerEvent) {
\r
9883 return delayedTimerCallback;
\r
9890 CancelDelayedEvent()
\r
9892 if (delayedTimerEvent) {
\r
9893 KillTimer(hwndMain, delayedTimerEvent);
\r
9894 delayedTimerEvent = 0;
\r
9898 DWORD GetWin32Priority(int nice)
\r
9899 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9901 REALTIME_PRIORITY_CLASS 0x00000100
\r
9902 HIGH_PRIORITY_CLASS 0x00000080
\r
9903 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9904 NORMAL_PRIORITY_CLASS 0x00000020
\r
9905 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9906 IDLE_PRIORITY_CLASS 0x00000040
\r
9908 if (nice < -15) return 0x00000080;
\r
9909 if (nice < 0) return 0x00008000;
\r
9910 if (nice == 0) return 0x00000020;
\r
9911 if (nice < 15) return 0x00004000;
\r
9912 return 0x00000040;
\r
9915 /* Start a child process running the given program.
\r
9916 The process's standard output can be read from "from", and its
\r
9917 standard input can be written to "to".
\r
9918 Exit with fatal error if anything goes wrong.
\r
9919 Returns an opaque pointer that can be used to destroy the process
\r
9923 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9925 #define BUFSIZE 4096
\r
9927 HANDLE hChildStdinRd, hChildStdinWr,
\r
9928 hChildStdoutRd, hChildStdoutWr;
\r
9929 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9930 SECURITY_ATTRIBUTES saAttr;
\r
9932 PROCESS_INFORMATION piProcInfo;
\r
9933 STARTUPINFO siStartInfo;
\r
9935 char buf[MSG_SIZ];
\r
9938 if (appData.debugMode) {
\r
9939 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9944 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9945 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9946 saAttr.bInheritHandle = TRUE;
\r
9947 saAttr.lpSecurityDescriptor = NULL;
\r
9950 * The steps for redirecting child's STDOUT:
\r
9951 * 1. Create anonymous pipe to be STDOUT for child.
\r
9952 * 2. Create a noninheritable duplicate of read handle,
\r
9953 * and close the inheritable read handle.
\r
9956 /* Create a pipe for the child's STDOUT. */
\r
9957 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9958 return GetLastError();
\r
9961 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9962 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9963 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9964 FALSE, /* not inherited */
\r
9965 DUPLICATE_SAME_ACCESS);
\r
9967 return GetLastError();
\r
9969 CloseHandle(hChildStdoutRd);
\r
9972 * The steps for redirecting child's STDIN:
\r
9973 * 1. Create anonymous pipe to be STDIN for child.
\r
9974 * 2. Create a noninheritable duplicate of write handle,
\r
9975 * and close the inheritable write handle.
\r
9978 /* Create a pipe for the child's STDIN. */
\r
9979 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9980 return GetLastError();
\r
9983 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9984 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9985 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9986 FALSE, /* not inherited */
\r
9987 DUPLICATE_SAME_ACCESS);
\r
9989 return GetLastError();
\r
9991 CloseHandle(hChildStdinWr);
\r
9993 /* Arrange to (1) look in dir for the child .exe file, and
\r
9994 * (2) have dir be the child's working directory. Interpret
\r
9995 * dir relative to the directory WinBoard loaded from. */
\r
9996 GetCurrentDirectory(MSG_SIZ, buf);
\r
9997 SetCurrentDirectory(installDir);
\r
9998 SetCurrentDirectory(dir);
\r
10000 /* Now create the child process. */
\r
10002 siStartInfo.cb = sizeof(STARTUPINFO);
\r
10003 siStartInfo.lpReserved = NULL;
\r
10004 siStartInfo.lpDesktop = NULL;
\r
10005 siStartInfo.lpTitle = NULL;
\r
10006 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
10007 siStartInfo.cbReserved2 = 0;
\r
10008 siStartInfo.lpReserved2 = NULL;
\r
10009 siStartInfo.hStdInput = hChildStdinRd;
\r
10010 siStartInfo.hStdOutput = hChildStdoutWr;
\r
10011 siStartInfo.hStdError = hChildStdoutWr;
\r
10013 fSuccess = CreateProcess(NULL,
\r
10014 cmdLine, /* command line */
\r
10015 NULL, /* process security attributes */
\r
10016 NULL, /* primary thread security attrs */
\r
10017 TRUE, /* handles are inherited */
\r
10018 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
10019 NULL, /* use parent's environment */
\r
10021 &siStartInfo, /* STARTUPINFO pointer */
\r
10022 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
10024 err = GetLastError();
\r
10025 SetCurrentDirectory(buf); /* return to prev directory */
\r
10026 if (! fSuccess) {
\r
10030 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
10031 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
10032 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
10035 /* Close the handles we don't need in the parent */
\r
10036 CloseHandle(piProcInfo.hThread);
\r
10037 CloseHandle(hChildStdinRd);
\r
10038 CloseHandle(hChildStdoutWr);
\r
10040 /* Prepare return value */
\r
10041 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10042 cp->kind = CPReal;
\r
10043 cp->hProcess = piProcInfo.hProcess;
\r
10044 cp->pid = piProcInfo.dwProcessId;
\r
10045 cp->hFrom = hChildStdoutRdDup;
\r
10046 cp->hTo = hChildStdinWrDup;
\r
10048 *pr = (void *) cp;
\r
10050 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
10051 2000 where engines sometimes don't see the initial command(s)
\r
10052 from WinBoard and hang. I don't understand how that can happen,
\r
10053 but the Sleep is harmless, so I've put it in. Others have also
\r
10054 reported what may be the same problem, so hopefully this will fix
\r
10055 it for them too. */
\r
10063 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
10065 ChildProc *cp; int result;
\r
10067 cp = (ChildProc *) pr;
\r
10068 if (cp == NULL) return;
\r
10070 switch (cp->kind) {
\r
10072 /* TerminateProcess is considered harmful, so... */
\r
10073 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
10074 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
10075 /* The following doesn't work because the chess program
\r
10076 doesn't "have the same console" as WinBoard. Maybe
\r
10077 we could arrange for this even though neither WinBoard
\r
10078 nor the chess program uses a console for stdio? */
\r
10079 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
10081 /* [AS] Special termination modes for misbehaving programs... */
\r
10082 if( signal == 9 ) {
\r
10083 result = TerminateProcess( cp->hProcess, 0 );
\r
10085 if ( appData.debugMode) {
\r
10086 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
10089 else if( signal == 10 ) {
\r
10090 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
10092 if( dw != WAIT_OBJECT_0 ) {
\r
10093 result = TerminateProcess( cp->hProcess, 0 );
\r
10095 if ( appData.debugMode) {
\r
10096 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
10102 CloseHandle(cp->hProcess);
\r
10106 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
10110 closesocket(cp->sock);
\r
10115 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
10116 closesocket(cp->sock);
\r
10117 closesocket(cp->sock2);
\r
10125 InterruptChildProcess(ProcRef pr)
\r
10129 cp = (ChildProc *) pr;
\r
10130 if (cp == NULL) return;
\r
10131 switch (cp->kind) {
\r
10133 /* The following doesn't work because the chess program
\r
10134 doesn't "have the same console" as WinBoard. Maybe
\r
10135 we could arrange for this even though neither WinBoard
\r
10136 nor the chess program uses a console for stdio */
\r
10137 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
10142 /* Can't interrupt */
\r
10146 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
10153 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
10155 char cmdLine[MSG_SIZ];
\r
10157 if (port[0] == NULLCHAR) {
\r
10158 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
10160 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
10162 return StartChildProcess(cmdLine, "", pr);
\r
10166 /* Code to open TCP sockets */
\r
10169 OpenTCP(char *host, char *port, ProcRef *pr)
\r
10174 struct sockaddr_in sa, mysa;
\r
10175 struct hostent FAR *hp;
\r
10176 unsigned short uport;
\r
10177 WORD wVersionRequested;
\r
10180 /* Initialize socket DLL */
\r
10181 wVersionRequested = MAKEWORD(1, 1);
\r
10182 err = WSAStartup(wVersionRequested, &wsaData);
\r
10183 if (err != 0) return err;
\r
10185 /* Make socket */
\r
10186 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10187 err = WSAGetLastError();
\r
10192 /* Bind local address using (mostly) don't-care values.
\r
10194 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10195 mysa.sin_family = AF_INET;
\r
10196 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10197 uport = (unsigned short) 0;
\r
10198 mysa.sin_port = htons(uport);
\r
10199 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10200 == SOCKET_ERROR) {
\r
10201 err = WSAGetLastError();
\r
10206 /* Resolve remote host name */
\r
10207 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10208 if (!(hp = gethostbyname(host))) {
\r
10209 unsigned int b0, b1, b2, b3;
\r
10211 err = WSAGetLastError();
\r
10213 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10214 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10215 hp->h_addrtype = AF_INET;
\r
10216 hp->h_length = 4;
\r
10217 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10218 hp->h_addr_list[0] = (char *) malloc(4);
\r
10219 hp->h_addr_list[0][0] = (char) b0;
\r
10220 hp->h_addr_list[0][1] = (char) b1;
\r
10221 hp->h_addr_list[0][2] = (char) b2;
\r
10222 hp->h_addr_list[0][3] = (char) b3;
\r
10228 sa.sin_family = hp->h_addrtype;
\r
10229 uport = (unsigned short) atoi(port);
\r
10230 sa.sin_port = htons(uport);
\r
10231 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10233 /* Make connection */
\r
10234 if (connect(s, (struct sockaddr *) &sa,
\r
10235 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10236 err = WSAGetLastError();
\r
10241 /* Prepare return value */
\r
10242 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10243 cp->kind = CPSock;
\r
10245 *pr = (ProcRef *) cp;
\r
10251 OpenCommPort(char *name, ProcRef *pr)
\r
10256 char fullname[MSG_SIZ];
\r
10258 if (*name != '\\')
\r
10259 sprintf(fullname, "\\\\.\\%s", name);
\r
10261 strcpy(fullname, name);
\r
10263 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10264 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10265 if (h == (HANDLE) -1) {
\r
10266 return GetLastError();
\r
10270 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10272 /* Accumulate characters until a 100ms pause, then parse */
\r
10273 ct.ReadIntervalTimeout = 100;
\r
10274 ct.ReadTotalTimeoutMultiplier = 0;
\r
10275 ct.ReadTotalTimeoutConstant = 0;
\r
10276 ct.WriteTotalTimeoutMultiplier = 0;
\r
10277 ct.WriteTotalTimeoutConstant = 0;
\r
10278 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10280 /* Prepare return value */
\r
10281 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10282 cp->kind = CPComm;
\r
10285 *pr = (ProcRef *) cp;
\r
10291 OpenLoopback(ProcRef *pr)
\r
10293 DisplayFatalError("Not implemented", 0, 1);
\r
10299 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10303 SOCKET s, s2, s3;
\r
10304 struct sockaddr_in sa, mysa;
\r
10305 struct hostent FAR *hp;
\r
10306 unsigned short uport;
\r
10307 WORD wVersionRequested;
\r
10310 char stderrPortStr[MSG_SIZ];
\r
10312 /* Initialize socket DLL */
\r
10313 wVersionRequested = MAKEWORD(1, 1);
\r
10314 err = WSAStartup(wVersionRequested, &wsaData);
\r
10315 if (err != 0) return err;
\r
10317 /* Resolve remote host name */
\r
10318 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10319 if (!(hp = gethostbyname(host))) {
\r
10320 unsigned int b0, b1, b2, b3;
\r
10322 err = WSAGetLastError();
\r
10324 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10325 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10326 hp->h_addrtype = AF_INET;
\r
10327 hp->h_length = 4;
\r
10328 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10329 hp->h_addr_list[0] = (char *) malloc(4);
\r
10330 hp->h_addr_list[0][0] = (char) b0;
\r
10331 hp->h_addr_list[0][1] = (char) b1;
\r
10332 hp->h_addr_list[0][2] = (char) b2;
\r
10333 hp->h_addr_list[0][3] = (char) b3;
\r
10339 sa.sin_family = hp->h_addrtype;
\r
10340 uport = (unsigned short) 514;
\r
10341 sa.sin_port = htons(uport);
\r
10342 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10344 /* Bind local socket to unused "privileged" port address
\r
10346 s = INVALID_SOCKET;
\r
10347 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10348 mysa.sin_family = AF_INET;
\r
10349 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10350 for (fromPort = 1023;; fromPort--) {
\r
10351 if (fromPort < 0) {
\r
10353 return WSAEADDRINUSE;
\r
10355 if (s == INVALID_SOCKET) {
\r
10356 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10357 err = WSAGetLastError();
\r
10362 uport = (unsigned short) fromPort;
\r
10363 mysa.sin_port = htons(uport);
\r
10364 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10365 == SOCKET_ERROR) {
\r
10366 err = WSAGetLastError();
\r
10367 if (err == WSAEADDRINUSE) continue;
\r
10371 if (connect(s, (struct sockaddr *) &sa,
\r
10372 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10373 err = WSAGetLastError();
\r
10374 if (err == WSAEADDRINUSE) {
\r
10385 /* Bind stderr local socket to unused "privileged" port address
\r
10387 s2 = INVALID_SOCKET;
\r
10388 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10389 mysa.sin_family = AF_INET;
\r
10390 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10391 for (fromPort = 1023;; fromPort--) {
\r
10392 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10393 if (fromPort < 0) {
\r
10394 (void) closesocket(s);
\r
10396 return WSAEADDRINUSE;
\r
10398 if (s2 == INVALID_SOCKET) {
\r
10399 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10400 err = WSAGetLastError();
\r
10406 uport = (unsigned short) fromPort;
\r
10407 mysa.sin_port = htons(uport);
\r
10408 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10409 == SOCKET_ERROR) {
\r
10410 err = WSAGetLastError();
\r
10411 if (err == WSAEADDRINUSE) continue;
\r
10412 (void) closesocket(s);
\r
10416 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10417 err = WSAGetLastError();
\r
10418 if (err == WSAEADDRINUSE) {
\r
10420 s2 = INVALID_SOCKET;
\r
10423 (void) closesocket(s);
\r
10424 (void) closesocket(s2);
\r
10430 prevStderrPort = fromPort; // remember port used
\r
10431 sprintf(stderrPortStr, "%d", fromPort);
\r
10433 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10434 err = WSAGetLastError();
\r
10435 (void) closesocket(s);
\r
10436 (void) closesocket(s2);
\r
10441 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10442 err = WSAGetLastError();
\r
10443 (void) closesocket(s);
\r
10444 (void) closesocket(s2);
\r
10448 if (*user == NULLCHAR) user = UserName();
\r
10449 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10450 err = WSAGetLastError();
\r
10451 (void) closesocket(s);
\r
10452 (void) closesocket(s2);
\r
10456 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10457 err = WSAGetLastError();
\r
10458 (void) closesocket(s);
\r
10459 (void) closesocket(s2);
\r
10464 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10465 err = WSAGetLastError();
\r
10466 (void) closesocket(s);
\r
10467 (void) closesocket(s2);
\r
10471 (void) closesocket(s2); /* Stop listening */
\r
10473 /* Prepare return value */
\r
10474 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10475 cp->kind = CPRcmd;
\r
10478 *pr = (ProcRef *) cp;
\r
10485 AddInputSource(ProcRef pr, int lineByLine,
\r
10486 InputCallback func, VOIDSTAR closure)
\r
10488 InputSource *is, *is2 = NULL;
\r
10489 ChildProc *cp = (ChildProc *) pr;
\r
10491 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10492 is->lineByLine = lineByLine;
\r
10494 is->closure = closure;
\r
10495 is->second = NULL;
\r
10496 is->next = is->buf;
\r
10497 if (pr == NoProc) {
\r
10498 is->kind = CPReal;
\r
10499 consoleInputSource = is;
\r
10501 is->kind = cp->kind;
\r
10503 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10504 we create all threads suspended so that the is->hThread variable can be
\r
10505 safely assigned, then let the threads start with ResumeThread.
\r
10507 switch (cp->kind) {
\r
10509 is->hFile = cp->hFrom;
\r
10510 cp->hFrom = NULL; /* now owned by InputThread */
\r
10512 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10513 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10517 is->hFile = cp->hFrom;
\r
10518 cp->hFrom = NULL; /* now owned by InputThread */
\r
10520 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10521 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10525 is->sock = cp->sock;
\r
10527 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10528 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10532 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10534 is->sock = cp->sock;
\r
10535 is->second = is2;
\r
10536 is2->sock = cp->sock2;
\r
10537 is2->second = is2;
\r
10539 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10540 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10542 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10543 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10547 if( is->hThread != NULL ) {
\r
10548 ResumeThread( is->hThread );
\r
10551 if( is2 != NULL && is2->hThread != NULL ) {
\r
10552 ResumeThread( is2->hThread );
\r
10556 return (InputSourceRef) is;
\r
10560 RemoveInputSource(InputSourceRef isr)
\r
10564 is = (InputSource *) isr;
\r
10565 is->hThread = NULL; /* tell thread to stop */
\r
10566 CloseHandle(is->hThread);
\r
10567 if (is->second != NULL) {
\r
10568 is->second->hThread = NULL;
\r
10569 CloseHandle(is->second->hThread);
\r
10575 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10578 int outCount = SOCKET_ERROR;
\r
10579 ChildProc *cp = (ChildProc *) pr;
\r
10580 static OVERLAPPED ovl;
\r
10582 if (pr == NoProc) {
\r
10583 ConsoleOutput(message, count, FALSE);
\r
10587 if (ovl.hEvent == NULL) {
\r
10588 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10590 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10592 switch (cp->kind) {
\r
10595 outCount = send(cp->sock, message, count, 0);
\r
10596 if (outCount == SOCKET_ERROR) {
\r
10597 *outError = WSAGetLastError();
\r
10599 *outError = NO_ERROR;
\r
10604 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10605 &dOutCount, NULL)) {
\r
10606 *outError = NO_ERROR;
\r
10607 outCount = (int) dOutCount;
\r
10609 *outError = GetLastError();
\r
10614 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10615 &dOutCount, &ovl);
\r
10616 if (*outError == NO_ERROR) {
\r
10617 outCount = (int) dOutCount;
\r
10625 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10628 /* Ignore delay, not implemented for WinBoard */
\r
10629 return OutputToProcess(pr, message, count, outError);
\r
10634 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10635 char *buf, int count, int error)
\r
10637 DisplayFatalError("Not implemented", 0, 1);
\r
10640 /* see wgamelist.c for Game List functions */
\r
10641 /* see wedittags.c for Edit Tags functions */
\r
10648 char buf[MSG_SIZ];
\r
10651 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10652 f = fopen(buf, "r");
\r
10654 ProcessICSInitScript(f);
\r
10662 StartAnalysisClock()
\r
10664 if (analysisTimerEvent) return;
\r
10665 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10666 (UINT) 2000, NULL);
\r
10670 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10672 static HANDLE hwndText;
\r
10674 static int sizeX, sizeY;
\r
10675 int newSizeX, newSizeY, flags;
\r
10678 switch (message) {
\r
10679 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10680 /* Initialize the dialog items */
\r
10681 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10682 SetWindowText(hDlg, analysisTitle);
\r
10683 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10684 /* Size and position the dialog */
\r
10685 if (!analysisDialog) {
\r
10686 analysisDialog = hDlg;
\r
10687 flags = SWP_NOZORDER;
\r
10688 GetClientRect(hDlg, &rect);
\r
10689 sizeX = rect.right;
\r
10690 sizeY = rect.bottom;
\r
10691 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10692 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10693 WINDOWPLACEMENT wp;
\r
10694 EnsureOnScreen(&analysisX, &analysisY, 0, 0);
\r
10695 wp.length = sizeof(WINDOWPLACEMENT);
\r
10697 wp.showCmd = SW_SHOW;
\r
10698 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10699 wp.rcNormalPosition.left = analysisX;
\r
10700 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10701 wp.rcNormalPosition.top = analysisY;
\r
10702 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10703 SetWindowPlacement(hDlg, &wp);
\r
10705 GetClientRect(hDlg, &rect);
\r
10706 newSizeX = rect.right;
\r
10707 newSizeY = rect.bottom;
\r
10708 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10709 newSizeX, newSizeY);
\r
10710 sizeX = newSizeX;
\r
10711 sizeY = newSizeY;
\r
10716 case WM_COMMAND: /* message: received a command */
\r
10717 switch (LOWORD(wParam)) {
\r
10719 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10720 ExitAnalyzeMode();
\r
10732 newSizeX = LOWORD(lParam);
\r
10733 newSizeY = HIWORD(lParam);
\r
10734 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10735 sizeX = newSizeX;
\r
10736 sizeY = newSizeY;
\r
10739 case WM_GETMINMAXINFO:
\r
10740 /* Prevent resizing window too small */
\r
10741 mmi = (MINMAXINFO *) lParam;
\r
10742 mmi->ptMinTrackSize.x = 100;
\r
10743 mmi->ptMinTrackSize.y = 100;
\r
10750 AnalysisPopUp(char* title, char* str)
\r
10756 EngineOutputPopUp();
\r
10759 if (str == NULL) str = "";
\r
10760 p = (char *) malloc(2 * strlen(str) + 2);
\r
10763 if (*str == '\n') *q++ = '\r';
\r
10767 if (analysisText != NULL) free(analysisText);
\r
10768 analysisText = p;
\r
10770 if (analysisDialog) {
\r
10771 SetWindowText(analysisDialog, title);
\r
10772 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10773 ShowWindow(analysisDialog, SW_SHOW);
\r
10775 analysisTitle = title;
\r
10776 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10777 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10778 hwndMain, (DLGPROC)lpProc);
\r
10779 FreeProcInstance(lpProc);
\r
10781 analysisDialogUp = TRUE;
\r
10785 AnalysisPopDown()
\r
10787 if (analysisDialog) {
\r
10788 ShowWindow(analysisDialog, SW_HIDE);
\r
10790 analysisDialogUp = FALSE;
\r
10795 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10797 highlightInfo.sq[0].x = fromX;
\r
10798 highlightInfo.sq[0].y = fromY;
\r
10799 highlightInfo.sq[1].x = toX;
\r
10800 highlightInfo.sq[1].y = toY;
\r
10804 ClearHighlights()
\r
10806 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10807 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10811 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10813 premoveHighlightInfo.sq[0].x = fromX;
\r
10814 premoveHighlightInfo.sq[0].y = fromY;
\r
10815 premoveHighlightInfo.sq[1].x = toX;
\r
10816 premoveHighlightInfo.sq[1].y = toY;
\r
10820 ClearPremoveHighlights()
\r
10822 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10823 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10827 ShutDownFrontEnd()
\r
10829 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10830 DeleteClipboardTempFiles();
\r
10836 if (IsIconic(hwndMain))
\r
10837 ShowWindow(hwndMain, SW_RESTORE);
\r
10839 SetActiveWindow(hwndMain);
\r
10843 * Prototypes for animation support routines
\r
10845 static void ScreenSquare(int column, int row, POINT * pt);
\r
10846 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10847 POINT frames[], int * nFrames);
\r
10851 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10852 { // [HGM] atomic: animate blast wave
\r
10854 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10855 explodeInfo.fromX = fromX;
\r
10856 explodeInfo.fromY = fromY;
\r
10857 explodeInfo.toX = toX;
\r
10858 explodeInfo.toY = toY;
\r
10859 for(i=1; i<nFrames; i++) {
\r
10860 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10861 DrawPosition(FALSE, NULL);
\r
10862 Sleep(appData.animSpeed);
\r
10864 explodeInfo.radius = 0;
\r
10865 DrawPosition(TRUE, NULL);
\r
10868 #define kFactor 4
\r
10871 AnimateMove(board, fromX, fromY, toX, toY)
\r
10878 ChessSquare piece;
\r
10879 POINT start, finish, mid;
\r
10880 POINT frames[kFactor * 2 + 1];
\r
10883 if (!appData.animate) return;
\r
10884 if (doingSizing) return;
\r
10885 if (fromY < 0 || fromX < 0) return;
\r
10886 piece = board[fromY][fromX];
\r
10887 if (piece >= EmptySquare) return;
\r
10889 ScreenSquare(fromX, fromY, &start);
\r
10890 ScreenSquare(toX, toY, &finish);
\r
10892 /* All pieces except knights move in straight line */
\r
10893 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10894 mid.x = start.x + (finish.x - start.x) / 2;
\r
10895 mid.y = start.y + (finish.y - start.y) / 2;
\r
10897 /* Knight: make diagonal movement then straight */
\r
10898 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10899 mid.x = start.x + (finish.x - start.x) / 2;
\r
10900 mid.y = finish.y;
\r
10902 mid.x = finish.x;
\r
10903 mid.y = start.y + (finish.y - start.y) / 2;
\r
10907 /* Don't use as many frames for very short moves */
\r
10908 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10909 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10911 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10913 animInfo.from.x = fromX;
\r
10914 animInfo.from.y = fromY;
\r
10915 animInfo.to.x = toX;
\r
10916 animInfo.to.y = toY;
\r
10917 animInfo.lastpos = start;
\r
10918 animInfo.piece = piece;
\r
10919 for (n = 0; n < nFrames; n++) {
\r
10920 animInfo.pos = frames[n];
\r
10921 DrawPosition(FALSE, NULL);
\r
10922 animInfo.lastpos = animInfo.pos;
\r
10923 Sleep(appData.animSpeed);
\r
10925 animInfo.pos = finish;
\r
10926 DrawPosition(FALSE, NULL);
\r
10927 animInfo.piece = EmptySquare;
\r
10928 if(gameInfo.variant == VariantAtomic &&
\r
10929 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10930 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10933 /* Convert board position to corner of screen rect and color */
\r
10936 ScreenSquare(column, row, pt)
\r
10937 int column; int row; POINT * pt;
\r
10940 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10941 pt->y = lineGap + row * (squareSize + lineGap);
\r
10943 pt->x = lineGap + column * (squareSize + lineGap);
\r
10944 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10948 /* Generate a series of frame coords from start->mid->finish.
\r
10949 The movement rate doubles until the half way point is
\r
10950 reached, then halves back down to the final destination,
\r
10951 which gives a nice slow in/out effect. The algorithmn
\r
10952 may seem to generate too many intermediates for short
\r
10953 moves, but remember that the purpose is to attract the
\r
10954 viewers attention to the piece about to be moved and
\r
10955 then to where it ends up. Too few frames would be less
\r
10959 Tween(start, mid, finish, factor, frames, nFrames)
\r
10960 POINT * start; POINT * mid;
\r
10961 POINT * finish; int factor;
\r
10962 POINT frames[]; int * nFrames;
\r
10964 int n, fraction = 1, count = 0;
\r
10966 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10967 for (n = 0; n < factor; n++)
\r
10969 for (n = 0; n < factor; n++) {
\r
10970 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10971 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10973 fraction = fraction / 2;
\r
10977 frames[count] = *mid;
\r
10980 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10982 for (n = 0; n < factor; n++) {
\r
10983 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10984 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10986 fraction = fraction * 2;
\r
10988 *nFrames = count;
\r
10992 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10997 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10998 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
11000 OutputDebugString( buf );
\r
11003 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
11005 EvalGraphSet( first, last, current, pvInfoList );
\r
11008 void SetProgramStats( FrontEndProgramStats * stats )
\r
11013 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
11014 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
11016 OutputDebugString( buf );
\r
11019 EngineOutputUpdate( stats );
\r