2 * WinBoard.c -- Windows NT front end to XBoard
\r
3 * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
\r
5 * Copyright 1991 by Digital Equipment Corporation, Maynard,
\r
6 * Massachusetts. Enhancements Copyright
\r
7 * 1992-2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software
\r
10 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
11 * which was written and is copyrighted by Wayne Christopher.
\r
13 * The following terms apply to Digital Equipment Corporation's copyright
\r
14 * interest in XBoard:
\r
15 * ------------------------------------------------------------------------
\r
16 * All Rights Reserved
\r
18 * Permission to use, copy, modify, and distribute this software and its
\r
19 * documentation for any purpose and without fee is hereby granted,
\r
20 * provided that the above copyright notice appear in all copies and that
\r
21 * both that copyright notice and this permission notice appear in
\r
22 * supporting documentation, and that the name of Digital not be
\r
23 * used in advertising or publicity pertaining to distribution of the
\r
24 * software without specific, written prior permission.
\r
26 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
27 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
28 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
29 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
30 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
31 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
33 * ------------------------------------------------------------------------
\r
35 * The following terms apply to the enhanced version of XBoard
\r
36 * distributed by the Free Software Foundation:
\r
37 * ------------------------------------------------------------------------
\r
39 * GNU XBoard is free software: you can redistribute it and/or modify
\r
40 * it under the terms of the GNU General Public License as published by
\r
41 * the Free Software Foundation, either version 3 of the License, or (at
\r
42 * your option) any later version.
\r
44 * GNU XBoard is distributed in the hope that it will be useful, but
\r
45 * WITHOUT ANY WARRANTY; without even the implied warranty of
\r
46 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
47 * General Public License for more details.
\r
49 * You should have received a copy of the GNU General Public License
\r
50 * along with this program. If not, see http://www.gnu.org/licenses/. *
\r
52 *------------------------------------------------------------------------
\r
53 ** See the file ChangeLog for a revision history. */
\r
57 #include <windows.h>
\r
58 #include <winuser.h>
\r
59 #include <winsock.h>
\r
60 #include <commctrl.h>
\r
66 #include <sys/stat.h>
\r
69 #include <commdlg.h>
\r
71 #include <richedit.h>
\r
72 #include <mmsystem.h>
\r
81 #include "winboard.h"
\r
82 #include "frontend.h"
\r
83 #include "backend.h"
\r
85 #include "wclipbrd.h"
\r
86 #include "wgamelist.h"
\r
87 #include "wedittags.h"
\r
88 #include "woptions.h"
\r
89 #include "wsockerr.h"
\r
90 #include "defaults.h"
\r
94 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
97 void mysrandom(unsigned int seed);
\r
99 extern int whiteFlag, blackFlag;
\r
100 Boolean flipClock = FALSE;
\r
102 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
103 VOID NewVariantPopup(HWND hwnd);
\r
104 int FinishMove P((ChessMove moveType, int fromX, int fromY, int toX, int toY,
\r
105 /*char*/int promoChar));
\r
106 void AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames);
\r
109 ChessSquare piece;
\r
110 POINT pos; /* window coordinates of current pos */
\r
111 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
112 POINT from; /* board coordinates of the piece's orig pos */
\r
113 POINT to; /* board coordinates of the piece's new pos */
\r
116 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
119 POINT start; /* window coordinates of start pos */
\r
120 POINT pos; /* window coordinates of current pos */
\r
121 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
122 POINT from; /* board coordinates of the piece's orig pos */
\r
125 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
128 POINT sq[2]; /* board coordinates of from, to squares */
\r
131 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
132 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
134 typedef struct { // [HGM] atomic
\r
135 int fromX, fromY, toX, toY, radius;
\r
138 static ExplodeInfo explodeInfo;
\r
140 /* Window class names */
\r
141 char szAppName[] = "WinBoard";
\r
142 char szConsoleName[] = "WBConsole";
\r
144 /* Title bar text */
\r
145 char szTitle[] = "WinBoard";
\r
146 char szConsoleTitle[] = "ICS Interaction";
\r
149 char *settingsFileName;
\r
150 BOOLEAN saveSettingsOnExit;
\r
151 char installDir[MSG_SIZ];
\r
153 BoardSize boardSize;
\r
154 BOOLEAN chessProgram;
\r
155 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
156 static int squareSize, lineGap, minorSize;
\r
157 static int winWidth, winHeight;
\r
158 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
159 static int logoHeight = 0;
\r
160 static char messageText[MESSAGE_TEXT_MAX];
\r
161 static int clockTimerEvent = 0;
\r
162 static int loadGameTimerEvent = 0;
\r
163 static int analysisTimerEvent = 0;
\r
164 static DelayedEventCallback delayedTimerCallback;
\r
165 static int delayedTimerEvent = 0;
\r
166 static int buttonCount = 2;
\r
167 char *icsTextMenuString;
\r
169 char *firstChessProgramNames;
\r
170 char *secondChessProgramNames;
\r
172 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
174 #define PALETTESIZE 256
\r
176 HINSTANCE hInst; /* current instance */
\r
177 HWND hwndMain = NULL; /* root window*/
\r
178 HWND hwndConsole = NULL;
\r
179 BOOLEAN alwaysOnTop = FALSE;
\r
181 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
182 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
184 ColorClass currentColorClass;
\r
186 HWND hCommPort = NULL; /* currently open comm port */
\r
187 static HWND hwndPause; /* pause button */
\r
188 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
189 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
190 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
191 explodeBrush, /* [HGM] atomic */
\r
192 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
193 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
194 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
195 static HPEN gridPen = NULL;
\r
196 static HPEN highlightPen = NULL;
\r
197 static HPEN premovePen = NULL;
\r
198 static NPLOGPALETTE pLogPal;
\r
199 static BOOL paletteChanged = FALSE;
\r
200 static HICON iconWhite, iconBlack, iconCurrent;
\r
201 static int doingSizing = FALSE;
\r
202 static int lastSizing = 0;
\r
203 static int prevStderrPort;
\r
205 /* [AS] Support for background textures */
\r
206 #define BACK_TEXTURE_MODE_DISABLED 0
\r
207 #define BACK_TEXTURE_MODE_PLAIN 1
\r
208 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
210 static HBITMAP liteBackTexture = NULL;
\r
211 static HBITMAP darkBackTexture = NULL;
\r
212 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
213 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
214 static int backTextureSquareSize = 0;
\r
215 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
217 #if __GNUC__ && !defined(_winmajor)
\r
218 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
220 #define oldDialog (_winmajor < 4)
\r
223 char *defaultTextAttribs[] =
\r
225 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
226 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
236 int cliWidth, cliHeight;
\r
239 SizeInfo sizeInfo[] =
\r
241 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
242 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
243 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
244 { "petite", 33, 1, 1, 1, 0, 0 },
\r
245 { "slim", 37, 2, 1, 0, 0, 0 },
\r
246 { "small", 40, 2, 1, 0, 0, 0 },
\r
247 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
248 { "middling", 49, 2, 0, 0, 0, 0 },
\r
249 { "average", 54, 2, 0, 0, 0, 0 },
\r
250 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
251 { "medium", 64, 3, 0, 0, 0, 0 },
\r
252 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
253 { "large", 80, 3, 0, 0, 0, 0 },
\r
254 { "big", 87, 3, 0, 0, 0, 0 },
\r
255 { "huge", 95, 3, 0, 0, 0, 0 },
\r
256 { "giant", 108, 3, 0, 0, 0, 0 },
\r
257 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
258 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
259 { NULL, 0, 0, 0, 0, 0, 0 }
\r
262 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
263 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
265 { 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
266 { 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
267 { 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
268 { 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
269 { 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
270 { 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
271 { 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
272 { 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
273 { 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
274 { 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
275 { 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
276 { 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
277 { 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
278 { 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
279 { 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
280 { 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
281 { 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
282 { 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
285 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
294 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
295 #define N_BUTTONS 5
\r
297 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
299 {"<<", IDM_ToStart, NULL, NULL},
\r
300 {"<", IDM_Backward, NULL, NULL},
\r
301 {"P", IDM_Pause, NULL, NULL},
\r
302 {">", IDM_Forward, NULL, NULL},
\r
303 {">>", IDM_ToEnd, NULL, NULL},
\r
306 int tinyLayout = 0, smallLayout = 0;
\r
307 #define MENU_BAR_ITEMS 6
\r
308 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
309 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
310 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
314 MySound sounds[(int)NSoundClasses];
\r
315 MyTextAttribs textAttribs[(int)NColorClasses];
\r
317 MyColorizeAttribs colorizeAttribs[] = {
\r
318 { (COLORREF)0, 0, "Shout Text" },
\r
319 { (COLORREF)0, 0, "SShout/CShout" },
\r
320 { (COLORREF)0, 0, "Channel 1 Text" },
\r
321 { (COLORREF)0, 0, "Channel Text" },
\r
322 { (COLORREF)0, 0, "Kibitz Text" },
\r
323 { (COLORREF)0, 0, "Tell Text" },
\r
324 { (COLORREF)0, 0, "Challenge Text" },
\r
325 { (COLORREF)0, 0, "Request Text" },
\r
326 { (COLORREF)0, 0, "Seek Text" },
\r
327 { (COLORREF)0, 0, "Normal Text" },
\r
328 { (COLORREF)0, 0, "None" }
\r
333 static char *commentTitle;
\r
334 static char *commentText;
\r
335 static int commentIndex;
\r
336 static Boolean editComment = FALSE;
\r
337 HWND commentDialog = NULL;
\r
338 BOOLEAN commentDialogUp = FALSE;
\r
339 static int commentX, commentY, commentH, commentW;
\r
341 static char *analysisTitle;
\r
342 static char *analysisText;
\r
343 HWND analysisDialog = NULL;
\r
344 BOOLEAN analysisDialogUp = FALSE;
\r
345 static int analysisX, analysisY, analysisH, analysisW;
\r
347 char errorTitle[MSG_SIZ];
\r
348 char errorMessage[2*MSG_SIZ];
\r
349 HWND errorDialog = NULL;
\r
350 BOOLEAN moveErrorMessageUp = FALSE;
\r
351 BOOLEAN consoleEcho = TRUE;
\r
352 CHARFORMAT consoleCF;
\r
353 COLORREF consoleBackgroundColor;
\r
355 char *programVersion;
\r
361 typedef int CPKind;
\r
370 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
373 #define INPUT_SOURCE_BUF_SIZE 4096
\r
375 typedef struct _InputSource {
\r
382 char buf[INPUT_SOURCE_BUF_SIZE];
\r
386 InputCallback func;
\r
387 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
391 InputSource *consoleInputSource;
\r
396 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
397 VOID ConsoleCreate();
\r
399 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
400 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
401 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
402 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
404 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
405 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
406 void ParseIcsTextMenu(char *icsTextMenuString);
\r
407 VOID PopUpMoveDialog(char firstchar);
\r
408 VOID PopUpNameDialog(char firstchar);
\r
409 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
413 int GameListOptions();
\r
415 HWND moveHistoryDialog = NULL;
\r
416 BOOLEAN moveHistoryDialogUp = FALSE;
\r
418 WindowPlacement wpMoveHistory;
\r
420 HWND evalGraphDialog = NULL;
\r
421 BOOLEAN evalGraphDialogUp = FALSE;
\r
423 WindowPlacement wpEvalGraph;
\r
425 HWND engineOutputDialog = NULL;
\r
426 BOOLEAN engineOutputDialogUp = FALSE;
\r
428 WindowPlacement wpEngineOutput;
\r
430 VOID MoveHistoryPopUp();
\r
431 VOID MoveHistoryPopDown();
\r
432 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
433 BOOL MoveHistoryIsUp();
\r
435 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
436 VOID EvalGraphPopUp();
\r
437 VOID EvalGraphPopDown();
\r
438 BOOL EvalGraphIsUp();
\r
440 VOID EngineOutputPopUp();
\r
441 VOID EngineOutputPopDown();
\r
442 BOOL EngineOutputIsUp();
\r
443 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
445 VOID GothicPopUp(char *title, VariantClass variant);
\r
447 * Setting "frozen" should disable all user input other than deleting
\r
448 * the window. We do this while engines are initializing themselves.
\r
450 static int frozen = 0;
\r
451 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
457 if (frozen) return;
\r
459 hmenu = GetMenu(hwndMain);
\r
460 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
461 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
463 DrawMenuBar(hwndMain);
\r
466 /* Undo a FreezeUI */
\r
472 if (!frozen) return;
\r
474 hmenu = GetMenu(hwndMain);
\r
475 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
476 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
478 DrawMenuBar(hwndMain);
\r
481 /*---------------------------------------------------------------------------*\
\r
485 \*---------------------------------------------------------------------------*/
\r
488 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
489 LPSTR lpCmdLine, int nCmdShow)
\r
492 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
493 // INITCOMMONCONTROLSEX ex;
\r
497 LoadLibrary("RICHED32.DLL");
\r
498 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
500 if (!InitApplication(hInstance)) {
\r
503 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
507 // InitCommonControlsEx(&ex);
\r
508 InitCommonControls();
\r
510 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
511 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
512 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
514 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
516 while (GetMessage(&msg, /* message structure */
\r
517 NULL, /* handle of window receiving the message */
\r
518 0, /* lowest message to examine */
\r
519 0)) /* highest message to examine */
\r
521 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
522 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
523 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
524 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
525 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
526 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
527 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
528 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
529 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
530 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
531 TranslateMessage(&msg); /* Translates virtual key codes */
\r
532 DispatchMessage(&msg); /* Dispatches message to window */
\r
537 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
540 /*---------------------------------------------------------------------------*\
\r
542 * Initialization functions
\r
544 \*---------------------------------------------------------------------------*/
\r
547 InitApplication(HINSTANCE hInstance)
\r
551 /* Fill in window class structure with parameters that describe the */
\r
554 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
555 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
556 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
557 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
558 wc.hInstance = hInstance; /* Owner of this class */
\r
559 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
560 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
561 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
562 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
563 wc.lpszClassName = szAppName; /* Name to register as */
\r
565 /* Register the window class and return success/failure code. */
\r
566 if (!RegisterClass(&wc)) return FALSE;
\r
568 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
569 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
571 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
572 wc.hInstance = hInstance;
\r
573 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
574 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
575 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
576 wc.lpszMenuName = NULL;
\r
577 wc.lpszClassName = szConsoleName;
\r
579 if (!RegisterClass(&wc)) return FALSE;
\r
584 /* Set by InitInstance, used by EnsureOnScreen */
\r
585 int screenHeight, screenWidth;
\r
588 EnsureOnScreen(int *x, int *y)
\r
590 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
591 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
592 if (*x > screenWidth - 32) *x = 0;
\r
593 if (*y > screenHeight - 32) *y = 0;
\r
594 if (*x < 0) *x = 0;
\r
595 if (*y < 0) *y = 0;
\r
596 // if (*x < 10) *x = 10;
\r
597 // if (*y < gap) *y = gap;
\r
601 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
603 HWND hwnd; /* Main window handle. */
\r
605 WINDOWPLACEMENT wp;
\r
608 hInst = hInstance; /* Store instance handle in our global variable */
\r
610 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
611 *filepart = NULLCHAR;
\r
613 GetCurrentDirectory(MSG_SIZ, installDir);
\r
615 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
616 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
617 if (appData.debugMode) {
\r
618 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
619 setbuf(debugFP, NULL);
\r
624 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
625 // InitEngineUCI( installDir, &second );
\r
627 /* Create a main window for this application instance. */
\r
628 hwnd = CreateWindow(szAppName, szTitle,
\r
629 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
630 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
631 NULL, NULL, hInstance, NULL);
\r
634 /* If window could not be created, return "failure" */
\r
639 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
640 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
641 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
643 if (first.programLogo == NULL && appData.debugMode) {
\r
644 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
646 } else if(appData.autoLogo) {
\r
647 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
649 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
650 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
654 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
655 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
657 if (second.programLogo == NULL && appData.debugMode) {
\r
658 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
660 } else if(appData.autoLogo) {
\r
661 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
663 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
664 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
668 iconWhite = LoadIcon(hInstance, "icon_white");
\r
669 iconBlack = LoadIcon(hInstance, "icon_black");
\r
670 iconCurrent = iconWhite;
\r
671 InitDrawingColors();
\r
672 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
673 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
674 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
675 /* Compute window size for each board size, and use the largest
\r
676 size that fits on this screen as the default. */
\r
677 InitDrawingSizes((BoardSize)ibs, 0);
\r
678 if (boardSize == (BoardSize)-1 &&
\r
679 winHeight <= screenHeight
\r
680 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
681 && winWidth <= screenWidth) {
\r
682 boardSize = (BoardSize)ibs;
\r
686 InitDrawingSizes(boardSize, 0);
\r
688 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
690 /* [AS] Load textures if specified */
\r
691 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
693 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
694 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
695 liteBackTextureMode = appData.liteBackTextureMode;
\r
697 if (liteBackTexture == NULL && appData.debugMode) {
\r
698 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
702 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
703 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
704 darkBackTextureMode = appData.darkBackTextureMode;
\r
706 if (darkBackTexture == NULL && appData.debugMode) {
\r
707 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
711 mysrandom( (unsigned) time(NULL) );
\r
713 /* [AS] Restore layout */
\r
714 if( wpMoveHistory.visible ) {
\r
715 MoveHistoryPopUp();
\r
718 if( wpEvalGraph.visible ) {
\r
722 if( wpEngineOutput.visible ) {
\r
723 EngineOutputPopUp();
\r
728 /* Make the window visible; update its client area; and return "success" */
\r
729 EnsureOnScreen(&boardX, &boardY);
\r
730 wp.length = sizeof(WINDOWPLACEMENT);
\r
732 wp.showCmd = nCmdShow;
\r
733 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
734 wp.rcNormalPosition.left = boardX;
\r
735 wp.rcNormalPosition.right = boardX + winWidth;
\r
736 wp.rcNormalPosition.top = boardY;
\r
737 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
738 SetWindowPlacement(hwndMain, &wp);
\r
740 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
741 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
744 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
745 if( gameInfo.variant != VariantFischeRandom ) {
\r
746 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
751 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
752 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
754 ShowWindow(hwndConsole, nCmdShow);
\r
756 UpdateWindow(hwnd);
\r
764 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
765 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
766 ArgSettingsFilename
\r
774 String *pString; // ArgString
\r
775 int *pInt; // ArgInt
\r
776 float *pFloat; // ArgFloat
\r
777 Boolean *pBoolean; // ArgBoolean
\r
778 COLORREF *pColor; // ArgColor
\r
779 ColorClass cc; // ArgAttribs
\r
780 String *pFilename; // ArgFilename
\r
781 BoardSize *pBoardSize; // ArgBoardSize
\r
782 int whichFont; // ArgFont
\r
783 DCB *pDCB; // ArgCommSettings
\r
784 String *pFilename; // ArgSettingsFilename
\r
792 ArgDescriptor argDescriptors[] = {
\r
793 /* positional arguments */
\r
794 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
795 { "", ArgNone, NULL },
\r
796 /* keyword arguments */
\r
797 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
798 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
799 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
800 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
801 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
802 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
803 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
804 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
805 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
806 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
807 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
808 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
809 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
810 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
811 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
812 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
813 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
814 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
816 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
818 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
820 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
821 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
823 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
824 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
825 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
826 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
827 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
828 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
829 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
830 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
831 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
832 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
833 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
834 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
835 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
836 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
837 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
838 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
839 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
840 /*!!bitmapDirectory?*/
\r
841 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
842 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
843 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
844 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
845 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
846 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
847 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
848 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
849 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
850 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
851 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
852 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
853 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
854 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
855 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
856 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
857 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
858 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
859 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
860 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
861 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
862 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
863 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
864 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
865 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
866 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
867 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
868 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
869 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
870 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
871 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
872 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
873 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
874 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
875 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
876 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
877 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
878 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
879 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
880 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
881 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
882 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
883 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
884 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
885 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
886 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
887 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
888 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
889 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
890 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
891 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
892 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
893 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
894 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
895 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
896 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
897 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
898 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
899 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
900 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
901 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
902 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
903 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
904 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
905 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
906 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
907 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
908 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
909 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
910 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
911 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
912 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
913 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
914 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
915 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
916 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
917 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
918 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
919 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
920 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
921 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
922 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
923 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
924 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
925 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
926 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
927 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
928 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
929 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
930 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
931 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
932 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
933 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
934 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
935 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
936 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
937 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
938 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
939 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
940 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
941 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
942 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
943 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
944 TRUE }, /* must come after all fonts */
\r
945 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
946 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
947 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
948 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
949 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
950 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
951 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
952 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
953 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
954 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
955 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
956 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
957 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
958 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
959 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
960 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
961 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
962 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
963 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
964 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
965 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
966 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
967 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
968 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
969 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
970 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
971 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
972 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
973 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
974 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
975 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
977 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
978 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
980 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
981 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
982 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
983 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
984 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
985 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
986 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
987 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
988 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
989 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
990 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
991 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
992 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
993 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
994 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
995 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
996 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
997 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
998 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
999 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1000 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1001 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1002 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1003 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1004 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1005 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1006 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1007 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1008 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1009 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1010 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1011 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1012 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1013 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1014 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1015 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1016 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1017 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1018 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1019 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1020 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1021 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1022 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1023 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1024 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1025 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1026 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1027 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1028 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1029 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1030 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1031 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1032 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1033 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1034 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1035 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1036 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1037 { "highlightLastMove", ArgBoolean,
\r
1038 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1039 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1040 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1041 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1042 { "highlightDragging", ArgBoolean,
\r
1043 (LPVOID) &appData.highlightDragging, TRUE },
\r
1044 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1045 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1046 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1047 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1048 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1049 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1050 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1051 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1052 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1053 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1054 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1055 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1056 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1057 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1058 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1059 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1060 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1061 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1062 { "soundShout", ArgFilename,
\r
1063 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1064 { "soundSShout", ArgFilename,
\r
1065 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1066 { "soundChannel1", ArgFilename,
\r
1067 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1068 { "soundChannel", ArgFilename,
\r
1069 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1070 { "soundKibitz", ArgFilename,
\r
1071 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1072 { "soundTell", ArgFilename,
\r
1073 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1074 { "soundChallenge", ArgFilename,
\r
1075 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1076 { "soundRequest", ArgFilename,
\r
1077 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1078 { "soundSeek", ArgFilename,
\r
1079 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1080 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1081 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1082 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1083 { "soundIcsLoss", ArgFilename,
\r
1084 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1085 { "soundIcsDraw", ArgFilename,
\r
1086 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1087 { "soundIcsUnfinished", ArgFilename,
\r
1088 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1089 { "soundIcsAlarm", ArgFilename,
\r
1090 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1091 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1092 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1093 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1094 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1095 { "reuseChessPrograms", ArgBoolean,
\r
1096 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1097 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1098 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1099 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1100 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1101 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1102 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1103 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1104 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1105 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1106 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1107 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1108 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1109 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1110 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1111 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1112 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1113 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1114 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1115 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1116 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1117 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1118 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1119 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1120 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1121 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1122 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1123 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1124 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1125 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1126 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1127 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1128 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1129 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1130 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1131 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1132 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1133 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1135 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1137 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1138 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1139 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1140 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1141 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1142 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1143 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1144 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1145 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1146 /* [AS] New features */
\r
1147 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1148 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1149 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1150 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1151 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1152 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1153 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1154 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1155 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1156 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1157 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1158 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1159 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1160 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1161 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1162 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1163 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1164 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1165 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1166 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1167 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1168 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1169 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1170 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1171 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1172 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1173 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1174 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1175 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1176 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1177 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1178 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1179 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1180 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1181 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1182 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1183 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1184 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1185 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1186 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1187 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1188 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1189 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1190 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1191 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1192 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1193 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1194 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1195 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1196 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1198 /* [AS] Layout stuff */
\r
1199 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1200 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1201 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1202 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1203 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1205 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1206 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1207 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1208 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1209 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1211 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1212 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1213 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1214 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1215 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1217 /* [HGM] board-size, adjudication and misc. options */
\r
1218 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1219 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1220 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1221 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1222 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1223 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1224 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1225 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1226 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1227 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1228 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1229 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1230 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1231 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1232 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1233 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1234 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1235 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1236 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1237 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1238 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1239 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1240 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1241 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1242 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1243 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1244 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1245 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1246 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1247 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1248 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1251 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1252 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1253 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1254 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1255 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1256 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1257 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1258 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1259 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1260 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1261 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1262 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1263 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1265 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1266 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1267 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1268 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1269 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1270 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1271 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1273 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1274 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1275 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1276 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1277 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1278 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1279 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1280 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1281 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1282 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1283 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1284 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1285 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1286 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1287 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1288 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1289 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1290 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1292 /* [HGM] options for broadcasting and time odds */
\r
1293 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1294 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1295 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1296 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1297 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1298 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1299 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1300 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1301 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1302 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1303 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1304 { NULL, ArgNone, NULL, FALSE }
\r
1308 /* Kludge for indirection files on command line */
\r
1309 char* lastIndirectionFilename;
\r
1310 ArgDescriptor argDescriptorIndirection =
\r
1311 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1315 ExitArgError(char *msg, char *badArg)
\r
1317 char buf[MSG_SIZ];
\r
1319 sprintf(buf, "%s %s", msg, badArg);
\r
1320 DisplayFatalError(buf, 0, 2);
\r
1324 /* Command line font name parser. NULL name means do nothing.
\r
1325 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1326 For backward compatibility, syntax without the colon is also
\r
1327 accepted, but font names with digits in them won't work in that case.
\r
1330 ParseFontName(char *name, MyFontParams *mfp)
\r
1333 if (name == NULL) return;
\r
1335 q = strchr(p, ':');
\r
1337 if (q - p >= sizeof(mfp->faceName))
\r
1338 ExitArgError("Font name too long:", name);
\r
1339 memcpy(mfp->faceName, p, q - p);
\r
1340 mfp->faceName[q - p] = NULLCHAR;
\r
1343 q = mfp->faceName;
\r
1344 while (*p && !isdigit(*p)) {
\r
1346 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1347 ExitArgError("Font name too long:", name);
\r
1349 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1352 if (!*p) ExitArgError("Font point size missing:", name);
\r
1353 mfp->pointSize = (float) atof(p);
\r
1354 mfp->bold = (strchr(p, 'b') != NULL);
\r
1355 mfp->italic = (strchr(p, 'i') != NULL);
\r
1356 mfp->underline = (strchr(p, 'u') != NULL);
\r
1357 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1360 /* Color name parser.
\r
1361 X version accepts X color names, but this one
\r
1362 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1364 ParseColorName(char *name)
\r
1366 int red, green, blue, count;
\r
1367 char buf[MSG_SIZ];
\r
1369 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1371 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1372 &red, &green, &blue);
\r
1375 sprintf(buf, "Can't parse color name %s", name);
\r
1376 DisplayError(buf, 0);
\r
1377 return RGB(0, 0, 0);
\r
1379 return PALETTERGB(red, green, blue);
\r
1383 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1385 char *e = argValue;
\r
1389 if (*e == 'b') eff |= CFE_BOLD;
\r
1390 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1391 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1392 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1393 else if (*e == '#' || isdigit(*e)) break;
\r
1397 *color = ParseColorName(e);
\r
1402 ParseBoardSize(char *name)
\r
1404 BoardSize bs = SizeTiny;
\r
1405 while (sizeInfo[bs].name != NULL) {
\r
1406 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1409 ExitArgError("Unrecognized board size value", name);
\r
1410 return bs; /* not reached */
\r
1415 StringGet(void *getClosure)
\r
1417 char **p = (char **) getClosure;
\r
1422 FileGet(void *getClosure)
\r
1425 FILE* f = (FILE*) getClosure;
\r
1428 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1435 /* Parse settings file named "name". If file found, return the
\r
1436 full name in fullname and return TRUE; else return FALSE */
\r
1438 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1442 int ok; char buf[MSG_SIZ];
\r
1444 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1445 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1446 sprintf(buf, "%s.ini", name);
\r
1447 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1450 f = fopen(fullname, "r");
\r
1452 ParseArgs(FileGet, f);
\r
1461 ParseArgs(GetFunc get, void *cl)
\r
1463 char argName[ARG_MAX];
\r
1464 char argValue[ARG_MAX];
\r
1465 ArgDescriptor *ad;
\r
1474 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1475 if (ch == NULLCHAR) break;
\r
1477 /* Comment to end of line */
\r
1479 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1481 } else if (ch == '/' || ch == '-') {
\r
1484 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1485 ch != '\n' && ch != '\t') {
\r
1491 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1492 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1494 if (ad->argName == NULL)
\r
1495 ExitArgError("Unrecognized argument", argName);
\r
1497 } else if (ch == '@') {
\r
1498 /* Indirection file */
\r
1499 ad = &argDescriptorIndirection;
\r
1502 /* Positional argument */
\r
1503 ad = &argDescriptors[posarg++];
\r
1504 strcpy(argName, ad->argName);
\r
1507 if (ad->argType == ArgTrue) {
\r
1508 *(Boolean *) ad->argLoc = TRUE;
\r
1511 if (ad->argType == ArgFalse) {
\r
1512 *(Boolean *) ad->argLoc = FALSE;
\r
1516 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1517 if (ch == NULLCHAR || ch == '\n') {
\r
1518 ExitArgError("No value provided for argument", argName);
\r
1522 // Quoting with { }. No characters have to (or can) be escaped.
\r
1523 // Thus the string cannot contain a '}' character.
\r
1543 } else if (ch == '\'' || ch == '"') {
\r
1544 // Quoting with ' ' or " ", with \ as escape character.
\r
1545 // Inconvenient for long strings that may contain Windows filenames.
\r
1562 if (ch == start) {
\r
1571 if (ad->argType == ArgFilename
\r
1572 || ad->argType == ArgSettingsFilename) {
\r
1578 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1602 for (i = 0; i < 3; i++) {
\r
1603 if (ch >= '0' && ch <= '7') {
\r
1604 octval = octval*8 + (ch - '0');
\r
1611 *q++ = (char) octval;
\r
1622 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1629 switch (ad->argType) {
\r
1631 *(int *) ad->argLoc = atoi(argValue);
\r
1635 *(float *) ad->argLoc = (float) atof(argValue);
\r
1640 *(char **) ad->argLoc = strdup(argValue);
\r
1643 case ArgSettingsFilename:
\r
1645 char fullname[MSG_SIZ];
\r
1646 if (ParseSettingsFile(argValue, fullname)) {
\r
1647 if (ad->argLoc != NULL) {
\r
1648 *(char **) ad->argLoc = strdup(fullname);
\r
1651 if (ad->argLoc != NULL) {
\r
1653 ExitArgError("Failed to open indirection file", argValue);
\r
1660 switch (argValue[0]) {
\r
1663 *(Boolean *) ad->argLoc = TRUE;
\r
1667 *(Boolean *) ad->argLoc = FALSE;
\r
1670 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1676 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1679 case ArgAttribs: {
\r
1680 ColorClass cc = (ColorClass)ad->argLoc;
\r
1681 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1685 case ArgBoardSize:
\r
1686 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1690 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1693 case ArgCommSettings:
\r
1694 ParseCommSettings(argValue, &dcb);
\r
1698 ExitArgError("Unrecognized argument", argValue);
\r
1707 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1709 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1710 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1713 lf->lfEscapement = 0;
\r
1714 lf->lfOrientation = 0;
\r
1715 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1716 lf->lfItalic = mfp->italic;
\r
1717 lf->lfUnderline = mfp->underline;
\r
1718 lf->lfStrikeOut = mfp->strikeout;
\r
1719 lf->lfCharSet = DEFAULT_CHARSET;
\r
1720 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1721 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1722 lf->lfQuality = DEFAULT_QUALITY;
\r
1723 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1724 strcpy(lf->lfFaceName, mfp->faceName);
\r
1728 CreateFontInMF(MyFont *mf)
\r
1730 LFfromMFP(&mf->lf, &mf->mfp);
\r
1731 if (mf->hf) DeleteObject(mf->hf);
\r
1732 mf->hf = CreateFontIndirect(&mf->lf);
\r
1736 SetDefaultTextAttribs()
\r
1739 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1740 ParseAttribs(&textAttribs[cc].color,
\r
1741 &textAttribs[cc].effects,
\r
1742 defaultTextAttribs[cc]);
\r
1747 SetDefaultSounds()
\r
1751 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1752 textAttribs[cc].sound.name = strdup("");
\r
1753 textAttribs[cc].sound.data = NULL;
\r
1755 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1756 sounds[sc].name = strdup("");
\r
1757 sounds[sc].data = NULL;
\r
1759 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1767 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1768 MyLoadSound(&textAttribs[cc].sound);
\r
1770 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1771 MyLoadSound(&sounds[sc]);
\r
1776 InitAppData(LPSTR lpCmdLine)
\r
1779 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1782 programName = szAppName;
\r
1784 /* Initialize to defaults */
\r
1785 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1786 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1787 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1788 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1789 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1790 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1791 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1792 SetDefaultTextAttribs();
\r
1793 SetDefaultSounds();
\r
1794 appData.movesPerSession = MOVES_PER_SESSION;
\r
1795 appData.initString = INIT_STRING;
\r
1796 appData.secondInitString = INIT_STRING;
\r
1797 appData.firstComputerString = COMPUTER_STRING;
\r
1798 appData.secondComputerString = COMPUTER_STRING;
\r
1799 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1800 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1801 appData.firstPlaysBlack = FALSE;
\r
1802 appData.noChessProgram = FALSE;
\r
1803 chessProgram = FALSE;
\r
1804 appData.firstHost = FIRST_HOST;
\r
1805 appData.secondHost = SECOND_HOST;
\r
1806 appData.firstDirectory = FIRST_DIRECTORY;
\r
1807 appData.secondDirectory = SECOND_DIRECTORY;
\r
1808 appData.bitmapDirectory = "";
\r
1809 appData.remoteShell = REMOTE_SHELL;
\r
1810 appData.remoteUser = "";
\r
1811 appData.timeDelay = TIME_DELAY;
\r
1812 appData.timeControl = TIME_CONTROL;
\r
1813 appData.timeIncrement = TIME_INCREMENT;
\r
1814 appData.icsActive = FALSE;
\r
1815 appData.icsHost = "";
\r
1816 appData.icsPort = ICS_PORT;
\r
1817 appData.icsCommPort = ICS_COMM_PORT;
\r
1818 appData.icsLogon = ICS_LOGON;
\r
1819 appData.icsHelper = "";
\r
1820 appData.useTelnet = FALSE;
\r
1821 appData.telnetProgram = TELNET_PROGRAM;
\r
1822 appData.gateway = "";
\r
1823 appData.loadGameFile = "";
\r
1824 appData.loadGameIndex = 0;
\r
1825 appData.saveGameFile = "";
\r
1826 appData.autoSaveGames = FALSE;
\r
1827 appData.loadPositionFile = "";
\r
1828 appData.loadPositionIndex = 1;
\r
1829 appData.savePositionFile = "";
\r
1830 appData.matchMode = FALSE;
\r
1831 appData.matchGames = 0;
\r
1832 appData.monoMode = FALSE;
\r
1833 appData.debugMode = FALSE;
\r
1834 appData.clockMode = TRUE;
\r
1835 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1836 appData.Iconic = FALSE; /*unused*/
\r
1837 appData.searchTime = "";
\r
1838 appData.searchDepth = 0;
\r
1839 appData.showCoords = FALSE;
\r
1840 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1841 appData.autoCallFlag = FALSE;
\r
1842 appData.flipView = FALSE;
\r
1843 appData.autoFlipView = TRUE;
\r
1844 appData.cmailGameName = "";
\r
1845 appData.alwaysPromoteToQueen = FALSE;
\r
1846 appData.oldSaveStyle = FALSE;
\r
1847 appData.quietPlay = FALSE;
\r
1848 appData.showThinking = FALSE;
\r
1849 appData.ponderNextMove = TRUE;
\r
1850 appData.periodicUpdates = TRUE;
\r
1851 appData.popupExitMessage = TRUE;
\r
1852 appData.popupMoveErrors = FALSE;
\r
1853 appData.autoObserve = FALSE;
\r
1854 appData.autoComment = FALSE;
\r
1855 appData.animate = TRUE;
\r
1856 appData.animSpeed = 10;
\r
1857 appData.animateDragging = TRUE;
\r
1858 appData.highlightLastMove = TRUE;
\r
1859 appData.getMoveList = TRUE;
\r
1860 appData.testLegality = TRUE;
\r
1861 appData.premove = TRUE;
\r
1862 appData.premoveWhite = FALSE;
\r
1863 appData.premoveWhiteText = "";
\r
1864 appData.premoveBlack = FALSE;
\r
1865 appData.premoveBlackText = "";
\r
1866 appData.icsAlarm = TRUE;
\r
1867 appData.icsAlarmTime = 5000;
\r
1868 appData.autoRaiseBoard = TRUE;
\r
1869 appData.localLineEditing = TRUE;
\r
1870 appData.colorize = TRUE;
\r
1871 appData.reuseFirst = TRUE;
\r
1872 appData.reuseSecond = TRUE;
\r
1873 appData.blindfold = FALSE;
\r
1874 appData.icsEngineAnalyze = FALSE;
\r
1875 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1876 dcb.DCBlength = sizeof(DCB);
\r
1877 dcb.BaudRate = 9600;
\r
1878 dcb.fBinary = TRUE;
\r
1879 dcb.fParity = FALSE;
\r
1880 dcb.fOutxCtsFlow = FALSE;
\r
1881 dcb.fOutxDsrFlow = FALSE;
\r
1882 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1883 dcb.fDsrSensitivity = FALSE;
\r
1884 dcb.fTXContinueOnXoff = TRUE;
\r
1885 dcb.fOutX = FALSE;
\r
1887 dcb.fNull = FALSE;
\r
1888 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1889 dcb.fAbortOnError = FALSE;
\r
1891 dcb.Parity = SPACEPARITY;
\r
1892 dcb.StopBits = ONESTOPBIT;
\r
1893 settingsFileName = SETTINGS_FILE;
\r
1894 saveSettingsOnExit = TRUE;
\r
1895 boardX = CW_USEDEFAULT;
\r
1896 boardY = CW_USEDEFAULT;
\r
1897 consoleX = CW_USEDEFAULT;
\r
1898 consoleY = CW_USEDEFAULT;
\r
1899 consoleW = CW_USEDEFAULT;
\r
1900 consoleH = CW_USEDEFAULT;
\r
1901 analysisX = CW_USEDEFAULT;
\r
1902 analysisY = CW_USEDEFAULT;
\r
1903 analysisW = CW_USEDEFAULT;
\r
1904 analysisH = CW_USEDEFAULT;
\r
1905 commentX = CW_USEDEFAULT;
\r
1906 commentY = CW_USEDEFAULT;
\r
1907 commentW = CW_USEDEFAULT;
\r
1908 commentH = CW_USEDEFAULT;
\r
1909 editTagsX = CW_USEDEFAULT;
\r
1910 editTagsY = CW_USEDEFAULT;
\r
1911 editTagsW = CW_USEDEFAULT;
\r
1912 editTagsH = CW_USEDEFAULT;
\r
1913 gameListX = CW_USEDEFAULT;
\r
1914 gameListY = CW_USEDEFAULT;
\r
1915 gameListW = CW_USEDEFAULT;
\r
1916 gameListH = CW_USEDEFAULT;
\r
1917 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1918 icsNames = ICS_NAMES;
\r
1919 firstChessProgramNames = FCP_NAMES;
\r
1920 secondChessProgramNames = SCP_NAMES;
\r
1921 appData.initialMode = "";
\r
1922 appData.variant = "normal";
\r
1923 appData.firstProtocolVersion = PROTOVER;
\r
1924 appData.secondProtocolVersion = PROTOVER;
\r
1925 appData.showButtonBar = TRUE;
\r
1927 /* [AS] New properties (see comments in header file) */
\r
1928 appData.firstScoreIsAbsolute = FALSE;
\r
1929 appData.secondScoreIsAbsolute = FALSE;
\r
1930 appData.saveExtendedInfoInPGN = FALSE;
\r
1931 appData.hideThinkingFromHuman = FALSE;
\r
1932 appData.liteBackTextureFile = "";
\r
1933 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1934 appData.darkBackTextureFile = "";
\r
1935 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1936 appData.renderPiecesWithFont = "";
\r
1937 appData.fontToPieceTable = "";
\r
1938 appData.fontBackColorWhite = 0;
\r
1939 appData.fontForeColorWhite = 0;
\r
1940 appData.fontBackColorBlack = 0;
\r
1941 appData.fontForeColorBlack = 0;
\r
1942 appData.fontPieceSize = 80;
\r
1943 appData.overrideLineGap = 1;
\r
1944 appData.adjudicateLossThreshold = 0;
\r
1945 appData.delayBeforeQuit = 0;
\r
1946 appData.delayAfterQuit = 0;
\r
1947 appData.nameOfDebugFile = "winboard.debug";
\r
1948 appData.pgnEventHeader = "Computer Chess Game";
\r
1949 appData.defaultFrcPosition = -1;
\r
1950 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1951 appData.saveOutOfBookInfo = TRUE;
\r
1952 appData.showEvalInMoveHistory = TRUE;
\r
1953 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1954 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1955 appData.highlightMoveWithArrow = FALSE;
\r
1956 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1957 appData.useStickyWindows = TRUE;
\r
1958 appData.adjudicateDrawMoves = 0;
\r
1959 appData.autoDisplayComment = TRUE;
\r
1960 appData.autoDisplayTags = TRUE;
\r
1961 appData.firstIsUCI = FALSE;
\r
1962 appData.secondIsUCI = FALSE;
\r
1963 appData.firstHasOwnBookUCI = TRUE;
\r
1964 appData.secondHasOwnBookUCI = TRUE;
\r
1965 appData.polyglotDir = "";
\r
1966 appData.usePolyglotBook = FALSE;
\r
1967 appData.polyglotBook = "";
\r
1968 appData.defaultHashSize = 64;
\r
1969 appData.defaultCacheSizeEGTB = 4;
\r
1970 appData.defaultPathEGTB = "c:\\egtb";
\r
1971 appData.firstOptions = "";
\r
1972 appData.secondOptions = "";
\r
1974 InitWindowPlacement( &wpMoveHistory );
\r
1975 InitWindowPlacement( &wpEvalGraph );
\r
1976 InitWindowPlacement( &wpEngineOutput );
\r
1978 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1979 appData.NrFiles = -1;
\r
1980 appData.NrRanks = -1;
\r
1981 appData.holdingsSize = -1;
\r
1982 appData.testClaims = FALSE;
\r
1983 appData.checkMates = FALSE;
\r
1984 appData.materialDraws= FALSE;
\r
1985 appData.trivialDraws = FALSE;
\r
1986 appData.ruleMoves = 51;
\r
1987 appData.drawRepeats = 6;
\r
1988 appData.matchPause = 10000;
\r
1989 appData.alphaRank = FALSE;
\r
1990 appData.allWhite = FALSE;
\r
1991 appData.upsideDown = FALSE;
\r
1992 appData.serverPause = 15;
\r
1993 appData.serverMovesName = NULL;
\r
1994 appData.suppressLoadMoves = FALSE;
\r
1995 appData.firstTimeOdds = 1;
\r
1996 appData.secondTimeOdds = 1;
\r
1997 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
1998 appData.secondAccumulateTC = 1;
\r
1999 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2000 appData.secondNPS = -1;
\r
2001 appData.engineComments = 1;
\r
2002 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2003 appData.egtFormats = "";
\r
2006 appData.zippyTalk = ZIPPY_TALK;
\r
2007 appData.zippyPlay = ZIPPY_PLAY;
\r
2008 appData.zippyLines = ZIPPY_LINES;
\r
2009 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2010 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2011 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2012 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2013 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2014 appData.zippyUseI = ZIPPY_USE_I;
\r
2015 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2016 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2017 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2018 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2019 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2020 appData.zippyAbort = ZIPPY_ABORT;
\r
2021 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2022 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2023 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2026 /* Point font array elements to structures and
\r
2027 parse default font names */
\r
2028 for (i=0; i<NUM_FONTS; i++) {
\r
2029 for (j=0; j<NUM_SIZES; j++) {
\r
2030 font[j][i] = &fontRec[j][i];
\r
2031 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2035 /* Parse default settings file if any */
\r
2036 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2037 settingsFileName = strdup(buf);
\r
2040 /* Parse command line */
\r
2041 ParseArgs(StringGet, &lpCmdLine);
\r
2043 /* [HGM] make sure board size is acceptable */
\r
2044 if(appData.NrFiles > BOARD_SIZE ||
\r
2045 appData.NrRanks > BOARD_SIZE )
\r
2046 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2048 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2049 * with options from the command line, we now make an even higher priority
\r
2050 * overrule by WB options attached to the engine command line. This so that
\r
2051 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2054 if(appData.firstChessProgram != NULL) {
\r
2055 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2056 static char *f = "first";
\r
2057 char buf[MSG_SIZ], *q = buf;
\r
2058 if(p != NULL) { // engine command line contains WinBoard options
\r
2059 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2060 ParseArgs(StringGet, &q);
\r
2061 p[-1] = 0; // cut them offengine command line
\r
2064 // now do same for second chess program
\r
2065 if(appData.secondChessProgram != NULL) {
\r
2066 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2067 static char *s = "second";
\r
2068 char buf[MSG_SIZ], *q = buf;
\r
2069 if(p != NULL) { // engine command line contains WinBoard options
\r
2070 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2071 ParseArgs(StringGet, &q);
\r
2072 p[-1] = 0; // cut them offengine command line
\r
2077 /* Propagate options that affect others */
\r
2078 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2079 if (appData.icsActive || appData.noChessProgram) {
\r
2080 chessProgram = FALSE; /* not local chess program mode */
\r
2083 /* Open startup dialog if needed */
\r
2084 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2085 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2086 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2087 *appData.secondChessProgram == NULLCHAR))) {
\r
2090 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2091 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2092 FreeProcInstance(lpProc);
\r
2095 /* Make sure save files land in the right (?) directory */
\r
2096 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2097 appData.saveGameFile = strdup(buf);
\r
2099 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2100 appData.savePositionFile = strdup(buf);
\r
2103 /* Finish initialization for fonts and sounds */
\r
2104 for (i=0; i<NUM_FONTS; i++) {
\r
2105 for (j=0; j<NUM_SIZES; j++) {
\r
2106 CreateFontInMF(font[j][i]);
\r
2109 /* xboard, and older WinBoards, controlled the move sound with the
\r
2110 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2111 always turn the option on (so that the backend will call us),
\r
2112 then let the user turn the sound off by setting it to silence if
\r
2113 desired. To accommodate old winboard.ini files saved by old
\r
2114 versions of WinBoard, we also turn off the sound if the option
\r
2115 was initially set to false. */
\r
2116 if (!appData.ringBellAfterMoves) {
\r
2117 sounds[(int)SoundMove].name = strdup("");
\r
2118 appData.ringBellAfterMoves = TRUE;
\r
2120 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2121 SetCurrentDirectory(installDir);
\r
2123 SetCurrentDirectory(currDir);
\r
2125 p = icsTextMenuString;
\r
2126 if (p[0] == '@') {
\r
2127 FILE* f = fopen(p + 1, "r");
\r
2129 DisplayFatalError(p + 1, errno, 2);
\r
2132 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2134 buf[i] = NULLCHAR;
\r
2137 ParseIcsTextMenu(strdup(p));
\r
2144 HMENU hmenu = GetMenu(hwndMain);
\r
2146 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2147 MF_BYCOMMAND|((appData.icsActive &&
\r
2148 *appData.icsCommPort != NULLCHAR) ?
\r
2149 MF_ENABLED : MF_GRAYED));
\r
2150 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2151 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2152 MF_CHECKED : MF_UNCHECKED));
\r
2157 SaveSettings(char* name)
\r
2160 ArgDescriptor *ad;
\r
2161 WINDOWPLACEMENT wp;
\r
2162 char dir[MSG_SIZ];
\r
2164 if (!hwndMain) return;
\r
2166 GetCurrentDirectory(MSG_SIZ, dir);
\r
2167 SetCurrentDirectory(installDir);
\r
2168 f = fopen(name, "w");
\r
2169 SetCurrentDirectory(dir);
\r
2171 DisplayError(name, errno);
\r
2174 fprintf(f, ";\n");
\r
2175 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2176 fprintf(f, ";\n");
\r
2177 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2178 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2179 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2180 fprintf(f, ";\n");
\r
2182 wp.length = sizeof(WINDOWPLACEMENT);
\r
2183 GetWindowPlacement(hwndMain, &wp);
\r
2184 boardX = wp.rcNormalPosition.left;
\r
2185 boardY = wp.rcNormalPosition.top;
\r
2187 if (hwndConsole) {
\r
2188 GetWindowPlacement(hwndConsole, &wp);
\r
2189 consoleX = wp.rcNormalPosition.left;
\r
2190 consoleY = wp.rcNormalPosition.top;
\r
2191 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2192 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2195 if (analysisDialog) {
\r
2196 GetWindowPlacement(analysisDialog, &wp);
\r
2197 analysisX = wp.rcNormalPosition.left;
\r
2198 analysisY = wp.rcNormalPosition.top;
\r
2199 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2200 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2203 if (commentDialog) {
\r
2204 GetWindowPlacement(commentDialog, &wp);
\r
2205 commentX = wp.rcNormalPosition.left;
\r
2206 commentY = wp.rcNormalPosition.top;
\r
2207 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2208 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2211 if (editTagsDialog) {
\r
2212 GetWindowPlacement(editTagsDialog, &wp);
\r
2213 editTagsX = wp.rcNormalPosition.left;
\r
2214 editTagsY = wp.rcNormalPosition.top;
\r
2215 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2216 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2219 if (gameListDialog) {
\r
2220 GetWindowPlacement(gameListDialog, &wp);
\r
2221 gameListX = wp.rcNormalPosition.left;
\r
2222 gameListY = wp.rcNormalPosition.top;
\r
2223 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2224 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2227 /* [AS] Move history */
\r
2228 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2230 if( moveHistoryDialog ) {
\r
2231 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2232 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2233 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2234 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2235 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2238 /* [AS] Eval graph */
\r
2239 wpEvalGraph.visible = EvalGraphIsUp();
\r
2241 if( evalGraphDialog ) {
\r
2242 GetWindowPlacement(evalGraphDialog, &wp);
\r
2243 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2244 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2245 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2246 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2249 /* [AS] Engine output */
\r
2250 wpEngineOutput.visible = EngineOutputIsUp();
\r
2252 if( engineOutputDialog ) {
\r
2253 GetWindowPlacement(engineOutputDialog, &wp);
\r
2254 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2255 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2256 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2257 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2260 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2261 if (!ad->save) continue;
\r
2262 switch (ad->argType) {
\r
2265 char *p = *(char **)ad->argLoc;
\r
2266 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2267 /* Quote multiline values or \-containing values
\r
2268 with { } if possible */
\r
2269 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2271 /* Else quote with " " */
\r
2272 fprintf(f, "/%s=\"", ad->argName);
\r
2274 if (*p == '\n') fprintf(f, "\n");
\r
2275 else if (*p == '\r') fprintf(f, "\\r");
\r
2276 else if (*p == '\t') fprintf(f, "\\t");
\r
2277 else if (*p == '\b') fprintf(f, "\\b");
\r
2278 else if (*p == '\f') fprintf(f, "\\f");
\r
2279 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2280 else if (*p == '\"') fprintf(f, "\\\"");
\r
2281 else if (*p == '\\') fprintf(f, "\\\\");
\r
2285 fprintf(f, "\"\n");
\r
2290 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2293 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2296 fprintf(f, "/%s=%s\n", ad->argName,
\r
2297 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2300 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2303 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2307 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2308 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2309 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2314 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2315 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2316 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2317 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2318 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2319 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2320 (ta->effects) ? " " : "",
\r
2321 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2325 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2326 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2328 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2331 case ArgBoardSize:
\r
2332 fprintf(f, "/%s=%s\n", ad->argName,
\r
2333 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2338 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2339 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2340 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2341 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2342 ad->argName, mfp->faceName, mfp->pointSize,
\r
2343 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2344 mfp->bold ? "b" : "",
\r
2345 mfp->italic ? "i" : "",
\r
2346 mfp->underline ? "u" : "",
\r
2347 mfp->strikeout ? "s" : "");
\r
2351 case ArgCommSettings:
\r
2352 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2354 case ArgSettingsFilename: ;
\r
2362 /*---------------------------------------------------------------------------*\
\r
2364 * GDI board drawing routines
\r
2366 \*---------------------------------------------------------------------------*/
\r
2368 /* [AS] Draw square using background texture */
\r
2369 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2374 return; /* Should never happen! */
\r
2377 SetGraphicsMode( dst, GM_ADVANCED );
\r
2384 /* X reflection */
\r
2389 x.eDx = (FLOAT) dw + dx - 1;
\r
2392 SetWorldTransform( dst, &x );
\r
2395 /* Y reflection */
\r
2401 x.eDy = (FLOAT) dh + dy - 1;
\r
2403 SetWorldTransform( dst, &x );
\r
2411 x.eDx = (FLOAT) dx;
\r
2412 x.eDy = (FLOAT) dy;
\r
2415 SetWorldTransform( dst, &x );
\r
2419 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2427 SetWorldTransform( dst, &x );
\r
2429 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2432 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2434 PM_WP = (int) WhitePawn,
\r
2435 PM_WN = (int) WhiteKnight,
\r
2436 PM_WB = (int) WhiteBishop,
\r
2437 PM_WR = (int) WhiteRook,
\r
2438 PM_WQ = (int) WhiteQueen,
\r
2439 PM_WF = (int) WhiteFerz,
\r
2440 PM_WW = (int) WhiteWazir,
\r
2441 PM_WE = (int) WhiteAlfil,
\r
2442 PM_WM = (int) WhiteMan,
\r
2443 PM_WO = (int) WhiteCannon,
\r
2444 PM_WU = (int) WhiteUnicorn,
\r
2445 PM_WH = (int) WhiteNightrider,
\r
2446 PM_WA = (int) WhiteAngel,
\r
2447 PM_WC = (int) WhiteMarshall,
\r
2448 PM_WAB = (int) WhiteCardinal,
\r
2449 PM_WD = (int) WhiteDragon,
\r
2450 PM_WL = (int) WhiteLance,
\r
2451 PM_WS = (int) WhiteCobra,
\r
2452 PM_WV = (int) WhiteFalcon,
\r
2453 PM_WSG = (int) WhiteSilver,
\r
2454 PM_WG = (int) WhiteGrasshopper,
\r
2455 PM_WK = (int) WhiteKing,
\r
2456 PM_BP = (int) BlackPawn,
\r
2457 PM_BN = (int) BlackKnight,
\r
2458 PM_BB = (int) BlackBishop,
\r
2459 PM_BR = (int) BlackRook,
\r
2460 PM_BQ = (int) BlackQueen,
\r
2461 PM_BF = (int) BlackFerz,
\r
2462 PM_BW = (int) BlackWazir,
\r
2463 PM_BE = (int) BlackAlfil,
\r
2464 PM_BM = (int) BlackMan,
\r
2465 PM_BO = (int) BlackCannon,
\r
2466 PM_BU = (int) BlackUnicorn,
\r
2467 PM_BH = (int) BlackNightrider,
\r
2468 PM_BA = (int) BlackAngel,
\r
2469 PM_BC = (int) BlackMarshall,
\r
2470 PM_BG = (int) BlackGrasshopper,
\r
2471 PM_BAB = (int) BlackCardinal,
\r
2472 PM_BD = (int) BlackDragon,
\r
2473 PM_BL = (int) BlackLance,
\r
2474 PM_BS = (int) BlackCobra,
\r
2475 PM_BV = (int) BlackFalcon,
\r
2476 PM_BSG = (int) BlackSilver,
\r
2477 PM_BK = (int) BlackKing
\r
2480 static HFONT hPieceFont = NULL;
\r
2481 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2482 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2483 static int fontBitmapSquareSize = 0;
\r
2484 static char pieceToFontChar[(int) EmptySquare] =
\r
2485 { 'p', 'n', 'b', 'r', 'q',
\r
2486 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2487 'k', 'o', 'm', 'v', 't', 'w',
\r
2488 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2491 extern BOOL SetCharTable( char *table, const char * map );
\r
2492 /* [HGM] moved to backend.c */
\r
2494 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2497 BYTE r1 = GetRValue( color );
\r
2498 BYTE g1 = GetGValue( color );
\r
2499 BYTE b1 = GetBValue( color );
\r
2505 /* Create a uniform background first */
\r
2506 hbrush = CreateSolidBrush( color );
\r
2507 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2508 FillRect( hdc, &rc, hbrush );
\r
2509 DeleteObject( hbrush );
\r
2512 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2513 int steps = squareSize / 2;
\r
2516 for( i=0; i<steps; i++ ) {
\r
2517 BYTE r = r1 - (r1-r2) * i / steps;
\r
2518 BYTE g = g1 - (g1-g2) * i / steps;
\r
2519 BYTE b = b1 - (b1-b2) * i / steps;
\r
2521 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2522 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2523 FillRect( hdc, &rc, hbrush );
\r
2524 DeleteObject(hbrush);
\r
2527 else if( mode == 2 ) {
\r
2528 /* Diagonal gradient, good more or less for every piece */
\r
2529 POINT triangle[3];
\r
2530 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2531 HBRUSH hbrush_old;
\r
2532 int steps = squareSize;
\r
2535 triangle[0].x = squareSize - steps;
\r
2536 triangle[0].y = squareSize;
\r
2537 triangle[1].x = squareSize;
\r
2538 triangle[1].y = squareSize;
\r
2539 triangle[2].x = squareSize;
\r
2540 triangle[2].y = squareSize - steps;
\r
2542 for( i=0; i<steps; i++ ) {
\r
2543 BYTE r = r1 - (r1-r2) * i / steps;
\r
2544 BYTE g = g1 - (g1-g2) * i / steps;
\r
2545 BYTE b = b1 - (b1-b2) * i / steps;
\r
2547 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2548 hbrush_old = SelectObject( hdc, hbrush );
\r
2549 Polygon( hdc, triangle, 3 );
\r
2550 SelectObject( hdc, hbrush_old );
\r
2551 DeleteObject(hbrush);
\r
2556 SelectObject( hdc, hpen );
\r
2561 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2562 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2563 piece: follow the steps as explained below.
\r
2565 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2569 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2573 int backColor = whitePieceColor;
\r
2574 int foreColor = blackPieceColor;
\r
2576 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2577 backColor = appData.fontBackColorWhite;
\r
2578 foreColor = appData.fontForeColorWhite;
\r
2580 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2581 backColor = appData.fontBackColorBlack;
\r
2582 foreColor = appData.fontForeColorBlack;
\r
2586 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2588 hbm_old = SelectObject( hdc, hbm );
\r
2592 rc.right = squareSize;
\r
2593 rc.bottom = squareSize;
\r
2595 /* Step 1: background is now black */
\r
2596 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2598 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2600 pt.x = (squareSize - sz.cx) / 2;
\r
2601 pt.y = (squareSize - sz.cy) / 2;
\r
2603 SetBkMode( hdc, TRANSPARENT );
\r
2604 SetTextColor( hdc, chroma );
\r
2605 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2606 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2608 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2609 /* Step 3: the area outside the piece is filled with white */
\r
2610 // FloodFill( hdc, 0, 0, chroma );
\r
2611 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2612 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2613 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2614 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2615 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2617 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2618 but if the start point is not inside the piece we're lost!
\r
2619 There should be a better way to do this... if we could create a region or path
\r
2620 from the fill operation we would be fine for example.
\r
2622 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2623 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2625 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2626 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2627 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2629 SelectObject( dc2, bm2 );
\r
2630 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2631 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2632 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2633 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2634 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2637 DeleteObject( bm2 );
\r
2640 SetTextColor( hdc, 0 );
\r
2642 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2643 draw the piece again in black for safety.
\r
2645 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2647 SelectObject( hdc, hbm_old );
\r
2649 if( hPieceMask[index] != NULL ) {
\r
2650 DeleteObject( hPieceMask[index] );
\r
2653 hPieceMask[index] = hbm;
\r
2656 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2658 SelectObject( hdc, hbm );
\r
2661 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2662 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2663 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2665 SelectObject( dc1, hPieceMask[index] );
\r
2666 SelectObject( dc2, bm2 );
\r
2667 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2668 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2671 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2672 the piece background and deletes (makes transparent) the rest.
\r
2673 Thanks to that mask, we are free to paint the background with the greates
\r
2674 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2675 We use this, to make gradients and give the pieces a "roundish" look.
\r
2677 SetPieceBackground( hdc, backColor, 2 );
\r
2678 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2682 DeleteObject( bm2 );
\r
2685 SetTextColor( hdc, foreColor );
\r
2686 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2688 SelectObject( hdc, hbm_old );
\r
2690 if( hPieceFace[index] != NULL ) {
\r
2691 DeleteObject( hPieceFace[index] );
\r
2694 hPieceFace[index] = hbm;
\r
2697 static int TranslatePieceToFontPiece( int piece )
\r
2727 case BlackMarshall:
\r
2731 case BlackNightrider:
\r
2737 case BlackUnicorn:
\r
2741 case BlackGrasshopper:
\r
2753 case BlackCardinal:
\r
2760 case WhiteMarshall:
\r
2764 case WhiteNightrider:
\r
2770 case WhiteUnicorn:
\r
2774 case WhiteGrasshopper:
\r
2786 case WhiteCardinal:
\r
2795 void CreatePiecesFromFont()
\r
2798 HDC hdc_window = NULL;
\r
2804 if( fontBitmapSquareSize < 0 ) {
\r
2805 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2809 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2810 fontBitmapSquareSize = -1;
\r
2814 if( fontBitmapSquareSize != squareSize ) {
\r
2815 hdc_window = GetDC( hwndMain );
\r
2816 hdc = CreateCompatibleDC( hdc_window );
\r
2818 if( hPieceFont != NULL ) {
\r
2819 DeleteObject( hPieceFont );
\r
2822 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2823 hPieceMask[i] = NULL;
\r
2824 hPieceFace[i] = NULL;
\r
2830 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2831 fontHeight = appData.fontPieceSize;
\r
2834 fontHeight = (fontHeight * squareSize) / 100;
\r
2836 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2838 lf.lfEscapement = 0;
\r
2839 lf.lfOrientation = 0;
\r
2840 lf.lfWeight = FW_NORMAL;
\r
2842 lf.lfUnderline = 0;
\r
2843 lf.lfStrikeOut = 0;
\r
2844 lf.lfCharSet = DEFAULT_CHARSET;
\r
2845 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2846 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2847 lf.lfQuality = PROOF_QUALITY;
\r
2848 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2849 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2850 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2852 hPieceFont = CreateFontIndirect( &lf );
\r
2854 if( hPieceFont == NULL ) {
\r
2855 fontBitmapSquareSize = -2;
\r
2858 /* Setup font-to-piece character table */
\r
2859 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2860 /* No (or wrong) global settings, try to detect the font */
\r
2861 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2863 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2865 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2866 /* DiagramTT* family */
\r
2867 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2869 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2870 /* Fairy symbols */
\r
2871 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2873 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2874 /* Good Companion (Some characters get warped as literal :-( */
\r
2875 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2876 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2877 SetCharTable(pieceToFontChar, s);
\r
2880 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2881 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2885 /* Create bitmaps */
\r
2886 hfont_old = SelectObject( hdc, hPieceFont );
\r
2888 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2889 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2890 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2891 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2892 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2893 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2894 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2895 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2896 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2897 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2898 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2899 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2901 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2902 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2903 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2904 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2905 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2906 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2907 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2908 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2909 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2910 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2911 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
2912 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
2913 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
2914 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
2915 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
2916 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
2917 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2918 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2919 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2920 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2921 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2922 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2923 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2924 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2925 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2926 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2927 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
2928 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
2929 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
2930 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
2931 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
2932 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
2934 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2935 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2936 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2938 SelectObject( hdc, hfont_old );
\r
2940 fontBitmapSquareSize = squareSize;
\r
2944 if( hdc != NULL ) {
\r
2948 if( hdc_window != NULL ) {
\r
2949 ReleaseDC( hwndMain, hdc_window );
\r
2954 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2958 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2959 if (gameInfo.event &&
\r
2960 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2961 strcmp(name, "k80s") == 0) {
\r
2962 strcpy(name, "tim");
\r
2964 return LoadBitmap(hinst, name);
\r
2968 /* Insert a color into the program's logical palette
\r
2969 structure. This code assumes the given color is
\r
2970 the result of the RGB or PALETTERGB macro, and it
\r
2971 knows how those macros work (which is documented).
\r
2974 InsertInPalette(COLORREF color)
\r
2976 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2978 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2979 DisplayFatalError("Too many colors", 0, 1);
\r
2980 pLogPal->palNumEntries--;
\r
2984 pe->peFlags = (char) 0;
\r
2985 pe->peRed = (char) (0xFF & color);
\r
2986 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2987 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2993 InitDrawingColors()
\r
2995 if (pLogPal == NULL) {
\r
2996 /* Allocate enough memory for a logical palette with
\r
2997 * PALETTESIZE entries and set the size and version fields
\r
2998 * of the logical palette structure.
\r
3000 pLogPal = (NPLOGPALETTE)
\r
3001 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3002 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3003 pLogPal->palVersion = 0x300;
\r
3005 pLogPal->palNumEntries = 0;
\r
3007 InsertInPalette(lightSquareColor);
\r
3008 InsertInPalette(darkSquareColor);
\r
3009 InsertInPalette(whitePieceColor);
\r
3010 InsertInPalette(blackPieceColor);
\r
3011 InsertInPalette(highlightSquareColor);
\r
3012 InsertInPalette(premoveHighlightColor);
\r
3014 /* create a logical color palette according the information
\r
3015 * in the LOGPALETTE structure.
\r
3017 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3019 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3020 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3021 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3022 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3023 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3024 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3025 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3026 /* [AS] Force rendering of the font-based pieces */
\r
3027 if( fontBitmapSquareSize > 0 ) {
\r
3028 fontBitmapSquareSize = 0;
\r
3034 BoardWidth(int boardSize, int n)
\r
3035 { /* [HGM] argument n added to allow different width and height */
\r
3036 int lineGap = sizeInfo[boardSize].lineGap;
\r
3038 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3039 lineGap = appData.overrideLineGap;
\r
3042 return (n + 1) * lineGap +
\r
3043 n * sizeInfo[boardSize].squareSize;
\r
3046 /* Respond to board resize by dragging edge */
\r
3048 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3050 BoardSize newSize = NUM_SIZES - 1;
\r
3051 static int recurse = 0;
\r
3052 if (IsIconic(hwndMain)) return;
\r
3053 if (recurse > 0) return;
\r
3055 while (newSize > 0) {
\r
3056 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3057 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3058 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3061 boardSize = newSize;
\r
3062 InitDrawingSizes(boardSize, flags);
\r
3069 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3071 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3072 ChessSquare piece;
\r
3073 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3075 SIZE clockSize, messageSize;
\r
3077 char buf[MSG_SIZ];
\r
3079 HMENU hmenu = GetMenu(hwndMain);
\r
3080 RECT crect, wrect;
\r
3082 LOGBRUSH logbrush;
\r
3084 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3085 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3087 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3088 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3090 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3091 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3092 squareSize = sizeInfo[boardSize].squareSize;
\r
3093 lineGap = sizeInfo[boardSize].lineGap;
\r
3094 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3096 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3097 lineGap = appData.overrideLineGap;
\r
3100 if (tinyLayout != oldTinyLayout) {
\r
3101 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3103 style &= ~WS_SYSMENU;
\r
3104 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3105 "&Minimize\tCtrl+F4");
\r
3107 style |= WS_SYSMENU;
\r
3108 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3110 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3112 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3113 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3114 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3116 DrawMenuBar(hwndMain);
\r
3119 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3120 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3122 /* Get text area sizes */
\r
3123 hdc = GetDC(hwndMain);
\r
3124 if (appData.clockMode) {
\r
3125 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3127 sprintf(buf, "White");
\r
3129 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3130 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3131 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3132 str = "We only care about the height here";
\r
3133 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3134 SelectObject(hdc, oldFont);
\r
3135 ReleaseDC(hwndMain, hdc);
\r
3137 /* Compute where everything goes */
\r
3138 if(first.programLogo || second.programLogo) {
\r
3139 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3140 logoHeight = 2*clockSize.cy;
\r
3141 leftLogoRect.left = OUTER_MARGIN;
\r
3142 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3143 leftLogoRect.top = OUTER_MARGIN;
\r
3144 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3146 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3147 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3148 rightLogoRect.top = OUTER_MARGIN;
\r
3149 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3152 blackRect.left = leftLogoRect.right;
\r
3153 blackRect.right = rightLogoRect.left;
\r
3154 blackRect.top = OUTER_MARGIN;
\r
3155 blackRect.bottom = blackRect.top + clockSize.cy;
\r
3157 whiteRect.left = blackRect.left ;
\r
3158 whiteRect.right = blackRect.right;
\r
3159 whiteRect.top = blackRect.bottom;
\r
3160 whiteRect.bottom = leftLogoRect.bottom;
\r
3162 whiteRect.left = OUTER_MARGIN;
\r
3163 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3164 whiteRect.top = OUTER_MARGIN + logoHeight;
\r
3165 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3167 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3168 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3169 blackRect.top = whiteRect.top;
\r
3170 blackRect.bottom = whiteRect.bottom;
\r
3173 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3174 if (appData.showButtonBar) {
\r
3175 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3176 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3178 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3180 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3181 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3183 boardRect.left = OUTER_MARGIN;
\r
3184 boardRect.right = boardRect.left + boardWidth;
\r
3185 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3186 boardRect.bottom = boardRect.top + boardHeight;
\r
3188 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3189 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3190 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3191 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3192 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3193 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3194 GetWindowRect(hwndMain, &wrect);
\r
3195 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3196 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3197 /* compensate if menu bar wrapped */
\r
3198 GetClientRect(hwndMain, &crect);
\r
3199 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3200 winHeight += offby;
\r
3202 case WMSZ_TOPLEFT:
\r
3203 SetWindowPos(hwndMain, NULL,
\r
3204 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3205 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3208 case WMSZ_TOPRIGHT:
\r
3210 SetWindowPos(hwndMain, NULL,
\r
3211 wrect.left, wrect.bottom - winHeight,
\r
3212 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3215 case WMSZ_BOTTOMLEFT:
\r
3217 SetWindowPos(hwndMain, NULL,
\r
3218 wrect.right - winWidth, wrect.top,
\r
3219 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3222 case WMSZ_BOTTOMRIGHT:
\r
3226 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3227 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3232 for (i = 0; i < N_BUTTONS; i++) {
\r
3233 if (buttonDesc[i].hwnd != NULL) {
\r
3234 DestroyWindow(buttonDesc[i].hwnd);
\r
3235 buttonDesc[i].hwnd = NULL;
\r
3237 if (appData.showButtonBar) {
\r
3238 buttonDesc[i].hwnd =
\r
3239 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3240 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3241 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3242 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3243 (HMENU) buttonDesc[i].id,
\r
3244 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3246 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3247 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3248 MAKELPARAM(FALSE, 0));
\r
3250 if (buttonDesc[i].id == IDM_Pause)
\r
3251 hwndPause = buttonDesc[i].hwnd;
\r
3252 buttonDesc[i].wndproc = (WNDPROC)
\r
3253 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3256 if (gridPen != NULL) DeleteObject(gridPen);
\r
3257 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3258 if (premovePen != NULL) DeleteObject(premovePen);
\r
3259 if (lineGap != 0) {
\r
3260 logbrush.lbStyle = BS_SOLID;
\r
3261 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3263 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3264 lineGap, &logbrush, 0, NULL);
\r
3265 logbrush.lbColor = highlightSquareColor;
\r
3267 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3268 lineGap, &logbrush, 0, NULL);
\r
3270 logbrush.lbColor = premoveHighlightColor;
\r
3272 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3273 lineGap, &logbrush, 0, NULL);
\r
3275 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3276 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3277 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3278 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3279 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3280 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3281 BOARD_WIDTH * (squareSize + lineGap);
\r
3282 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3284 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3285 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3286 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3287 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3288 lineGap / 2 + (i * (squareSize + lineGap));
\r
3289 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3290 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3291 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3295 /* [HGM] Licensing requirement */
\r
3297 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3300 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3302 GothicPopUp( "", VariantNormal);
\r
3305 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3306 oldBoardSize = boardSize;
\r
3307 oldTinyLayout = tinyLayout;
\r
3309 /* Load piece bitmaps for this board size */
\r
3310 for (i=0; i<=2; i++) {
\r
3311 for (piece = WhitePawn;
\r
3312 (int) piece < (int) BlackPawn;
\r
3313 piece = (ChessSquare) ((int) piece + 1)) {
\r
3314 if (pieceBitmap[i][piece] != NULL)
\r
3315 DeleteObject(pieceBitmap[i][piece]);
\r
3319 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3320 // Orthodox Chess pieces
\r
3321 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3322 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3323 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3324 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3325 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3326 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3327 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3328 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3329 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3330 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3331 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3332 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3333 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3334 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3335 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3336 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3337 // in Shogi, Hijack the unused Queen for Lance
\r
3338 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3339 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3340 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3342 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3343 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3344 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3347 if(squareSize <= 72 && squareSize >= 33) {
\r
3348 /* A & C are available in most sizes now */
\r
3349 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3350 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3351 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3352 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3353 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3354 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3355 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3356 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3357 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3358 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3359 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3360 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3361 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3362 } else { // Smirf-like
\r
3363 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3364 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3365 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3367 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3368 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3369 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3370 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3371 } else { // WinBoard standard
\r
3372 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3373 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3374 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3379 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3380 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3381 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3382 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3383 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3384 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3385 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3386 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3387 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3388 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3389 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3390 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3391 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3392 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3393 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3394 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3395 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3396 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3397 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3398 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3399 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3400 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3401 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3402 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3403 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3404 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3405 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3406 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3407 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3408 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3409 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3411 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3412 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3413 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3414 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3415 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3416 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3417 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3418 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3419 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3420 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3421 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3422 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3423 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3425 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3426 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3427 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3428 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3429 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3430 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3431 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3432 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3433 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3434 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3435 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3436 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3439 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3440 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3441 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3442 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3443 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3444 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3445 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3446 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3447 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3448 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3449 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3450 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3451 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3452 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3453 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3457 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3458 /* special Shogi support in this size */
\r
3459 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3460 for (piece = WhitePawn;
\r
3461 (int) piece < (int) BlackPawn;
\r
3462 piece = (ChessSquare) ((int) piece + 1)) {
\r
3463 if (pieceBitmap[i][piece] != NULL)
\r
3464 DeleteObject(pieceBitmap[i][piece]);
\r
3467 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3468 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3469 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3470 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3471 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3472 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3473 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3474 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3475 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3476 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3477 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3478 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3479 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3480 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3481 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3482 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3483 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3484 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3485 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3486 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3487 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3488 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3489 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3490 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3491 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3492 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3493 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3494 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3495 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3496 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3497 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3498 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3499 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3500 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3501 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3502 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3503 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3504 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3505 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3506 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3507 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3508 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3514 PieceBitmap(ChessSquare p, int kind)
\r
3516 if ((int) p >= (int) BlackPawn)
\r
3517 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3519 return pieceBitmap[kind][(int) p];
\r
3522 /***************************************************************/
\r
3524 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3525 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3527 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3528 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3532 SquareToPos(int row, int column, int * x, int * y)
\r
3535 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3536 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3538 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3539 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3544 DrawCoordsOnDC(HDC hdc)
\r
3546 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
3547 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
3548 char str[2] = { NULLCHAR, NULLCHAR };
\r
3549 int oldMode, oldAlign, x, y, start, i;
\r
3553 if (!appData.showCoords)
\r
3556 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3558 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3559 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3560 oldAlign = GetTextAlign(hdc);
\r
3561 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3563 y = boardRect.top + lineGap;
\r
3564 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3566 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3567 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3568 str[0] = files[start + i];
\r
3569 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3570 y += squareSize + lineGap;
\r
3573 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3575 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3576 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3577 str[0] = ranks[start + i];
\r
3578 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3579 x += squareSize + lineGap;
\r
3582 SelectObject(hdc, oldBrush);
\r
3583 SetBkMode(hdc, oldMode);
\r
3584 SetTextAlign(hdc, oldAlign);
\r
3585 SelectObject(hdc, oldFont);
\r
3589 DrawGridOnDC(HDC hdc)
\r
3593 if (lineGap != 0) {
\r
3594 oldPen = SelectObject(hdc, gridPen);
\r
3595 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3596 SelectObject(hdc, oldPen);
\r
3600 #define HIGHLIGHT_PEN 0
\r
3601 #define PREMOVE_PEN 1
\r
3604 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3607 HPEN oldPen, hPen;
\r
3608 if (lineGap == 0) return;
\r
3610 x1 = boardRect.left +
\r
3611 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3612 y1 = boardRect.top +
\r
3613 lineGap/2 + y * (squareSize + lineGap);
\r
3615 x1 = boardRect.left +
\r
3616 lineGap/2 + x * (squareSize + lineGap);
\r
3617 y1 = boardRect.top +
\r
3618 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3620 hPen = pen ? premovePen : highlightPen;
\r
3621 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3622 MoveToEx(hdc, x1, y1, NULL);
\r
3623 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3624 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3625 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3626 LineTo(hdc, x1, y1);
\r
3627 SelectObject(hdc, oldPen);
\r
3631 DrawHighlightsOnDC(HDC hdc)
\r
3634 for (i=0; i<2; i++) {
\r
3635 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3636 DrawHighlightOnDC(hdc, TRUE,
\r
3637 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3640 for (i=0; i<2; i++) {
\r
3641 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3642 premoveHighlightInfo.sq[i].y >= 0) {
\r
3643 DrawHighlightOnDC(hdc, TRUE,
\r
3644 premoveHighlightInfo.sq[i].x,
\r
3645 premoveHighlightInfo.sq[i].y,
\r
3651 /* Note: sqcolor is used only in monoMode */
\r
3652 /* Note that this code is largely duplicated in woptions.c,
\r
3653 function DrawSampleSquare, so that needs to be updated too */
\r
3655 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3657 HBITMAP oldBitmap;
\r
3661 if (appData.blindfold) return;
\r
3663 /* [AS] Use font-based pieces if needed */
\r
3664 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3665 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3666 CreatePiecesFromFont();
\r
3668 if( fontBitmapSquareSize == squareSize ) {
\r
3669 int index = TranslatePieceToFontPiece(piece);
\r
3671 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3675 squareSize, squareSize,
\r
3680 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3684 squareSize, squareSize,
\r
3693 if (appData.monoMode) {
\r
3694 SelectObject(tmphdc, PieceBitmap(piece,
\r
3695 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3696 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3697 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3699 tmpSize = squareSize;
\r
3701 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3702 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3703 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3704 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3705 x += (squareSize - minorSize)>>1;
\r
3706 y += squareSize - minorSize - 2;
\r
3707 tmpSize = minorSize;
\r
3709 if (color || appData.allWhite ) {
\r
3710 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3712 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3713 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3714 if(appData.upsideDown && color==flipView)
\r
3715 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3717 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3719 /* Use black piece color for outline of white pieces */
\r
3720 /* Not sure this looks really good (though xboard does it).
\r
3721 Maybe better to have another selectable color, default black */
\r
3722 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3723 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3724 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3726 /* Use black for outline of white pieces */
\r
3727 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3728 if(appData.upsideDown && color==flipView)
\r
3729 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3731 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3735 /* Use white piece color for details of black pieces */
\r
3736 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3737 WHITE_PIECE ones aren't always the right shape. */
\r
3738 /* Not sure this looks really good (though xboard does it).
\r
3739 Maybe better to have another selectable color, default medium gray? */
\r
3740 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3741 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3742 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3743 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3744 SelectObject(hdc, blackPieceBrush);
\r
3745 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3747 /* Use square color for details of black pieces */
\r
3748 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3749 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3750 if(appData.upsideDown && !flipView)
\r
3751 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3753 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3756 SelectObject(hdc, oldBrush);
\r
3757 SelectObject(tmphdc, oldBitmap);
\r
3761 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3762 int GetBackTextureMode( int algo )
\r
3764 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3768 case BACK_TEXTURE_MODE_PLAIN:
\r
3769 result = 1; /* Always use identity map */
\r
3771 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3772 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3780 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3781 to handle redraws cleanly (as random numbers would always be different).
\r
3783 VOID RebuildTextureSquareInfo()
\r
3793 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3795 if( liteBackTexture != NULL ) {
\r
3796 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3797 lite_w = bi.bmWidth;
\r
3798 lite_h = bi.bmHeight;
\r
3802 if( darkBackTexture != NULL ) {
\r
3803 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3804 dark_w = bi.bmWidth;
\r
3805 dark_h = bi.bmHeight;
\r
3809 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3810 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3811 if( (col + row) & 1 ) {
\r
3813 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3814 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3815 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3816 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3821 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3822 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3823 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3824 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3831 /* [AS] Arrow highlighting support */
\r
3833 static int A_WIDTH = 5; /* Width of arrow body */
\r
3835 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3836 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3838 static double Sqr( double x )
\r
3843 static int Round( double x )
\r
3845 return (int) (x + 0.5);
\r
3848 /* Draw an arrow between two points using current settings */
\r
3849 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3852 double dx, dy, j, k, x, y;
\r
3854 if( d_x == s_x ) {
\r
3855 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3857 arrow[0].x = s_x + A_WIDTH;
\r
3860 arrow[1].x = s_x + A_WIDTH;
\r
3861 arrow[1].y = d_y - h;
\r
3863 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3864 arrow[2].y = d_y - h;
\r
3869 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3870 arrow[4].y = d_y - h;
\r
3872 arrow[5].x = s_x - A_WIDTH;
\r
3873 arrow[5].y = d_y - h;
\r
3875 arrow[6].x = s_x - A_WIDTH;
\r
3878 else if( d_y == s_y ) {
\r
3879 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3882 arrow[0].y = s_y + A_WIDTH;
\r
3884 arrow[1].x = d_x - w;
\r
3885 arrow[1].y = s_y + A_WIDTH;
\r
3887 arrow[2].x = d_x - w;
\r
3888 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3893 arrow[4].x = d_x - w;
\r
3894 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3896 arrow[5].x = d_x - w;
\r
3897 arrow[5].y = s_y - A_WIDTH;
\r
3900 arrow[6].y = s_y - A_WIDTH;
\r
3903 /* [AS] Needed a lot of paper for this! :-) */
\r
3904 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3905 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3907 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3909 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3914 arrow[0].x = Round(x - j);
\r
3915 arrow[0].y = Round(y + j*dx);
\r
3917 arrow[1].x = Round(x + j);
\r
3918 arrow[1].y = Round(y - j*dx);
\r
3921 x = (double) d_x - k;
\r
3922 y = (double) d_y - k*dy;
\r
3925 x = (double) d_x + k;
\r
3926 y = (double) d_y + k*dy;
\r
3929 arrow[2].x = Round(x + j);
\r
3930 arrow[2].y = Round(y - j*dx);
\r
3932 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3933 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3938 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3939 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3941 arrow[6].x = Round(x - j);
\r
3942 arrow[6].y = Round(y + j*dx);
\r
3945 Polygon( hdc, arrow, 7 );
\r
3948 /* [AS] Draw an arrow between two squares */
\r
3949 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3951 int s_x, s_y, d_x, d_y;
\r
3958 if( s_col == d_col && s_row == d_row ) {
\r
3962 /* Get source and destination points */
\r
3963 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3964 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3967 d_y += squareSize / 4;
\r
3969 else if( d_y < s_y ) {
\r
3970 d_y += 3 * squareSize / 4;
\r
3973 d_y += squareSize / 2;
\r
3977 d_x += squareSize / 4;
\r
3979 else if( d_x < s_x ) {
\r
3980 d_x += 3 * squareSize / 4;
\r
3983 d_x += squareSize / 2;
\r
3986 s_x += squareSize / 2;
\r
3987 s_y += squareSize / 2;
\r
3989 /* Adjust width */
\r
3990 A_WIDTH = squareSize / 14;
\r
3993 stLB.lbStyle = BS_SOLID;
\r
3994 stLB.lbColor = appData.highlightArrowColor;
\r
3997 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3998 holdpen = SelectObject( hdc, hpen );
\r
3999 hbrush = CreateBrushIndirect( &stLB );
\r
4000 holdbrush = SelectObject( hdc, hbrush );
\r
4002 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4004 SelectObject( hdc, holdpen );
\r
4005 SelectObject( hdc, holdbrush );
\r
4006 DeleteObject( hpen );
\r
4007 DeleteObject( hbrush );
\r
4010 BOOL HasHighlightInfo()
\r
4012 BOOL result = FALSE;
\r
4014 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4015 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4023 BOOL IsDrawArrowEnabled()
\r
4025 BOOL result = FALSE;
\r
4027 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4034 VOID DrawArrowHighlight( HDC hdc )
\r
4036 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4037 DrawArrowBetweenSquares( hdc,
\r
4038 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4039 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4043 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4045 HRGN result = NULL;
\r
4047 if( HasHighlightInfo() ) {
\r
4048 int x1, y1, x2, y2;
\r
4049 int sx, sy, dx, dy;
\r
4051 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4052 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4054 sx = MIN( x1, x2 );
\r
4055 sy = MIN( y1, y2 );
\r
4056 dx = MAX( x1, x2 ) + squareSize;
\r
4057 dy = MAX( y1, y2 ) + squareSize;
\r
4059 result = CreateRectRgn( sx, sy, dx, dy );
\r
4066 Warning: this function modifies the behavior of several other functions.
\r
4068 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4069 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4070 repaint is scattered all over the place, which is not good for features such as
\r
4071 "arrow highlighting" that require a full repaint of the board.
\r
4073 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4074 user interaction, when speed is not so important) but especially to avoid errors
\r
4075 in the displayed graphics.
\r
4077 In such patched places, I always try refer to this function so there is a single
\r
4078 place to maintain knowledge.
\r
4080 To restore the original behavior, just return FALSE unconditionally.
\r
4082 BOOL IsFullRepaintPreferrable()
\r
4084 BOOL result = FALSE;
\r
4086 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4087 /* Arrow may appear on the board */
\r
4095 This function is called by DrawPosition to know whether a full repaint must
\r
4098 Only DrawPosition may directly call this function, which makes use of
\r
4099 some state information. Other function should call DrawPosition specifying
\r
4100 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4102 BOOL DrawPositionNeedsFullRepaint()
\r
4104 BOOL result = FALSE;
\r
4107 Probably a slightly better policy would be to trigger a full repaint
\r
4108 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4109 but animation is fast enough that it's difficult to notice.
\r
4111 if( animInfo.piece == EmptySquare ) {
\r
4112 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4121 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4123 int row, column, x, y, square_color, piece_color;
\r
4124 ChessSquare piece;
\r
4126 HDC texture_hdc = NULL;
\r
4128 /* [AS] Initialize background textures if needed */
\r
4129 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4130 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4131 if( backTextureSquareSize != squareSize
\r
4132 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4133 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4134 backTextureSquareSize = squareSize;
\r
4135 RebuildTextureSquareInfo();
\r
4138 texture_hdc = CreateCompatibleDC( hdc );
\r
4141 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4142 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4144 SquareToPos(row, column, &x, &y);
\r
4146 piece = board[row][column];
\r
4148 square_color = ((column + row) % 2) == 1;
\r
4149 if( gameInfo.variant == VariantXiangqi ) {
\r
4150 square_color = !InPalace(row, column);
\r
4151 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4152 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4154 piece_color = (int) piece < (int) BlackPawn;
\r
4157 /* [HGM] holdings file: light square or black */
\r
4158 if(column == BOARD_LEFT-2) {
\r
4159 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4162 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4166 if(column == BOARD_RGHT + 1 ) {
\r
4167 if( row < gameInfo.holdingsSize )
\r
4170 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4174 if(column == BOARD_LEFT-1 ) /* left align */
\r
4175 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4176 else if( column == BOARD_RGHT) /* right align */
\r
4177 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4179 if (appData.monoMode) {
\r
4180 if (piece == EmptySquare) {
\r
4181 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4182 square_color ? WHITENESS : BLACKNESS);
\r
4184 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4187 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4188 /* [AS] Draw the square using a texture bitmap */
\r
4189 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4190 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4191 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4194 squareSize, squareSize,
\r
4197 backTextureSquareInfo[r][c].mode,
\r
4198 backTextureSquareInfo[r][c].x,
\r
4199 backTextureSquareInfo[r][c].y );
\r
4201 SelectObject( texture_hdc, hbm );
\r
4203 if (piece != EmptySquare) {
\r
4204 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4208 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4210 oldBrush = SelectObject(hdc, brush );
\r
4211 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4212 SelectObject(hdc, oldBrush);
\r
4213 if (piece != EmptySquare)
\r
4214 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4219 if( texture_hdc != NULL ) {
\r
4220 DeleteDC( texture_hdc );
\r
4224 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4225 void fputDW(FILE *f, int x)
\r
4227 fputc(x & 255, f);
\r
4228 fputc(x>>8 & 255, f);
\r
4229 fputc(x>>16 & 255, f);
\r
4230 fputc(x>>24 & 255, f);
\r
4233 #define MAX_CLIPS 200 /* more than enough */
\r
4236 DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)
\r
4238 // HBITMAP bufferBitmap;
\r
4243 int w = 100, h = 50;
\r
4245 if(cps->programLogo == NULL) return;
\r
4246 // GetClientRect(hwndMain, &Rect);
\r
4247 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4248 // Rect.bottom-Rect.top+1);
\r
4249 tmphdc = CreateCompatibleDC(hdc);
\r
4250 hbm = SelectObject(tmphdc, (HBITMAP) cps->programLogo);
\r
4251 if( GetObject( cps->programLogo, sizeof(bi), &bi ) > 0 ) {
\r
4255 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4256 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4257 SelectObject(tmphdc, hbm);
\r
4262 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4264 static Board lastReq, lastDrawn;
\r
4265 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4266 static int lastDrawnFlipView = 0;
\r
4267 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4268 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4271 HBITMAP bufferBitmap;
\r
4272 HBITMAP oldBitmap;
\r
4274 HRGN clips[MAX_CLIPS];
\r
4275 ChessSquare dragged_piece = EmptySquare;
\r
4277 /* I'm undecided on this - this function figures out whether a full
\r
4278 * repaint is necessary on its own, so there's no real reason to have the
\r
4279 * caller tell it that. I think this can safely be set to FALSE - but
\r
4280 * if we trust the callers not to request full repaints unnessesarily, then
\r
4281 * we could skip some clipping work. In other words, only request a full
\r
4282 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4283 * gamestart and similar) --Hawk
\r
4285 Boolean fullrepaint = repaint;
\r
4287 if( DrawPositionNeedsFullRepaint() ) {
\r
4288 fullrepaint = TRUE;
\r
4292 if( fullrepaint ) {
\r
4293 static int repaint_count = 0;
\r
4297 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4298 OutputDebugString( buf );
\r
4302 if (board == NULL) {
\r
4303 if (!lastReqValid) {
\r
4308 CopyBoard(lastReq, board);
\r
4312 if (doingSizing) {
\r
4316 if (IsIconic(hwndMain)) {
\r
4320 if (hdc == NULL) {
\r
4321 hdc = GetDC(hwndMain);
\r
4322 if (!appData.monoMode) {
\r
4323 SelectPalette(hdc, hPal, FALSE);
\r
4324 RealizePalette(hdc);
\r
4328 releaseDC = FALSE;
\r
4332 fprintf(debugFP, "*******************************\n"
\r
4334 "dragInfo.from (%d,%d)\n"
\r
4335 "dragInfo.start (%d,%d)\n"
\r
4336 "dragInfo.pos (%d,%d)\n"
\r
4337 "dragInfo.lastpos (%d,%d)\n",
\r
4338 repaint ? "TRUE" : "FALSE",
\r
4339 dragInfo.from.x, dragInfo.from.y,
\r
4340 dragInfo.start.x, dragInfo.start.y,
\r
4341 dragInfo.pos.x, dragInfo.pos.y,
\r
4342 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4343 fprintf(debugFP, "prev: ");
\r
4344 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4345 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4346 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4349 fprintf(debugFP, "\n");
\r
4350 fprintf(debugFP, "board: ");
\r
4351 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4352 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4353 fprintf(debugFP, "%d ", board[row][column]);
\r
4356 fprintf(debugFP, "\n");
\r
4360 /* Create some work-DCs */
\r
4361 hdcmem = CreateCompatibleDC(hdc);
\r
4362 tmphdc = CreateCompatibleDC(hdc);
\r
4364 /* If dragging is in progress, we temporarely remove the piece */
\r
4365 /* [HGM] or temporarily decrease count if stacked */
\r
4366 /* !! Moved to before board compare !! */
\r
4367 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4368 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4369 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4370 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4371 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4373 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4374 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4375 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4377 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4380 /* Figure out which squares need updating by comparing the
\r
4381 * newest board with the last drawn board and checking if
\r
4382 * flipping has changed.
\r
4384 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4385 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4386 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4387 if (lastDrawn[row][column] != board[row][column]) {
\r
4388 SquareToPos(row, column, &x, &y);
\r
4389 clips[num_clips++] =
\r
4390 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4394 for (i=0; i<2; i++) {
\r
4395 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4396 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4397 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4398 lastDrawnHighlight.sq[i].y >= 0) {
\r
4399 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4400 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4401 clips[num_clips++] =
\r
4402 CreateRectRgn(x - lineGap, y - lineGap,
\r
4403 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4405 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4406 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4407 clips[num_clips++] =
\r
4408 CreateRectRgn(x - lineGap, y - lineGap,
\r
4409 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4413 for (i=0; i<2; i++) {
\r
4414 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4415 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4416 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4417 lastDrawnPremove.sq[i].y >= 0) {
\r
4418 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4419 lastDrawnPremove.sq[i].x, &x, &y);
\r
4420 clips[num_clips++] =
\r
4421 CreateRectRgn(x - lineGap, y - lineGap,
\r
4422 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4424 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4425 premoveHighlightInfo.sq[i].y >= 0) {
\r
4426 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4427 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4428 clips[num_clips++] =
\r
4429 CreateRectRgn(x - lineGap, y - lineGap,
\r
4430 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4435 fullrepaint = TRUE;
\r
4438 /* Create a buffer bitmap - this is the actual bitmap
\r
4439 * being written to. When all the work is done, we can
\r
4440 * copy it to the real DC (the screen). This avoids
\r
4441 * the problems with flickering.
\r
4443 GetClientRect(hwndMain, &Rect);
\r
4444 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4445 Rect.bottom-Rect.top+1);
\r
4446 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4447 if (!appData.monoMode) {
\r
4448 SelectPalette(hdcmem, hPal, FALSE);
\r
4451 /* Create clips for dragging */
\r
4452 if (!fullrepaint) {
\r
4453 if (dragInfo.from.x >= 0) {
\r
4454 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4455 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4457 if (dragInfo.start.x >= 0) {
\r
4458 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4459 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4461 if (dragInfo.pos.x >= 0) {
\r
4462 x = dragInfo.pos.x - squareSize / 2;
\r
4463 y = dragInfo.pos.y - squareSize / 2;
\r
4464 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4466 if (dragInfo.lastpos.x >= 0) {
\r
4467 x = dragInfo.lastpos.x - squareSize / 2;
\r
4468 y = dragInfo.lastpos.y - squareSize / 2;
\r
4469 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4473 /* Are we animating a move?
\r
4475 * - remove the piece from the board (temporarely)
\r
4476 * - calculate the clipping region
\r
4478 if (!fullrepaint) {
\r
4479 if (animInfo.piece != EmptySquare) {
\r
4480 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4481 x = boardRect.left + animInfo.lastpos.x;
\r
4482 y = boardRect.top + animInfo.lastpos.y;
\r
4483 x2 = boardRect.left + animInfo.pos.x;
\r
4484 y2 = boardRect.top + animInfo.pos.y;
\r
4485 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4486 /* Slight kludge. The real problem is that after AnimateMove is
\r
4487 done, the position on the screen does not match lastDrawn.
\r
4488 This currently causes trouble only on e.p. captures in
\r
4489 atomic, where the piece moves to an empty square and then
\r
4490 explodes. The old and new positions both had an empty square
\r
4491 at the destination, but animation has drawn a piece there and
\r
4492 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4493 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4497 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4498 if (num_clips == 0)
\r
4499 fullrepaint = TRUE;
\r
4501 /* Set clipping on the memory DC */
\r
4502 if (!fullrepaint) {
\r
4503 SelectClipRgn(hdcmem, clips[0]);
\r
4504 for (x = 1; x < num_clips; x++) {
\r
4505 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4506 abort(); // this should never ever happen!
\r
4510 /* Do all the drawing to the memory DC */
\r
4511 if(explodeInfo.radius) { // [HGM] atomic
\r
4513 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4514 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4515 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4516 x += squareSize/2;
\r
4517 y += squareSize/2;
\r
4518 if(!fullrepaint) {
\r
4519 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4520 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4522 DrawGridOnDC(hdcmem);
\r
4523 DrawHighlightsOnDC(hdcmem);
\r
4524 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4525 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4526 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4527 SelectObject(hdcmem, oldBrush);
\r
4529 DrawGridOnDC(hdcmem);
\r
4530 DrawHighlightsOnDC(hdcmem);
\r
4531 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4534 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);
\r
4535 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);
\r
4538 if( appData.highlightMoveWithArrow ) {
\r
4539 DrawArrowHighlight(hdcmem);
\r
4542 DrawCoordsOnDC(hdcmem);
\r
4544 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4545 /* to make sure lastDrawn contains what is actually drawn */
\r
4547 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4548 if (dragged_piece != EmptySquare) {
\r
4549 /* [HGM] or restack */
\r
4550 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4551 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4553 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4554 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4555 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4556 x = dragInfo.pos.x - squareSize / 2;
\r
4557 y = dragInfo.pos.y - squareSize / 2;
\r
4558 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4559 ((int) dragged_piece < (int) BlackPawn),
\r
4560 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4563 /* Put the animated piece back into place and draw it */
\r
4564 if (animInfo.piece != EmptySquare) {
\r
4565 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4566 x = boardRect.left + animInfo.pos.x;
\r
4567 y = boardRect.top + animInfo.pos.y;
\r
4568 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4569 ((int) animInfo.piece < (int) BlackPawn),
\r
4570 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4573 /* Release the bufferBitmap by selecting in the old bitmap
\r
4574 * and delete the memory DC
\r
4576 SelectObject(hdcmem, oldBitmap);
\r
4579 /* Set clipping on the target DC */
\r
4580 if (!fullrepaint) {
\r
4581 SelectClipRgn(hdc, clips[0]);
\r
4582 for (x = 1; x < num_clips; x++) {
\r
4583 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4584 abort(); // this should never ever happen!
\r
4588 /* Copy the new bitmap onto the screen in one go.
\r
4589 * This way we avoid any flickering
\r
4591 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4592 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4593 boardRect.right - boardRect.left,
\r
4594 boardRect.bottom - boardRect.top,
\r
4595 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4596 if(saveDiagFlag) {
\r
4597 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4598 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4600 GetObject(bufferBitmap, sizeof(b), &b);
\r
4601 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4602 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4603 bih.biWidth = b.bmWidth;
\r
4604 bih.biHeight = b.bmHeight;
\r
4606 bih.biBitCount = b.bmBitsPixel;
\r
4607 bih.biCompression = 0;
\r
4608 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4609 bih.biXPelsPerMeter = 0;
\r
4610 bih.biYPelsPerMeter = 0;
\r
4611 bih.biClrUsed = 0;
\r
4612 bih.biClrImportant = 0;
\r
4613 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4614 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4615 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4616 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4619 wb = b.bmWidthBytes;
\r
4621 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4622 int k = ((int*) pData)[i];
\r
4623 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4624 if(j >= 16) break;
\r
4626 if(j >= nrColors) nrColors = j+1;
\r
4628 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4630 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4631 for(w=0; w<(wb>>2); w+=2) {
\r
4632 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4633 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4634 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4635 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4636 pData[p++] = m | j<<4;
\r
4638 while(p&3) pData[p++] = 0;
\r
4641 wb = ((wb+31)>>5)<<2;
\r
4643 // write BITMAPFILEHEADER
\r
4644 fprintf(diagFile, "BM");
\r
4645 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4646 fputDW(diagFile, 0);
\r
4647 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4648 // write BITMAPINFOHEADER
\r
4649 fputDW(diagFile, 40);
\r
4650 fputDW(diagFile, b.bmWidth);
\r
4651 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4652 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4653 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4654 fputDW(diagFile, 0);
\r
4655 fputDW(diagFile, 0);
\r
4656 fputDW(diagFile, 0);
\r
4657 fputDW(diagFile, 0);
\r
4658 fputDW(diagFile, 0);
\r
4659 fputDW(diagFile, 0);
\r
4660 // write color table
\r
4662 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4663 // write bitmap data
\r
4664 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4665 fputc(pData[i], diagFile);
\r
4670 SelectObject(tmphdc, oldBitmap);
\r
4672 /* Massive cleanup */
\r
4673 for (x = 0; x < num_clips; x++)
\r
4674 DeleteObject(clips[x]);
\r
4677 DeleteObject(bufferBitmap);
\r
4680 ReleaseDC(hwndMain, hdc);
\r
4682 if (lastDrawnFlipView != flipView) {
\r
4684 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4686 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4689 /* CopyBoard(lastDrawn, board);*/
\r
4690 lastDrawnHighlight = highlightInfo;
\r
4691 lastDrawnPremove = premoveHighlightInfo;
\r
4692 lastDrawnFlipView = flipView;
\r
4693 lastDrawnValid = 1;
\r
4696 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4701 saveDiagFlag = 1; diagFile = f;
\r
4702 HDCDrawPosition(NULL, TRUE, NULL);
\r
4706 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4713 /*---------------------------------------------------------------------------*\
\r
4714 | CLIENT PAINT PROCEDURE
\r
4715 | This is the main event-handler for the WM_PAINT message.
\r
4717 \*---------------------------------------------------------------------------*/
\r
4719 PaintProc(HWND hwnd)
\r
4725 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4726 if (IsIconic(hwnd)) {
\r
4727 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4729 if (!appData.monoMode) {
\r
4730 SelectPalette(hdc, hPal, FALSE);
\r
4731 RealizePalette(hdc);
\r
4733 HDCDrawPosition(hdc, 1, NULL);
\r
4735 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4736 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4737 ETO_CLIPPED|ETO_OPAQUE,
\r
4738 &messageRect, messageText, strlen(messageText), NULL);
\r
4739 SelectObject(hdc, oldFont);
\r
4740 DisplayBothClocks();
\r
4742 EndPaint(hwnd,&ps);
\r
4750 * If the user selects on a border boundary, return -1; if off the board,
\r
4751 * return -2. Otherwise map the event coordinate to the square.
\r
4752 * The offset boardRect.left or boardRect.top must already have been
\r
4753 * subtracted from x.
\r
4756 EventToSquare(int x)
\r
4763 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4765 x /= (squareSize + lineGap);
\r
4766 if (x >= BOARD_SIZE)
\r
4777 DropEnable dropEnables[] = {
\r
4778 { 'P', DP_Pawn, "Pawn" },
\r
4779 { 'N', DP_Knight, "Knight" },
\r
4780 { 'B', DP_Bishop, "Bishop" },
\r
4781 { 'R', DP_Rook, "Rook" },
\r
4782 { 'Q', DP_Queen, "Queen" },
\r
4786 SetupDropMenu(HMENU hmenu)
\r
4788 int i, count, enable;
\r
4790 extern char white_holding[], black_holding[];
\r
4791 char item[MSG_SIZ];
\r
4793 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4794 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4795 dropEnables[i].piece);
\r
4797 while (p && *p++ == dropEnables[i].piece) count++;
\r
4798 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4799 enable = count > 0 || !appData.testLegality
\r
4800 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4801 && !appData.icsActive);
\r
4802 ModifyMenu(hmenu, dropEnables[i].command,
\r
4803 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4804 dropEnables[i].command, item);
\r
4808 static int fromX = -1, fromY = -1, toX, toY;
\r
4810 /* Event handler for mouse messages */
\r
4812 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4816 static int recursive = 0;
\r
4818 // BOOLEAN needsRedraw = FALSE;
\r
4819 BOOLEAN saveAnimate;
\r
4820 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4821 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4822 ChessMove moveType;
\r
4825 if (message == WM_MBUTTONUP) {
\r
4826 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4827 to the middle button: we simulate pressing the left button too!
\r
4829 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4830 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4836 pt.x = LOWORD(lParam);
\r
4837 pt.y = HIWORD(lParam);
\r
4838 x = EventToSquare(pt.x - boardRect.left);
\r
4839 y = EventToSquare(pt.y - boardRect.top);
\r
4840 if (!flipView && y >= 0) {
\r
4841 y = BOARD_HEIGHT - 1 - y;
\r
4843 if (flipView && x >= 0) {
\r
4844 x = BOARD_WIDTH - 1 - x;
\r
4847 switch (message) {
\r
4848 case WM_LBUTTONDOWN:
\r
4849 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4850 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4851 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4852 if(gameInfo.holdingsWidth &&
\r
4853 (WhiteOnMove(currentMove)
\r
4854 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4855 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4856 // click in right holdings, for determining promotion piece
\r
4857 ChessSquare p = boards[currentMove][y][x];
\r
4858 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4859 if(p != EmptySquare) {
\r
4860 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4861 fromX = fromY = -1;
\r
4865 DrawPosition(FALSE, boards[currentMove]);
\r
4869 sameAgain = FALSE;
\r
4871 /* Downclick vertically off board; check if on clock */
\r
4872 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4873 if (gameMode == EditPosition) {
\r
4874 SetWhiteToPlayEvent();
\r
4875 } else if (gameMode == IcsPlayingBlack ||
\r
4876 gameMode == MachinePlaysWhite) {
\r
4878 } else if (gameMode == EditGame) {
\r
4879 AdjustClock((logoHeight > 0 ? flipView: flipClock), -1);
\r
4881 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4882 if (gameMode == EditPosition) {
\r
4883 SetBlackToPlayEvent();
\r
4884 } else if (gameMode == IcsPlayingWhite ||
\r
4885 gameMode == MachinePlaysBlack) {
\r
4887 } else if (gameMode == EditGame) {
\r
4888 AdjustClock(!(logoHeight > 0 ? flipView: flipClock), -1);
\r
4891 if (!appData.highlightLastMove) {
\r
4892 ClearHighlights();
\r
4893 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4895 fromX = fromY = -1;
\r
4896 dragInfo.start.x = dragInfo.start.y = -1;
\r
4897 dragInfo.from = dragInfo.start;
\r
4899 } else if (x < 0 || y < 0
\r
4900 /* [HGM] block clicks between board and holdings */
\r
4901 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4902 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4903 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4904 /* EditPosition, empty square, or different color piece;
\r
4905 click-click move is possible */
\r
4908 } else if (fromX == x && fromY == y) {
\r
4909 /* Downclick on same square again */
\r
4910 ClearHighlights();
\r
4911 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4912 sameAgain = TRUE;
\r
4913 } else if (fromX != -1 &&
\r
4914 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4916 /* Downclick on different square. */
\r
4917 /* [HGM] if on holdings file, should count as new first click ! */
\r
4918 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4921 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4922 to make sure move is legal before showing promotion popup */
\r
4923 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4924 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4925 fromX = fromY = -1;
\r
4926 ClearHighlights();
\r
4927 DrawPosition(FALSE, boards[currentMove]);
\r
4930 if(moveType != ImpossibleMove) {
\r
4931 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4932 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4933 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4934 appData.alwaysPromoteToQueen)) {
\r
4935 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4936 if (!appData.highlightLastMove) {
\r
4937 ClearHighlights();
\r
4938 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4941 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4942 SetHighlights(fromX, fromY, toX, toY);
\r
4943 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4944 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4945 If promotion to Q is legal, all are legal! */
\r
4946 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4947 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4948 // kludge to temporarily execute move on display, wthout promotng yet
\r
4949 promotionChoice = TRUE;
\r
4950 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4951 boards[currentMove][toY][toX] = p;
\r
4952 DrawPosition(FALSE, boards[currentMove]);
\r
4953 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4954 boards[currentMove][toY][toX] = q;
\r
4956 PromotionPopup(hwnd);
\r
4957 } else { /* not a promotion */
\r
4958 if (appData.animate || appData.highlightLastMove) {
\r
4959 SetHighlights(fromX, fromY, toX, toY);
\r
4961 ClearHighlights();
\r
4963 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4964 fromX = fromY = -1;
\r
4965 if (appData.animate && !appData.highlightLastMove) {
\r
4966 ClearHighlights();
\r
4967 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4973 /* [HGM] it seemed that braces were missing here */
\r
4974 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4975 fromX = fromY = -1;
\r
4979 ClearHighlights();
\r
4980 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4982 /* First downclick, or restart on a square with same color piece */
\r
4983 if (!frozen && OKToStartUserMove(x, y)) {
\r
4986 dragInfo.lastpos = pt;
\r
4987 dragInfo.from.x = fromX;
\r
4988 dragInfo.from.y = fromY;
\r
4989 dragInfo.start = dragInfo.from;
\r
4990 SetCapture(hwndMain);
\r
4992 fromX = fromY = -1;
\r
4993 dragInfo.start.x = dragInfo.start.y = -1;
\r
4994 dragInfo.from = dragInfo.start;
\r
4995 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4999 case WM_LBUTTONUP:
\r
5001 if (fromX == -1) break;
\r
5002 if (x == fromX && y == fromY) {
\r
5003 dragInfo.from.x = dragInfo.from.y = -1;
\r
5004 /* Upclick on same square */
\r
5006 /* Clicked same square twice: abort click-click move */
\r
5007 fromX = fromY = -1;
\r
5009 ClearPremoveHighlights();
\r
5011 /* First square clicked: start click-click move */
\r
5012 SetHighlights(fromX, fromY, -1, -1);
\r
5014 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5015 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5016 /* Errant click; ignore */
\r
5019 /* Finish drag move. */
\r
5020 if (appData.debugMode) {
\r
5021 fprintf(debugFP, "release\n");
\r
5023 dragInfo.from.x = dragInfo.from.y = -1;
\r
5026 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5027 appData.animate = appData.animate && !appData.animateDragging;
\r
5028 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5029 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5030 fromX = fromY = -1;
\r
5031 ClearHighlights();
\r
5032 DrawPosition(FALSE, boards[currentMove]);
\r
5035 if(moveType != ImpossibleMove) {
\r
5036 /* [HGM] use move type to determine if move is promotion.
\r
5037 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5038 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5039 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5040 appData.alwaysPromoteToQueen))
\r
5041 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5043 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5044 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5045 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5046 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5047 // kludge to temporarily execute move on display, wthout promotng yet
\r
5048 promotionChoice = TRUE;
\r
5049 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5050 boards[currentMove][toY][toX] = p;
\r
5051 DrawPosition(FALSE, boards[currentMove]);
\r
5052 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5053 boards[currentMove][toY][toX] = q;
\r
5056 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5058 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5059 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5060 moveType == WhiteCapturesEnPassant ||
\r
5061 moveType == BlackCapturesEnPassant ) )
\r
5062 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5063 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5066 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5067 appData.animate = saveAnimate;
\r
5068 fromX = fromY = -1;
\r
5069 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5070 ClearHighlights();
\r
5072 if (appData.animate || appData.animateDragging ||
\r
5073 appData.highlightDragging || gotPremove) {
\r
5074 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5077 dragInfo.start.x = dragInfo.start.y = -1;
\r
5078 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5081 case WM_MOUSEMOVE:
\r
5082 if ((appData.animateDragging || appData.highlightDragging)
\r
5083 && (wParam & MK_LBUTTON)
\r
5084 && dragInfo.from.x >= 0)
\r
5086 BOOL full_repaint = FALSE;
\r
5088 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5089 if (appData.animateDragging) {
\r
5090 dragInfo.pos = pt;
\r
5092 if (appData.highlightDragging) {
\r
5093 SetHighlights(fromX, fromY, x, y);
\r
5094 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5095 full_repaint = TRUE;
\r
5099 DrawPosition( full_repaint, NULL);
\r
5101 dragInfo.lastpos = dragInfo.pos;
\r
5105 case WM_MOUSEWHEEL: // [DM]
\r
5106 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5107 /* Mouse Wheel is being rolled forward
\r
5108 * Play moves forward
\r
5110 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5111 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5112 /* Mouse Wheel is being rolled backward
\r
5113 * Play moves backward
\r
5115 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5116 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5120 case WM_MBUTTONDOWN:
\r
5121 case WM_RBUTTONDOWN:
\r
5124 fromX = fromY = -1;
\r
5125 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5126 dragInfo.start.x = dragInfo.start.y = -1;
\r
5127 dragInfo.from = dragInfo.start;
\r
5128 dragInfo.lastpos = dragInfo.pos;
\r
5129 if (appData.highlightDragging) {
\r
5130 ClearHighlights();
\r
5133 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5134 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5135 if (gameMode == EditGame) AdjustClock((logoHeight > 0 ? flipView: flipClock), 1);
\r
5136 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5137 if (gameMode == EditGame) AdjustClock(!(logoHeight > 0 ? flipView: flipClock), 1);
\r
5140 DrawPosition(TRUE, NULL);
\r
5142 switch (gameMode) {
\r
5143 case EditPosition:
\r
5144 case IcsExamining:
\r
5145 if (x < 0 || y < 0) break;
\r
5148 if (message == WM_MBUTTONDOWN) {
\r
5149 buttonCount = 3; /* even if system didn't think so */
\r
5150 if (wParam & MK_SHIFT)
\r
5151 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5153 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5154 } else { /* message == WM_RBUTTONDOWN */
\r
5156 if (buttonCount == 3) {
\r
5157 if (wParam & MK_SHIFT)
\r
5158 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5160 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5162 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5165 /* Just have one menu, on the right button. Windows users don't
\r
5166 think to try the middle one, and sometimes other software steals
\r
5167 it, or it doesn't really exist. */
\r
5168 if(gameInfo.variant != VariantShogi)
\r
5169 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5171 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5175 case IcsPlayingWhite:
\r
5176 case IcsPlayingBlack:
\r
5178 case MachinePlaysWhite:
\r
5179 case MachinePlaysBlack:
\r
5180 if (appData.testLegality &&
\r
5181 gameInfo.variant != VariantBughouse &&
\r
5182 gameInfo.variant != VariantCrazyhouse) break;
\r
5183 if (x < 0 || y < 0) break;
\r
5186 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5187 SetupDropMenu(hmenu);
\r
5188 MenuPopup(hwnd, pt, hmenu, -1);
\r
5199 /* Preprocess messages for buttons in main window */
\r
5201 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5203 int id = GetWindowLong(hwnd, GWL_ID);
\r
5206 for (i=0; i<N_BUTTONS; i++) {
\r
5207 if (buttonDesc[i].id == id) break;
\r
5209 if (i == N_BUTTONS) return 0;
\r
5210 switch (message) {
\r
5215 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5216 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5223 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5226 if (appData.icsActive) {
\r
5227 if (GetKeyState(VK_SHIFT) < 0) {
\r
5229 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5230 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5234 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5235 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5242 if (appData.icsActive) {
\r
5243 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5244 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5246 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5248 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5249 PopUpMoveDialog((char)wParam);
\r
5255 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5258 /* Process messages for Promotion dialog box */
\r
5260 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5264 switch (message) {
\r
5265 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5266 /* Center the dialog over the application window */
\r
5267 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5268 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5269 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5270 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5271 SW_SHOW : SW_HIDE);
\r
5272 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5273 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5274 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5275 PieceToChar(WhiteAngel) != '~') ||
\r
5276 (PieceToChar(BlackAngel) >= 'A' &&
\r
5277 PieceToChar(BlackAngel) != '~') ) ?
\r
5278 SW_SHOW : SW_HIDE);
\r
5279 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5280 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5281 PieceToChar(WhiteMarshall) != '~') ||
\r
5282 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5283 PieceToChar(BlackMarshall) != '~') ) ?
\r
5284 SW_SHOW : SW_HIDE);
\r
5285 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5286 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5287 gameInfo.variant != VariantShogi ?
\r
5288 SW_SHOW : SW_HIDE);
\r
5289 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5290 gameInfo.variant != VariantShogi ?
\r
5291 SW_SHOW : SW_HIDE);
\r
5292 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5293 gameInfo.variant == VariantShogi ?
\r
5294 SW_SHOW : SW_HIDE);
\r
5295 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5296 gameInfo.variant == VariantShogi ?
\r
5297 SW_SHOW : SW_HIDE);
\r
5298 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5299 gameInfo.variant == VariantSuper ?
\r
5300 SW_SHOW : SW_HIDE);
\r
5303 case WM_COMMAND: /* message: received a command */
\r
5304 switch (LOWORD(wParam)) {
\r
5306 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5307 ClearHighlights();
\r
5308 DrawPosition(FALSE, NULL);
\r
5311 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5314 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5317 promoChar = PieceToChar(BlackRook);
\r
5320 promoChar = PieceToChar(BlackBishop);
\r
5322 case PB_Chancellor:
\r
5323 promoChar = PieceToChar(BlackMarshall);
\r
5325 case PB_Archbishop:
\r
5326 promoChar = PieceToChar(BlackAngel);
\r
5329 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5334 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5335 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5336 only show the popup when we are already sure the move is valid or
\r
5337 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5338 will figure out it is a promotion from the promoChar. */
\r
5339 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5340 if (!appData.highlightLastMove) {
\r
5341 ClearHighlights();
\r
5342 DrawPosition(FALSE, NULL);
\r
5349 /* Pop up promotion dialog */
\r
5351 PromotionPopup(HWND hwnd)
\r
5355 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5356 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5357 hwnd, (DLGPROC)lpProc);
\r
5358 FreeProcInstance(lpProc);
\r
5361 /* Toggle ShowThinking */
\r
5363 ToggleShowThinking()
\r
5365 appData.showThinking = !appData.showThinking;
\r
5366 ShowThinkingEvent();
\r
5370 LoadGameDialog(HWND hwnd, char* title)
\r
5374 char fileTitle[MSG_SIZ];
\r
5375 f = OpenFileDialog(hwnd, "rb", "",
\r
5376 appData.oldSaveStyle ? "gam" : "pgn",
\r
5378 title, &number, fileTitle, NULL);
\r
5380 cmailMsgLoaded = FALSE;
\r
5381 if (number == 0) {
\r
5382 int error = GameListBuild(f);
\r
5384 DisplayError("Cannot build game list", error);
\r
5385 } else if (!ListEmpty(&gameList) &&
\r
5386 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5387 GameListPopUp(f, fileTitle);
\r
5390 GameListDestroy();
\r
5393 LoadGame(f, number, fileTitle, FALSE);
\r
5398 ChangedConsoleFont()
\r
5401 CHARRANGE tmpsel, sel;
\r
5402 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5403 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5404 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5407 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5408 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5409 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5410 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5411 * size. This was undocumented in the version of MSVC++ that I had
\r
5412 * when I wrote the code, but is apparently documented now.
\r
5414 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5415 cfmt.bCharSet = f->lf.lfCharSet;
\r
5416 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5417 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5418 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5419 /* Why are the following seemingly needed too? */
\r
5420 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5421 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5422 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5424 tmpsel.cpMax = -1; /*999999?*/
\r
5425 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5426 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5427 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5428 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5430 paraf.cbSize = sizeof(paraf);
\r
5431 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5432 paraf.dxStartIndent = 0;
\r
5433 paraf.dxOffset = WRAP_INDENT;
\r
5434 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5435 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5438 /*---------------------------------------------------------------------------*\
\r
5440 * Window Proc for main window
\r
5442 \*---------------------------------------------------------------------------*/
\r
5444 /* Process messages for main window, etc. */
\r
5446 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5449 int wmId, wmEvent;
\r
5453 char fileTitle[MSG_SIZ];
\r
5454 char buf[MSG_SIZ];
\r
5455 static SnapData sd;
\r
5457 switch (message) {
\r
5459 case WM_PAINT: /* message: repaint portion of window */
\r
5463 case WM_ERASEBKGND:
\r
5464 if (IsIconic(hwnd)) {
\r
5465 /* Cheat; change the message */
\r
5466 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5468 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5472 case WM_LBUTTONDOWN:
\r
5473 case WM_MBUTTONDOWN:
\r
5474 case WM_RBUTTONDOWN:
\r
5475 case WM_LBUTTONUP:
\r
5476 case WM_MBUTTONUP:
\r
5477 case WM_RBUTTONUP:
\r
5478 case WM_MOUSEMOVE:
\r
5479 case WM_MOUSEWHEEL:
\r
5480 MouseEvent(hwnd, message, wParam, lParam);
\r
5485 if (appData.icsActive) {
\r
5486 if (wParam == '\t') {
\r
5487 if (GetKeyState(VK_SHIFT) < 0) {
\r
5489 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5490 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5494 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5495 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5499 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5500 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5502 SendMessage(h, message, wParam, lParam);
\r
5504 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5505 PopUpMoveDialog((char)wParam);
\r
5509 case WM_PALETTECHANGED:
\r
5510 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5512 HDC hdc = GetDC(hwndMain);
\r
5513 SelectPalette(hdc, hPal, TRUE);
\r
5514 nnew = RealizePalette(hdc);
\r
5516 paletteChanged = TRUE;
\r
5518 UpdateColors(hdc);
\r
5520 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5523 ReleaseDC(hwnd, hdc);
\r
5527 case WM_QUERYNEWPALETTE:
\r
5528 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5530 HDC hdc = GetDC(hwndMain);
\r
5531 paletteChanged = FALSE;
\r
5532 SelectPalette(hdc, hPal, FALSE);
\r
5533 nnew = RealizePalette(hdc);
\r
5535 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5537 ReleaseDC(hwnd, hdc);
\r
5542 case WM_COMMAND: /* message: command from application menu */
\r
5543 wmId = LOWORD(wParam);
\r
5544 wmEvent = HIWORD(wParam);
\r
5549 AnalysisPopDown();
\r
5552 case IDM_NewGameFRC:
\r
5553 if( NewGameFRC() == 0 ) {
\r
5555 AnalysisPopDown();
\r
5559 case IDM_NewVariant:
\r
5560 NewVariantPopup(hwnd);
\r
5563 case IDM_LoadGame:
\r
5564 LoadGameDialog(hwnd, "Load Game from File");
\r
5567 case IDM_LoadNextGame:
\r
5571 case IDM_LoadPrevGame:
\r
5575 case IDM_ReloadGame:
\r
5579 case IDM_LoadPosition:
\r
5580 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5581 Reset(FALSE, TRUE);
\r
5584 f = OpenFileDialog(hwnd, "rb", "",
\r
5585 appData.oldSaveStyle ? "pos" : "fen",
\r
5587 "Load Position from File", &number, fileTitle, NULL);
\r
5589 LoadPosition(f, number, fileTitle);
\r
5593 case IDM_LoadNextPosition:
\r
5594 ReloadPosition(1);
\r
5597 case IDM_LoadPrevPosition:
\r
5598 ReloadPosition(-1);
\r
5601 case IDM_ReloadPosition:
\r
5602 ReloadPosition(0);
\r
5605 case IDM_SaveGame:
\r
5606 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5607 f = OpenFileDialog(hwnd, "a", defName,
\r
5608 appData.oldSaveStyle ? "gam" : "pgn",
\r
5610 "Save Game to File", NULL, fileTitle, NULL);
\r
5612 SaveGame(f, 0, "");
\r
5616 case IDM_SavePosition:
\r
5617 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5618 f = OpenFileDialog(hwnd, "a", defName,
\r
5619 appData.oldSaveStyle ? "pos" : "fen",
\r
5621 "Save Position to File", NULL, fileTitle, NULL);
\r
5623 SavePosition(f, 0, "");
\r
5627 case IDM_SaveDiagram:
\r
5628 defName = "diagram";
\r
5629 f = OpenFileDialog(hwnd, "wb", defName,
\r
5632 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5638 case IDM_CopyGame:
\r
5639 CopyGameToClipboard();
\r
5642 case IDM_PasteGame:
\r
5643 PasteGameFromClipboard();
\r
5646 case IDM_CopyGameListToClipboard:
\r
5647 CopyGameListToClipboard();
\r
5650 /* [AS] Autodetect FEN or PGN data */
\r
5651 case IDM_PasteAny:
\r
5652 PasteGameOrFENFromClipboard();
\r
5655 /* [AS] Move history */
\r
5656 case IDM_ShowMoveHistory:
\r
5657 if( MoveHistoryIsUp() ) {
\r
5658 MoveHistoryPopDown();
\r
5661 MoveHistoryPopUp();
\r
5665 /* [AS] Eval graph */
\r
5666 case IDM_ShowEvalGraph:
\r
5667 if( EvalGraphIsUp() ) {
\r
5668 EvalGraphPopDown();
\r
5675 /* [AS] Engine output */
\r
5676 case IDM_ShowEngineOutput:
\r
5677 if( EngineOutputIsUp() ) {
\r
5678 EngineOutputPopDown();
\r
5681 EngineOutputPopUp();
\r
5685 /* [AS] User adjudication */
\r
5686 case IDM_UserAdjudication_White:
\r
5687 UserAdjudicationEvent( +1 );
\r
5690 case IDM_UserAdjudication_Black:
\r
5691 UserAdjudicationEvent( -1 );
\r
5694 case IDM_UserAdjudication_Draw:
\r
5695 UserAdjudicationEvent( 0 );
\r
5698 /* [AS] Game list options dialog */
\r
5699 case IDM_GameListOptions:
\r
5700 GameListOptions();
\r
5703 case IDM_CopyPosition:
\r
5704 CopyFENToClipboard();
\r
5707 case IDM_PastePosition:
\r
5708 PasteFENFromClipboard();
\r
5711 case IDM_MailMove:
\r
5715 case IDM_ReloadCMailMsg:
\r
5716 Reset(TRUE, TRUE);
\r
5717 ReloadCmailMsgEvent(FALSE);
\r
5720 case IDM_Minimize:
\r
5721 ShowWindow(hwnd, SW_MINIMIZE);
\r
5728 case IDM_MachineWhite:
\r
5729 MachineWhiteEvent();
\r
5731 * refresh the tags dialog only if it's visible
\r
5733 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5735 tags = PGNTags(&gameInfo);
\r
5736 TagsPopUp(tags, CmailMsg());
\r
5741 case IDM_MachineBlack:
\r
5742 MachineBlackEvent();
\r
5744 * refresh the tags dialog only if it's visible
\r
5746 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5748 tags = PGNTags(&gameInfo);
\r
5749 TagsPopUp(tags, CmailMsg());
\r
5754 case IDM_TwoMachines:
\r
5755 TwoMachinesEvent();
\r
5757 * refresh the tags dialog only if it's visible
\r
5759 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5761 tags = PGNTags(&gameInfo);
\r
5762 TagsPopUp(tags, CmailMsg());
\r
5767 case IDM_AnalysisMode:
\r
5768 if (!first.analysisSupport) {
\r
5769 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5770 DisplayError(buf, 0);
\r
5772 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5773 if (appData.icsActive) {
\r
5774 if (gameMode != IcsObserving) {
\r
5775 sprintf(buf, "You are not observing a game");
\r
5776 DisplayError(buf, 0);
\r
5777 /* secure check */
\r
5778 if (appData.icsEngineAnalyze) {
\r
5779 if (appData.debugMode)
\r
5780 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5781 ExitAnalyzeMode();
\r
5787 /* if enable, user want disable icsEngineAnalyze */
\r
5788 if (appData.icsEngineAnalyze) {
\r
5789 ExitAnalyzeMode();
\r
5793 appData.icsEngineAnalyze = TRUE;
\r
5794 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5797 if (!appData.showThinking) ToggleShowThinking();
\r
5798 AnalyzeModeEvent();
\r
5802 case IDM_AnalyzeFile:
\r
5803 if (!first.analysisSupport) {
\r
5804 char buf[MSG_SIZ];
\r
5805 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5806 DisplayError(buf, 0);
\r
5808 if (!appData.showThinking) ToggleShowThinking();
\r
5809 AnalyzeFileEvent();
\r
5810 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5811 AnalysisPeriodicEvent(1);
\r
5815 case IDM_IcsClient:
\r
5819 case IDM_EditGame:
\r
5823 case IDM_EditPosition:
\r
5824 EditPositionEvent();
\r
5827 case IDM_Training:
\r
5831 case IDM_ShowGameList:
\r
5832 ShowGameListProc();
\r
5835 case IDM_EditTags:
\r
5839 case IDM_EditComment:
\r
5840 if (commentDialogUp && editComment) {
\r
5843 EditCommentEvent();
\r
5863 case IDM_CallFlag:
\r
5883 case IDM_StopObserving:
\r
5884 StopObservingEvent();
\r
5887 case IDM_StopExamining:
\r
5888 StopExaminingEvent();
\r
5891 case IDM_TypeInMove:
\r
5892 PopUpMoveDialog('\000');
\r
5895 case IDM_TypeInName:
\r
5896 PopUpNameDialog('\000');
\r
5899 case IDM_Backward:
\r
5901 SetFocus(hwndMain);
\r
5906 SetFocus(hwndMain);
\r
5911 SetFocus(hwndMain);
\r
5916 SetFocus(hwndMain);
\r
5923 case IDM_TruncateGame:
\r
5924 TruncateGameEvent();
\r
5931 case IDM_RetractMove:
\r
5932 RetractMoveEvent();
\r
5935 case IDM_FlipView:
\r
5936 flipView = !flipView;
\r
5937 DrawPosition(FALSE, NULL);
\r
5940 case IDM_FlipClock:
\r
5941 flipClock = !flipClock;
\r
5942 DisplayBothClocks();
\r
5945 case IDM_GeneralOptions:
\r
5946 GeneralOptionsPopup(hwnd);
\r
5947 DrawPosition(TRUE, NULL);
\r
5950 case IDM_BoardOptions:
\r
5951 BoardOptionsPopup(hwnd);
\r
5954 case IDM_EnginePlayOptions:
\r
5955 EnginePlayOptionsPopup(hwnd);
\r
5958 case IDM_OptionsUCI:
\r
5959 UciOptionsPopup(hwnd);
\r
5962 case IDM_IcsOptions:
\r
5963 IcsOptionsPopup(hwnd);
\r
5967 FontsOptionsPopup(hwnd);
\r
5971 SoundOptionsPopup(hwnd);
\r
5974 case IDM_CommPort:
\r
5975 CommPortOptionsPopup(hwnd);
\r
5978 case IDM_LoadOptions:
\r
5979 LoadOptionsPopup(hwnd);
\r
5982 case IDM_SaveOptions:
\r
5983 SaveOptionsPopup(hwnd);
\r
5986 case IDM_TimeControl:
\r
5987 TimeControlOptionsPopup(hwnd);
\r
5990 case IDM_SaveSettings:
\r
5991 SaveSettings(settingsFileName);
\r
5994 case IDM_SaveSettingsOnExit:
\r
5995 saveSettingsOnExit = !saveSettingsOnExit;
\r
5996 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5997 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5998 MF_CHECKED : MF_UNCHECKED));
\r
6009 case IDM_AboutGame:
\r
6014 appData.debugMode = !appData.debugMode;
\r
6015 if (appData.debugMode) {
\r
6016 char dir[MSG_SIZ];
\r
6017 GetCurrentDirectory(MSG_SIZ, dir);
\r
6018 SetCurrentDirectory(installDir);
\r
6019 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6020 SetCurrentDirectory(dir);
\r
6021 setbuf(debugFP, NULL);
\r
6028 case IDM_HELPCONTENTS:
\r
6029 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6030 MessageBox (GetFocus(),
\r
6031 "Unable to activate help",
\r
6032 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6036 case IDM_HELPSEARCH:
\r
6037 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
6038 MessageBox (GetFocus(),
\r
6039 "Unable to activate help",
\r
6040 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6044 case IDM_HELPHELP:
\r
6045 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6046 MessageBox (GetFocus(),
\r
6047 "Unable to activate help",
\r
6048 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6053 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6055 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6056 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6057 FreeProcInstance(lpProc);
\r
6060 case IDM_DirectCommand1:
\r
6061 AskQuestionEvent("Direct Command",
\r
6062 "Send to chess program:", "", "1");
\r
6064 case IDM_DirectCommand2:
\r
6065 AskQuestionEvent("Direct Command",
\r
6066 "Send to second chess program:", "", "2");
\r
6069 case EP_WhitePawn:
\r
6070 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6071 fromX = fromY = -1;
\r
6074 case EP_WhiteKnight:
\r
6075 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6076 fromX = fromY = -1;
\r
6079 case EP_WhiteBishop:
\r
6080 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6081 fromX = fromY = -1;
\r
6084 case EP_WhiteRook:
\r
6085 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6086 fromX = fromY = -1;
\r
6089 case EP_WhiteQueen:
\r
6090 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6091 fromX = fromY = -1;
\r
6094 case EP_WhiteFerz:
\r
6095 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6096 fromX = fromY = -1;
\r
6099 case EP_WhiteWazir:
\r
6100 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6101 fromX = fromY = -1;
\r
6104 case EP_WhiteAlfil:
\r
6105 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6106 fromX = fromY = -1;
\r
6109 case EP_WhiteCannon:
\r
6110 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6111 fromX = fromY = -1;
\r
6114 case EP_WhiteCardinal:
\r
6115 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6116 fromX = fromY = -1;
\r
6119 case EP_WhiteMarshall:
\r
6120 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6121 fromX = fromY = -1;
\r
6124 case EP_WhiteKing:
\r
6125 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6126 fromX = fromY = -1;
\r
6129 case EP_BlackPawn:
\r
6130 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6131 fromX = fromY = -1;
\r
6134 case EP_BlackKnight:
\r
6135 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6136 fromX = fromY = -1;
\r
6139 case EP_BlackBishop:
\r
6140 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6141 fromX = fromY = -1;
\r
6144 case EP_BlackRook:
\r
6145 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6146 fromX = fromY = -1;
\r
6149 case EP_BlackQueen:
\r
6150 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6151 fromX = fromY = -1;
\r
6154 case EP_BlackFerz:
\r
6155 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6156 fromX = fromY = -1;
\r
6159 case EP_BlackWazir:
\r
6160 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6161 fromX = fromY = -1;
\r
6164 case EP_BlackAlfil:
\r
6165 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6166 fromX = fromY = -1;
\r
6169 case EP_BlackCannon:
\r
6170 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6171 fromX = fromY = -1;
\r
6174 case EP_BlackCardinal:
\r
6175 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6176 fromX = fromY = -1;
\r
6179 case EP_BlackMarshall:
\r
6180 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6181 fromX = fromY = -1;
\r
6184 case EP_BlackKing:
\r
6185 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6186 fromX = fromY = -1;
\r
6189 case EP_EmptySquare:
\r
6190 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6191 fromX = fromY = -1;
\r
6194 case EP_ClearBoard:
\r
6195 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6196 fromX = fromY = -1;
\r
6200 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6201 fromX = fromY = -1;
\r
6205 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6206 fromX = fromY = -1;
\r
6210 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6211 fromX = fromY = -1;
\r
6215 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6216 fromX = fromY = -1;
\r
6220 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6221 fromX = fromY = -1;
\r
6225 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6226 fromX = fromY = -1;
\r
6230 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6231 fromX = fromY = -1;
\r
6235 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6236 fromX = fromY = -1;
\r
6240 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6241 fromX = fromY = -1;
\r
6245 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6251 case CLOCK_TIMER_ID:
\r
6252 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6253 clockTimerEvent = 0;
\r
6254 DecrementClocks(); /* call into back end */
\r
6256 case LOAD_GAME_TIMER_ID:
\r
6257 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6258 loadGameTimerEvent = 0;
\r
6259 AutoPlayGameLoop(); /* call into back end */
\r
6261 case ANALYSIS_TIMER_ID:
\r
6262 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6263 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6264 AnalysisPeriodicEvent(0);
\r
6266 KillTimer(hwnd, analysisTimerEvent);
\r
6267 analysisTimerEvent = 0;
\r
6270 case DELAYED_TIMER_ID:
\r
6271 KillTimer(hwnd, delayedTimerEvent);
\r
6272 delayedTimerEvent = 0;
\r
6273 delayedTimerCallback();
\r
6278 case WM_USER_Input:
\r
6279 InputEvent(hwnd, message, wParam, lParam);
\r
6282 /* [AS] Also move "attached" child windows */
\r
6283 case WM_WINDOWPOSCHANGING:
\r
6285 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6286 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6288 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6289 /* Window is moving */
\r
6292 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6293 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6294 rcMain.right = boardX + winWidth;
\r
6295 rcMain.top = boardY;
\r
6296 rcMain.bottom = boardY + winHeight;
\r
6298 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6299 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6300 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6307 /* [AS] Snapping */
\r
6308 case WM_ENTERSIZEMOVE:
\r
6309 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6310 if (hwnd == hwndMain) {
\r
6311 doingSizing = TRUE;
\r
6314 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6318 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6319 if (hwnd == hwndMain) {
\r
6320 lastSizing = wParam;
\r
6325 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6326 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6328 case WM_EXITSIZEMOVE:
\r
6329 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6330 if (hwnd == hwndMain) {
\r
6332 doingSizing = FALSE;
\r
6333 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6334 GetClientRect(hwnd, &client);
\r
6335 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6337 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6339 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6342 case WM_DESTROY: /* message: window being destroyed */
\r
6343 PostQuitMessage(0);
\r
6347 if (hwnd == hwndMain) {
\r
6352 default: /* Passes it on if unprocessed */
\r
6353 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6358 /*---------------------------------------------------------------------------*\
\r
6360 * Misc utility routines
\r
6362 \*---------------------------------------------------------------------------*/
\r
6365 * Decent random number generator, at least not as bad as Windows
\r
6366 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6368 unsigned int randstate;
\r
6373 randstate = randstate * 1664525 + 1013904223;
\r
6374 return (int) randstate & 0x7fffffff;
\r
6378 mysrandom(unsigned int seed)
\r
6385 * returns TRUE if user selects a different color, FALSE otherwise
\r
6389 ChangeColor(HWND hwnd, COLORREF *which)
\r
6391 static BOOL firstTime = TRUE;
\r
6392 static DWORD customColors[16];
\r
6394 COLORREF newcolor;
\r
6399 /* Make initial colors in use available as custom colors */
\r
6400 /* Should we put the compiled-in defaults here instead? */
\r
6402 customColors[i++] = lightSquareColor & 0xffffff;
\r
6403 customColors[i++] = darkSquareColor & 0xffffff;
\r
6404 customColors[i++] = whitePieceColor & 0xffffff;
\r
6405 customColors[i++] = blackPieceColor & 0xffffff;
\r
6406 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6407 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6409 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6410 customColors[i++] = textAttribs[ccl].color;
\r
6412 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6413 firstTime = FALSE;
\r
6416 cc.lStructSize = sizeof(cc);
\r
6417 cc.hwndOwner = hwnd;
\r
6418 cc.hInstance = NULL;
\r
6419 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6420 cc.lpCustColors = (LPDWORD) customColors;
\r
6421 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6423 if (!ChooseColor(&cc)) return FALSE;
\r
6425 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6426 if (newcolor == *which) return FALSE;
\r
6427 *which = newcolor;
\r
6431 InitDrawingColors();
\r
6432 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6437 MyLoadSound(MySound *ms)
\r
6443 if (ms->data) free(ms->data);
\r
6446 switch (ms->name[0]) {
\r
6452 /* System sound from Control Panel. Don't preload here. */
\r
6456 if (ms->name[1] == NULLCHAR) {
\r
6457 /* "!" alone = silence */
\r
6460 /* Builtin wave resource. Error if not found. */
\r
6461 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6462 if (h == NULL) break;
\r
6463 ms->data = (void *)LoadResource(hInst, h);
\r
6464 if (h == NULL) break;
\r
6469 /* .wav file. Error if not found. */
\r
6470 f = fopen(ms->name, "rb");
\r
6471 if (f == NULL) break;
\r
6472 if (fstat(fileno(f), &st) < 0) break;
\r
6473 ms->data = malloc(st.st_size);
\r
6474 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6480 char buf[MSG_SIZ];
\r
6481 sprintf(buf, "Error loading sound %s", ms->name);
\r
6482 DisplayError(buf, GetLastError());
\r
6488 MyPlaySound(MySound *ms)
\r
6490 BOOLEAN ok = FALSE;
\r
6491 switch (ms->name[0]) {
\r
6497 /* System sound from Control Panel (deprecated feature).
\r
6498 "$" alone or an unset sound name gets default beep (still in use). */
\r
6499 if (ms->name[1]) {
\r
6500 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6502 if (!ok) ok = MessageBeep(MB_OK);
\r
6505 /* Builtin wave resource, or "!" alone for silence */
\r
6506 if (ms->name[1]) {
\r
6507 if (ms->data == NULL) return FALSE;
\r
6508 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6514 /* .wav file. Error if not found. */
\r
6515 if (ms->data == NULL) return FALSE;
\r
6516 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6519 /* Don't print an error: this can happen innocently if the sound driver
\r
6520 is busy; for instance, if another instance of WinBoard is playing
\r
6521 a sound at about the same time. */
\r
6524 char buf[MSG_SIZ];
\r
6525 sprintf(buf, "Error playing sound %s", ms->name);
\r
6526 DisplayError(buf, GetLastError());
\r
6534 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6537 OPENFILENAME *ofn;
\r
6538 static UINT *number; /* gross that this is static */
\r
6540 switch (message) {
\r
6541 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6542 /* Center the dialog over the application window */
\r
6543 ofn = (OPENFILENAME *) lParam;
\r
6544 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6545 number = (UINT *) ofn->lCustData;
\r
6546 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6550 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6551 return FALSE; /* Allow for further processing */
\r
6554 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6555 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6557 return FALSE; /* Allow for further processing */
\r
6563 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6565 static UINT *number;
\r
6566 OPENFILENAME *ofname;
\r
6569 case WM_INITDIALOG:
\r
6570 ofname = (OPENFILENAME *)lParam;
\r
6571 number = (UINT *)(ofname->lCustData);
\r
6574 ofnot = (OFNOTIFY *)lParam;
\r
6575 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6576 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6585 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6586 char *nameFilt, char *dlgTitle, UINT *number,
\r
6587 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6589 OPENFILENAME openFileName;
\r
6590 char buf1[MSG_SIZ];
\r
6593 if (fileName == NULL) fileName = buf1;
\r
6594 if (defName == NULL) {
\r
6595 strcpy(fileName, "*.");
\r
6596 strcat(fileName, defExt);
\r
6598 strcpy(fileName, defName);
\r
6600 if (fileTitle) strcpy(fileTitle, "");
\r
6601 if (number) *number = 0;
\r
6603 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6604 openFileName.hwndOwner = hwnd;
\r
6605 openFileName.hInstance = (HANDLE) hInst;
\r
6606 openFileName.lpstrFilter = nameFilt;
\r
6607 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6608 openFileName.nMaxCustFilter = 0L;
\r
6609 openFileName.nFilterIndex = 1L;
\r
6610 openFileName.lpstrFile = fileName;
\r
6611 openFileName.nMaxFile = MSG_SIZ;
\r
6612 openFileName.lpstrFileTitle = fileTitle;
\r
6613 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6614 openFileName.lpstrInitialDir = NULL;
\r
6615 openFileName.lpstrTitle = dlgTitle;
\r
6616 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6617 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6618 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6619 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6620 openFileName.nFileOffset = 0;
\r
6621 openFileName.nFileExtension = 0;
\r
6622 openFileName.lpstrDefExt = defExt;
\r
6623 openFileName.lCustData = (LONG) number;
\r
6624 openFileName.lpfnHook = oldDialog ?
\r
6625 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6626 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6628 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6629 GetOpenFileName(&openFileName)) {
\r
6630 /* open the file */
\r
6631 f = fopen(openFileName.lpstrFile, write);
\r
6633 MessageBox(hwnd, "File open failed", NULL,
\r
6634 MB_OK|MB_ICONEXCLAMATION);
\r
6638 int err = CommDlgExtendedError();
\r
6639 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6648 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6650 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6653 * Get the first pop-up menu in the menu template. This is the
\r
6654 * menu that TrackPopupMenu displays.
\r
6656 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6658 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6661 * TrackPopup uses screen coordinates, so convert the
\r
6662 * coordinates of the mouse click to screen coordinates.
\r
6664 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6666 /* Draw and track the floating pop-up menu. */
\r
6667 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6668 pt.x, pt.y, 0, hwnd, NULL);
\r
6670 /* Destroy the menu.*/
\r
6671 DestroyMenu(hmenu);
\r
6676 int sizeX, sizeY, newSizeX, newSizeY;
\r
6678 } ResizeEditPlusButtonsClosure;
\r
6681 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6683 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6687 if (hChild == cl->hText) return TRUE;
\r
6688 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6689 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6690 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6691 ScreenToClient(cl->hDlg, &pt);
\r
6692 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6693 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6697 /* Resize a dialog that has a (rich) edit field filling most of
\r
6698 the top, with a row of buttons below */
\r
6700 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6703 int newTextHeight, newTextWidth;
\r
6704 ResizeEditPlusButtonsClosure cl;
\r
6706 /*if (IsIconic(hDlg)) return;*/
\r
6707 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6709 cl.hdwp = BeginDeferWindowPos(8);
\r
6711 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6712 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6713 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6714 if (newTextHeight < 0) {
\r
6715 newSizeY += -newTextHeight;
\r
6716 newTextHeight = 0;
\r
6718 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6719 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6725 cl.newSizeX = newSizeX;
\r
6726 cl.newSizeY = newSizeY;
\r
6727 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6729 EndDeferWindowPos(cl.hdwp);
\r
6732 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6734 RECT rChild, rParent;
\r
6735 int wChild, hChild, wParent, hParent;
\r
6736 int wScreen, hScreen, xNew, yNew;
\r
6739 /* Get the Height and Width of the child window */
\r
6740 GetWindowRect (hwndChild, &rChild);
\r
6741 wChild = rChild.right - rChild.left;
\r
6742 hChild = rChild.bottom - rChild.top;
\r
6744 /* Get the Height and Width of the parent window */
\r
6745 GetWindowRect (hwndParent, &rParent);
\r
6746 wParent = rParent.right - rParent.left;
\r
6747 hParent = rParent.bottom - rParent.top;
\r
6749 /* Get the display limits */
\r
6750 hdc = GetDC (hwndChild);
\r
6751 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6752 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6753 ReleaseDC(hwndChild, hdc);
\r
6755 /* Calculate new X position, then adjust for screen */
\r
6756 xNew = rParent.left + ((wParent - wChild) /2);
\r
6759 } else if ((xNew+wChild) > wScreen) {
\r
6760 xNew = wScreen - wChild;
\r
6763 /* Calculate new Y position, then adjust for screen */
\r
6765 yNew = rParent.top + ((hParent - hChild) /2);
\r
6768 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6773 } else if ((yNew+hChild) > hScreen) {
\r
6774 yNew = hScreen - hChild;
\r
6777 /* Set it, and return */
\r
6778 return SetWindowPos (hwndChild, NULL,
\r
6779 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6782 /* Center one window over another */
\r
6783 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6785 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6788 /*---------------------------------------------------------------------------*\
\r
6790 * Startup Dialog functions
\r
6792 \*---------------------------------------------------------------------------*/
\r
6794 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6796 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6798 while (*cd != NULL) {
\r
6799 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6805 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6807 char buf1[ARG_MAX];
\r
6810 if (str[0] == '@') {
\r
6811 FILE* f = fopen(str + 1, "r");
\r
6813 DisplayFatalError(str + 1, errno, 2);
\r
6816 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6818 buf1[len] = NULLCHAR;
\r
6822 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6825 char buf[MSG_SIZ];
\r
6826 char *end = strchr(str, '\n');
\r
6827 if (end == NULL) return;
\r
6828 memcpy(buf, str, end - str);
\r
6829 buf[end - str] = NULLCHAR;
\r
6830 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6836 SetStartupDialogEnables(HWND hDlg)
\r
6838 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6839 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6840 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6841 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6842 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6843 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6844 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6845 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6846 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6847 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6848 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6849 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6850 IsDlgButtonChecked(hDlg, OPT_View));
\r
6854 QuoteForFilename(char *filename)
\r
6856 int dquote, space;
\r
6857 dquote = strchr(filename, '"') != NULL;
\r
6858 space = strchr(filename, ' ') != NULL;
\r
6859 if (dquote || space) {
\r
6871 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6873 char buf[MSG_SIZ];
\r
6876 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6877 q = QuoteForFilename(nthcp);
\r
6878 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6879 if (*nthdir != NULLCHAR) {
\r
6880 q = QuoteForFilename(nthdir);
\r
6881 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6883 if (*nthcp == NULLCHAR) {
\r
6884 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6885 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6886 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6887 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6892 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6894 char buf[MSG_SIZ];
\r
6898 switch (message) {
\r
6899 case WM_INITDIALOG:
\r
6900 /* Center the dialog */
\r
6901 CenterWindow (hDlg, GetDesktopWindow());
\r
6902 /* Initialize the dialog items */
\r
6903 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6904 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6905 firstChessProgramNames);
\r
6906 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6907 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6908 secondChessProgramNames);
\r
6909 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6910 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6911 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6912 if (*appData.icsHelper != NULLCHAR) {
\r
6913 char *q = QuoteForFilename(appData.icsHelper);
\r
6914 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6916 if (*appData.icsHost == NULLCHAR) {
\r
6917 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6918 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6919 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6920 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6921 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6924 if (appData.icsActive) {
\r
6925 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6927 else if (appData.noChessProgram) {
\r
6928 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6931 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6934 SetStartupDialogEnables(hDlg);
\r
6938 switch (LOWORD(wParam)) {
\r
6940 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6941 strcpy(buf, "/fcp=");
\r
6942 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6944 ParseArgs(StringGet, &p);
\r
6945 strcpy(buf, "/scp=");
\r
6946 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6948 ParseArgs(StringGet, &p);
\r
6949 appData.noChessProgram = FALSE;
\r
6950 appData.icsActive = FALSE;
\r
6951 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6952 strcpy(buf, "/ics /icshost=");
\r
6953 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6955 ParseArgs(StringGet, &p);
\r
6956 if (appData.zippyPlay) {
\r
6957 strcpy(buf, "/fcp=");
\r
6958 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6960 ParseArgs(StringGet, &p);
\r
6962 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6963 appData.noChessProgram = TRUE;
\r
6964 appData.icsActive = FALSE;
\r
6966 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6967 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6970 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6971 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6973 ParseArgs(StringGet, &p);
\r
6975 EndDialog(hDlg, TRUE);
\r
6982 case IDM_HELPCONTENTS:
\r
6983 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6984 MessageBox (GetFocus(),
\r
6985 "Unable to activate help",
\r
6986 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6991 SetStartupDialogEnables(hDlg);
\r
6999 /*---------------------------------------------------------------------------*\
\r
7001 * About box dialog functions
\r
7003 \*---------------------------------------------------------------------------*/
\r
7005 /* Process messages for "About" dialog box */
\r
7007 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7009 switch (message) {
\r
7010 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7011 /* Center the dialog over the application window */
\r
7012 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7013 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7016 case WM_COMMAND: /* message: received a command */
\r
7017 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7018 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7019 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7027 /*---------------------------------------------------------------------------*\
\r
7029 * Comment Dialog functions
\r
7031 \*---------------------------------------------------------------------------*/
\r
7034 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7036 static HANDLE hwndText = NULL;
\r
7037 int len, newSizeX, newSizeY, flags;
\r
7038 static int sizeX, sizeY;
\r
7043 switch (message) {
\r
7044 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7045 /* Initialize the dialog items */
\r
7046 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7047 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7048 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7049 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7050 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7051 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7052 SetWindowText(hDlg, commentTitle);
\r
7053 if (editComment) {
\r
7054 SetFocus(hwndText);
\r
7056 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7058 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7059 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7060 MAKELPARAM(FALSE, 0));
\r
7061 /* Size and position the dialog */
\r
7062 if (!commentDialog) {
\r
7063 commentDialog = hDlg;
\r
7064 flags = SWP_NOZORDER;
\r
7065 GetClientRect(hDlg, &rect);
\r
7066 sizeX = rect.right;
\r
7067 sizeY = rect.bottom;
\r
7068 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7069 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7070 WINDOWPLACEMENT wp;
\r
7071 EnsureOnScreen(&commentX, &commentY);
\r
7072 wp.length = sizeof(WINDOWPLACEMENT);
\r
7074 wp.showCmd = SW_SHOW;
\r
7075 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7076 wp.rcNormalPosition.left = commentX;
\r
7077 wp.rcNormalPosition.right = commentX + commentW;
\r
7078 wp.rcNormalPosition.top = commentY;
\r
7079 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7080 SetWindowPlacement(hDlg, &wp);
\r
7082 GetClientRect(hDlg, &rect);
\r
7083 newSizeX = rect.right;
\r
7084 newSizeY = rect.bottom;
\r
7085 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7086 newSizeX, newSizeY);
\r
7093 case WM_COMMAND: /* message: received a command */
\r
7094 switch (LOWORD(wParam)) {
\r
7096 if (editComment) {
\r
7098 /* Read changed options from the dialog box */
\r
7099 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7100 len = GetWindowTextLength(hwndText);
\r
7101 str = (char *) malloc(len + 1);
\r
7102 GetWindowText(hwndText, str, len + 1);
\r
7111 ReplaceComment(commentIndex, str);
\r
7118 case OPT_CancelComment:
\r
7122 case OPT_ClearComment:
\r
7123 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7126 case OPT_EditComment:
\r
7127 EditCommentEvent();
\r
7136 newSizeX = LOWORD(lParam);
\r
7137 newSizeY = HIWORD(lParam);
\r
7138 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7143 case WM_GETMINMAXINFO:
\r
7144 /* Prevent resizing window too small */
\r
7145 mmi = (MINMAXINFO *) lParam;
\r
7146 mmi->ptMinTrackSize.x = 100;
\r
7147 mmi->ptMinTrackSize.y = 100;
\r
7154 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7159 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7161 if (str == NULL) str = "";
\r
7162 p = (char *) malloc(2 * strlen(str) + 2);
\r
7165 if (*str == '\n') *q++ = '\r';
\r
7169 if (commentText != NULL) free(commentText);
\r
7171 commentIndex = index;
\r
7172 commentTitle = title;
\r
7174 editComment = edit;
\r
7176 if (commentDialog) {
\r
7177 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7178 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7180 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7181 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7182 hwndMain, (DLGPROC)lpProc);
\r
7183 FreeProcInstance(lpProc);
\r
7185 commentDialogUp = TRUE;
\r
7189 /*---------------------------------------------------------------------------*\
\r
7191 * Type-in move dialog functions
\r
7193 \*---------------------------------------------------------------------------*/
\r
7196 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7198 char move[MSG_SIZ];
\r
7200 ChessMove moveType;
\r
7201 int fromX, fromY, toX, toY;
\r
7204 switch (message) {
\r
7205 case WM_INITDIALOG:
\r
7206 move[0] = (char) lParam;
\r
7207 move[1] = NULLCHAR;
\r
7208 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7209 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7210 SetWindowText(hInput, move);
\r
7212 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7216 switch (LOWORD(wParam)) {
\r
7218 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7219 gameMode != Training) {
\r
7220 DisplayMoveError("Displayed move is not current");
\r
7222 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7223 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7224 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7225 if (gameMode != Training)
\r
7226 forwardMostMove = currentMove;
\r
7227 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7229 DisplayMoveError("Could not parse move");
\r
7232 EndDialog(hDlg, TRUE);
\r
7235 EndDialog(hDlg, FALSE);
\r
7246 PopUpMoveDialog(char firstchar)
\r
7250 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7251 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7252 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7253 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7254 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7255 gameMode == Training) {
\r
7256 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7257 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7258 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7259 FreeProcInstance(lpProc);
\r
7263 /*---------------------------------------------------------------------------*\
\r
7265 * Type-in name dialog functions
\r
7267 \*---------------------------------------------------------------------------*/
\r
7270 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7272 char move[MSG_SIZ];
\r
7275 switch (message) {
\r
7276 case WM_INITDIALOG:
\r
7277 move[0] = (char) lParam;
\r
7278 move[1] = NULLCHAR;
\r
7279 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7280 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7281 SetWindowText(hInput, move);
\r
7283 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7287 switch (LOWORD(wParam)) {
\r
7289 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7290 appData.userName = strdup(move);
\r
7292 EndDialog(hDlg, TRUE);
\r
7295 EndDialog(hDlg, FALSE);
\r
7306 PopUpNameDialog(char firstchar)
\r
7310 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7311 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7312 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7313 FreeProcInstance(lpProc);
\r
7316 /*---------------------------------------------------------------------------*\
\r
7320 \*---------------------------------------------------------------------------*/
\r
7322 /* Nonmodal error box */
\r
7323 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7324 WPARAM wParam, LPARAM lParam);
\r
7327 ErrorPopUp(char *title, char *content)
\r
7331 BOOLEAN modal = hwndMain == NULL;
\r
7349 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7350 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7353 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7355 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7356 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7357 hwndMain, (DLGPROC)lpProc);
\r
7358 FreeProcInstance(lpProc);
\r
7365 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7366 if (errorDialog == NULL) return;
\r
7367 DestroyWindow(errorDialog);
\r
7368 errorDialog = NULL;
\r
7372 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7377 switch (message) {
\r
7378 case WM_INITDIALOG:
\r
7379 GetWindowRect(hDlg, &rChild);
\r
7382 SetWindowPos(hDlg, NULL, rChild.left,
\r
7383 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7384 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7388 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7389 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7390 and it doesn't work when you resize the dialog.
\r
7391 For now, just give it a default position.
\r
7393 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7395 errorDialog = hDlg;
\r
7396 SetWindowText(hDlg, errorTitle);
\r
7397 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7398 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7402 switch (LOWORD(wParam)) {
\r
7405 if (errorDialog == hDlg) errorDialog = NULL;
\r
7406 DestroyWindow(hDlg);
\r
7418 HWND gothicDialog = NULL;
\r
7421 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7425 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7427 switch (message) {
\r
7428 case WM_INITDIALOG:
\r
7429 GetWindowRect(hDlg, &rChild);
\r
7431 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7435 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7436 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7437 and it doesn't work when you resize the dialog.
\r
7438 For now, just give it a default position.
\r
7440 gothicDialog = hDlg;
\r
7441 SetWindowText(hDlg, errorTitle);
\r
7442 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7443 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7447 switch (LOWORD(wParam)) {
\r
7450 if (errorDialog == hDlg) errorDialog = NULL;
\r
7451 DestroyWindow(hDlg);
\r
7463 GothicPopUp(char *title, VariantClass variant)
\r
7466 static char *lastTitle;
\r
7468 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7469 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7471 if(lastTitle != title && gothicDialog != NULL) {
\r
7472 DestroyWindow(gothicDialog);
\r
7473 gothicDialog = NULL;
\r
7475 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7476 title = lastTitle;
\r
7477 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7478 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7479 hwndMain, (DLGPROC)lpProc);
\r
7480 FreeProcInstance(lpProc);
\r
7485 /*---------------------------------------------------------------------------*\
\r
7487 * Ics Interaction console functions
\r
7489 \*---------------------------------------------------------------------------*/
\r
7491 #define HISTORY_SIZE 64
\r
7492 static char *history[HISTORY_SIZE];
\r
7493 int histIn = 0, histP = 0;
\r
7496 SaveInHistory(char *cmd)
\r
7498 if (history[histIn] != NULL) {
\r
7499 free(history[histIn]);
\r
7500 history[histIn] = NULL;
\r
7502 if (*cmd == NULLCHAR) return;
\r
7503 history[histIn] = StrSave(cmd);
\r
7504 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7505 if (history[histIn] != NULL) {
\r
7506 free(history[histIn]);
\r
7507 history[histIn] = NULL;
\r
7513 PrevInHistory(char *cmd)
\r
7516 if (histP == histIn) {
\r
7517 if (history[histIn] != NULL) free(history[histIn]);
\r
7518 history[histIn] = StrSave(cmd);
\r
7520 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7521 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7523 return history[histP];
\r
7529 if (histP == histIn) return NULL;
\r
7530 histP = (histP + 1) % HISTORY_SIZE;
\r
7531 return history[histP];
\r
7538 BOOLEAN immediate;
\r
7539 } IcsTextMenuEntry;
\r
7540 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7541 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7544 ParseIcsTextMenu(char *icsTextMenuString)
\r
7547 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7548 char *p = icsTextMenuString;
\r
7549 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7552 if (e->command != NULL) {
\r
7554 e->command = NULL;
\r
7558 e = icsTextMenuEntry;
\r
7559 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7560 if (*p == ';' || *p == '\n') {
\r
7561 e->item = strdup("-");
\r
7562 e->command = NULL;
\r
7564 } else if (*p == '-') {
\r
7565 e->item = strdup("-");
\r
7566 e->command = NULL;
\r
7570 char *q, *r, *s, *t;
\r
7572 q = strchr(p, ',');
\r
7573 if (q == NULL) break;
\r
7575 r = strchr(q + 1, ',');
\r
7576 if (r == NULL) break;
\r
7578 s = strchr(r + 1, ',');
\r
7579 if (s == NULL) break;
\r
7582 t = strchr(s + 1, c);
\r
7585 t = strchr(s + 1, c);
\r
7587 if (t != NULL) *t = NULLCHAR;
\r
7588 e->item = strdup(p);
\r
7589 e->command = strdup(q + 1);
\r
7590 e->getname = *(r + 1) != '0';
\r
7591 e->immediate = *(s + 1) != '0';
\r
7595 if (t == NULL) break;
\r
7604 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7608 hmenu = LoadMenu(hInst, "TextMenu");
\r
7609 h = GetSubMenu(hmenu, 0);
\r
7611 if (strcmp(e->item, "-") == 0) {
\r
7612 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7614 if (e->item[0] == '|') {
\r
7615 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7616 IDM_CommandX + i, &e->item[1]);
\r
7618 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7627 WNDPROC consoleTextWindowProc;
\r
7630 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7632 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7633 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7637 SetWindowText(hInput, command);
\r
7639 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7641 sel.cpMin = 999999;
\r
7642 sel.cpMax = 999999;
\r
7643 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7648 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7649 if (sel.cpMin == sel.cpMax) {
\r
7650 /* Expand to surrounding word */
\r
7653 tr.chrg.cpMax = sel.cpMin;
\r
7654 tr.chrg.cpMin = --sel.cpMin;
\r
7655 if (sel.cpMin < 0) break;
\r
7656 tr.lpstrText = name;
\r
7657 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7658 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7662 tr.chrg.cpMin = sel.cpMax;
\r
7663 tr.chrg.cpMax = ++sel.cpMax;
\r
7664 tr.lpstrText = name;
\r
7665 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7666 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7669 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7670 MessageBeep(MB_ICONEXCLAMATION);
\r
7674 tr.lpstrText = name;
\r
7675 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7677 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7678 MessageBeep(MB_ICONEXCLAMATION);
\r
7681 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7684 sprintf(buf, "%s %s", command, name);
\r
7685 SetWindowText(hInput, buf);
\r
7686 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7688 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7689 SetWindowText(hInput, buf);
\r
7690 sel.cpMin = 999999;
\r
7691 sel.cpMax = 999999;
\r
7692 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7698 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7703 switch (message) {
\r
7705 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7708 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7711 sel.cpMin = 999999;
\r
7712 sel.cpMax = 999999;
\r
7713 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7714 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7719 if (wParam == '\t') {
\r
7720 if (GetKeyState(VK_SHIFT) < 0) {
\r
7722 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7723 if (buttonDesc[0].hwnd) {
\r
7724 SetFocus(buttonDesc[0].hwnd);
\r
7726 SetFocus(hwndMain);
\r
7730 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7733 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7735 SendMessage(hInput, message, wParam, lParam);
\r
7739 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7741 return SendMessage(hInput, message, wParam, lParam);
\r
7742 case WM_MBUTTONDOWN:
\r
7743 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7744 case WM_RBUTTONDOWN:
\r
7745 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7746 /* Move selection here if it was empty */
\r
7748 pt.x = LOWORD(lParam);
\r
7749 pt.y = HIWORD(lParam);
\r
7750 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7751 if (sel.cpMin == sel.cpMax) {
\r
7752 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7753 sel.cpMax = sel.cpMin;
\r
7754 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7756 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7759 case WM_RBUTTONUP:
\r
7760 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7761 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7762 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7765 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7766 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7767 if (sel.cpMin == sel.cpMax) {
\r
7768 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7769 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7771 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7772 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7774 pt.x = LOWORD(lParam);
\r
7775 pt.y = HIWORD(lParam);
\r
7776 MenuPopup(hwnd, pt, hmenu, -1);
\r
7780 switch (LOWORD(wParam)) {
\r
7781 case IDM_QuickPaste:
\r
7783 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7784 if (sel.cpMin == sel.cpMax) {
\r
7785 MessageBeep(MB_ICONEXCLAMATION);
\r
7788 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7789 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7790 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7795 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7798 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7801 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7805 int i = LOWORD(wParam) - IDM_CommandX;
\r
7806 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7807 icsTextMenuEntry[i].command != NULL) {
\r
7808 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7809 icsTextMenuEntry[i].getname,
\r
7810 icsTextMenuEntry[i].immediate);
\r
7818 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7821 WNDPROC consoleInputWindowProc;
\r
7824 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7826 char buf[MSG_SIZ];
\r
7828 static BOOL sendNextChar = FALSE;
\r
7829 static BOOL quoteNextChar = FALSE;
\r
7830 InputSource *is = consoleInputSource;
\r
7834 switch (message) {
\r
7836 if (!appData.localLineEditing || sendNextChar) {
\r
7837 is->buf[0] = (CHAR) wParam;
\r
7839 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7840 sendNextChar = FALSE;
\r
7843 if (quoteNextChar) {
\r
7844 buf[0] = (char) wParam;
\r
7845 buf[1] = NULLCHAR;
\r
7846 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7847 quoteNextChar = FALSE;
\r
7851 case '\r': /* Enter key */
\r
7852 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7853 if (consoleEcho) SaveInHistory(is->buf);
\r
7854 is->buf[is->count++] = '\n';
\r
7855 is->buf[is->count] = NULLCHAR;
\r
7856 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7857 if (consoleEcho) {
\r
7858 ConsoleOutput(is->buf, is->count, TRUE);
\r
7859 } else if (appData.localLineEditing) {
\r
7860 ConsoleOutput("\n", 1, TRUE);
\r
7863 case '\033': /* Escape key */
\r
7864 SetWindowText(hwnd, "");
\r
7865 cf.cbSize = sizeof(CHARFORMAT);
\r
7866 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7867 if (consoleEcho) {
\r
7868 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7870 cf.crTextColor = COLOR_ECHOOFF;
\r
7872 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7873 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7875 case '\t': /* Tab key */
\r
7876 if (GetKeyState(VK_SHIFT) < 0) {
\r
7878 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7881 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7882 if (buttonDesc[0].hwnd) {
\r
7883 SetFocus(buttonDesc[0].hwnd);
\r
7885 SetFocus(hwndMain);
\r
7889 case '\023': /* Ctrl+S */
\r
7890 sendNextChar = TRUE;
\r
7892 case '\021': /* Ctrl+Q */
\r
7893 quoteNextChar = TRUE;
\r
7902 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7903 p = PrevInHistory(buf);
\r
7905 SetWindowText(hwnd, p);
\r
7906 sel.cpMin = 999999;
\r
7907 sel.cpMax = 999999;
\r
7908 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7913 p = NextInHistory();
\r
7915 SetWindowText(hwnd, p);
\r
7916 sel.cpMin = 999999;
\r
7917 sel.cpMax = 999999;
\r
7918 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7924 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7928 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7932 case WM_MBUTTONDOWN:
\r
7933 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7934 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7936 case WM_RBUTTONUP:
\r
7937 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7938 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7939 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7943 hmenu = LoadMenu(hInst, "InputMenu");
\r
7944 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7945 if (sel.cpMin == sel.cpMax) {
\r
7946 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7947 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7949 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7950 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7952 pt.x = LOWORD(lParam);
\r
7953 pt.y = HIWORD(lParam);
\r
7954 MenuPopup(hwnd, pt, hmenu, -1);
\r
7958 switch (LOWORD(wParam)) {
\r
7960 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7962 case IDM_SelectAll:
\r
7964 sel.cpMax = -1; /*999999?*/
\r
7965 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7968 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7971 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7974 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7979 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7982 #define CO_MAX 100000
\r
7983 #define CO_TRIM 1000
\r
7986 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7988 static SnapData sd;
\r
7989 static HWND hText, hInput /*, hFocus*/;
\r
7990 // InputSource *is = consoleInputSource;
\r
7992 static int sizeX, sizeY;
\r
7993 int newSizeX, newSizeY;
\r
7996 switch (message) {
\r
7997 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7998 hwndConsole = hDlg;
\r
7999 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8000 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8002 consoleTextWindowProc = (WNDPROC)
\r
8003 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8004 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8005 consoleInputWindowProc = (WNDPROC)
\r
8006 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8007 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8008 Colorize(ColorNormal, TRUE);
\r
8009 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8010 ChangedConsoleFont();
\r
8011 GetClientRect(hDlg, &rect);
\r
8012 sizeX = rect.right;
\r
8013 sizeY = rect.bottom;
\r
8014 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
8015 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
8016 WINDOWPLACEMENT wp;
\r
8017 EnsureOnScreen(&consoleX, &consoleY);
\r
8018 wp.length = sizeof(WINDOWPLACEMENT);
\r
8020 wp.showCmd = SW_SHOW;
\r
8021 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8022 wp.rcNormalPosition.left = consoleX;
\r
8023 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8024 wp.rcNormalPosition.top = consoleY;
\r
8025 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8026 SetWindowPlacement(hDlg, &wp);
\r
8029 // [HGM] Chessknight's change 2004-07-13
\r
8030 else { /* Determine Defaults */
\r
8031 WINDOWPLACEMENT wp;
\r
8032 consoleX = winWidth + 1;
\r
8033 consoleY = boardY;
\r
8034 consoleW = screenWidth - winWidth;
\r
8035 consoleH = winHeight;
\r
8036 EnsureOnScreen(&consoleX, &consoleY);
\r
8037 wp.length = sizeof(WINDOWPLACEMENT);
\r
8039 wp.showCmd = SW_SHOW;
\r
8040 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8041 wp.rcNormalPosition.left = consoleX;
\r
8042 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8043 wp.rcNormalPosition.top = consoleY;
\r
8044 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8045 SetWindowPlacement(hDlg, &wp);
\r
8060 if (IsIconic(hDlg)) break;
\r
8061 newSizeX = LOWORD(lParam);
\r
8062 newSizeY = HIWORD(lParam);
\r
8063 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8064 RECT rectText, rectInput;
\r
8066 int newTextHeight, newTextWidth;
\r
8067 GetWindowRect(hText, &rectText);
\r
8068 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8069 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8070 if (newTextHeight < 0) {
\r
8071 newSizeY += -newTextHeight;
\r
8072 newTextHeight = 0;
\r
8074 SetWindowPos(hText, NULL, 0, 0,
\r
8075 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8076 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8077 pt.x = rectInput.left;
\r
8078 pt.y = rectInput.top + newSizeY - sizeY;
\r
8079 ScreenToClient(hDlg, &pt);
\r
8080 SetWindowPos(hInput, NULL,
\r
8081 pt.x, pt.y, /* needs client coords */
\r
8082 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8083 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8089 case WM_GETMINMAXINFO:
\r
8090 /* Prevent resizing window too small */
\r
8091 mmi = (MINMAXINFO *) lParam;
\r
8092 mmi->ptMinTrackSize.x = 100;
\r
8093 mmi->ptMinTrackSize.y = 100;
\r
8096 /* [AS] Snapping */
\r
8097 case WM_ENTERSIZEMOVE:
\r
8098 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8101 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8104 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8106 case WM_EXITSIZEMOVE:
\r
8107 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8110 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8118 if (hwndConsole) return;
\r
8119 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8120 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8125 ConsoleOutput(char* data, int length, int forceVisible)
\r
8130 char buf[CO_MAX+1];
\r
8133 static int delayLF = 0;
\r
8134 CHARRANGE savesel, sel;
\r
8136 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8144 while (length--) {
\r
8152 } else if (*p == '\007') {
\r
8153 MyPlaySound(&sounds[(int)SoundBell]);
\r
8160 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8161 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8162 /* Save current selection */
\r
8163 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8164 exlen = GetWindowTextLength(hText);
\r
8165 /* Find out whether current end of text is visible */
\r
8166 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8167 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8168 /* Trim existing text if it's too long */
\r
8169 if (exlen + (q - buf) > CO_MAX) {
\r
8170 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8173 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8174 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8176 savesel.cpMin -= trim;
\r
8177 savesel.cpMax -= trim;
\r
8178 if (exlen < 0) exlen = 0;
\r
8179 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8180 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8182 /* Append the new text */
\r
8183 sel.cpMin = exlen;
\r
8184 sel.cpMax = exlen;
\r
8185 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8186 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8187 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8188 if (forceVisible || exlen == 0 ||
\r
8189 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8190 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8191 /* Scroll to make new end of text visible if old end of text
\r
8192 was visible or new text is an echo of user typein */
\r
8193 sel.cpMin = 9999999;
\r
8194 sel.cpMax = 9999999;
\r
8195 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8196 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8197 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8198 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8200 if (savesel.cpMax == exlen || forceVisible) {
\r
8201 /* Move insert point to new end of text if it was at the old
\r
8202 end of text or if the new text is an echo of user typein */
\r
8203 sel.cpMin = 9999999;
\r
8204 sel.cpMax = 9999999;
\r
8205 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8207 /* Restore previous selection */
\r
8208 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8210 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8217 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8221 COLORREF oldFg, oldBg;
\r
8225 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8227 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8228 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8229 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8232 rect.right = x + squareSize;
\r
8234 rect.bottom = y + squareSize;
\r
8237 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8238 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8239 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8240 &rect, str, strlen(str), NULL);
\r
8242 (void) SetTextColor(hdc, oldFg);
\r
8243 (void) SetBkColor(hdc, oldBg);
\r
8244 (void) SelectObject(hdc, oldFont);
\r
8248 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8249 RECT *rect, char *color, char *flagFell)
\r
8253 COLORREF oldFg, oldBg;
\r
8256 if (appData.clockMode) {
\r
8258 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8260 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
8267 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8268 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8270 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8271 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8273 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8275 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8276 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8277 rect, str, strlen(str), NULL);
\r
8279 (void) SetTextColor(hdc, oldFg);
\r
8280 (void) SetBkColor(hdc, oldBg);
\r
8281 (void) SelectObject(hdc, oldFont);
\r
8286 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8292 if( count <= 0 ) {
\r
8293 if (appData.debugMode) {
\r
8294 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8297 return ERROR_INVALID_USER_BUFFER;
\r
8300 ResetEvent(ovl->hEvent);
\r
8301 ovl->Offset = ovl->OffsetHigh = 0;
\r
8302 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8306 err = GetLastError();
\r
8307 if (err == ERROR_IO_PENDING) {
\r
8308 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8312 err = GetLastError();
\r
8319 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8324 ResetEvent(ovl->hEvent);
\r
8325 ovl->Offset = ovl->OffsetHigh = 0;
\r
8326 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8330 err = GetLastError();
\r
8331 if (err == ERROR_IO_PENDING) {
\r
8332 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8336 err = GetLastError();
\r
8342 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8343 void CheckForInputBufferFull( InputSource * is )
\r
8345 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8346 /* Look for end of line */
\r
8347 char * p = is->buf;
\r
8349 while( p < is->next && *p != '\n' ) {
\r
8353 if( p >= is->next ) {
\r
8354 if (appData.debugMode) {
\r
8355 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8358 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8359 is->count = (DWORD) -1;
\r
8360 is->next = is->buf;
\r
8366 InputThread(LPVOID arg)
\r
8371 is = (InputSource *) arg;
\r
8372 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8373 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8374 while (is->hThread != NULL) {
\r
8375 is->error = DoReadFile(is->hFile, is->next,
\r
8376 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8377 &is->count, &ovl);
\r
8378 if (is->error == NO_ERROR) {
\r
8379 is->next += is->count;
\r
8381 if (is->error == ERROR_BROKEN_PIPE) {
\r
8382 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8385 is->count = (DWORD) -1;
\r
8386 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8391 CheckForInputBufferFull( is );
\r
8393 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8395 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8397 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8400 CloseHandle(ovl.hEvent);
\r
8401 CloseHandle(is->hFile);
\r
8403 if (appData.debugMode) {
\r
8404 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8411 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8413 NonOvlInputThread(LPVOID arg)
\r
8420 is = (InputSource *) arg;
\r
8421 while (is->hThread != NULL) {
\r
8422 is->error = ReadFile(is->hFile, is->next,
\r
8423 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8424 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8425 if (is->error == NO_ERROR) {
\r
8426 /* Change CRLF to LF */
\r
8427 if (is->next > is->buf) {
\r
8429 i = is->count + 1;
\r
8437 if (prev == '\r' && *p == '\n') {
\r
8449 if (is->error == ERROR_BROKEN_PIPE) {
\r
8450 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8453 is->count = (DWORD) -1;
\r
8457 CheckForInputBufferFull( is );
\r
8459 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8461 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8463 if (is->count < 0) break; /* Quit on error */
\r
8465 CloseHandle(is->hFile);
\r
8470 SocketInputThread(LPVOID arg)
\r
8474 is = (InputSource *) arg;
\r
8475 while (is->hThread != NULL) {
\r
8476 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8477 if ((int)is->count == SOCKET_ERROR) {
\r
8478 is->count = (DWORD) -1;
\r
8479 is->error = WSAGetLastError();
\r
8481 is->error = NO_ERROR;
\r
8482 is->next += is->count;
\r
8483 if (is->count == 0 && is->second == is) {
\r
8484 /* End of file on stderr; quit with no message */
\r
8488 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8490 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8492 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8498 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8502 is = (InputSource *) lParam;
\r
8503 if (is->lineByLine) {
\r
8504 /* Feed in lines one by one */
\r
8505 char *p = is->buf;
\r
8507 while (q < is->next) {
\r
8508 if (*q++ == '\n') {
\r
8509 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8514 /* Move any partial line to the start of the buffer */
\r
8516 while (p < is->next) {
\r
8521 if (is->error != NO_ERROR || is->count == 0) {
\r
8522 /* Notify backend of the error. Note: If there was a partial
\r
8523 line at the end, it is not flushed through. */
\r
8524 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8527 /* Feed in the whole chunk of input at once */
\r
8528 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8529 is->next = is->buf;
\r
8533 /*---------------------------------------------------------------------------*\
\r
8535 * Menu enables. Used when setting various modes.
\r
8537 \*---------------------------------------------------------------------------*/
\r
8545 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8547 while (enab->item > 0) {
\r
8548 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8553 Enables gnuEnables[] = {
\r
8554 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8555 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8556 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8557 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8558 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8559 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8560 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8561 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8562 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8563 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8567 Enables icsEnables[] = {
\r
8568 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8569 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8570 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8571 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8572 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8573 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8574 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8575 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8576 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8577 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8578 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8579 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8584 Enables zippyEnables[] = {
\r
8585 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8586 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8587 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8592 Enables ncpEnables[] = {
\r
8593 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8594 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8595 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8596 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8597 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8598 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8599 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8600 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8601 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8602 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8603 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8604 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8605 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8606 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8607 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8611 Enables trainingOnEnables[] = {
\r
8612 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8613 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8614 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8615 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8616 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8617 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8618 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8619 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8623 Enables trainingOffEnables[] = {
\r
8624 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8625 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8626 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8627 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8628 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8629 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8630 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8631 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8635 /* These modify either ncpEnables or gnuEnables */
\r
8636 Enables cmailEnables[] = {
\r
8637 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8638 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8639 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8640 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8641 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8642 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8643 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8647 Enables machineThinkingEnables[] = {
\r
8648 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8649 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8650 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8651 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8652 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8653 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8654 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8655 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8656 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8657 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8658 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8659 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8660 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8661 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8662 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8666 Enables userThinkingEnables[] = {
\r
8667 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8668 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8669 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8670 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8671 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8672 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8673 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8674 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8675 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8676 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8677 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8678 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8679 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8680 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8681 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8685 /*---------------------------------------------------------------------------*\
\r
8687 * Front-end interface functions exported by XBoard.
\r
8688 * Functions appear in same order as prototypes in frontend.h.
\r
8690 \*---------------------------------------------------------------------------*/
\r
8694 static UINT prevChecked = 0;
\r
8695 static int prevPausing = 0;
\r
8698 if (pausing != prevPausing) {
\r
8699 prevPausing = pausing;
\r
8700 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8701 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8702 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8705 switch (gameMode) {
\r
8706 case BeginningOfGame:
\r
8707 if (appData.icsActive)
\r
8708 nowChecked = IDM_IcsClient;
\r
8709 else if (appData.noChessProgram)
\r
8710 nowChecked = IDM_EditGame;
\r
8712 nowChecked = IDM_MachineBlack;
\r
8714 case MachinePlaysBlack:
\r
8715 nowChecked = IDM_MachineBlack;
\r
8717 case MachinePlaysWhite:
\r
8718 nowChecked = IDM_MachineWhite;
\r
8720 case TwoMachinesPlay:
\r
8721 nowChecked = IDM_TwoMachines;
\r
8724 nowChecked = IDM_AnalysisMode;
\r
8727 nowChecked = IDM_AnalyzeFile;
\r
8730 nowChecked = IDM_EditGame;
\r
8732 case PlayFromGameFile:
\r
8733 nowChecked = IDM_LoadGame;
\r
8735 case EditPosition:
\r
8736 nowChecked = IDM_EditPosition;
\r
8739 nowChecked = IDM_Training;
\r
8741 case IcsPlayingWhite:
\r
8742 case IcsPlayingBlack:
\r
8743 case IcsObserving:
\r
8745 nowChecked = IDM_IcsClient;
\r
8752 if (prevChecked != 0)
\r
8753 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8754 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8755 if (nowChecked != 0)
\r
8756 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8757 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8759 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8760 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8761 MF_BYCOMMAND|MF_ENABLED);
\r
8763 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8764 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8767 prevChecked = nowChecked;
\r
8769 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8770 if (appData.icsActive) {
\r
8771 if (appData.icsEngineAnalyze) {
\r
8772 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8773 MF_BYCOMMAND|MF_CHECKED);
\r
8775 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8776 MF_BYCOMMAND|MF_UNCHECKED);
\r
8784 HMENU hmenu = GetMenu(hwndMain);
\r
8785 SetMenuEnables(hmenu, icsEnables);
\r
8786 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8787 MF_BYPOSITION|MF_ENABLED);
\r
8789 if (appData.zippyPlay) {
\r
8790 SetMenuEnables(hmenu, zippyEnables);
\r
8791 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8792 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8793 MF_BYCOMMAND|MF_ENABLED);
\r
8801 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8807 HMENU hmenu = GetMenu(hwndMain);
\r
8808 SetMenuEnables(hmenu, ncpEnables);
\r
8809 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8810 MF_BYPOSITION|MF_GRAYED);
\r
8811 DrawMenuBar(hwndMain);
\r
8817 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8821 SetTrainingModeOn()
\r
8824 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8825 for (i = 0; i < N_BUTTONS; i++) {
\r
8826 if (buttonDesc[i].hwnd != NULL)
\r
8827 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8832 VOID SetTrainingModeOff()
\r
8835 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8836 for (i = 0; i < N_BUTTONS; i++) {
\r
8837 if (buttonDesc[i].hwnd != NULL)
\r
8838 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8844 SetUserThinkingEnables()
\r
8846 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8850 SetMachineThinkingEnables()
\r
8852 HMENU hMenu = GetMenu(hwndMain);
\r
8853 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8855 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8857 if (gameMode == MachinePlaysBlack) {
\r
8858 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8859 } else if (gameMode == MachinePlaysWhite) {
\r
8860 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8861 } else if (gameMode == TwoMachinesPlay) {
\r
8862 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8868 DisplayTitle(char *str)
\r
8870 char title[MSG_SIZ], *host;
\r
8871 if (str[0] != NULLCHAR) {
\r
8872 strcpy(title, str);
\r
8873 } else if (appData.icsActive) {
\r
8874 if (appData.icsCommPort[0] != NULLCHAR)
\r
8877 host = appData.icsHost;
\r
8878 sprintf(title, "%s: %s", szTitle, host);
\r
8879 } else if (appData.noChessProgram) {
\r
8880 strcpy(title, szTitle);
\r
8882 strcpy(title, szTitle);
\r
8883 strcat(title, ": ");
\r
8884 strcat(title, first.tidy);
\r
8886 SetWindowText(hwndMain, title);
\r
8891 DisplayMessage(char *str1, char *str2)
\r
8895 int remain = MESSAGE_TEXT_MAX - 1;
\r
8898 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8899 messageText[0] = NULLCHAR;
\r
8901 len = strlen(str1);
\r
8902 if (len > remain) len = remain;
\r
8903 strncpy(messageText, str1, len);
\r
8904 messageText[len] = NULLCHAR;
\r
8907 if (*str2 && remain >= 2) {
\r
8909 strcat(messageText, " ");
\r
8912 len = strlen(str2);
\r
8913 if (len > remain) len = remain;
\r
8914 strncat(messageText, str2, len);
\r
8916 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8918 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8919 hdc = GetDC(hwndMain);
\r
8920 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8921 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8922 &messageRect, messageText, strlen(messageText), NULL);
\r
8923 (void) SelectObject(hdc, oldFont);
\r
8924 (void) ReleaseDC(hwndMain, hdc);
\r
8928 DisplayError(char *str, int error)
\r
8930 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8936 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8937 NULL, error, LANG_NEUTRAL,
\r
8938 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8940 sprintf(buf, "%s:\n%s", str, buf2);
\r
8942 ErrorMap *em = errmap;
\r
8943 while (em->err != 0 && em->err != error) em++;
\r
8944 if (em->err != 0) {
\r
8945 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8947 sprintf(buf, "%s:\nError code %d", str, error);
\r
8952 ErrorPopUp("Error", buf);
\r
8957 DisplayMoveError(char *str)
\r
8959 fromX = fromY = -1;
\r
8960 ClearHighlights();
\r
8961 DrawPosition(FALSE, NULL);
\r
8962 if (appData.popupMoveErrors) {
\r
8963 ErrorPopUp("Error", str);
\r
8965 DisplayMessage(str, "");
\r
8966 moveErrorMessageUp = TRUE;
\r
8971 DisplayFatalError(char *str, int error, int exitStatus)
\r
8973 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8975 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8978 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8979 NULL, error, LANG_NEUTRAL,
\r
8980 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8982 sprintf(buf, "%s:\n%s", str, buf2);
\r
8984 ErrorMap *em = errmap;
\r
8985 while (em->err != 0 && em->err != error) em++;
\r
8986 if (em->err != 0) {
\r
8987 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8989 sprintf(buf, "%s:\nError code %d", str, error);
\r
8994 if (appData.debugMode) {
\r
8995 fprintf(debugFP, "%s: %s\n", label, str);
\r
8997 if (appData.popupExitMessage) {
\r
8998 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8999 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9001 ExitEvent(exitStatus);
\r
9006 DisplayInformation(char *str)
\r
9008 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9013 DisplayNote(char *str)
\r
9015 ErrorPopUp("Note", str);
\r
9020 char *title, *question, *replyPrefix;
\r
9025 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9027 static QuestionParams *qp;
\r
9028 char reply[MSG_SIZ];
\r
9031 switch (message) {
\r
9032 case WM_INITDIALOG:
\r
9033 qp = (QuestionParams *) lParam;
\r
9034 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9035 SetWindowText(hDlg, qp->title);
\r
9036 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9037 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9041 switch (LOWORD(wParam)) {
\r
9043 strcpy(reply, qp->replyPrefix);
\r
9044 if (*reply) strcat(reply, " ");
\r
9045 len = strlen(reply);
\r
9046 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9047 strcat(reply, "\n");
\r
9048 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9049 EndDialog(hDlg, TRUE);
\r
9050 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9053 EndDialog(hDlg, FALSE);
\r
9064 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9066 QuestionParams qp;
\r
9070 qp.question = question;
\r
9071 qp.replyPrefix = replyPrefix;
\r
9073 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9074 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9075 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9076 FreeProcInstance(lpProc);
\r
9079 /* [AS] Pick FRC position */
\r
9080 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9082 static int * lpIndexFRC;
\r
9088 case WM_INITDIALOG:
\r
9089 lpIndexFRC = (int *) lParam;
\r
9091 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9093 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9094 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9095 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9096 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9101 switch( LOWORD(wParam) ) {
\r
9103 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9104 EndDialog( hDlg, 0 );
\r
9105 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9108 EndDialog( hDlg, 1 );
\r
9110 case IDC_NFG_Edit:
\r
9111 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9112 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9114 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9117 case IDC_NFG_Random:
\r
9118 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9119 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9132 int index = appData.defaultFrcPosition;
\r
9133 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9135 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9137 if( result == 0 ) {
\r
9138 appData.defaultFrcPosition = index;
\r
9144 /* [AS] Game list options */
\r
9150 static GLT_Item GLT_ItemInfo[] = {
\r
9151 { GLT_EVENT, "Event" },
\r
9152 { GLT_SITE, "Site" },
\r
9153 { GLT_DATE, "Date" },
\r
9154 { GLT_ROUND, "Round" },
\r
9155 { GLT_PLAYERS, "Players" },
\r
9156 { GLT_RESULT, "Result" },
\r
9157 { GLT_WHITE_ELO, "White Rating" },
\r
9158 { GLT_BLACK_ELO, "Black Rating" },
\r
9159 { GLT_TIME_CONTROL,"Time Control" },
\r
9160 { GLT_VARIANT, "Variant" },
\r
9161 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9165 const char * GLT_FindItem( char id )
\r
9167 const char * result = 0;
\r
9169 GLT_Item * list = GLT_ItemInfo;
\r
9171 while( list->id != 0 ) {
\r
9172 if( list->id == id ) {
\r
9173 result = list->name;
\r
9183 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9185 const char * name = GLT_FindItem( id );
\r
9188 if( index >= 0 ) {
\r
9189 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9192 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9197 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9201 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9204 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9208 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9210 pc = GLT_ALL_TAGS;
\r
9213 if( strchr( tags, *pc ) == 0 ) {
\r
9214 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9219 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9222 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9224 char result = '\0';
\r
9227 GLT_Item * list = GLT_ItemInfo;
\r
9229 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9230 while( list->id != 0 ) {
\r
9231 if( strcmp( list->name, name ) == 0 ) {
\r
9232 result = list->id;
\r
9243 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9245 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9246 int idx2 = idx1 + delta;
\r
9247 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9249 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9252 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9253 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9254 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9255 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9259 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9261 static char glt[64];
\r
9262 static char * lpUserGLT;
\r
9266 case WM_INITDIALOG:
\r
9267 lpUserGLT = (char *) lParam;
\r
9269 strcpy( glt, lpUserGLT );
\r
9271 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9273 /* Initialize list */
\r
9274 GLT_TagsToList( hDlg, glt );
\r
9276 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9281 switch( LOWORD(wParam) ) {
\r
9284 char * pc = lpUserGLT;
\r
9286 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9290 id = GLT_ListItemToTag( hDlg, idx );
\r
9294 } while( id != '\0' );
\r
9296 EndDialog( hDlg, 0 );
\r
9299 EndDialog( hDlg, 1 );
\r
9302 case IDC_GLT_Default:
\r
9303 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9304 GLT_TagsToList( hDlg, glt );
\r
9307 case IDC_GLT_Restore:
\r
9308 strcpy( glt, lpUserGLT );
\r
9309 GLT_TagsToList( hDlg, glt );
\r
9313 GLT_MoveSelection( hDlg, -1 );
\r
9316 case IDC_GLT_Down:
\r
9317 GLT_MoveSelection( hDlg, +1 );
\r
9327 int GameListOptions()
\r
9331 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9333 strcpy( glt, appData.gameListTags );
\r
9335 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9337 if( result == 0 ) {
\r
9338 /* [AS] Memory leak here! */
\r
9339 appData.gameListTags = strdup( glt );
\r
9347 DisplayIcsInteractionTitle(char *str)
\r
9349 char consoleTitle[MSG_SIZ];
\r
9351 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9352 SetWindowText(hwndConsole, consoleTitle);
\r
9356 DrawPosition(int fullRedraw, Board board)
\r
9358 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9365 fromX = fromY = -1;
\r
9366 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9367 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9368 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9369 dragInfo.lastpos = dragInfo.pos;
\r
9370 dragInfo.start.x = dragInfo.start.y = -1;
\r
9371 dragInfo.from = dragInfo.start;
\r
9373 DrawPosition(TRUE, NULL);
\r
9379 CommentPopUp(char *title, char *str)
\r
9381 HWND hwnd = GetActiveWindow();
\r
9382 EitherCommentPopUp(0, title, str, FALSE);
\r
9383 SetActiveWindow(hwnd);
\r
9387 CommentPopDown(void)
\r
9389 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9390 if (commentDialog) {
\r
9391 ShowWindow(commentDialog, SW_HIDE);
\r
9393 commentDialogUp = FALSE;
\r
9397 EditCommentPopUp(int index, char *title, char *str)
\r
9399 EitherCommentPopUp(index, title, str, TRUE);
\r
9406 MyPlaySound(&sounds[(int)SoundMove]);
\r
9409 VOID PlayIcsWinSound()
\r
9411 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9414 VOID PlayIcsLossSound()
\r
9416 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9419 VOID PlayIcsDrawSound()
\r
9421 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9424 VOID PlayIcsUnfinishedSound()
\r
9426 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9432 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9440 consoleEcho = TRUE;
\r
9441 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9442 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9443 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9452 consoleEcho = FALSE;
\r
9453 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9454 /* This works OK: set text and background both to the same color */
\r
9456 cf.crTextColor = COLOR_ECHOOFF;
\r
9457 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9458 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9461 /* No Raw()...? */
\r
9463 void Colorize(ColorClass cc, int continuation)
\r
9465 currentColorClass = cc;
\r
9466 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9467 consoleCF.crTextColor = textAttribs[cc].color;
\r
9468 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9469 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9475 static char buf[MSG_SIZ];
\r
9476 DWORD bufsiz = MSG_SIZ;
\r
9478 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9479 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9481 if (!GetUserName(buf, &bufsiz)) {
\r
9482 /*DisplayError("Error getting user name", GetLastError());*/
\r
9483 strcpy(buf, "User");
\r
9491 static char buf[MSG_SIZ];
\r
9492 DWORD bufsiz = MSG_SIZ;
\r
9494 if (!GetComputerName(buf, &bufsiz)) {
\r
9495 /*DisplayError("Error getting host name", GetLastError());*/
\r
9496 strcpy(buf, "Unknown");
\r
9503 ClockTimerRunning()
\r
9505 return clockTimerEvent != 0;
\r
9511 if (clockTimerEvent == 0) return FALSE;
\r
9512 KillTimer(hwndMain, clockTimerEvent);
\r
9513 clockTimerEvent = 0;
\r
9518 StartClockTimer(long millisec)
\r
9520 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9521 (UINT) millisec, NULL);
\r
9525 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9528 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9530 if(appData.noGUI) return;
\r
9531 hdc = GetDC(hwndMain);
\r
9532 if (!IsIconic(hwndMain)) {
\r
9533 DisplayAClock(hdc, timeRemaining, highlight,
\r
9534 (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);
\r
9536 if (highlight && iconCurrent == iconBlack) {
\r
9537 iconCurrent = iconWhite;
\r
9538 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9539 if (IsIconic(hwndMain)) {
\r
9540 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9543 (void) ReleaseDC(hwndMain, hdc);
\r
9545 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9549 DisplayBlackClock(long timeRemaining, int highlight)
\r
9552 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9554 if(appData.noGUI) return;
\r
9555 hdc = GetDC(hwndMain);
\r
9556 if (!IsIconic(hwndMain)) {
\r
9557 DisplayAClock(hdc, timeRemaining, highlight,
\r
9558 (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);
\r
9560 if (highlight && iconCurrent == iconWhite) {
\r
9561 iconCurrent = iconBlack;
\r
9562 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9563 if (IsIconic(hwndMain)) {
\r
9564 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9567 (void) ReleaseDC(hwndMain, hdc);
\r
9569 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9574 LoadGameTimerRunning()
\r
9576 return loadGameTimerEvent != 0;
\r
9580 StopLoadGameTimer()
\r
9582 if (loadGameTimerEvent == 0) return FALSE;
\r
9583 KillTimer(hwndMain, loadGameTimerEvent);
\r
9584 loadGameTimerEvent = 0;
\r
9589 StartLoadGameTimer(long millisec)
\r
9591 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9592 (UINT) millisec, NULL);
\r
9600 char fileTitle[MSG_SIZ];
\r
9602 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9603 f = OpenFileDialog(hwndMain, "a", defName,
\r
9604 appData.oldSaveStyle ? "gam" : "pgn",
\r
9606 "Save Game to File", NULL, fileTitle, NULL);
\r
9608 SaveGame(f, 0, "");
\r
9615 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9617 if (delayedTimerEvent != 0) {
\r
9618 if (appData.debugMode) {
\r
9619 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9621 KillTimer(hwndMain, delayedTimerEvent);
\r
9622 delayedTimerEvent = 0;
\r
9623 delayedTimerCallback();
\r
9625 delayedTimerCallback = cb;
\r
9626 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9627 (UINT) millisec, NULL);
\r
9630 DelayedEventCallback
\r
9633 if (delayedTimerEvent) {
\r
9634 return delayedTimerCallback;
\r
9641 CancelDelayedEvent()
\r
9643 if (delayedTimerEvent) {
\r
9644 KillTimer(hwndMain, delayedTimerEvent);
\r
9645 delayedTimerEvent = 0;
\r
9649 DWORD GetWin32Priority(int nice)
\r
9650 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9652 REALTIME_PRIORITY_CLASS 0x00000100
\r
9653 HIGH_PRIORITY_CLASS 0x00000080
\r
9654 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9655 NORMAL_PRIORITY_CLASS 0x00000020
\r
9656 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9657 IDLE_PRIORITY_CLASS 0x00000040
\r
9659 if (nice < -15) return 0x00000080;
\r
9660 if (nice < 0) return 0x00008000;
\r
9661 if (nice == 0) return 0x00000020;
\r
9662 if (nice < 15) return 0x00004000;
\r
9663 return 0x00000040;
\r
9666 /* Start a child process running the given program.
\r
9667 The process's standard output can be read from "from", and its
\r
9668 standard input can be written to "to".
\r
9669 Exit with fatal error if anything goes wrong.
\r
9670 Returns an opaque pointer that can be used to destroy the process
\r
9674 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9676 #define BUFSIZE 4096
\r
9678 HANDLE hChildStdinRd, hChildStdinWr,
\r
9679 hChildStdoutRd, hChildStdoutWr;
\r
9680 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9681 SECURITY_ATTRIBUTES saAttr;
\r
9683 PROCESS_INFORMATION piProcInfo;
\r
9684 STARTUPINFO siStartInfo;
\r
9686 char buf[MSG_SIZ];
\r
9689 if (appData.debugMode) {
\r
9690 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9695 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9696 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9697 saAttr.bInheritHandle = TRUE;
\r
9698 saAttr.lpSecurityDescriptor = NULL;
\r
9701 * The steps for redirecting child's STDOUT:
\r
9702 * 1. Create anonymous pipe to be STDOUT for child.
\r
9703 * 2. Create a noninheritable duplicate of read handle,
\r
9704 * and close the inheritable read handle.
\r
9707 /* Create a pipe for the child's STDOUT. */
\r
9708 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9709 return GetLastError();
\r
9712 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9713 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9714 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9715 FALSE, /* not inherited */
\r
9716 DUPLICATE_SAME_ACCESS);
\r
9718 return GetLastError();
\r
9720 CloseHandle(hChildStdoutRd);
\r
9723 * The steps for redirecting child's STDIN:
\r
9724 * 1. Create anonymous pipe to be STDIN for child.
\r
9725 * 2. Create a noninheritable duplicate of write handle,
\r
9726 * and close the inheritable write handle.
\r
9729 /* Create a pipe for the child's STDIN. */
\r
9730 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9731 return GetLastError();
\r
9734 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9735 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9736 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9737 FALSE, /* not inherited */
\r
9738 DUPLICATE_SAME_ACCESS);
\r
9740 return GetLastError();
\r
9742 CloseHandle(hChildStdinWr);
\r
9744 /* Arrange to (1) look in dir for the child .exe file, and
\r
9745 * (2) have dir be the child's working directory. Interpret
\r
9746 * dir relative to the directory WinBoard loaded from. */
\r
9747 GetCurrentDirectory(MSG_SIZ, buf);
\r
9748 SetCurrentDirectory(installDir);
\r
9749 SetCurrentDirectory(dir);
\r
9751 /* Now create the child process. */
\r
9753 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9754 siStartInfo.lpReserved = NULL;
\r
9755 siStartInfo.lpDesktop = NULL;
\r
9756 siStartInfo.lpTitle = NULL;
\r
9757 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9758 siStartInfo.cbReserved2 = 0;
\r
9759 siStartInfo.lpReserved2 = NULL;
\r
9760 siStartInfo.hStdInput = hChildStdinRd;
\r
9761 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9762 siStartInfo.hStdError = hChildStdoutWr;
\r
9764 fSuccess = CreateProcess(NULL,
\r
9765 cmdLine, /* command line */
\r
9766 NULL, /* process security attributes */
\r
9767 NULL, /* primary thread security attrs */
\r
9768 TRUE, /* handles are inherited */
\r
9769 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9770 NULL, /* use parent's environment */
\r
9772 &siStartInfo, /* STARTUPINFO pointer */
\r
9773 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9775 err = GetLastError();
\r
9776 SetCurrentDirectory(buf); /* return to prev directory */
\r
9781 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9782 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9783 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9786 /* Close the handles we don't need in the parent */
\r
9787 CloseHandle(piProcInfo.hThread);
\r
9788 CloseHandle(hChildStdinRd);
\r
9789 CloseHandle(hChildStdoutWr);
\r
9791 /* Prepare return value */
\r
9792 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9793 cp->kind = CPReal;
\r
9794 cp->hProcess = piProcInfo.hProcess;
\r
9795 cp->pid = piProcInfo.dwProcessId;
\r
9796 cp->hFrom = hChildStdoutRdDup;
\r
9797 cp->hTo = hChildStdinWrDup;
\r
9799 *pr = (void *) cp;
\r
9801 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9802 2000 where engines sometimes don't see the initial command(s)
\r
9803 from WinBoard and hang. I don't understand how that can happen,
\r
9804 but the Sleep is harmless, so I've put it in. Others have also
\r
9805 reported what may be the same problem, so hopefully this will fix
\r
9806 it for them too. */
\r
9814 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9816 ChildProc *cp; int result;
\r
9818 cp = (ChildProc *) pr;
\r
9819 if (cp == NULL) return;
\r
9821 switch (cp->kind) {
\r
9823 /* TerminateProcess is considered harmful, so... */
\r
9824 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9825 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9826 /* The following doesn't work because the chess program
\r
9827 doesn't "have the same console" as WinBoard. Maybe
\r
9828 we could arrange for this even though neither WinBoard
\r
9829 nor the chess program uses a console for stdio? */
\r
9830 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9832 /* [AS] Special termination modes for misbehaving programs... */
\r
9833 if( signal == 9 ) {
\r
9834 result = TerminateProcess( cp->hProcess, 0 );
\r
9836 if ( appData.debugMode) {
\r
9837 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9840 else if( signal == 10 ) {
\r
9841 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9843 if( dw != WAIT_OBJECT_0 ) {
\r
9844 result = TerminateProcess( cp->hProcess, 0 );
\r
9846 if ( appData.debugMode) {
\r
9847 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9853 CloseHandle(cp->hProcess);
\r
9857 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9861 closesocket(cp->sock);
\r
9866 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9867 closesocket(cp->sock);
\r
9868 closesocket(cp->sock2);
\r
9876 InterruptChildProcess(ProcRef pr)
\r
9880 cp = (ChildProc *) pr;
\r
9881 if (cp == NULL) return;
\r
9882 switch (cp->kind) {
\r
9884 /* The following doesn't work because the chess program
\r
9885 doesn't "have the same console" as WinBoard. Maybe
\r
9886 we could arrange for this even though neither WinBoard
\r
9887 nor the chess program uses a console for stdio */
\r
9888 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9893 /* Can't interrupt */
\r
9897 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9904 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9906 char cmdLine[MSG_SIZ];
\r
9908 if (port[0] == NULLCHAR) {
\r
9909 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9911 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9913 return StartChildProcess(cmdLine, "", pr);
\r
9917 /* Code to open TCP sockets */
\r
9920 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9925 struct sockaddr_in sa, mysa;
\r
9926 struct hostent FAR *hp;
\r
9927 unsigned short uport;
\r
9928 WORD wVersionRequested;
\r
9931 /* Initialize socket DLL */
\r
9932 wVersionRequested = MAKEWORD(1, 1);
\r
9933 err = WSAStartup(wVersionRequested, &wsaData);
\r
9934 if (err != 0) return err;
\r
9937 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9938 err = WSAGetLastError();
\r
9943 /* Bind local address using (mostly) don't-care values.
\r
9945 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9946 mysa.sin_family = AF_INET;
\r
9947 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9948 uport = (unsigned short) 0;
\r
9949 mysa.sin_port = htons(uport);
\r
9950 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9951 == SOCKET_ERROR) {
\r
9952 err = WSAGetLastError();
\r
9957 /* Resolve remote host name */
\r
9958 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9959 if (!(hp = gethostbyname(host))) {
\r
9960 unsigned int b0, b1, b2, b3;
\r
9962 err = WSAGetLastError();
\r
9964 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9965 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9966 hp->h_addrtype = AF_INET;
\r
9968 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9969 hp->h_addr_list[0] = (char *) malloc(4);
\r
9970 hp->h_addr_list[0][0] = (char) b0;
\r
9971 hp->h_addr_list[0][1] = (char) b1;
\r
9972 hp->h_addr_list[0][2] = (char) b2;
\r
9973 hp->h_addr_list[0][3] = (char) b3;
\r
9979 sa.sin_family = hp->h_addrtype;
\r
9980 uport = (unsigned short) atoi(port);
\r
9981 sa.sin_port = htons(uport);
\r
9982 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9984 /* Make connection */
\r
9985 if (connect(s, (struct sockaddr *) &sa,
\r
9986 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9987 err = WSAGetLastError();
\r
9992 /* Prepare return value */
\r
9993 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9994 cp->kind = CPSock;
\r
9996 *pr = (ProcRef *) cp;
\r
10002 OpenCommPort(char *name, ProcRef *pr)
\r
10007 char fullname[MSG_SIZ];
\r
10009 if (*name != '\\')
\r
10010 sprintf(fullname, "\\\\.\\%s", name);
\r
10012 strcpy(fullname, name);
\r
10014 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10015 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10016 if (h == (HANDLE) -1) {
\r
10017 return GetLastError();
\r
10021 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10023 /* Accumulate characters until a 100ms pause, then parse */
\r
10024 ct.ReadIntervalTimeout = 100;
\r
10025 ct.ReadTotalTimeoutMultiplier = 0;
\r
10026 ct.ReadTotalTimeoutConstant = 0;
\r
10027 ct.WriteTotalTimeoutMultiplier = 0;
\r
10028 ct.WriteTotalTimeoutConstant = 0;
\r
10029 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10031 /* Prepare return value */
\r
10032 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10033 cp->kind = CPComm;
\r
10036 *pr = (ProcRef *) cp;
\r
10042 OpenLoopback(ProcRef *pr)
\r
10044 DisplayFatalError("Not implemented", 0, 1);
\r
10050 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10054 SOCKET s, s2, s3;
\r
10055 struct sockaddr_in sa, mysa;
\r
10056 struct hostent FAR *hp;
\r
10057 unsigned short uport;
\r
10058 WORD wVersionRequested;
\r
10061 char stderrPortStr[MSG_SIZ];
\r
10063 /* Initialize socket DLL */
\r
10064 wVersionRequested = MAKEWORD(1, 1);
\r
10065 err = WSAStartup(wVersionRequested, &wsaData);
\r
10066 if (err != 0) return err;
\r
10068 /* Resolve remote host name */
\r
10069 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10070 if (!(hp = gethostbyname(host))) {
\r
10071 unsigned int b0, b1, b2, b3;
\r
10073 err = WSAGetLastError();
\r
10075 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10076 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10077 hp->h_addrtype = AF_INET;
\r
10078 hp->h_length = 4;
\r
10079 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10080 hp->h_addr_list[0] = (char *) malloc(4);
\r
10081 hp->h_addr_list[0][0] = (char) b0;
\r
10082 hp->h_addr_list[0][1] = (char) b1;
\r
10083 hp->h_addr_list[0][2] = (char) b2;
\r
10084 hp->h_addr_list[0][3] = (char) b3;
\r
10090 sa.sin_family = hp->h_addrtype;
\r
10091 uport = (unsigned short) 514;
\r
10092 sa.sin_port = htons(uport);
\r
10093 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10095 /* Bind local socket to unused "privileged" port address
\r
10097 s = INVALID_SOCKET;
\r
10098 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10099 mysa.sin_family = AF_INET;
\r
10100 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10101 for (fromPort = 1023;; fromPort--) {
\r
10102 if (fromPort < 0) {
\r
10104 return WSAEADDRINUSE;
\r
10106 if (s == INVALID_SOCKET) {
\r
10107 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10108 err = WSAGetLastError();
\r
10113 uport = (unsigned short) fromPort;
\r
10114 mysa.sin_port = htons(uport);
\r
10115 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10116 == SOCKET_ERROR) {
\r
10117 err = WSAGetLastError();
\r
10118 if (err == WSAEADDRINUSE) continue;
\r
10122 if (connect(s, (struct sockaddr *) &sa,
\r
10123 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10124 err = WSAGetLastError();
\r
10125 if (err == WSAEADDRINUSE) {
\r
10136 /* Bind stderr local socket to unused "privileged" port address
\r
10138 s2 = INVALID_SOCKET;
\r
10139 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10140 mysa.sin_family = AF_INET;
\r
10141 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10142 for (fromPort = 1023;; fromPort--) {
\r
10143 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10144 if (fromPort < 0) {
\r
10145 (void) closesocket(s);
\r
10147 return WSAEADDRINUSE;
\r
10149 if (s2 == INVALID_SOCKET) {
\r
10150 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10151 err = WSAGetLastError();
\r
10157 uport = (unsigned short) fromPort;
\r
10158 mysa.sin_port = htons(uport);
\r
10159 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10160 == SOCKET_ERROR) {
\r
10161 err = WSAGetLastError();
\r
10162 if (err == WSAEADDRINUSE) continue;
\r
10163 (void) closesocket(s);
\r
10167 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10168 err = WSAGetLastError();
\r
10169 if (err == WSAEADDRINUSE) {
\r
10171 s2 = INVALID_SOCKET;
\r
10174 (void) closesocket(s);
\r
10175 (void) closesocket(s2);
\r
10181 prevStderrPort = fromPort; // remember port used
\r
10182 sprintf(stderrPortStr, "%d", fromPort);
\r
10184 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10185 err = WSAGetLastError();
\r
10186 (void) closesocket(s);
\r
10187 (void) closesocket(s2);
\r
10192 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10193 err = WSAGetLastError();
\r
10194 (void) closesocket(s);
\r
10195 (void) closesocket(s2);
\r
10199 if (*user == NULLCHAR) user = UserName();
\r
10200 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10201 err = WSAGetLastError();
\r
10202 (void) closesocket(s);
\r
10203 (void) closesocket(s2);
\r
10207 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10208 err = WSAGetLastError();
\r
10209 (void) closesocket(s);
\r
10210 (void) closesocket(s2);
\r
10215 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10216 err = WSAGetLastError();
\r
10217 (void) closesocket(s);
\r
10218 (void) closesocket(s2);
\r
10222 (void) closesocket(s2); /* Stop listening */
\r
10224 /* Prepare return value */
\r
10225 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10226 cp->kind = CPRcmd;
\r
10229 *pr = (ProcRef *) cp;
\r
10236 AddInputSource(ProcRef pr, int lineByLine,
\r
10237 InputCallback func, VOIDSTAR closure)
\r
10239 InputSource *is, *is2 = NULL;
\r
10240 ChildProc *cp = (ChildProc *) pr;
\r
10242 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10243 is->lineByLine = lineByLine;
\r
10245 is->closure = closure;
\r
10246 is->second = NULL;
\r
10247 is->next = is->buf;
\r
10248 if (pr == NoProc) {
\r
10249 is->kind = CPReal;
\r
10250 consoleInputSource = is;
\r
10252 is->kind = cp->kind;
\r
10254 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10255 we create all threads suspended so that the is->hThread variable can be
\r
10256 safely assigned, then let the threads start with ResumeThread.
\r
10258 switch (cp->kind) {
\r
10260 is->hFile = cp->hFrom;
\r
10261 cp->hFrom = NULL; /* now owned by InputThread */
\r
10263 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10264 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10268 is->hFile = cp->hFrom;
\r
10269 cp->hFrom = NULL; /* now owned by InputThread */
\r
10271 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10272 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10276 is->sock = cp->sock;
\r
10278 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10279 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10283 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10285 is->sock = cp->sock;
\r
10286 is->second = is2;
\r
10287 is2->sock = cp->sock2;
\r
10288 is2->second = is2;
\r
10290 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10291 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10293 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10294 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10298 if( is->hThread != NULL ) {
\r
10299 ResumeThread( is->hThread );
\r
10302 if( is2 != NULL && is2->hThread != NULL ) {
\r
10303 ResumeThread( is2->hThread );
\r
10307 return (InputSourceRef) is;
\r
10311 RemoveInputSource(InputSourceRef isr)
\r
10315 is = (InputSource *) isr;
\r
10316 is->hThread = NULL; /* tell thread to stop */
\r
10317 CloseHandle(is->hThread);
\r
10318 if (is->second != NULL) {
\r
10319 is->second->hThread = NULL;
\r
10320 CloseHandle(is->second->hThread);
\r
10326 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10329 int outCount = SOCKET_ERROR;
\r
10330 ChildProc *cp = (ChildProc *) pr;
\r
10331 static OVERLAPPED ovl;
\r
10333 if (pr == NoProc) {
\r
10334 ConsoleOutput(message, count, FALSE);
\r
10338 if (ovl.hEvent == NULL) {
\r
10339 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10341 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10343 switch (cp->kind) {
\r
10346 outCount = send(cp->sock, message, count, 0);
\r
10347 if (outCount == SOCKET_ERROR) {
\r
10348 *outError = WSAGetLastError();
\r
10350 *outError = NO_ERROR;
\r
10355 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10356 &dOutCount, NULL)) {
\r
10357 *outError = NO_ERROR;
\r
10358 outCount = (int) dOutCount;
\r
10360 *outError = GetLastError();
\r
10365 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10366 &dOutCount, &ovl);
\r
10367 if (*outError == NO_ERROR) {
\r
10368 outCount = (int) dOutCount;
\r
10376 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10379 /* Ignore delay, not implemented for WinBoard */
\r
10380 return OutputToProcess(pr, message, count, outError);
\r
10385 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10386 char *buf, int count, int error)
\r
10388 DisplayFatalError("Not implemented", 0, 1);
\r
10391 /* see wgamelist.c for Game List functions */
\r
10392 /* see wedittags.c for Edit Tags functions */
\r
10399 char buf[MSG_SIZ];
\r
10402 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10403 f = fopen(buf, "r");
\r
10405 ProcessICSInitScript(f);
\r
10413 StartAnalysisClock()
\r
10415 if (analysisTimerEvent) return;
\r
10416 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10417 (UINT) 2000, NULL);
\r
10421 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10423 static HANDLE hwndText;
\r
10425 static int sizeX, sizeY;
\r
10426 int newSizeX, newSizeY, flags;
\r
10429 switch (message) {
\r
10430 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10431 /* Initialize the dialog items */
\r
10432 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10433 SetWindowText(hDlg, analysisTitle);
\r
10434 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10435 /* Size and position the dialog */
\r
10436 if (!analysisDialog) {
\r
10437 analysisDialog = hDlg;
\r
10438 flags = SWP_NOZORDER;
\r
10439 GetClientRect(hDlg, &rect);
\r
10440 sizeX = rect.right;
\r
10441 sizeY = rect.bottom;
\r
10442 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10443 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10444 WINDOWPLACEMENT wp;
\r
10445 EnsureOnScreen(&analysisX, &analysisY);
\r
10446 wp.length = sizeof(WINDOWPLACEMENT);
\r
10448 wp.showCmd = SW_SHOW;
\r
10449 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10450 wp.rcNormalPosition.left = analysisX;
\r
10451 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10452 wp.rcNormalPosition.top = analysisY;
\r
10453 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10454 SetWindowPlacement(hDlg, &wp);
\r
10456 GetClientRect(hDlg, &rect);
\r
10457 newSizeX = rect.right;
\r
10458 newSizeY = rect.bottom;
\r
10459 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10460 newSizeX, newSizeY);
\r
10461 sizeX = newSizeX;
\r
10462 sizeY = newSizeY;
\r
10467 case WM_COMMAND: /* message: received a command */
\r
10468 switch (LOWORD(wParam)) {
\r
10470 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10471 ExitAnalyzeMode();
\r
10483 newSizeX = LOWORD(lParam);
\r
10484 newSizeY = HIWORD(lParam);
\r
10485 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10486 sizeX = newSizeX;
\r
10487 sizeY = newSizeY;
\r
10490 case WM_GETMINMAXINFO:
\r
10491 /* Prevent resizing window too small */
\r
10492 mmi = (MINMAXINFO *) lParam;
\r
10493 mmi->ptMinTrackSize.x = 100;
\r
10494 mmi->ptMinTrackSize.y = 100;
\r
10501 AnalysisPopUp(char* title, char* str)
\r
10507 EngineOutputPopUp();
\r
10510 if (str == NULL) str = "";
\r
10511 p = (char *) malloc(2 * strlen(str) + 2);
\r
10514 if (*str == '\n') *q++ = '\r';
\r
10518 if (analysisText != NULL) free(analysisText);
\r
10519 analysisText = p;
\r
10521 if (analysisDialog) {
\r
10522 SetWindowText(analysisDialog, title);
\r
10523 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10524 ShowWindow(analysisDialog, SW_SHOW);
\r
10526 analysisTitle = title;
\r
10527 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10528 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10529 hwndMain, (DLGPROC)lpProc);
\r
10530 FreeProcInstance(lpProc);
\r
10532 analysisDialogUp = TRUE;
\r
10536 AnalysisPopDown()
\r
10538 if (analysisDialog) {
\r
10539 ShowWindow(analysisDialog, SW_HIDE);
\r
10541 analysisDialogUp = FALSE;
\r
10546 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10548 highlightInfo.sq[0].x = fromX;
\r
10549 highlightInfo.sq[0].y = fromY;
\r
10550 highlightInfo.sq[1].x = toX;
\r
10551 highlightInfo.sq[1].y = toY;
\r
10555 ClearHighlights()
\r
10557 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10558 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10562 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10564 premoveHighlightInfo.sq[0].x = fromX;
\r
10565 premoveHighlightInfo.sq[0].y = fromY;
\r
10566 premoveHighlightInfo.sq[1].x = toX;
\r
10567 premoveHighlightInfo.sq[1].y = toY;
\r
10571 ClearPremoveHighlights()
\r
10573 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10574 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10578 ShutDownFrontEnd()
\r
10580 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10581 DeleteClipboardTempFiles();
\r
10587 if (IsIconic(hwndMain))
\r
10588 ShowWindow(hwndMain, SW_RESTORE);
\r
10590 SetActiveWindow(hwndMain);
\r
10594 * Prototypes for animation support routines
\r
10596 static void ScreenSquare(int column, int row, POINT * pt);
\r
10597 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10598 POINT frames[], int * nFrames);
\r
10602 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10603 { // [HGM] atomic: animate blast wave
\r
10605 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10606 explodeInfo.fromX = fromX;
\r
10607 explodeInfo.fromY = fromY;
\r
10608 explodeInfo.toX = toX;
\r
10609 explodeInfo.toY = toY;
\r
10610 for(i=1; i<nFrames; i++) {
\r
10611 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10612 DrawPosition(FALSE, NULL);
\r
10613 Sleep(appData.animSpeed);
\r
10615 explodeInfo.radius = 0;
\r
10616 DrawPosition(TRUE, NULL);
\r
10619 #define kFactor 4
\r
10622 AnimateMove(board, fromX, fromY, toX, toY)
\r
10629 ChessSquare piece;
\r
10630 POINT start, finish, mid;
\r
10631 POINT frames[kFactor * 2 + 1];
\r
10634 if (!appData.animate) return;
\r
10635 if (doingSizing) return;
\r
10636 if (fromY < 0 || fromX < 0) return;
\r
10637 piece = board[fromY][fromX];
\r
10638 if (piece >= EmptySquare) return;
\r
10640 ScreenSquare(fromX, fromY, &start);
\r
10641 ScreenSquare(toX, toY, &finish);
\r
10643 /* All pieces except knights move in straight line */
\r
10644 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10645 mid.x = start.x + (finish.x - start.x) / 2;
\r
10646 mid.y = start.y + (finish.y - start.y) / 2;
\r
10648 /* Knight: make diagonal movement then straight */
\r
10649 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10650 mid.x = start.x + (finish.x - start.x) / 2;
\r
10651 mid.y = finish.y;
\r
10653 mid.x = finish.x;
\r
10654 mid.y = start.y + (finish.y - start.y) / 2;
\r
10658 /* Don't use as many frames for very short moves */
\r
10659 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10660 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10662 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10664 animInfo.from.x = fromX;
\r
10665 animInfo.from.y = fromY;
\r
10666 animInfo.to.x = toX;
\r
10667 animInfo.to.y = toY;
\r
10668 animInfo.lastpos = start;
\r
10669 animInfo.piece = piece;
\r
10670 for (n = 0; n < nFrames; n++) {
\r
10671 animInfo.pos = frames[n];
\r
10672 DrawPosition(FALSE, NULL);
\r
10673 animInfo.lastpos = animInfo.pos;
\r
10674 Sleep(appData.animSpeed);
\r
10676 animInfo.pos = finish;
\r
10677 DrawPosition(FALSE, NULL);
\r
10678 animInfo.piece = EmptySquare;
\r
10679 if(gameInfo.variant == VariantAtomic &&
\r
10680 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10681 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10684 /* Convert board position to corner of screen rect and color */
\r
10687 ScreenSquare(column, row, pt)
\r
10688 int column; int row; POINT * pt;
\r
10691 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10692 pt->y = lineGap + row * (squareSize + lineGap);
\r
10694 pt->x = lineGap + column * (squareSize + lineGap);
\r
10695 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10699 /* Generate a series of frame coords from start->mid->finish.
\r
10700 The movement rate doubles until the half way point is
\r
10701 reached, then halves back down to the final destination,
\r
10702 which gives a nice slow in/out effect. The algorithmn
\r
10703 may seem to generate too many intermediates for short
\r
10704 moves, but remember that the purpose is to attract the
\r
10705 viewers attention to the piece about to be moved and
\r
10706 then to where it ends up. Too few frames would be less
\r
10710 Tween(start, mid, finish, factor, frames, nFrames)
\r
10711 POINT * start; POINT * mid;
\r
10712 POINT * finish; int factor;
\r
10713 POINT frames[]; int * nFrames;
\r
10715 int n, fraction = 1, count = 0;
\r
10717 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10718 for (n = 0; n < factor; n++)
\r
10720 for (n = 0; n < factor; n++) {
\r
10721 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10722 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10724 fraction = fraction / 2;
\r
10728 frames[count] = *mid;
\r
10731 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10733 for (n = 0; n < factor; n++) {
\r
10734 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10735 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10737 fraction = fraction * 2;
\r
10739 *nFrames = count;
\r
10743 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10748 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10749 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10751 OutputDebugString( buf );
\r
10754 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10756 EvalGraphSet( first, last, current, pvInfoList );
\r
10759 void SetProgramStats( FrontEndProgramStats * stats )
\r
10764 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10765 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10767 OutputDebugString( buf );
\r
10770 EngineOutputUpdate( stats );
\r