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 { "zippyShortGame", ArgInt, (LPVOID)&appData.zippyShortGame, FALSE },
\r
1290 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1291 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1293 /* [HGM] options for broadcasting and time odds */
\r
1294 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1295 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1296 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1297 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1298 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1299 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1300 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1301 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1302 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1303 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1304 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1305 { NULL, ArgNone, NULL, FALSE }
\r
1309 /* Kludge for indirection files on command line */
\r
1310 char* lastIndirectionFilename;
\r
1311 ArgDescriptor argDescriptorIndirection =
\r
1312 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1316 ExitArgError(char *msg, char *badArg)
\r
1318 char buf[MSG_SIZ];
\r
1320 sprintf(buf, "%s %s", msg, badArg);
\r
1321 DisplayFatalError(buf, 0, 2);
\r
1325 /* Command line font name parser. NULL name means do nothing.
\r
1326 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1327 For backward compatibility, syntax without the colon is also
\r
1328 accepted, but font names with digits in them won't work in that case.
\r
1331 ParseFontName(char *name, MyFontParams *mfp)
\r
1334 if (name == NULL) return;
\r
1336 q = strchr(p, ':');
\r
1338 if (q - p >= sizeof(mfp->faceName))
\r
1339 ExitArgError("Font name too long:", name);
\r
1340 memcpy(mfp->faceName, p, q - p);
\r
1341 mfp->faceName[q - p] = NULLCHAR;
\r
1344 q = mfp->faceName;
\r
1345 while (*p && !isdigit(*p)) {
\r
1347 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1348 ExitArgError("Font name too long:", name);
\r
1350 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1353 if (!*p) ExitArgError("Font point size missing:", name);
\r
1354 mfp->pointSize = (float) atof(p);
\r
1355 mfp->bold = (strchr(p, 'b') != NULL);
\r
1356 mfp->italic = (strchr(p, 'i') != NULL);
\r
1357 mfp->underline = (strchr(p, 'u') != NULL);
\r
1358 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1361 /* Color name parser.
\r
1362 X version accepts X color names, but this one
\r
1363 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1365 ParseColorName(char *name)
\r
1367 int red, green, blue, count;
\r
1368 char buf[MSG_SIZ];
\r
1370 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1372 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1373 &red, &green, &blue);
\r
1376 sprintf(buf, "Can't parse color name %s", name);
\r
1377 DisplayError(buf, 0);
\r
1378 return RGB(0, 0, 0);
\r
1380 return PALETTERGB(red, green, blue);
\r
1384 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1386 char *e = argValue;
\r
1390 if (*e == 'b') eff |= CFE_BOLD;
\r
1391 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1392 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1393 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1394 else if (*e == '#' || isdigit(*e)) break;
\r
1398 *color = ParseColorName(e);
\r
1403 ParseBoardSize(char *name)
\r
1405 BoardSize bs = SizeTiny;
\r
1406 while (sizeInfo[bs].name != NULL) {
\r
1407 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1410 ExitArgError("Unrecognized board size value", name);
\r
1411 return bs; /* not reached */
\r
1416 StringGet(void *getClosure)
\r
1418 char **p = (char **) getClosure;
\r
1423 FileGet(void *getClosure)
\r
1426 FILE* f = (FILE*) getClosure;
\r
1429 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1436 /* Parse settings file named "name". If file found, return the
\r
1437 full name in fullname and return TRUE; else return FALSE */
\r
1439 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1443 int ok; char buf[MSG_SIZ];
\r
1445 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1446 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1447 sprintf(buf, "%s.ini", name);
\r
1448 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1451 f = fopen(fullname, "r");
\r
1453 ParseArgs(FileGet, f);
\r
1462 ParseArgs(GetFunc get, void *cl)
\r
1464 char argName[ARG_MAX];
\r
1465 char argValue[ARG_MAX];
\r
1466 ArgDescriptor *ad;
\r
1475 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1476 if (ch == NULLCHAR) break;
\r
1478 /* Comment to end of line */
\r
1480 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1482 } else if (ch == '/' || ch == '-') {
\r
1485 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1486 ch != '\n' && ch != '\t') {
\r
1492 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1493 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1495 if (ad->argName == NULL)
\r
1496 ExitArgError("Unrecognized argument", argName);
\r
1498 } else if (ch == '@') {
\r
1499 /* Indirection file */
\r
1500 ad = &argDescriptorIndirection;
\r
1503 /* Positional argument */
\r
1504 ad = &argDescriptors[posarg++];
\r
1505 strcpy(argName, ad->argName);
\r
1508 if (ad->argType == ArgTrue) {
\r
1509 *(Boolean *) ad->argLoc = TRUE;
\r
1512 if (ad->argType == ArgFalse) {
\r
1513 *(Boolean *) ad->argLoc = FALSE;
\r
1517 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1518 if (ch == NULLCHAR || ch == '\n') {
\r
1519 ExitArgError("No value provided for argument", argName);
\r
1523 // Quoting with { }. No characters have to (or can) be escaped.
\r
1524 // Thus the string cannot contain a '}' character.
\r
1544 } else if (ch == '\'' || ch == '"') {
\r
1545 // Quoting with ' ' or " ", with \ as escape character.
\r
1546 // Inconvenient for long strings that may contain Windows filenames.
\r
1563 if (ch == start) {
\r
1572 if (ad->argType == ArgFilename
\r
1573 || ad->argType == ArgSettingsFilename) {
\r
1579 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1603 for (i = 0; i < 3; i++) {
\r
1604 if (ch >= '0' && ch <= '7') {
\r
1605 octval = octval*8 + (ch - '0');
\r
1612 *q++ = (char) octval;
\r
1623 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1630 switch (ad->argType) {
\r
1632 *(int *) ad->argLoc = atoi(argValue);
\r
1636 *(float *) ad->argLoc = (float) atof(argValue);
\r
1641 *(char **) ad->argLoc = strdup(argValue);
\r
1644 case ArgSettingsFilename:
\r
1646 char fullname[MSG_SIZ];
\r
1647 if (ParseSettingsFile(argValue, fullname)) {
\r
1648 if (ad->argLoc != NULL) {
\r
1649 *(char **) ad->argLoc = strdup(fullname);
\r
1652 if (ad->argLoc != NULL) {
\r
1654 ExitArgError("Failed to open indirection file", argValue);
\r
1661 switch (argValue[0]) {
\r
1664 *(Boolean *) ad->argLoc = TRUE;
\r
1668 *(Boolean *) ad->argLoc = FALSE;
\r
1671 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1677 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1680 case ArgAttribs: {
\r
1681 ColorClass cc = (ColorClass)ad->argLoc;
\r
1682 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1686 case ArgBoardSize:
\r
1687 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1691 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1694 case ArgCommSettings:
\r
1695 ParseCommSettings(argValue, &dcb);
\r
1699 ExitArgError("Unrecognized argument", argValue);
\r
1708 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1710 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1711 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1714 lf->lfEscapement = 0;
\r
1715 lf->lfOrientation = 0;
\r
1716 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1717 lf->lfItalic = mfp->italic;
\r
1718 lf->lfUnderline = mfp->underline;
\r
1719 lf->lfStrikeOut = mfp->strikeout;
\r
1720 lf->lfCharSet = DEFAULT_CHARSET;
\r
1721 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1722 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1723 lf->lfQuality = DEFAULT_QUALITY;
\r
1724 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1725 strcpy(lf->lfFaceName, mfp->faceName);
\r
1729 CreateFontInMF(MyFont *mf)
\r
1731 LFfromMFP(&mf->lf, &mf->mfp);
\r
1732 if (mf->hf) DeleteObject(mf->hf);
\r
1733 mf->hf = CreateFontIndirect(&mf->lf);
\r
1737 SetDefaultTextAttribs()
\r
1740 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1741 ParseAttribs(&textAttribs[cc].color,
\r
1742 &textAttribs[cc].effects,
\r
1743 defaultTextAttribs[cc]);
\r
1748 SetDefaultSounds()
\r
1752 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1753 textAttribs[cc].sound.name = strdup("");
\r
1754 textAttribs[cc].sound.data = NULL;
\r
1756 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1757 sounds[sc].name = strdup("");
\r
1758 sounds[sc].data = NULL;
\r
1760 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1768 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1769 MyLoadSound(&textAttribs[cc].sound);
\r
1771 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1772 MyLoadSound(&sounds[sc]);
\r
1777 InitAppData(LPSTR lpCmdLine)
\r
1780 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1783 programName = szAppName;
\r
1785 /* Initialize to defaults */
\r
1786 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1787 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1788 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1789 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1790 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1791 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1792 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1793 SetDefaultTextAttribs();
\r
1794 SetDefaultSounds();
\r
1795 appData.movesPerSession = MOVES_PER_SESSION;
\r
1796 appData.initString = INIT_STRING;
\r
1797 appData.secondInitString = INIT_STRING;
\r
1798 appData.firstComputerString = COMPUTER_STRING;
\r
1799 appData.secondComputerString = COMPUTER_STRING;
\r
1800 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1801 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1802 appData.firstPlaysBlack = FALSE;
\r
1803 appData.noChessProgram = FALSE;
\r
1804 chessProgram = FALSE;
\r
1805 appData.firstHost = FIRST_HOST;
\r
1806 appData.secondHost = SECOND_HOST;
\r
1807 appData.firstDirectory = FIRST_DIRECTORY;
\r
1808 appData.secondDirectory = SECOND_DIRECTORY;
\r
1809 appData.bitmapDirectory = "";
\r
1810 appData.remoteShell = REMOTE_SHELL;
\r
1811 appData.remoteUser = "";
\r
1812 appData.timeDelay = TIME_DELAY;
\r
1813 appData.timeControl = TIME_CONTROL;
\r
1814 appData.timeIncrement = TIME_INCREMENT;
\r
1815 appData.icsActive = FALSE;
\r
1816 appData.icsHost = "";
\r
1817 appData.icsPort = ICS_PORT;
\r
1818 appData.icsCommPort = ICS_COMM_PORT;
\r
1819 appData.icsLogon = ICS_LOGON;
\r
1820 appData.icsHelper = "";
\r
1821 appData.useTelnet = FALSE;
\r
1822 appData.telnetProgram = TELNET_PROGRAM;
\r
1823 appData.gateway = "";
\r
1824 appData.loadGameFile = "";
\r
1825 appData.loadGameIndex = 0;
\r
1826 appData.saveGameFile = "";
\r
1827 appData.autoSaveGames = FALSE;
\r
1828 appData.loadPositionFile = "";
\r
1829 appData.loadPositionIndex = 1;
\r
1830 appData.savePositionFile = "";
\r
1831 appData.matchMode = FALSE;
\r
1832 appData.matchGames = 0;
\r
1833 appData.monoMode = FALSE;
\r
1834 appData.debugMode = FALSE;
\r
1835 appData.clockMode = TRUE;
\r
1836 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1837 appData.Iconic = FALSE; /*unused*/
\r
1838 appData.searchTime = "";
\r
1839 appData.searchDepth = 0;
\r
1840 appData.showCoords = FALSE;
\r
1841 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1842 appData.autoCallFlag = FALSE;
\r
1843 appData.flipView = FALSE;
\r
1844 appData.autoFlipView = TRUE;
\r
1845 appData.cmailGameName = "";
\r
1846 appData.alwaysPromoteToQueen = FALSE;
\r
1847 appData.oldSaveStyle = FALSE;
\r
1848 appData.quietPlay = FALSE;
\r
1849 appData.showThinking = FALSE;
\r
1850 appData.ponderNextMove = TRUE;
\r
1851 appData.periodicUpdates = TRUE;
\r
1852 appData.popupExitMessage = TRUE;
\r
1853 appData.popupMoveErrors = FALSE;
\r
1854 appData.autoObserve = FALSE;
\r
1855 appData.autoComment = FALSE;
\r
1856 appData.animate = TRUE;
\r
1857 appData.animSpeed = 10;
\r
1858 appData.animateDragging = TRUE;
\r
1859 appData.highlightLastMove = TRUE;
\r
1860 appData.getMoveList = TRUE;
\r
1861 appData.testLegality = TRUE;
\r
1862 appData.premove = TRUE;
\r
1863 appData.premoveWhite = FALSE;
\r
1864 appData.premoveWhiteText = "";
\r
1865 appData.premoveBlack = FALSE;
\r
1866 appData.premoveBlackText = "";
\r
1867 appData.icsAlarm = TRUE;
\r
1868 appData.icsAlarmTime = 5000;
\r
1869 appData.autoRaiseBoard = TRUE;
\r
1870 appData.localLineEditing = TRUE;
\r
1871 appData.colorize = TRUE;
\r
1872 appData.reuseFirst = TRUE;
\r
1873 appData.reuseSecond = TRUE;
\r
1874 appData.blindfold = FALSE;
\r
1875 appData.icsEngineAnalyze = FALSE;
\r
1876 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1877 dcb.DCBlength = sizeof(DCB);
\r
1878 dcb.BaudRate = 9600;
\r
1879 dcb.fBinary = TRUE;
\r
1880 dcb.fParity = FALSE;
\r
1881 dcb.fOutxCtsFlow = FALSE;
\r
1882 dcb.fOutxDsrFlow = FALSE;
\r
1883 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1884 dcb.fDsrSensitivity = FALSE;
\r
1885 dcb.fTXContinueOnXoff = TRUE;
\r
1886 dcb.fOutX = FALSE;
\r
1888 dcb.fNull = FALSE;
\r
1889 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1890 dcb.fAbortOnError = FALSE;
\r
1892 dcb.Parity = SPACEPARITY;
\r
1893 dcb.StopBits = ONESTOPBIT;
\r
1894 settingsFileName = SETTINGS_FILE;
\r
1895 saveSettingsOnExit = TRUE;
\r
1896 boardX = CW_USEDEFAULT;
\r
1897 boardY = CW_USEDEFAULT;
\r
1898 consoleX = CW_USEDEFAULT;
\r
1899 consoleY = CW_USEDEFAULT;
\r
1900 consoleW = CW_USEDEFAULT;
\r
1901 consoleH = CW_USEDEFAULT;
\r
1902 analysisX = CW_USEDEFAULT;
\r
1903 analysisY = CW_USEDEFAULT;
\r
1904 analysisW = CW_USEDEFAULT;
\r
1905 analysisH = CW_USEDEFAULT;
\r
1906 commentX = CW_USEDEFAULT;
\r
1907 commentY = CW_USEDEFAULT;
\r
1908 commentW = CW_USEDEFAULT;
\r
1909 commentH = CW_USEDEFAULT;
\r
1910 editTagsX = CW_USEDEFAULT;
\r
1911 editTagsY = CW_USEDEFAULT;
\r
1912 editTagsW = CW_USEDEFAULT;
\r
1913 editTagsH = CW_USEDEFAULT;
\r
1914 gameListX = CW_USEDEFAULT;
\r
1915 gameListY = CW_USEDEFAULT;
\r
1916 gameListW = CW_USEDEFAULT;
\r
1917 gameListH = CW_USEDEFAULT;
\r
1918 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1919 icsNames = ICS_NAMES;
\r
1920 firstChessProgramNames = FCP_NAMES;
\r
1921 secondChessProgramNames = SCP_NAMES;
\r
1922 appData.initialMode = "";
\r
1923 appData.variant = "normal";
\r
1924 appData.firstProtocolVersion = PROTOVER;
\r
1925 appData.secondProtocolVersion = PROTOVER;
\r
1926 appData.showButtonBar = TRUE;
\r
1928 /* [AS] New properties (see comments in header file) */
\r
1929 appData.firstScoreIsAbsolute = FALSE;
\r
1930 appData.secondScoreIsAbsolute = FALSE;
\r
1931 appData.saveExtendedInfoInPGN = FALSE;
\r
1932 appData.hideThinkingFromHuman = FALSE;
\r
1933 appData.liteBackTextureFile = "";
\r
1934 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1935 appData.darkBackTextureFile = "";
\r
1936 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1937 appData.renderPiecesWithFont = "";
\r
1938 appData.fontToPieceTable = "";
\r
1939 appData.fontBackColorWhite = 0;
\r
1940 appData.fontForeColorWhite = 0;
\r
1941 appData.fontBackColorBlack = 0;
\r
1942 appData.fontForeColorBlack = 0;
\r
1943 appData.fontPieceSize = 80;
\r
1944 appData.overrideLineGap = 1;
\r
1945 appData.adjudicateLossThreshold = 0;
\r
1946 appData.delayBeforeQuit = 0;
\r
1947 appData.delayAfterQuit = 0;
\r
1948 appData.nameOfDebugFile = "winboard.debug";
\r
1949 appData.pgnEventHeader = "Computer Chess Game";
\r
1950 appData.defaultFrcPosition = -1;
\r
1951 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1952 appData.saveOutOfBookInfo = TRUE;
\r
1953 appData.showEvalInMoveHistory = TRUE;
\r
1954 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1955 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1956 appData.highlightMoveWithArrow = FALSE;
\r
1957 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1958 appData.useStickyWindows = TRUE;
\r
1959 appData.adjudicateDrawMoves = 0;
\r
1960 appData.autoDisplayComment = TRUE;
\r
1961 appData.autoDisplayTags = TRUE;
\r
1962 appData.firstIsUCI = FALSE;
\r
1963 appData.secondIsUCI = FALSE;
\r
1964 appData.firstHasOwnBookUCI = TRUE;
\r
1965 appData.secondHasOwnBookUCI = TRUE;
\r
1966 appData.polyglotDir = "";
\r
1967 appData.usePolyglotBook = FALSE;
\r
1968 appData.polyglotBook = "";
\r
1969 appData.defaultHashSize = 64;
\r
1970 appData.defaultCacheSizeEGTB = 4;
\r
1971 appData.defaultPathEGTB = "c:\\egtb";
\r
1972 appData.firstOptions = "";
\r
1973 appData.secondOptions = "";
\r
1975 InitWindowPlacement( &wpMoveHistory );
\r
1976 InitWindowPlacement( &wpEvalGraph );
\r
1977 InitWindowPlacement( &wpEngineOutput );
\r
1979 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1980 appData.NrFiles = -1;
\r
1981 appData.NrRanks = -1;
\r
1982 appData.holdingsSize = -1;
\r
1983 appData.testClaims = FALSE;
\r
1984 appData.checkMates = FALSE;
\r
1985 appData.materialDraws= FALSE;
\r
1986 appData.trivialDraws = FALSE;
\r
1987 appData.ruleMoves = 51;
\r
1988 appData.drawRepeats = 6;
\r
1989 appData.matchPause = 10000;
\r
1990 appData.alphaRank = FALSE;
\r
1991 appData.allWhite = FALSE;
\r
1992 appData.upsideDown = FALSE;
\r
1993 appData.serverPause = 15;
\r
1994 appData.serverMovesName = NULL;
\r
1995 appData.suppressLoadMoves = FALSE;
\r
1996 appData.firstTimeOdds = 1;
\r
1997 appData.secondTimeOdds = 1;
\r
1998 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
1999 appData.secondAccumulateTC = 1;
\r
2000 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2001 appData.secondNPS = -1;
\r
2002 appData.engineComments = 1;
\r
2003 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2004 appData.egtFormats = "";
\r
2007 appData.zippyTalk = ZIPPY_TALK;
\r
2008 appData.zippyPlay = ZIPPY_PLAY;
\r
2009 appData.zippyLines = ZIPPY_LINES;
\r
2010 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2011 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2012 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2013 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2014 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2015 appData.zippyUseI = ZIPPY_USE_I;
\r
2016 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2017 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2018 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2019 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2020 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2021 appData.zippyAbort = ZIPPY_ABORT;
\r
2022 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2023 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2024 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2027 /* Point font array elements to structures and
\r
2028 parse default font names */
\r
2029 for (i=0; i<NUM_FONTS; i++) {
\r
2030 for (j=0; j<NUM_SIZES; j++) {
\r
2031 font[j][i] = &fontRec[j][i];
\r
2032 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2036 /* Parse default settings file if any */
\r
2037 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2038 settingsFileName = strdup(buf);
\r
2041 /* Parse command line */
\r
2042 ParseArgs(StringGet, &lpCmdLine);
\r
2044 /* [HGM] make sure board size is acceptable */
\r
2045 if(appData.NrFiles > BOARD_SIZE ||
\r
2046 appData.NrRanks > BOARD_SIZE )
\r
2047 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2049 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2050 * with options from the command line, we now make an even higher priority
\r
2051 * overrule by WB options attached to the engine command line. This so that
\r
2052 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2055 if(appData.firstChessProgram != NULL) {
\r
2056 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2057 static char *f = "first";
\r
2058 char buf[MSG_SIZ], *q = buf;
\r
2059 if(p != NULL) { // engine command line contains WinBoard options
\r
2060 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2061 ParseArgs(StringGet, &q);
\r
2062 p[-1] = 0; // cut them offengine command line
\r
2065 // now do same for second chess program
\r
2066 if(appData.secondChessProgram != NULL) {
\r
2067 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2068 static char *s = "second";
\r
2069 char buf[MSG_SIZ], *q = buf;
\r
2070 if(p != NULL) { // engine command line contains WinBoard options
\r
2071 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2072 ParseArgs(StringGet, &q);
\r
2073 p[-1] = 0; // cut them offengine command line
\r
2078 /* Propagate options that affect others */
\r
2079 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2080 if (appData.icsActive || appData.noChessProgram) {
\r
2081 chessProgram = FALSE; /* not local chess program mode */
\r
2084 /* Open startup dialog if needed */
\r
2085 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2086 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2087 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2088 *appData.secondChessProgram == NULLCHAR))) {
\r
2091 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2092 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2093 FreeProcInstance(lpProc);
\r
2096 /* Make sure save files land in the right (?) directory */
\r
2097 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2098 appData.saveGameFile = strdup(buf);
\r
2100 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2101 appData.savePositionFile = strdup(buf);
\r
2104 /* Finish initialization for fonts and sounds */
\r
2105 for (i=0; i<NUM_FONTS; i++) {
\r
2106 for (j=0; j<NUM_SIZES; j++) {
\r
2107 CreateFontInMF(font[j][i]);
\r
2110 /* xboard, and older WinBoards, controlled the move sound with the
\r
2111 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2112 always turn the option on (so that the backend will call us),
\r
2113 then let the user turn the sound off by setting it to silence if
\r
2114 desired. To accommodate old winboard.ini files saved by old
\r
2115 versions of WinBoard, we also turn off the sound if the option
\r
2116 was initially set to false. */
\r
2117 if (!appData.ringBellAfterMoves) {
\r
2118 sounds[(int)SoundMove].name = strdup("");
\r
2119 appData.ringBellAfterMoves = TRUE;
\r
2121 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2122 SetCurrentDirectory(installDir);
\r
2124 SetCurrentDirectory(currDir);
\r
2126 p = icsTextMenuString;
\r
2127 if (p[0] == '@') {
\r
2128 FILE* f = fopen(p + 1, "r");
\r
2130 DisplayFatalError(p + 1, errno, 2);
\r
2133 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2135 buf[i] = NULLCHAR;
\r
2138 ParseIcsTextMenu(strdup(p));
\r
2145 HMENU hmenu = GetMenu(hwndMain);
\r
2147 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2148 MF_BYCOMMAND|((appData.icsActive &&
\r
2149 *appData.icsCommPort != NULLCHAR) ?
\r
2150 MF_ENABLED : MF_GRAYED));
\r
2151 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2152 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2153 MF_CHECKED : MF_UNCHECKED));
\r
2158 SaveSettings(char* name)
\r
2161 ArgDescriptor *ad;
\r
2162 WINDOWPLACEMENT wp;
\r
2163 char dir[MSG_SIZ];
\r
2165 if (!hwndMain) return;
\r
2167 GetCurrentDirectory(MSG_SIZ, dir);
\r
2168 SetCurrentDirectory(installDir);
\r
2169 f = fopen(name, "w");
\r
2170 SetCurrentDirectory(dir);
\r
2172 DisplayError(name, errno);
\r
2175 fprintf(f, ";\n");
\r
2176 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2177 fprintf(f, ";\n");
\r
2178 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2179 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2180 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2181 fprintf(f, ";\n");
\r
2183 wp.length = sizeof(WINDOWPLACEMENT);
\r
2184 GetWindowPlacement(hwndMain, &wp);
\r
2185 boardX = wp.rcNormalPosition.left;
\r
2186 boardY = wp.rcNormalPosition.top;
\r
2188 if (hwndConsole) {
\r
2189 GetWindowPlacement(hwndConsole, &wp);
\r
2190 consoleX = wp.rcNormalPosition.left;
\r
2191 consoleY = wp.rcNormalPosition.top;
\r
2192 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2193 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2196 if (analysisDialog) {
\r
2197 GetWindowPlacement(analysisDialog, &wp);
\r
2198 analysisX = wp.rcNormalPosition.left;
\r
2199 analysisY = wp.rcNormalPosition.top;
\r
2200 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2201 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2204 if (commentDialog) {
\r
2205 GetWindowPlacement(commentDialog, &wp);
\r
2206 commentX = wp.rcNormalPosition.left;
\r
2207 commentY = wp.rcNormalPosition.top;
\r
2208 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2209 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2212 if (editTagsDialog) {
\r
2213 GetWindowPlacement(editTagsDialog, &wp);
\r
2214 editTagsX = wp.rcNormalPosition.left;
\r
2215 editTagsY = wp.rcNormalPosition.top;
\r
2216 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2217 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2220 if (gameListDialog) {
\r
2221 GetWindowPlacement(gameListDialog, &wp);
\r
2222 gameListX = wp.rcNormalPosition.left;
\r
2223 gameListY = wp.rcNormalPosition.top;
\r
2224 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2225 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2228 /* [AS] Move history */
\r
2229 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2231 if( moveHistoryDialog ) {
\r
2232 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2233 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2234 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2235 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2236 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2239 /* [AS] Eval graph */
\r
2240 wpEvalGraph.visible = EvalGraphIsUp();
\r
2242 if( evalGraphDialog ) {
\r
2243 GetWindowPlacement(evalGraphDialog, &wp);
\r
2244 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2245 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2246 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2247 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2250 /* [AS] Engine output */
\r
2251 wpEngineOutput.visible = EngineOutputIsUp();
\r
2253 if( engineOutputDialog ) {
\r
2254 GetWindowPlacement(engineOutputDialog, &wp);
\r
2255 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2256 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2257 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2258 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2261 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2262 if (!ad->save) continue;
\r
2263 switch (ad->argType) {
\r
2266 char *p = *(char **)ad->argLoc;
\r
2267 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2268 /* Quote multiline values or \-containing values
\r
2269 with { } if possible */
\r
2270 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2272 /* Else quote with " " */
\r
2273 fprintf(f, "/%s=\"", ad->argName);
\r
2275 if (*p == '\n') fprintf(f, "\n");
\r
2276 else if (*p == '\r') fprintf(f, "\\r");
\r
2277 else if (*p == '\t') fprintf(f, "\\t");
\r
2278 else if (*p == '\b') fprintf(f, "\\b");
\r
2279 else if (*p == '\f') fprintf(f, "\\f");
\r
2280 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2281 else if (*p == '\"') fprintf(f, "\\\"");
\r
2282 else if (*p == '\\') fprintf(f, "\\\\");
\r
2286 fprintf(f, "\"\n");
\r
2291 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2294 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2297 fprintf(f, "/%s=%s\n", ad->argName,
\r
2298 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2301 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2304 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2308 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2309 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2310 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2315 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2316 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2317 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2318 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2319 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2320 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2321 (ta->effects) ? " " : "",
\r
2322 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2326 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2327 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2329 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2332 case ArgBoardSize:
\r
2333 fprintf(f, "/%s=%s\n", ad->argName,
\r
2334 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2339 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2340 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2341 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2342 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2343 ad->argName, mfp->faceName, mfp->pointSize,
\r
2344 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2345 mfp->bold ? "b" : "",
\r
2346 mfp->italic ? "i" : "",
\r
2347 mfp->underline ? "u" : "",
\r
2348 mfp->strikeout ? "s" : "");
\r
2352 case ArgCommSettings:
\r
2353 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2355 case ArgSettingsFilename: ;
\r
2363 /*---------------------------------------------------------------------------*\
\r
2365 * GDI board drawing routines
\r
2367 \*---------------------------------------------------------------------------*/
\r
2369 /* [AS] Draw square using background texture */
\r
2370 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2375 return; /* Should never happen! */
\r
2378 SetGraphicsMode( dst, GM_ADVANCED );
\r
2385 /* X reflection */
\r
2390 x.eDx = (FLOAT) dw + dx - 1;
\r
2393 SetWorldTransform( dst, &x );
\r
2396 /* Y reflection */
\r
2402 x.eDy = (FLOAT) dh + dy - 1;
\r
2404 SetWorldTransform( dst, &x );
\r
2412 x.eDx = (FLOAT) dx;
\r
2413 x.eDy = (FLOAT) dy;
\r
2416 SetWorldTransform( dst, &x );
\r
2420 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2428 SetWorldTransform( dst, &x );
\r
2430 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2433 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2435 PM_WP = (int) WhitePawn,
\r
2436 PM_WN = (int) WhiteKnight,
\r
2437 PM_WB = (int) WhiteBishop,
\r
2438 PM_WR = (int) WhiteRook,
\r
2439 PM_WQ = (int) WhiteQueen,
\r
2440 PM_WF = (int) WhiteFerz,
\r
2441 PM_WW = (int) WhiteWazir,
\r
2442 PM_WE = (int) WhiteAlfil,
\r
2443 PM_WM = (int) WhiteMan,
\r
2444 PM_WO = (int) WhiteCannon,
\r
2445 PM_WU = (int) WhiteUnicorn,
\r
2446 PM_WH = (int) WhiteNightrider,
\r
2447 PM_WA = (int) WhiteAngel,
\r
2448 PM_WC = (int) WhiteMarshall,
\r
2449 PM_WAB = (int) WhiteCardinal,
\r
2450 PM_WD = (int) WhiteDragon,
\r
2451 PM_WL = (int) WhiteLance,
\r
2452 PM_WS = (int) WhiteCobra,
\r
2453 PM_WV = (int) WhiteFalcon,
\r
2454 PM_WSG = (int) WhiteSilver,
\r
2455 PM_WG = (int) WhiteGrasshopper,
\r
2456 PM_WK = (int) WhiteKing,
\r
2457 PM_BP = (int) BlackPawn,
\r
2458 PM_BN = (int) BlackKnight,
\r
2459 PM_BB = (int) BlackBishop,
\r
2460 PM_BR = (int) BlackRook,
\r
2461 PM_BQ = (int) BlackQueen,
\r
2462 PM_BF = (int) BlackFerz,
\r
2463 PM_BW = (int) BlackWazir,
\r
2464 PM_BE = (int) BlackAlfil,
\r
2465 PM_BM = (int) BlackMan,
\r
2466 PM_BO = (int) BlackCannon,
\r
2467 PM_BU = (int) BlackUnicorn,
\r
2468 PM_BH = (int) BlackNightrider,
\r
2469 PM_BA = (int) BlackAngel,
\r
2470 PM_BC = (int) BlackMarshall,
\r
2471 PM_BG = (int) BlackGrasshopper,
\r
2472 PM_BAB = (int) BlackCardinal,
\r
2473 PM_BD = (int) BlackDragon,
\r
2474 PM_BL = (int) BlackLance,
\r
2475 PM_BS = (int) BlackCobra,
\r
2476 PM_BV = (int) BlackFalcon,
\r
2477 PM_BSG = (int) BlackSilver,
\r
2478 PM_BK = (int) BlackKing
\r
2481 static HFONT hPieceFont = NULL;
\r
2482 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2483 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2484 static int fontBitmapSquareSize = 0;
\r
2485 static char pieceToFontChar[(int) EmptySquare] =
\r
2486 { 'p', 'n', 'b', 'r', 'q',
\r
2487 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2488 'k', 'o', 'm', 'v', 't', 'w',
\r
2489 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2492 extern BOOL SetCharTable( char *table, const char * map );
\r
2493 /* [HGM] moved to backend.c */
\r
2495 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2498 BYTE r1 = GetRValue( color );
\r
2499 BYTE g1 = GetGValue( color );
\r
2500 BYTE b1 = GetBValue( color );
\r
2506 /* Create a uniform background first */
\r
2507 hbrush = CreateSolidBrush( color );
\r
2508 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2509 FillRect( hdc, &rc, hbrush );
\r
2510 DeleteObject( hbrush );
\r
2513 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2514 int steps = squareSize / 2;
\r
2517 for( i=0; i<steps; i++ ) {
\r
2518 BYTE r = r1 - (r1-r2) * i / steps;
\r
2519 BYTE g = g1 - (g1-g2) * i / steps;
\r
2520 BYTE b = b1 - (b1-b2) * i / steps;
\r
2522 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2523 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2524 FillRect( hdc, &rc, hbrush );
\r
2525 DeleteObject(hbrush);
\r
2528 else if( mode == 2 ) {
\r
2529 /* Diagonal gradient, good more or less for every piece */
\r
2530 POINT triangle[3];
\r
2531 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2532 HBRUSH hbrush_old;
\r
2533 int steps = squareSize;
\r
2536 triangle[0].x = squareSize - steps;
\r
2537 triangle[0].y = squareSize;
\r
2538 triangle[1].x = squareSize;
\r
2539 triangle[1].y = squareSize;
\r
2540 triangle[2].x = squareSize;
\r
2541 triangle[2].y = squareSize - steps;
\r
2543 for( i=0; i<steps; i++ ) {
\r
2544 BYTE r = r1 - (r1-r2) * i / steps;
\r
2545 BYTE g = g1 - (g1-g2) * i / steps;
\r
2546 BYTE b = b1 - (b1-b2) * i / steps;
\r
2548 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2549 hbrush_old = SelectObject( hdc, hbrush );
\r
2550 Polygon( hdc, triangle, 3 );
\r
2551 SelectObject( hdc, hbrush_old );
\r
2552 DeleteObject(hbrush);
\r
2557 SelectObject( hdc, hpen );
\r
2562 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2563 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2564 piece: follow the steps as explained below.
\r
2566 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2570 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2574 int backColor = whitePieceColor;
\r
2575 int foreColor = blackPieceColor;
\r
2577 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2578 backColor = appData.fontBackColorWhite;
\r
2579 foreColor = appData.fontForeColorWhite;
\r
2581 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2582 backColor = appData.fontBackColorBlack;
\r
2583 foreColor = appData.fontForeColorBlack;
\r
2587 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2589 hbm_old = SelectObject( hdc, hbm );
\r
2593 rc.right = squareSize;
\r
2594 rc.bottom = squareSize;
\r
2596 /* Step 1: background is now black */
\r
2597 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2599 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2601 pt.x = (squareSize - sz.cx) / 2;
\r
2602 pt.y = (squareSize - sz.cy) / 2;
\r
2604 SetBkMode( hdc, TRANSPARENT );
\r
2605 SetTextColor( hdc, chroma );
\r
2606 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2607 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2609 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2610 /* Step 3: the area outside the piece is filled with white */
\r
2611 // FloodFill( hdc, 0, 0, chroma );
\r
2612 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2613 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2614 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2615 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2616 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2618 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2619 but if the start point is not inside the piece we're lost!
\r
2620 There should be a better way to do this... if we could create a region or path
\r
2621 from the fill operation we would be fine for example.
\r
2623 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2624 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2626 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2627 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2628 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2630 SelectObject( dc2, bm2 );
\r
2631 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2632 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2633 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2634 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2635 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2638 DeleteObject( bm2 );
\r
2641 SetTextColor( hdc, 0 );
\r
2643 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2644 draw the piece again in black for safety.
\r
2646 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2648 SelectObject( hdc, hbm_old );
\r
2650 if( hPieceMask[index] != NULL ) {
\r
2651 DeleteObject( hPieceMask[index] );
\r
2654 hPieceMask[index] = hbm;
\r
2657 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2659 SelectObject( hdc, hbm );
\r
2662 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2663 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2664 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2666 SelectObject( dc1, hPieceMask[index] );
\r
2667 SelectObject( dc2, bm2 );
\r
2668 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2669 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2672 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2673 the piece background and deletes (makes transparent) the rest.
\r
2674 Thanks to that mask, we are free to paint the background with the greates
\r
2675 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2676 We use this, to make gradients and give the pieces a "roundish" look.
\r
2678 SetPieceBackground( hdc, backColor, 2 );
\r
2679 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2683 DeleteObject( bm2 );
\r
2686 SetTextColor( hdc, foreColor );
\r
2687 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2689 SelectObject( hdc, hbm_old );
\r
2691 if( hPieceFace[index] != NULL ) {
\r
2692 DeleteObject( hPieceFace[index] );
\r
2695 hPieceFace[index] = hbm;
\r
2698 static int TranslatePieceToFontPiece( int piece )
\r
2728 case BlackMarshall:
\r
2732 case BlackNightrider:
\r
2738 case BlackUnicorn:
\r
2742 case BlackGrasshopper:
\r
2754 case BlackCardinal:
\r
2761 case WhiteMarshall:
\r
2765 case WhiteNightrider:
\r
2771 case WhiteUnicorn:
\r
2775 case WhiteGrasshopper:
\r
2787 case WhiteCardinal:
\r
2796 void CreatePiecesFromFont()
\r
2799 HDC hdc_window = NULL;
\r
2805 if( fontBitmapSquareSize < 0 ) {
\r
2806 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2810 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2811 fontBitmapSquareSize = -1;
\r
2815 if( fontBitmapSquareSize != squareSize ) {
\r
2816 hdc_window = GetDC( hwndMain );
\r
2817 hdc = CreateCompatibleDC( hdc_window );
\r
2819 if( hPieceFont != NULL ) {
\r
2820 DeleteObject( hPieceFont );
\r
2823 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2824 hPieceMask[i] = NULL;
\r
2825 hPieceFace[i] = NULL;
\r
2831 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2832 fontHeight = appData.fontPieceSize;
\r
2835 fontHeight = (fontHeight * squareSize) / 100;
\r
2837 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2839 lf.lfEscapement = 0;
\r
2840 lf.lfOrientation = 0;
\r
2841 lf.lfWeight = FW_NORMAL;
\r
2843 lf.lfUnderline = 0;
\r
2844 lf.lfStrikeOut = 0;
\r
2845 lf.lfCharSet = DEFAULT_CHARSET;
\r
2846 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2847 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2848 lf.lfQuality = PROOF_QUALITY;
\r
2849 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2850 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2851 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2853 hPieceFont = CreateFontIndirect( &lf );
\r
2855 if( hPieceFont == NULL ) {
\r
2856 fontBitmapSquareSize = -2;
\r
2859 /* Setup font-to-piece character table */
\r
2860 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2861 /* No (or wrong) global settings, try to detect the font */
\r
2862 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2864 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2866 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2867 /* DiagramTT* family */
\r
2868 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2870 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2871 /* Fairy symbols */
\r
2872 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2874 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2875 /* Good Companion (Some characters get warped as literal :-( */
\r
2876 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2877 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2878 SetCharTable(pieceToFontChar, s);
\r
2881 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2882 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2886 /* Create bitmaps */
\r
2887 hfont_old = SelectObject( hdc, hPieceFont );
\r
2889 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2890 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2891 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2892 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2893 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2894 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2895 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2896 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2897 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2898 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2899 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2900 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2902 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2903 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2904 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2905 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2906 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2907 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2908 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2909 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2910 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2911 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2912 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
2913 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
2914 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
2915 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
2916 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
2917 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
2918 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2919 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2920 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2921 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2922 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2923 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2924 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2925 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2926 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2927 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2928 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
2929 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
2930 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
2931 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
2932 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
2933 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
2935 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2936 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2937 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2939 SelectObject( hdc, hfont_old );
\r
2941 fontBitmapSquareSize = squareSize;
\r
2945 if( hdc != NULL ) {
\r
2949 if( hdc_window != NULL ) {
\r
2950 ReleaseDC( hwndMain, hdc_window );
\r
2955 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2959 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2960 if (gameInfo.event &&
\r
2961 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2962 strcmp(name, "k80s") == 0) {
\r
2963 strcpy(name, "tim");
\r
2965 return LoadBitmap(hinst, name);
\r
2969 /* Insert a color into the program's logical palette
\r
2970 structure. This code assumes the given color is
\r
2971 the result of the RGB or PALETTERGB macro, and it
\r
2972 knows how those macros work (which is documented).
\r
2975 InsertInPalette(COLORREF color)
\r
2977 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2979 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2980 DisplayFatalError("Too many colors", 0, 1);
\r
2981 pLogPal->palNumEntries--;
\r
2985 pe->peFlags = (char) 0;
\r
2986 pe->peRed = (char) (0xFF & color);
\r
2987 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2988 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2994 InitDrawingColors()
\r
2996 if (pLogPal == NULL) {
\r
2997 /* Allocate enough memory for a logical palette with
\r
2998 * PALETTESIZE entries and set the size and version fields
\r
2999 * of the logical palette structure.
\r
3001 pLogPal = (NPLOGPALETTE)
\r
3002 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3003 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3004 pLogPal->palVersion = 0x300;
\r
3006 pLogPal->palNumEntries = 0;
\r
3008 InsertInPalette(lightSquareColor);
\r
3009 InsertInPalette(darkSquareColor);
\r
3010 InsertInPalette(whitePieceColor);
\r
3011 InsertInPalette(blackPieceColor);
\r
3012 InsertInPalette(highlightSquareColor);
\r
3013 InsertInPalette(premoveHighlightColor);
\r
3015 /* create a logical color palette according the information
\r
3016 * in the LOGPALETTE structure.
\r
3018 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3020 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3021 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3022 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3023 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3024 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3025 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3026 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3027 /* [AS] Force rendering of the font-based pieces */
\r
3028 if( fontBitmapSquareSize > 0 ) {
\r
3029 fontBitmapSquareSize = 0;
\r
3035 BoardWidth(int boardSize, int n)
\r
3036 { /* [HGM] argument n added to allow different width and height */
\r
3037 int lineGap = sizeInfo[boardSize].lineGap;
\r
3039 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3040 lineGap = appData.overrideLineGap;
\r
3043 return (n + 1) * lineGap +
\r
3044 n * sizeInfo[boardSize].squareSize;
\r
3047 /* Respond to board resize by dragging edge */
\r
3049 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3051 BoardSize newSize = NUM_SIZES - 1;
\r
3052 static int recurse = 0;
\r
3053 if (IsIconic(hwndMain)) return;
\r
3054 if (recurse > 0) return;
\r
3056 while (newSize > 0) {
\r
3057 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3058 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3059 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3062 boardSize = newSize;
\r
3063 InitDrawingSizes(boardSize, flags);
\r
3070 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3072 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3073 ChessSquare piece;
\r
3074 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3076 SIZE clockSize, messageSize;
\r
3078 char buf[MSG_SIZ];
\r
3080 HMENU hmenu = GetMenu(hwndMain);
\r
3081 RECT crect, wrect;
\r
3083 LOGBRUSH logbrush;
\r
3085 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3086 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3088 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3089 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3091 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3092 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3093 squareSize = sizeInfo[boardSize].squareSize;
\r
3094 lineGap = sizeInfo[boardSize].lineGap;
\r
3095 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3097 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3098 lineGap = appData.overrideLineGap;
\r
3101 if (tinyLayout != oldTinyLayout) {
\r
3102 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3104 style &= ~WS_SYSMENU;
\r
3105 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3106 "&Minimize\tCtrl+F4");
\r
3108 style |= WS_SYSMENU;
\r
3109 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3111 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3113 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3114 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3115 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3117 DrawMenuBar(hwndMain);
\r
3120 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3121 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3123 /* Get text area sizes */
\r
3124 hdc = GetDC(hwndMain);
\r
3125 if (appData.clockMode) {
\r
3126 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3128 sprintf(buf, "White");
\r
3130 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3131 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3132 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3133 str = "We only care about the height here";
\r
3134 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3135 SelectObject(hdc, oldFont);
\r
3136 ReleaseDC(hwndMain, hdc);
\r
3138 /* Compute where everything goes */
\r
3139 if((first.programLogo || second.programLogo) && !tinyLayout) {
\r
3140 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3141 logoHeight = 2*clockSize.cy;
\r
3142 leftLogoRect.left = OUTER_MARGIN;
\r
3143 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3144 leftLogoRect.top = OUTER_MARGIN;
\r
3145 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3147 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3148 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3149 rightLogoRect.top = OUTER_MARGIN;
\r
3150 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3153 whiteRect.left = leftLogoRect.right;
\r
3154 whiteRect.right = OUTER_MARGIN + boardWidth/2 - INNER_MARGIN/2;
\r
3155 whiteRect.top = OUTER_MARGIN;
\r
3156 whiteRect.bottom = whiteRect.top + logoHeight;
\r
3158 blackRect.right = rightLogoRect.left;
\r
3159 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3160 blackRect.top = whiteRect.top;
\r
3161 blackRect.bottom = whiteRect.bottom;
\r
3163 whiteRect.left = OUTER_MARGIN;
\r
3164 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3165 whiteRect.top = OUTER_MARGIN;
\r
3166 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3168 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3169 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3170 blackRect.top = whiteRect.top;
\r
3171 blackRect.bottom = whiteRect.bottom;
\r
3174 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3175 if (appData.showButtonBar) {
\r
3176 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3177 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3179 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3181 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3182 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3184 boardRect.left = OUTER_MARGIN;
\r
3185 boardRect.right = boardRect.left + boardWidth;
\r
3186 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3187 boardRect.bottom = boardRect.top + boardHeight;
\r
3189 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3190 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3191 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3192 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3193 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3194 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3195 GetWindowRect(hwndMain, &wrect);
\r
3196 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3197 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3198 /* compensate if menu bar wrapped */
\r
3199 GetClientRect(hwndMain, &crect);
\r
3200 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3201 winHeight += offby;
\r
3203 case WMSZ_TOPLEFT:
\r
3204 SetWindowPos(hwndMain, NULL,
\r
3205 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3206 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3209 case WMSZ_TOPRIGHT:
\r
3211 SetWindowPos(hwndMain, NULL,
\r
3212 wrect.left, wrect.bottom - winHeight,
\r
3213 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3216 case WMSZ_BOTTOMLEFT:
\r
3218 SetWindowPos(hwndMain, NULL,
\r
3219 wrect.right - winWidth, wrect.top,
\r
3220 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3223 case WMSZ_BOTTOMRIGHT:
\r
3227 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3228 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3233 for (i = 0; i < N_BUTTONS; i++) {
\r
3234 if (buttonDesc[i].hwnd != NULL) {
\r
3235 DestroyWindow(buttonDesc[i].hwnd);
\r
3236 buttonDesc[i].hwnd = NULL;
\r
3238 if (appData.showButtonBar) {
\r
3239 buttonDesc[i].hwnd =
\r
3240 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3241 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3242 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3243 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3244 (HMENU) buttonDesc[i].id,
\r
3245 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3247 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3248 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3249 MAKELPARAM(FALSE, 0));
\r
3251 if (buttonDesc[i].id == IDM_Pause)
\r
3252 hwndPause = buttonDesc[i].hwnd;
\r
3253 buttonDesc[i].wndproc = (WNDPROC)
\r
3254 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3257 if (gridPen != NULL) DeleteObject(gridPen);
\r
3258 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3259 if (premovePen != NULL) DeleteObject(premovePen);
\r
3260 if (lineGap != 0) {
\r
3261 logbrush.lbStyle = BS_SOLID;
\r
3262 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3264 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3265 lineGap, &logbrush, 0, NULL);
\r
3266 logbrush.lbColor = highlightSquareColor;
\r
3268 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3269 lineGap, &logbrush, 0, NULL);
\r
3271 logbrush.lbColor = premoveHighlightColor;
\r
3273 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3274 lineGap, &logbrush, 0, NULL);
\r
3276 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3277 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3278 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3279 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3280 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3281 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3282 BOARD_WIDTH * (squareSize + lineGap);
\r
3283 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3285 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3286 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3287 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3288 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3289 lineGap / 2 + (i * (squareSize + lineGap));
\r
3290 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3291 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3292 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3296 /* [HGM] Licensing requirement */
\r
3298 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3301 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3303 GothicPopUp( "", VariantNormal);
\r
3306 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3307 oldBoardSize = boardSize;
\r
3308 oldTinyLayout = tinyLayout;
\r
3310 /* Load piece bitmaps for this board size */
\r
3311 for (i=0; i<=2; i++) {
\r
3312 for (piece = WhitePawn;
\r
3313 (int) piece < (int) BlackPawn;
\r
3314 piece = (ChessSquare) ((int) piece + 1)) {
\r
3315 if (pieceBitmap[i][piece] != NULL)
\r
3316 DeleteObject(pieceBitmap[i][piece]);
\r
3320 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3321 // Orthodox Chess pieces
\r
3322 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3323 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3324 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3325 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3326 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3327 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3328 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3329 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3330 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3331 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3332 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3333 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3334 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3335 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3336 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3337 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3338 // in Shogi, Hijack the unused Queen for Lance
\r
3339 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3340 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3341 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3343 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3344 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3345 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3348 if(squareSize <= 72 && squareSize >= 33) {
\r
3349 /* A & C are available in most sizes now */
\r
3350 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3351 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3352 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3353 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3354 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3355 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3356 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3357 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3358 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3359 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3360 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3361 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3362 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3363 } else { // Smirf-like
\r
3364 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3365 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3366 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3368 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3369 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3370 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3371 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3372 } else { // WinBoard standard
\r
3373 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3374 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3375 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3380 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3381 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3382 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3383 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3384 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3385 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3386 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3387 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3388 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3389 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3390 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3391 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3392 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3393 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3394 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3395 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3396 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3397 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3398 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3399 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3400 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3401 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3402 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3403 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3404 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3405 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3406 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3407 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3408 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3409 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3410 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3412 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3413 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3414 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3415 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3416 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3417 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3418 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3419 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3420 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3421 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3422 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3423 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3424 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3426 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3427 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3428 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3429 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3430 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3431 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3432 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3433 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3434 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3435 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3436 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3437 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3440 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3441 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3442 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3443 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3444 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3445 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3446 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3447 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3448 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3449 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3450 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3451 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3452 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3453 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3454 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3458 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3459 /* special Shogi support in this size */
\r
3460 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3461 for (piece = WhitePawn;
\r
3462 (int) piece < (int) BlackPawn;
\r
3463 piece = (ChessSquare) ((int) piece + 1)) {
\r
3464 if (pieceBitmap[i][piece] != NULL)
\r
3465 DeleteObject(pieceBitmap[i][piece]);
\r
3468 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3469 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3470 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3471 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3472 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3473 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3474 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3475 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3476 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3477 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3478 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3479 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3480 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3481 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3482 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3483 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3484 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3485 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3486 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3487 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3488 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3489 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3490 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3491 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3492 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3493 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3494 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3495 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3496 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3497 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3498 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3499 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3500 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3501 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3502 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3503 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3504 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3505 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3506 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3507 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3508 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3509 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3515 PieceBitmap(ChessSquare p, int kind)
\r
3517 if ((int) p >= (int) BlackPawn)
\r
3518 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3520 return pieceBitmap[kind][(int) p];
\r
3523 /***************************************************************/
\r
3525 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3526 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3528 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3529 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3533 SquareToPos(int row, int column, int * x, int * y)
\r
3536 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3537 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3539 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3540 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3545 DrawCoordsOnDC(HDC hdc)
\r
3547 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
3548 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
3549 char str[2] = { NULLCHAR, NULLCHAR };
\r
3550 int oldMode, oldAlign, x, y, start, i;
\r
3554 if (!appData.showCoords)
\r
3557 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3559 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3560 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3561 oldAlign = GetTextAlign(hdc);
\r
3562 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3564 y = boardRect.top + lineGap;
\r
3565 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3567 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3568 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3569 str[0] = files[start + i];
\r
3570 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3571 y += squareSize + lineGap;
\r
3574 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3576 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3577 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3578 str[0] = ranks[start + i];
\r
3579 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3580 x += squareSize + lineGap;
\r
3583 SelectObject(hdc, oldBrush);
\r
3584 SetBkMode(hdc, oldMode);
\r
3585 SetTextAlign(hdc, oldAlign);
\r
3586 SelectObject(hdc, oldFont);
\r
3590 DrawGridOnDC(HDC hdc)
\r
3594 if (lineGap != 0) {
\r
3595 oldPen = SelectObject(hdc, gridPen);
\r
3596 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3597 SelectObject(hdc, oldPen);
\r
3601 #define HIGHLIGHT_PEN 0
\r
3602 #define PREMOVE_PEN 1
\r
3605 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3608 HPEN oldPen, hPen;
\r
3609 if (lineGap == 0) return;
\r
3611 x1 = boardRect.left +
\r
3612 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3613 y1 = boardRect.top +
\r
3614 lineGap/2 + y * (squareSize + lineGap);
\r
3616 x1 = boardRect.left +
\r
3617 lineGap/2 + x * (squareSize + lineGap);
\r
3618 y1 = boardRect.top +
\r
3619 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3621 hPen = pen ? premovePen : highlightPen;
\r
3622 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3623 MoveToEx(hdc, x1, y1, NULL);
\r
3624 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3625 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3626 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3627 LineTo(hdc, x1, y1);
\r
3628 SelectObject(hdc, oldPen);
\r
3632 DrawHighlightsOnDC(HDC hdc)
\r
3635 for (i=0; i<2; i++) {
\r
3636 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3637 DrawHighlightOnDC(hdc, TRUE,
\r
3638 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3641 for (i=0; i<2; i++) {
\r
3642 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3643 premoveHighlightInfo.sq[i].y >= 0) {
\r
3644 DrawHighlightOnDC(hdc, TRUE,
\r
3645 premoveHighlightInfo.sq[i].x,
\r
3646 premoveHighlightInfo.sq[i].y,
\r
3652 /* Note: sqcolor is used only in monoMode */
\r
3653 /* Note that this code is largely duplicated in woptions.c,
\r
3654 function DrawSampleSquare, so that needs to be updated too */
\r
3656 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3658 HBITMAP oldBitmap;
\r
3662 if (appData.blindfold) return;
\r
3664 /* [AS] Use font-based pieces if needed */
\r
3665 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3666 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3667 CreatePiecesFromFont();
\r
3669 if( fontBitmapSquareSize == squareSize ) {
\r
3670 int index = TranslatePieceToFontPiece(piece);
\r
3672 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3676 squareSize, squareSize,
\r
3681 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3685 squareSize, squareSize,
\r
3694 if (appData.monoMode) {
\r
3695 SelectObject(tmphdc, PieceBitmap(piece,
\r
3696 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3697 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3698 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3700 tmpSize = squareSize;
\r
3702 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3703 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3704 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3705 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3706 x += (squareSize - minorSize)>>1;
\r
3707 y += squareSize - minorSize - 2;
\r
3708 tmpSize = minorSize;
\r
3710 if (color || appData.allWhite ) {
\r
3711 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3713 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3714 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3715 if(appData.upsideDown && color==flipView)
\r
3716 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3718 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3720 /* Use black piece color for outline of white pieces */
\r
3721 /* Not sure this looks really good (though xboard does it).
\r
3722 Maybe better to have another selectable color, default black */
\r
3723 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3724 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3725 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3727 /* Use black for outline of white pieces */
\r
3728 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3729 if(appData.upsideDown && color==flipView)
\r
3730 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3732 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3736 /* Use white piece color for details of black pieces */
\r
3737 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3738 WHITE_PIECE ones aren't always the right shape. */
\r
3739 /* Not sure this looks really good (though xboard does it).
\r
3740 Maybe better to have another selectable color, default medium gray? */
\r
3741 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3742 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3743 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3744 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3745 SelectObject(hdc, blackPieceBrush);
\r
3746 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3748 /* Use square color for details of black pieces */
\r
3749 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3750 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3751 if(appData.upsideDown && !flipView)
\r
3752 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3754 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3757 SelectObject(hdc, oldBrush);
\r
3758 SelectObject(tmphdc, oldBitmap);
\r
3762 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3763 int GetBackTextureMode( int algo )
\r
3765 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3769 case BACK_TEXTURE_MODE_PLAIN:
\r
3770 result = 1; /* Always use identity map */
\r
3772 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3773 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3781 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3782 to handle redraws cleanly (as random numbers would always be different).
\r
3784 VOID RebuildTextureSquareInfo()
\r
3794 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3796 if( liteBackTexture != NULL ) {
\r
3797 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3798 lite_w = bi.bmWidth;
\r
3799 lite_h = bi.bmHeight;
\r
3803 if( darkBackTexture != NULL ) {
\r
3804 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3805 dark_w = bi.bmWidth;
\r
3806 dark_h = bi.bmHeight;
\r
3810 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3811 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3812 if( (col + row) & 1 ) {
\r
3814 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3815 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3816 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3817 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3822 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3823 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3824 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3825 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3832 /* [AS] Arrow highlighting support */
\r
3834 static int A_WIDTH = 5; /* Width of arrow body */
\r
3836 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3837 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3839 static double Sqr( double x )
\r
3844 static int Round( double x )
\r
3846 return (int) (x + 0.5);
\r
3849 /* Draw an arrow between two points using current settings */
\r
3850 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3853 double dx, dy, j, k, x, y;
\r
3855 if( d_x == s_x ) {
\r
3856 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3858 arrow[0].x = s_x + A_WIDTH;
\r
3861 arrow[1].x = s_x + A_WIDTH;
\r
3862 arrow[1].y = d_y - h;
\r
3864 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3865 arrow[2].y = d_y - h;
\r
3870 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3871 arrow[4].y = d_y - h;
\r
3873 arrow[5].x = s_x - A_WIDTH;
\r
3874 arrow[5].y = d_y - h;
\r
3876 arrow[6].x = s_x - A_WIDTH;
\r
3879 else if( d_y == s_y ) {
\r
3880 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3883 arrow[0].y = s_y + A_WIDTH;
\r
3885 arrow[1].x = d_x - w;
\r
3886 arrow[1].y = s_y + A_WIDTH;
\r
3888 arrow[2].x = d_x - w;
\r
3889 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3894 arrow[4].x = d_x - w;
\r
3895 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3897 arrow[5].x = d_x - w;
\r
3898 arrow[5].y = s_y - A_WIDTH;
\r
3901 arrow[6].y = s_y - A_WIDTH;
\r
3904 /* [AS] Needed a lot of paper for this! :-) */
\r
3905 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3906 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3908 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3910 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3915 arrow[0].x = Round(x - j);
\r
3916 arrow[0].y = Round(y + j*dx);
\r
3918 arrow[1].x = Round(x + j);
\r
3919 arrow[1].y = Round(y - j*dx);
\r
3922 x = (double) d_x - k;
\r
3923 y = (double) d_y - k*dy;
\r
3926 x = (double) d_x + k;
\r
3927 y = (double) d_y + k*dy;
\r
3930 arrow[2].x = Round(x + j);
\r
3931 arrow[2].y = Round(y - j*dx);
\r
3933 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3934 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3939 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3940 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3942 arrow[6].x = Round(x - j);
\r
3943 arrow[6].y = Round(y + j*dx);
\r
3946 Polygon( hdc, arrow, 7 );
\r
3949 /* [AS] Draw an arrow between two squares */
\r
3950 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3952 int s_x, s_y, d_x, d_y;
\r
3959 if( s_col == d_col && s_row == d_row ) {
\r
3963 /* Get source and destination points */
\r
3964 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3965 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3968 d_y += squareSize / 4;
\r
3970 else if( d_y < s_y ) {
\r
3971 d_y += 3 * squareSize / 4;
\r
3974 d_y += squareSize / 2;
\r
3978 d_x += squareSize / 4;
\r
3980 else if( d_x < s_x ) {
\r
3981 d_x += 3 * squareSize / 4;
\r
3984 d_x += squareSize / 2;
\r
3987 s_x += squareSize / 2;
\r
3988 s_y += squareSize / 2;
\r
3990 /* Adjust width */
\r
3991 A_WIDTH = squareSize / 14;
\r
3994 stLB.lbStyle = BS_SOLID;
\r
3995 stLB.lbColor = appData.highlightArrowColor;
\r
3998 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3999 holdpen = SelectObject( hdc, hpen );
\r
4000 hbrush = CreateBrushIndirect( &stLB );
\r
4001 holdbrush = SelectObject( hdc, hbrush );
\r
4003 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4005 SelectObject( hdc, holdpen );
\r
4006 SelectObject( hdc, holdbrush );
\r
4007 DeleteObject( hpen );
\r
4008 DeleteObject( hbrush );
\r
4011 BOOL HasHighlightInfo()
\r
4013 BOOL result = FALSE;
\r
4015 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4016 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4024 BOOL IsDrawArrowEnabled()
\r
4026 BOOL result = FALSE;
\r
4028 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4035 VOID DrawArrowHighlight( HDC hdc )
\r
4037 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4038 DrawArrowBetweenSquares( hdc,
\r
4039 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4040 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4044 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4046 HRGN result = NULL;
\r
4048 if( HasHighlightInfo() ) {
\r
4049 int x1, y1, x2, y2;
\r
4050 int sx, sy, dx, dy;
\r
4052 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4053 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4055 sx = MIN( x1, x2 );
\r
4056 sy = MIN( y1, y2 );
\r
4057 dx = MAX( x1, x2 ) + squareSize;
\r
4058 dy = MAX( y1, y2 ) + squareSize;
\r
4060 result = CreateRectRgn( sx, sy, dx, dy );
\r
4067 Warning: this function modifies the behavior of several other functions.
\r
4069 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4070 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4071 repaint is scattered all over the place, which is not good for features such as
\r
4072 "arrow highlighting" that require a full repaint of the board.
\r
4074 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4075 user interaction, when speed is not so important) but especially to avoid errors
\r
4076 in the displayed graphics.
\r
4078 In such patched places, I always try refer to this function so there is a single
\r
4079 place to maintain knowledge.
\r
4081 To restore the original behavior, just return FALSE unconditionally.
\r
4083 BOOL IsFullRepaintPreferrable()
\r
4085 BOOL result = FALSE;
\r
4087 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4088 /* Arrow may appear on the board */
\r
4096 This function is called by DrawPosition to know whether a full repaint must
\r
4099 Only DrawPosition may directly call this function, which makes use of
\r
4100 some state information. Other function should call DrawPosition specifying
\r
4101 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4103 BOOL DrawPositionNeedsFullRepaint()
\r
4105 BOOL result = FALSE;
\r
4108 Probably a slightly better policy would be to trigger a full repaint
\r
4109 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4110 but animation is fast enough that it's difficult to notice.
\r
4112 if( animInfo.piece == EmptySquare ) {
\r
4113 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4122 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4124 int row, column, x, y, square_color, piece_color;
\r
4125 ChessSquare piece;
\r
4127 HDC texture_hdc = NULL;
\r
4129 /* [AS] Initialize background textures if needed */
\r
4130 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4131 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4132 if( backTextureSquareSize != squareSize
\r
4133 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4134 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4135 backTextureSquareSize = squareSize;
\r
4136 RebuildTextureSquareInfo();
\r
4139 texture_hdc = CreateCompatibleDC( hdc );
\r
4142 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4143 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4145 SquareToPos(row, column, &x, &y);
\r
4147 piece = board[row][column];
\r
4149 square_color = ((column + row) % 2) == 1;
\r
4150 if( gameInfo.variant == VariantXiangqi ) {
\r
4151 square_color = !InPalace(row, column);
\r
4152 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4153 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4155 piece_color = (int) piece < (int) BlackPawn;
\r
4158 /* [HGM] holdings file: light square or black */
\r
4159 if(column == BOARD_LEFT-2) {
\r
4160 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4163 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4167 if(column == BOARD_RGHT + 1 ) {
\r
4168 if( row < gameInfo.holdingsSize )
\r
4171 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4175 if(column == BOARD_LEFT-1 ) /* left align */
\r
4176 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4177 else if( column == BOARD_RGHT) /* right align */
\r
4178 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4180 if (appData.monoMode) {
\r
4181 if (piece == EmptySquare) {
\r
4182 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4183 square_color ? WHITENESS : BLACKNESS);
\r
4185 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4188 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4189 /* [AS] Draw the square using a texture bitmap */
\r
4190 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4191 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4192 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4195 squareSize, squareSize,
\r
4198 backTextureSquareInfo[r][c].mode,
\r
4199 backTextureSquareInfo[r][c].x,
\r
4200 backTextureSquareInfo[r][c].y );
\r
4202 SelectObject( texture_hdc, hbm );
\r
4204 if (piece != EmptySquare) {
\r
4205 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4209 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4211 oldBrush = SelectObject(hdc, brush );
\r
4212 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4213 SelectObject(hdc, oldBrush);
\r
4214 if (piece != EmptySquare)
\r
4215 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4220 if( texture_hdc != NULL ) {
\r
4221 DeleteDC( texture_hdc );
\r
4225 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4226 void fputDW(FILE *f, int x)
\r
4228 fputc(x & 255, f);
\r
4229 fputc(x>>8 & 255, f);
\r
4230 fputc(x>>16 & 255, f);
\r
4231 fputc(x>>24 & 255, f);
\r
4234 #define MAX_CLIPS 200 /* more than enough */
\r
4237 DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)
\r
4239 // HBITMAP bufferBitmap;
\r
4244 int w = 100, h = 50;
\r
4246 if(cps->programLogo == NULL) return;
\r
4247 // GetClientRect(hwndMain, &Rect);
\r
4248 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4249 // Rect.bottom-Rect.top+1);
\r
4250 tmphdc = CreateCompatibleDC(hdc);
\r
4251 hbm = SelectObject(tmphdc, (HBITMAP) cps->programLogo);
\r
4252 if( GetObject( cps->programLogo, sizeof(bi), &bi ) > 0 ) {
\r
4256 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4257 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4258 SelectObject(tmphdc, hbm);
\r
4263 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4265 static Board lastReq, lastDrawn;
\r
4266 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4267 static int lastDrawnFlipView = 0;
\r
4268 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4269 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4272 HBITMAP bufferBitmap;
\r
4273 HBITMAP oldBitmap;
\r
4275 HRGN clips[MAX_CLIPS];
\r
4276 ChessSquare dragged_piece = EmptySquare;
\r
4278 /* I'm undecided on this - this function figures out whether a full
\r
4279 * repaint is necessary on its own, so there's no real reason to have the
\r
4280 * caller tell it that. I think this can safely be set to FALSE - but
\r
4281 * if we trust the callers not to request full repaints unnessesarily, then
\r
4282 * we could skip some clipping work. In other words, only request a full
\r
4283 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4284 * gamestart and similar) --Hawk
\r
4286 Boolean fullrepaint = repaint;
\r
4288 if( DrawPositionNeedsFullRepaint() ) {
\r
4289 fullrepaint = TRUE;
\r
4293 if( fullrepaint ) {
\r
4294 static int repaint_count = 0;
\r
4298 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4299 OutputDebugString( buf );
\r
4303 if (board == NULL) {
\r
4304 if (!lastReqValid) {
\r
4309 CopyBoard(lastReq, board);
\r
4313 if (doingSizing) {
\r
4317 if (IsIconic(hwndMain)) {
\r
4321 if (hdc == NULL) {
\r
4322 hdc = GetDC(hwndMain);
\r
4323 if (!appData.monoMode) {
\r
4324 SelectPalette(hdc, hPal, FALSE);
\r
4325 RealizePalette(hdc);
\r
4329 releaseDC = FALSE;
\r
4333 fprintf(debugFP, "*******************************\n"
\r
4335 "dragInfo.from (%d,%d)\n"
\r
4336 "dragInfo.start (%d,%d)\n"
\r
4337 "dragInfo.pos (%d,%d)\n"
\r
4338 "dragInfo.lastpos (%d,%d)\n",
\r
4339 repaint ? "TRUE" : "FALSE",
\r
4340 dragInfo.from.x, dragInfo.from.y,
\r
4341 dragInfo.start.x, dragInfo.start.y,
\r
4342 dragInfo.pos.x, dragInfo.pos.y,
\r
4343 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4344 fprintf(debugFP, "prev: ");
\r
4345 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4346 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4347 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4350 fprintf(debugFP, "\n");
\r
4351 fprintf(debugFP, "board: ");
\r
4352 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4353 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4354 fprintf(debugFP, "%d ", board[row][column]);
\r
4357 fprintf(debugFP, "\n");
\r
4361 /* Create some work-DCs */
\r
4362 hdcmem = CreateCompatibleDC(hdc);
\r
4363 tmphdc = CreateCompatibleDC(hdc);
\r
4365 /* If dragging is in progress, we temporarely remove the piece */
\r
4366 /* [HGM] or temporarily decrease count if stacked */
\r
4367 /* !! Moved to before board compare !! */
\r
4368 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4369 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4370 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4371 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4372 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4374 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4375 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4376 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4378 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4381 /* Figure out which squares need updating by comparing the
\r
4382 * newest board with the last drawn board and checking if
\r
4383 * flipping has changed.
\r
4385 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4386 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4387 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4388 if (lastDrawn[row][column] != board[row][column]) {
\r
4389 SquareToPos(row, column, &x, &y);
\r
4390 clips[num_clips++] =
\r
4391 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4395 for (i=0; i<2; i++) {
\r
4396 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4397 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4398 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4399 lastDrawnHighlight.sq[i].y >= 0) {
\r
4400 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4401 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4402 clips[num_clips++] =
\r
4403 CreateRectRgn(x - lineGap, y - lineGap,
\r
4404 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4406 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4407 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4408 clips[num_clips++] =
\r
4409 CreateRectRgn(x - lineGap, y - lineGap,
\r
4410 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4414 for (i=0; i<2; i++) {
\r
4415 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4416 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4417 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4418 lastDrawnPremove.sq[i].y >= 0) {
\r
4419 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4420 lastDrawnPremove.sq[i].x, &x, &y);
\r
4421 clips[num_clips++] =
\r
4422 CreateRectRgn(x - lineGap, y - lineGap,
\r
4423 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4425 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4426 premoveHighlightInfo.sq[i].y >= 0) {
\r
4427 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4428 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4429 clips[num_clips++] =
\r
4430 CreateRectRgn(x - lineGap, y - lineGap,
\r
4431 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4436 fullrepaint = TRUE;
\r
4439 /* Create a buffer bitmap - this is the actual bitmap
\r
4440 * being written to. When all the work is done, we can
\r
4441 * copy it to the real DC (the screen). This avoids
\r
4442 * the problems with flickering.
\r
4444 GetClientRect(hwndMain, &Rect);
\r
4445 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4446 Rect.bottom-Rect.top+1);
\r
4447 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4448 if (!appData.monoMode) {
\r
4449 SelectPalette(hdcmem, hPal, FALSE);
\r
4452 /* Create clips for dragging */
\r
4453 if (!fullrepaint) {
\r
4454 if (dragInfo.from.x >= 0) {
\r
4455 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4456 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4458 if (dragInfo.start.x >= 0) {
\r
4459 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4460 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4462 if (dragInfo.pos.x >= 0) {
\r
4463 x = dragInfo.pos.x - squareSize / 2;
\r
4464 y = dragInfo.pos.y - squareSize / 2;
\r
4465 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4467 if (dragInfo.lastpos.x >= 0) {
\r
4468 x = dragInfo.lastpos.x - squareSize / 2;
\r
4469 y = dragInfo.lastpos.y - squareSize / 2;
\r
4470 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4474 /* Are we animating a move?
\r
4476 * - remove the piece from the board (temporarely)
\r
4477 * - calculate the clipping region
\r
4479 if (!fullrepaint) {
\r
4480 if (animInfo.piece != EmptySquare) {
\r
4481 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4482 x = boardRect.left + animInfo.lastpos.x;
\r
4483 y = boardRect.top + animInfo.lastpos.y;
\r
4484 x2 = boardRect.left + animInfo.pos.x;
\r
4485 y2 = boardRect.top + animInfo.pos.y;
\r
4486 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4487 /* Slight kludge. The real problem is that after AnimateMove is
\r
4488 done, the position on the screen does not match lastDrawn.
\r
4489 This currently causes trouble only on e.p. captures in
\r
4490 atomic, where the piece moves to an empty square and then
\r
4491 explodes. The old and new positions both had an empty square
\r
4492 at the destination, but animation has drawn a piece there and
\r
4493 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4494 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4498 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4499 if (num_clips == 0)
\r
4500 fullrepaint = TRUE;
\r
4502 /* Set clipping on the memory DC */
\r
4503 if (!fullrepaint) {
\r
4504 SelectClipRgn(hdcmem, clips[0]);
\r
4505 for (x = 1; x < num_clips; x++) {
\r
4506 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4507 abort(); // this should never ever happen!
\r
4511 /* Do all the drawing to the memory DC */
\r
4512 if(explodeInfo.radius) { // [HGM] atomic
\r
4514 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4515 board[explodeInfo.fromY][explodeInfo.fromX] = EmptySquare; // suppress display of capturer
\r
4516 SquareToPos(explodeInfo.toY, explodeInfo.toX, &x, &y);
\r
4517 x += squareSize/2;
\r
4518 y += squareSize/2;
\r
4519 if(!fullrepaint) {
\r
4520 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4521 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4523 DrawGridOnDC(hdcmem);
\r
4524 DrawHighlightsOnDC(hdcmem);
\r
4525 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4526 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4527 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4528 SelectObject(hdcmem, oldBrush);
\r
4530 DrawGridOnDC(hdcmem);
\r
4531 DrawHighlightsOnDC(hdcmem);
\r
4532 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4535 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);
\r
4536 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);
\r
4539 if( appData.highlightMoveWithArrow ) {
\r
4540 DrawArrowHighlight(hdcmem);
\r
4543 DrawCoordsOnDC(hdcmem);
\r
4545 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4546 /* to make sure lastDrawn contains what is actually drawn */
\r
4548 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4549 if (dragged_piece != EmptySquare) {
\r
4550 /* [HGM] or restack */
\r
4551 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4552 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4554 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4555 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4556 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4557 x = dragInfo.pos.x - squareSize / 2;
\r
4558 y = dragInfo.pos.y - squareSize / 2;
\r
4559 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4560 ((int) dragged_piece < (int) BlackPawn),
\r
4561 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4564 /* Put the animated piece back into place and draw it */
\r
4565 if (animInfo.piece != EmptySquare) {
\r
4566 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4567 x = boardRect.left + animInfo.pos.x;
\r
4568 y = boardRect.top + animInfo.pos.y;
\r
4569 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4570 ((int) animInfo.piece < (int) BlackPawn),
\r
4571 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4574 /* Release the bufferBitmap by selecting in the old bitmap
\r
4575 * and delete the memory DC
\r
4577 SelectObject(hdcmem, oldBitmap);
\r
4580 /* Set clipping on the target DC */
\r
4581 if (!fullrepaint) {
\r
4582 SelectClipRgn(hdc, clips[0]);
\r
4583 for (x = 1; x < num_clips; x++) {
\r
4584 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4585 abort(); // this should never ever happen!
\r
4589 /* Copy the new bitmap onto the screen in one go.
\r
4590 * This way we avoid any flickering
\r
4592 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4593 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4594 boardRect.right - boardRect.left,
\r
4595 boardRect.bottom - boardRect.top,
\r
4596 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4597 if(saveDiagFlag) {
\r
4598 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4599 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4601 GetObject(bufferBitmap, sizeof(b), &b);
\r
4602 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4603 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4604 bih.biWidth = b.bmWidth;
\r
4605 bih.biHeight = b.bmHeight;
\r
4607 bih.biBitCount = b.bmBitsPixel;
\r
4608 bih.biCompression = 0;
\r
4609 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4610 bih.biXPelsPerMeter = 0;
\r
4611 bih.biYPelsPerMeter = 0;
\r
4612 bih.biClrUsed = 0;
\r
4613 bih.biClrImportant = 0;
\r
4614 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4615 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4616 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4617 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4620 wb = b.bmWidthBytes;
\r
4622 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4623 int k = ((int*) pData)[i];
\r
4624 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4625 if(j >= 16) break;
\r
4627 if(j >= nrColors) nrColors = j+1;
\r
4629 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4631 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4632 for(w=0; w<(wb>>2); w+=2) {
\r
4633 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4634 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4635 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4636 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4637 pData[p++] = m | j<<4;
\r
4639 while(p&3) pData[p++] = 0;
\r
4642 wb = ((wb+31)>>5)<<2;
\r
4644 // write BITMAPFILEHEADER
\r
4645 fprintf(diagFile, "BM");
\r
4646 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4647 fputDW(diagFile, 0);
\r
4648 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4649 // write BITMAPINFOHEADER
\r
4650 fputDW(diagFile, 40);
\r
4651 fputDW(diagFile, b.bmWidth);
\r
4652 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4653 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4654 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\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 fputDW(diagFile, 0);
\r
4661 // write color table
\r
4663 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4664 // write bitmap data
\r
4665 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4666 fputc(pData[i], diagFile);
\r
4671 SelectObject(tmphdc, oldBitmap);
\r
4673 /* Massive cleanup */
\r
4674 for (x = 0; x < num_clips; x++)
\r
4675 DeleteObject(clips[x]);
\r
4678 DeleteObject(bufferBitmap);
\r
4681 ReleaseDC(hwndMain, hdc);
\r
4683 if (lastDrawnFlipView != flipView) {
\r
4685 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4687 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4690 /* CopyBoard(lastDrawn, board);*/
\r
4691 lastDrawnHighlight = highlightInfo;
\r
4692 lastDrawnPremove = premoveHighlightInfo;
\r
4693 lastDrawnFlipView = flipView;
\r
4694 lastDrawnValid = 1;
\r
4697 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4702 saveDiagFlag = 1; diagFile = f;
\r
4703 HDCDrawPosition(NULL, TRUE, NULL);
\r
4707 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4714 /*---------------------------------------------------------------------------*\
\r
4715 | CLIENT PAINT PROCEDURE
\r
4716 | This is the main event-handler for the WM_PAINT message.
\r
4718 \*---------------------------------------------------------------------------*/
\r
4720 PaintProc(HWND hwnd)
\r
4726 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4727 if (IsIconic(hwnd)) {
\r
4728 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4730 if (!appData.monoMode) {
\r
4731 SelectPalette(hdc, hPal, FALSE);
\r
4732 RealizePalette(hdc);
\r
4734 HDCDrawPosition(hdc, 1, NULL);
\r
4736 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4737 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4738 ETO_CLIPPED|ETO_OPAQUE,
\r
4739 &messageRect, messageText, strlen(messageText), NULL);
\r
4740 SelectObject(hdc, oldFont);
\r
4741 DisplayBothClocks();
\r
4743 EndPaint(hwnd,&ps);
\r
4751 * If the user selects on a border boundary, return -1; if off the board,
\r
4752 * return -2. Otherwise map the event coordinate to the square.
\r
4753 * The offset boardRect.left or boardRect.top must already have been
\r
4754 * subtracted from x.
\r
4757 EventToSquare(int x)
\r
4764 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4766 x /= (squareSize + lineGap);
\r
4767 if (x >= BOARD_SIZE)
\r
4778 DropEnable dropEnables[] = {
\r
4779 { 'P', DP_Pawn, "Pawn" },
\r
4780 { 'N', DP_Knight, "Knight" },
\r
4781 { 'B', DP_Bishop, "Bishop" },
\r
4782 { 'R', DP_Rook, "Rook" },
\r
4783 { 'Q', DP_Queen, "Queen" },
\r
4787 SetupDropMenu(HMENU hmenu)
\r
4789 int i, count, enable;
\r
4791 extern char white_holding[], black_holding[];
\r
4792 char item[MSG_SIZ];
\r
4794 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4795 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4796 dropEnables[i].piece);
\r
4798 while (p && *p++ == dropEnables[i].piece) count++;
\r
4799 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4800 enable = count > 0 || !appData.testLegality
\r
4801 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4802 && !appData.icsActive);
\r
4803 ModifyMenu(hmenu, dropEnables[i].command,
\r
4804 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4805 dropEnables[i].command, item);
\r
4809 static int fromX = -1, fromY = -1, toX, toY;
\r
4811 /* Event handler for mouse messages */
\r
4813 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4817 static int recursive = 0;
\r
4819 // BOOLEAN needsRedraw = FALSE;
\r
4820 BOOLEAN saveAnimate;
\r
4821 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4822 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4823 ChessMove moveType;
\r
4826 if (message == WM_MBUTTONUP) {
\r
4827 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4828 to the middle button: we simulate pressing the left button too!
\r
4830 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4831 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4837 pt.x = LOWORD(lParam);
\r
4838 pt.y = HIWORD(lParam);
\r
4839 x = EventToSquare(pt.x - boardRect.left);
\r
4840 y = EventToSquare(pt.y - boardRect.top);
\r
4841 if (!flipView && y >= 0) {
\r
4842 y = BOARD_HEIGHT - 1 - y;
\r
4844 if (flipView && x >= 0) {
\r
4845 x = BOARD_WIDTH - 1 - x;
\r
4848 switch (message) {
\r
4849 case WM_LBUTTONDOWN:
\r
4850 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4851 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4852 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4853 if(gameInfo.holdingsWidth &&
\r
4854 (WhiteOnMove(currentMove)
\r
4855 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4856 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4857 // click in right holdings, for determining promotion piece
\r
4858 ChessSquare p = boards[currentMove][y][x];
\r
4859 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4860 if(p != EmptySquare) {
\r
4861 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4862 fromX = fromY = -1;
\r
4866 DrawPosition(FALSE, boards[currentMove]);
\r
4870 sameAgain = FALSE;
\r
4872 /* Downclick vertically off board; check if on clock */
\r
4873 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4874 if (gameMode == EditPosition) {
\r
4875 SetWhiteToPlayEvent();
\r
4876 } else if (gameMode == IcsPlayingBlack ||
\r
4877 gameMode == MachinePlaysWhite) {
\r
4879 } else if (gameMode == EditGame) {
\r
4880 AdjustClock(flipClock, -1);
\r
4882 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4883 if (gameMode == EditPosition) {
\r
4884 SetBlackToPlayEvent();
\r
4885 } else if (gameMode == IcsPlayingWhite ||
\r
4886 gameMode == MachinePlaysBlack) {
\r
4888 } else if (gameMode == EditGame) {
\r
4889 AdjustClock(!flipClock, -1);
\r
4892 if (!appData.highlightLastMove) {
\r
4893 ClearHighlights();
\r
4894 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4896 fromX = fromY = -1;
\r
4897 dragInfo.start.x = dragInfo.start.y = -1;
\r
4898 dragInfo.from = dragInfo.start;
\r
4900 } else if (x < 0 || y < 0
\r
4901 /* [HGM] block clicks between board and holdings */
\r
4902 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4903 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4904 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4905 /* EditPosition, empty square, or different color piece;
\r
4906 click-click move is possible */
\r
4909 } else if (fromX == x && fromY == y) {
\r
4910 /* Downclick on same square again */
\r
4911 ClearHighlights();
\r
4912 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4913 sameAgain = TRUE;
\r
4914 } else if (fromX != -1 &&
\r
4915 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4917 /* Downclick on different square. */
\r
4918 /* [HGM] if on holdings file, should count as new first click ! */
\r
4919 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4922 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4923 to make sure move is legal before showing promotion popup */
\r
4924 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4925 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4926 fromX = fromY = -1;
\r
4927 ClearHighlights();
\r
4928 DrawPosition(FALSE, boards[currentMove]);
\r
4931 if(moveType != ImpossibleMove) {
\r
4932 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4933 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4934 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4935 appData.alwaysPromoteToQueen)) {
\r
4936 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4937 if (!appData.highlightLastMove) {
\r
4938 ClearHighlights();
\r
4939 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4942 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4943 SetHighlights(fromX, fromY, toX, toY);
\r
4944 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4945 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4946 If promotion to Q is legal, all are legal! */
\r
4947 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4948 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4949 // kludge to temporarily execute move on display, wthout promotng yet
\r
4950 promotionChoice = TRUE;
\r
4951 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4952 boards[currentMove][toY][toX] = p;
\r
4953 DrawPosition(FALSE, boards[currentMove]);
\r
4954 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4955 boards[currentMove][toY][toX] = q;
\r
4957 PromotionPopup(hwnd);
\r
4958 } else { /* not a promotion */
\r
4959 if (appData.animate || appData.highlightLastMove) {
\r
4960 SetHighlights(fromX, fromY, toX, toY);
\r
4962 ClearHighlights();
\r
4964 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4965 fromX = fromY = -1;
\r
4966 if (appData.animate && !appData.highlightLastMove) {
\r
4967 ClearHighlights();
\r
4968 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4974 /* [HGM] it seemed that braces were missing here */
\r
4975 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4976 fromX = fromY = -1;
\r
4980 ClearHighlights();
\r
4981 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4983 /* First downclick, or restart on a square with same color piece */
\r
4984 if (!frozen && OKToStartUserMove(x, y)) {
\r
4987 dragInfo.lastpos = pt;
\r
4988 dragInfo.from.x = fromX;
\r
4989 dragInfo.from.y = fromY;
\r
4990 dragInfo.start = dragInfo.from;
\r
4991 SetCapture(hwndMain);
\r
4993 fromX = fromY = -1;
\r
4994 dragInfo.start.x = dragInfo.start.y = -1;
\r
4995 dragInfo.from = dragInfo.start;
\r
4996 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
5000 case WM_LBUTTONUP:
\r
5002 if (fromX == -1) break;
\r
5003 if (x == fromX && y == fromY) {
\r
5004 dragInfo.from.x = dragInfo.from.y = -1;
\r
5005 /* Upclick on same square */
\r
5007 /* Clicked same square twice: abort click-click move */
\r
5008 fromX = fromY = -1;
\r
5010 ClearPremoveHighlights();
\r
5012 /* First square clicked: start click-click move */
\r
5013 SetHighlights(fromX, fromY, -1, -1);
\r
5015 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5016 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5017 /* Errant click; ignore */
\r
5020 /* Finish drag move. */
\r
5021 if (appData.debugMode) {
\r
5022 fprintf(debugFP, "release\n");
\r
5024 dragInfo.from.x = dragInfo.from.y = -1;
\r
5027 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5028 appData.animate = appData.animate && !appData.animateDragging;
\r
5029 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5030 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5031 fromX = fromY = -1;
\r
5032 ClearHighlights();
\r
5033 DrawPosition(FALSE, boards[currentMove]);
\r
5036 if(moveType != ImpossibleMove) {
\r
5037 /* [HGM] use move type to determine if move is promotion.
\r
5038 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5039 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5040 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5041 appData.alwaysPromoteToQueen))
\r
5042 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5044 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5045 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5046 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5047 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5048 // kludge to temporarily execute move on display, wthout promotng yet
\r
5049 promotionChoice = TRUE;
\r
5050 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5051 boards[currentMove][toY][toX] = p;
\r
5052 DrawPosition(FALSE, boards[currentMove]);
\r
5053 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5054 boards[currentMove][toY][toX] = q;
\r
5057 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5059 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5060 && (boards[currentMove][toY][toX] != EmptySquare ||
\r
5061 moveType == WhiteCapturesEnPassant ||
\r
5062 moveType == BlackCapturesEnPassant ) )
\r
5063 AnimateAtomicCapture(fromX, fromY, toX, toY, 20);
\r
5064 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5067 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5068 appData.animate = saveAnimate;
\r
5069 fromX = fromY = -1;
\r
5070 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5071 ClearHighlights();
\r
5073 if (appData.animate || appData.animateDragging ||
\r
5074 appData.highlightDragging || gotPremove) {
\r
5075 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5078 dragInfo.start.x = dragInfo.start.y = -1;
\r
5079 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5082 case WM_MOUSEMOVE:
\r
5083 if ((appData.animateDragging || appData.highlightDragging)
\r
5084 && (wParam & MK_LBUTTON)
\r
5085 && dragInfo.from.x >= 0)
\r
5087 BOOL full_repaint = FALSE;
\r
5089 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5090 if (appData.animateDragging) {
\r
5091 dragInfo.pos = pt;
\r
5093 if (appData.highlightDragging) {
\r
5094 SetHighlights(fromX, fromY, x, y);
\r
5095 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5096 full_repaint = TRUE;
\r
5100 DrawPosition( full_repaint, NULL);
\r
5102 dragInfo.lastpos = dragInfo.pos;
\r
5106 case WM_MOUSEWHEEL: // [DM]
\r
5107 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5108 /* Mouse Wheel is being rolled forward
\r
5109 * Play moves forward
\r
5111 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5112 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5113 /* Mouse Wheel is being rolled backward
\r
5114 * Play moves backward
\r
5116 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5117 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5121 case WM_MBUTTONDOWN:
\r
5122 case WM_RBUTTONDOWN:
\r
5125 fromX = fromY = -1;
\r
5126 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5127 dragInfo.start.x = dragInfo.start.y = -1;
\r
5128 dragInfo.from = dragInfo.start;
\r
5129 dragInfo.lastpos = dragInfo.pos;
\r
5130 if (appData.highlightDragging) {
\r
5131 ClearHighlights();
\r
5134 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5135 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5136 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
5137 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5138 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
5141 DrawPosition(TRUE, NULL);
\r
5143 switch (gameMode) {
\r
5144 case EditPosition:
\r
5145 case IcsExamining:
\r
5146 if (x < 0 || y < 0) break;
\r
5149 if (message == WM_MBUTTONDOWN) {
\r
5150 buttonCount = 3; /* even if system didn't think so */
\r
5151 if (wParam & MK_SHIFT)
\r
5152 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5154 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5155 } else { /* message == WM_RBUTTONDOWN */
\r
5157 if (buttonCount == 3) {
\r
5158 if (wParam & MK_SHIFT)
\r
5159 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5161 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5163 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5166 /* Just have one menu, on the right button. Windows users don't
\r
5167 think to try the middle one, and sometimes other software steals
\r
5168 it, or it doesn't really exist. */
\r
5169 if(gameInfo.variant != VariantShogi)
\r
5170 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5172 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5176 case IcsPlayingWhite:
\r
5177 case IcsPlayingBlack:
\r
5179 case MachinePlaysWhite:
\r
5180 case MachinePlaysBlack:
\r
5181 if (appData.testLegality &&
\r
5182 gameInfo.variant != VariantBughouse &&
\r
5183 gameInfo.variant != VariantCrazyhouse) break;
\r
5184 if (x < 0 || y < 0) break;
\r
5187 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5188 SetupDropMenu(hmenu);
\r
5189 MenuPopup(hwnd, pt, hmenu, -1);
\r
5200 /* Preprocess messages for buttons in main window */
\r
5202 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5204 int id = GetWindowLong(hwnd, GWL_ID);
\r
5207 for (i=0; i<N_BUTTONS; i++) {
\r
5208 if (buttonDesc[i].id == id) break;
\r
5210 if (i == N_BUTTONS) return 0;
\r
5211 switch (message) {
\r
5216 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5217 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5224 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5227 if (appData.icsActive) {
\r
5228 if (GetKeyState(VK_SHIFT) < 0) {
\r
5230 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5231 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5235 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5236 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5243 if (appData.icsActive) {
\r
5244 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5245 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5247 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5249 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5250 PopUpMoveDialog((char)wParam);
\r
5256 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5259 /* Process messages for Promotion dialog box */
\r
5261 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5265 switch (message) {
\r
5266 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5267 /* Center the dialog over the application window */
\r
5268 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5269 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5270 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5271 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5272 SW_SHOW : SW_HIDE);
\r
5273 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5274 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5275 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5276 PieceToChar(WhiteAngel) != '~') ||
\r
5277 (PieceToChar(BlackAngel) >= 'A' &&
\r
5278 PieceToChar(BlackAngel) != '~') ) ?
\r
5279 SW_SHOW : SW_HIDE);
\r
5280 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5281 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5282 PieceToChar(WhiteMarshall) != '~') ||
\r
5283 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5284 PieceToChar(BlackMarshall) != '~') ) ?
\r
5285 SW_SHOW : SW_HIDE);
\r
5286 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5287 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5288 gameInfo.variant != VariantShogi ?
\r
5289 SW_SHOW : SW_HIDE);
\r
5290 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5291 gameInfo.variant != VariantShogi ?
\r
5292 SW_SHOW : SW_HIDE);
\r
5293 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5294 gameInfo.variant == VariantShogi ?
\r
5295 SW_SHOW : SW_HIDE);
\r
5296 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5297 gameInfo.variant == VariantShogi ?
\r
5298 SW_SHOW : SW_HIDE);
\r
5299 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5300 gameInfo.variant == VariantSuper ?
\r
5301 SW_SHOW : SW_HIDE);
\r
5304 case WM_COMMAND: /* message: received a command */
\r
5305 switch (LOWORD(wParam)) {
\r
5307 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5308 ClearHighlights();
\r
5309 DrawPosition(FALSE, NULL);
\r
5312 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5315 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5318 promoChar = PieceToChar(BlackRook);
\r
5321 promoChar = PieceToChar(BlackBishop);
\r
5323 case PB_Chancellor:
\r
5324 promoChar = PieceToChar(BlackMarshall);
\r
5326 case PB_Archbishop:
\r
5327 promoChar = PieceToChar(BlackAngel);
\r
5330 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5335 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5336 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5337 only show the popup when we are already sure the move is valid or
\r
5338 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5339 will figure out it is a promotion from the promoChar. */
\r
5340 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5341 if (!appData.highlightLastMove) {
\r
5342 ClearHighlights();
\r
5343 DrawPosition(FALSE, NULL);
\r
5350 /* Pop up promotion dialog */
\r
5352 PromotionPopup(HWND hwnd)
\r
5356 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5357 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5358 hwnd, (DLGPROC)lpProc);
\r
5359 FreeProcInstance(lpProc);
\r
5362 /* Toggle ShowThinking */
\r
5364 ToggleShowThinking()
\r
5366 appData.showThinking = !appData.showThinking;
\r
5367 ShowThinkingEvent();
\r
5371 LoadGameDialog(HWND hwnd, char* title)
\r
5375 char fileTitle[MSG_SIZ];
\r
5376 f = OpenFileDialog(hwnd, "rb", "",
\r
5377 appData.oldSaveStyle ? "gam" : "pgn",
\r
5379 title, &number, fileTitle, NULL);
\r
5381 cmailMsgLoaded = FALSE;
\r
5382 if (number == 0) {
\r
5383 int error = GameListBuild(f);
\r
5385 DisplayError("Cannot build game list", error);
\r
5386 } else if (!ListEmpty(&gameList) &&
\r
5387 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5388 GameListPopUp(f, fileTitle);
\r
5391 GameListDestroy();
\r
5394 LoadGame(f, number, fileTitle, FALSE);
\r
5399 ChangedConsoleFont()
\r
5402 CHARRANGE tmpsel, sel;
\r
5403 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5404 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5405 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5408 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5409 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5410 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5411 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5412 * size. This was undocumented in the version of MSVC++ that I had
\r
5413 * when I wrote the code, but is apparently documented now.
\r
5415 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5416 cfmt.bCharSet = f->lf.lfCharSet;
\r
5417 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5418 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5419 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5420 /* Why are the following seemingly needed too? */
\r
5421 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5422 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5423 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5425 tmpsel.cpMax = -1; /*999999?*/
\r
5426 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5427 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5428 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5429 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5431 paraf.cbSize = sizeof(paraf);
\r
5432 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5433 paraf.dxStartIndent = 0;
\r
5434 paraf.dxOffset = WRAP_INDENT;
\r
5435 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5436 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5439 /*---------------------------------------------------------------------------*\
\r
5441 * Window Proc for main window
\r
5443 \*---------------------------------------------------------------------------*/
\r
5445 /* Process messages for main window, etc. */
\r
5447 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5450 int wmId, wmEvent;
\r
5454 char fileTitle[MSG_SIZ];
\r
5455 char buf[MSG_SIZ];
\r
5456 static SnapData sd;
\r
5458 switch (message) {
\r
5460 case WM_PAINT: /* message: repaint portion of window */
\r
5464 case WM_ERASEBKGND:
\r
5465 if (IsIconic(hwnd)) {
\r
5466 /* Cheat; change the message */
\r
5467 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5469 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5473 case WM_LBUTTONDOWN:
\r
5474 case WM_MBUTTONDOWN:
\r
5475 case WM_RBUTTONDOWN:
\r
5476 case WM_LBUTTONUP:
\r
5477 case WM_MBUTTONUP:
\r
5478 case WM_RBUTTONUP:
\r
5479 case WM_MOUSEMOVE:
\r
5480 case WM_MOUSEWHEEL:
\r
5481 MouseEvent(hwnd, message, wParam, lParam);
\r
5486 if (appData.icsActive) {
\r
5487 if (wParam == '\t') {
\r
5488 if (GetKeyState(VK_SHIFT) < 0) {
\r
5490 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5491 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5495 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5496 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5500 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5501 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5503 SendMessage(h, message, wParam, lParam);
\r
5505 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5506 PopUpMoveDialog((char)wParam);
\r
5510 case WM_PALETTECHANGED:
\r
5511 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5513 HDC hdc = GetDC(hwndMain);
\r
5514 SelectPalette(hdc, hPal, TRUE);
\r
5515 nnew = RealizePalette(hdc);
\r
5517 paletteChanged = TRUE;
\r
5519 UpdateColors(hdc);
\r
5521 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5524 ReleaseDC(hwnd, hdc);
\r
5528 case WM_QUERYNEWPALETTE:
\r
5529 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5531 HDC hdc = GetDC(hwndMain);
\r
5532 paletteChanged = FALSE;
\r
5533 SelectPalette(hdc, hPal, FALSE);
\r
5534 nnew = RealizePalette(hdc);
\r
5536 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5538 ReleaseDC(hwnd, hdc);
\r
5543 case WM_COMMAND: /* message: command from application menu */
\r
5544 wmId = LOWORD(wParam);
\r
5545 wmEvent = HIWORD(wParam);
\r
5550 AnalysisPopDown();
\r
5553 case IDM_NewGameFRC:
\r
5554 if( NewGameFRC() == 0 ) {
\r
5556 AnalysisPopDown();
\r
5560 case IDM_NewVariant:
\r
5561 NewVariantPopup(hwnd);
\r
5564 case IDM_LoadGame:
\r
5565 LoadGameDialog(hwnd, "Load Game from File");
\r
5568 case IDM_LoadNextGame:
\r
5572 case IDM_LoadPrevGame:
\r
5576 case IDM_ReloadGame:
\r
5580 case IDM_LoadPosition:
\r
5581 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5582 Reset(FALSE, TRUE);
\r
5585 f = OpenFileDialog(hwnd, "rb", "",
\r
5586 appData.oldSaveStyle ? "pos" : "fen",
\r
5588 "Load Position from File", &number, fileTitle, NULL);
\r
5590 LoadPosition(f, number, fileTitle);
\r
5594 case IDM_LoadNextPosition:
\r
5595 ReloadPosition(1);
\r
5598 case IDM_LoadPrevPosition:
\r
5599 ReloadPosition(-1);
\r
5602 case IDM_ReloadPosition:
\r
5603 ReloadPosition(0);
\r
5606 case IDM_SaveGame:
\r
5607 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5608 f = OpenFileDialog(hwnd, "a", defName,
\r
5609 appData.oldSaveStyle ? "gam" : "pgn",
\r
5611 "Save Game to File", NULL, fileTitle, NULL);
\r
5613 SaveGame(f, 0, "");
\r
5617 case IDM_SavePosition:
\r
5618 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5619 f = OpenFileDialog(hwnd, "a", defName,
\r
5620 appData.oldSaveStyle ? "pos" : "fen",
\r
5622 "Save Position to File", NULL, fileTitle, NULL);
\r
5624 SavePosition(f, 0, "");
\r
5628 case IDM_SaveDiagram:
\r
5629 defName = "diagram";
\r
5630 f = OpenFileDialog(hwnd, "wb", defName,
\r
5633 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5639 case IDM_CopyGame:
\r
5640 CopyGameToClipboard();
\r
5643 case IDM_PasteGame:
\r
5644 PasteGameFromClipboard();
\r
5647 case IDM_CopyGameListToClipboard:
\r
5648 CopyGameListToClipboard();
\r
5651 /* [AS] Autodetect FEN or PGN data */
\r
5652 case IDM_PasteAny:
\r
5653 PasteGameOrFENFromClipboard();
\r
5656 /* [AS] Move history */
\r
5657 case IDM_ShowMoveHistory:
\r
5658 if( MoveHistoryIsUp() ) {
\r
5659 MoveHistoryPopDown();
\r
5662 MoveHistoryPopUp();
\r
5666 /* [AS] Eval graph */
\r
5667 case IDM_ShowEvalGraph:
\r
5668 if( EvalGraphIsUp() ) {
\r
5669 EvalGraphPopDown();
\r
5676 /* [AS] Engine output */
\r
5677 case IDM_ShowEngineOutput:
\r
5678 if( EngineOutputIsUp() ) {
\r
5679 EngineOutputPopDown();
\r
5682 EngineOutputPopUp();
\r
5686 /* [AS] User adjudication */
\r
5687 case IDM_UserAdjudication_White:
\r
5688 UserAdjudicationEvent( +1 );
\r
5691 case IDM_UserAdjudication_Black:
\r
5692 UserAdjudicationEvent( -1 );
\r
5695 case IDM_UserAdjudication_Draw:
\r
5696 UserAdjudicationEvent( 0 );
\r
5699 /* [AS] Game list options dialog */
\r
5700 case IDM_GameListOptions:
\r
5701 GameListOptions();
\r
5704 case IDM_CopyPosition:
\r
5705 CopyFENToClipboard();
\r
5708 case IDM_PastePosition:
\r
5709 PasteFENFromClipboard();
\r
5712 case IDM_MailMove:
\r
5716 case IDM_ReloadCMailMsg:
\r
5717 Reset(TRUE, TRUE);
\r
5718 ReloadCmailMsgEvent(FALSE);
\r
5721 case IDM_Minimize:
\r
5722 ShowWindow(hwnd, SW_MINIMIZE);
\r
5729 case IDM_MachineWhite:
\r
5730 MachineWhiteEvent();
\r
5732 * refresh the tags dialog only if it's visible
\r
5734 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5736 tags = PGNTags(&gameInfo);
\r
5737 TagsPopUp(tags, CmailMsg());
\r
5742 case IDM_MachineBlack:
\r
5743 MachineBlackEvent();
\r
5745 * refresh the tags dialog only if it's visible
\r
5747 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5749 tags = PGNTags(&gameInfo);
\r
5750 TagsPopUp(tags, CmailMsg());
\r
5755 case IDM_TwoMachines:
\r
5756 TwoMachinesEvent();
\r
5758 * refresh the tags dialog only if it's visible
\r
5760 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5762 tags = PGNTags(&gameInfo);
\r
5763 TagsPopUp(tags, CmailMsg());
\r
5768 case IDM_AnalysisMode:
\r
5769 if (!first.analysisSupport) {
\r
5770 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5771 DisplayError(buf, 0);
\r
5773 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5774 if (appData.icsActive) {
\r
5775 if (gameMode != IcsObserving) {
\r
5776 sprintf(buf, "You are not observing a game");
\r
5777 DisplayError(buf, 0);
\r
5778 /* secure check */
\r
5779 if (appData.icsEngineAnalyze) {
\r
5780 if (appData.debugMode)
\r
5781 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5782 ExitAnalyzeMode();
\r
5788 /* if enable, user want disable icsEngineAnalyze */
\r
5789 if (appData.icsEngineAnalyze) {
\r
5790 ExitAnalyzeMode();
\r
5794 appData.icsEngineAnalyze = TRUE;
\r
5795 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5798 if (!appData.showThinking) ToggleShowThinking();
\r
5799 AnalyzeModeEvent();
\r
5803 case IDM_AnalyzeFile:
\r
5804 if (!first.analysisSupport) {
\r
5805 char buf[MSG_SIZ];
\r
5806 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5807 DisplayError(buf, 0);
\r
5809 if (!appData.showThinking) ToggleShowThinking();
\r
5810 AnalyzeFileEvent();
\r
5811 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5812 AnalysisPeriodicEvent(1);
\r
5816 case IDM_IcsClient:
\r
5820 case IDM_EditGame:
\r
5824 case IDM_EditPosition:
\r
5825 EditPositionEvent();
\r
5828 case IDM_Training:
\r
5832 case IDM_ShowGameList:
\r
5833 ShowGameListProc();
\r
5836 case IDM_EditTags:
\r
5840 case IDM_EditComment:
\r
5841 if (commentDialogUp && editComment) {
\r
5844 EditCommentEvent();
\r
5864 case IDM_CallFlag:
\r
5884 case IDM_StopObserving:
\r
5885 StopObservingEvent();
\r
5888 case IDM_StopExamining:
\r
5889 StopExaminingEvent();
\r
5892 case IDM_TypeInMove:
\r
5893 PopUpMoveDialog('\000');
\r
5896 case IDM_TypeInName:
\r
5897 PopUpNameDialog('\000');
\r
5900 case IDM_Backward:
\r
5902 SetFocus(hwndMain);
\r
5907 SetFocus(hwndMain);
\r
5912 SetFocus(hwndMain);
\r
5917 SetFocus(hwndMain);
\r
5924 case IDM_TruncateGame:
\r
5925 TruncateGameEvent();
\r
5932 case IDM_RetractMove:
\r
5933 RetractMoveEvent();
\r
5936 case IDM_FlipView:
\r
5937 flipView = !flipView;
\r
5938 DrawPosition(FALSE, NULL);
\r
5941 case IDM_FlipClock:
\r
5942 flipClock = !flipClock;
\r
5943 DisplayBothClocks();
\r
5944 DrawPosition(FALSE, NULL);
\r
5947 case IDM_GeneralOptions:
\r
5948 GeneralOptionsPopup(hwnd);
\r
5949 DrawPosition(TRUE, NULL);
\r
5952 case IDM_BoardOptions:
\r
5953 BoardOptionsPopup(hwnd);
\r
5956 case IDM_EnginePlayOptions:
\r
5957 EnginePlayOptionsPopup(hwnd);
\r
5960 case IDM_OptionsUCI:
\r
5961 UciOptionsPopup(hwnd);
\r
5964 case IDM_IcsOptions:
\r
5965 IcsOptionsPopup(hwnd);
\r
5969 FontsOptionsPopup(hwnd);
\r
5973 SoundOptionsPopup(hwnd);
\r
5976 case IDM_CommPort:
\r
5977 CommPortOptionsPopup(hwnd);
\r
5980 case IDM_LoadOptions:
\r
5981 LoadOptionsPopup(hwnd);
\r
5984 case IDM_SaveOptions:
\r
5985 SaveOptionsPopup(hwnd);
\r
5988 case IDM_TimeControl:
\r
5989 TimeControlOptionsPopup(hwnd);
\r
5992 case IDM_SaveSettings:
\r
5993 SaveSettings(settingsFileName);
\r
5996 case IDM_SaveSettingsOnExit:
\r
5997 saveSettingsOnExit = !saveSettingsOnExit;
\r
5998 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5999 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
6000 MF_CHECKED : MF_UNCHECKED));
\r
6011 case IDM_AboutGame:
\r
6016 appData.debugMode = !appData.debugMode;
\r
6017 if (appData.debugMode) {
\r
6018 char dir[MSG_SIZ];
\r
6019 GetCurrentDirectory(MSG_SIZ, dir);
\r
6020 SetCurrentDirectory(installDir);
\r
6021 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6022 SetCurrentDirectory(dir);
\r
6023 setbuf(debugFP, NULL);
\r
6030 case IDM_HELPCONTENTS:
\r
6031 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6032 MessageBox (GetFocus(),
\r
6033 "Unable to activate help",
\r
6034 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6038 case IDM_HELPSEARCH:
\r
6039 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
6040 MessageBox (GetFocus(),
\r
6041 "Unable to activate help",
\r
6042 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6046 case IDM_HELPHELP:
\r
6047 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6048 MessageBox (GetFocus(),
\r
6049 "Unable to activate help",
\r
6050 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6055 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6057 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6058 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6059 FreeProcInstance(lpProc);
\r
6062 case IDM_DirectCommand1:
\r
6063 AskQuestionEvent("Direct Command",
\r
6064 "Send to chess program:", "", "1");
\r
6066 case IDM_DirectCommand2:
\r
6067 AskQuestionEvent("Direct Command",
\r
6068 "Send to second chess program:", "", "2");
\r
6071 case EP_WhitePawn:
\r
6072 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6073 fromX = fromY = -1;
\r
6076 case EP_WhiteKnight:
\r
6077 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6078 fromX = fromY = -1;
\r
6081 case EP_WhiteBishop:
\r
6082 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6083 fromX = fromY = -1;
\r
6086 case EP_WhiteRook:
\r
6087 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6088 fromX = fromY = -1;
\r
6091 case EP_WhiteQueen:
\r
6092 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6093 fromX = fromY = -1;
\r
6096 case EP_WhiteFerz:
\r
6097 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6098 fromX = fromY = -1;
\r
6101 case EP_WhiteWazir:
\r
6102 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6103 fromX = fromY = -1;
\r
6106 case EP_WhiteAlfil:
\r
6107 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6108 fromX = fromY = -1;
\r
6111 case EP_WhiteCannon:
\r
6112 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6113 fromX = fromY = -1;
\r
6116 case EP_WhiteCardinal:
\r
6117 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6118 fromX = fromY = -1;
\r
6121 case EP_WhiteMarshall:
\r
6122 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6123 fromX = fromY = -1;
\r
6126 case EP_WhiteKing:
\r
6127 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6128 fromX = fromY = -1;
\r
6131 case EP_BlackPawn:
\r
6132 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6133 fromX = fromY = -1;
\r
6136 case EP_BlackKnight:
\r
6137 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6138 fromX = fromY = -1;
\r
6141 case EP_BlackBishop:
\r
6142 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6143 fromX = fromY = -1;
\r
6146 case EP_BlackRook:
\r
6147 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6148 fromX = fromY = -1;
\r
6151 case EP_BlackQueen:
\r
6152 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6153 fromX = fromY = -1;
\r
6156 case EP_BlackFerz:
\r
6157 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6158 fromX = fromY = -1;
\r
6161 case EP_BlackWazir:
\r
6162 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6163 fromX = fromY = -1;
\r
6166 case EP_BlackAlfil:
\r
6167 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6168 fromX = fromY = -1;
\r
6171 case EP_BlackCannon:
\r
6172 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6173 fromX = fromY = -1;
\r
6176 case EP_BlackCardinal:
\r
6177 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6178 fromX = fromY = -1;
\r
6181 case EP_BlackMarshall:
\r
6182 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6183 fromX = fromY = -1;
\r
6186 case EP_BlackKing:
\r
6187 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6188 fromX = fromY = -1;
\r
6191 case EP_EmptySquare:
\r
6192 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6193 fromX = fromY = -1;
\r
6196 case EP_ClearBoard:
\r
6197 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6198 fromX = fromY = -1;
\r
6202 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6203 fromX = fromY = -1;
\r
6207 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6208 fromX = fromY = -1;
\r
6212 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6213 fromX = fromY = -1;
\r
6217 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6218 fromX = fromY = -1;
\r
6222 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6223 fromX = fromY = -1;
\r
6227 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6228 fromX = fromY = -1;
\r
6232 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6233 fromX = fromY = -1;
\r
6237 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6238 fromX = fromY = -1;
\r
6242 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6243 fromX = fromY = -1;
\r
6247 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6253 case CLOCK_TIMER_ID:
\r
6254 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6255 clockTimerEvent = 0;
\r
6256 DecrementClocks(); /* call into back end */
\r
6258 case LOAD_GAME_TIMER_ID:
\r
6259 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6260 loadGameTimerEvent = 0;
\r
6261 AutoPlayGameLoop(); /* call into back end */
\r
6263 case ANALYSIS_TIMER_ID:
\r
6264 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6265 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6266 AnalysisPeriodicEvent(0);
\r
6268 KillTimer(hwnd, analysisTimerEvent);
\r
6269 analysisTimerEvent = 0;
\r
6272 case DELAYED_TIMER_ID:
\r
6273 KillTimer(hwnd, delayedTimerEvent);
\r
6274 delayedTimerEvent = 0;
\r
6275 delayedTimerCallback();
\r
6280 case WM_USER_Input:
\r
6281 InputEvent(hwnd, message, wParam, lParam);
\r
6284 /* [AS] Also move "attached" child windows */
\r
6285 case WM_WINDOWPOSCHANGING:
\r
6287 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6288 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6290 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6291 /* Window is moving */
\r
6294 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6295 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6296 rcMain.right = boardX + winWidth;
\r
6297 rcMain.top = boardY;
\r
6298 rcMain.bottom = boardY + winHeight;
\r
6300 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6301 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6302 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6309 /* [AS] Snapping */
\r
6310 case WM_ENTERSIZEMOVE:
\r
6311 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6312 if (hwnd == hwndMain) {
\r
6313 doingSizing = TRUE;
\r
6316 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6320 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6321 if (hwnd == hwndMain) {
\r
6322 lastSizing = wParam;
\r
6327 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6328 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6330 case WM_EXITSIZEMOVE:
\r
6331 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6332 if (hwnd == hwndMain) {
\r
6334 doingSizing = FALSE;
\r
6335 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6336 GetClientRect(hwnd, &client);
\r
6337 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6339 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6341 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6344 case WM_DESTROY: /* message: window being destroyed */
\r
6345 PostQuitMessage(0);
\r
6349 if (hwnd == hwndMain) {
\r
6354 default: /* Passes it on if unprocessed */
\r
6355 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6360 /*---------------------------------------------------------------------------*\
\r
6362 * Misc utility routines
\r
6364 \*---------------------------------------------------------------------------*/
\r
6367 * Decent random number generator, at least not as bad as Windows
\r
6368 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6370 unsigned int randstate;
\r
6375 randstate = randstate * 1664525 + 1013904223;
\r
6376 return (int) randstate & 0x7fffffff;
\r
6380 mysrandom(unsigned int seed)
\r
6387 * returns TRUE if user selects a different color, FALSE otherwise
\r
6391 ChangeColor(HWND hwnd, COLORREF *which)
\r
6393 static BOOL firstTime = TRUE;
\r
6394 static DWORD customColors[16];
\r
6396 COLORREF newcolor;
\r
6401 /* Make initial colors in use available as custom colors */
\r
6402 /* Should we put the compiled-in defaults here instead? */
\r
6404 customColors[i++] = lightSquareColor & 0xffffff;
\r
6405 customColors[i++] = darkSquareColor & 0xffffff;
\r
6406 customColors[i++] = whitePieceColor & 0xffffff;
\r
6407 customColors[i++] = blackPieceColor & 0xffffff;
\r
6408 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6409 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6411 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6412 customColors[i++] = textAttribs[ccl].color;
\r
6414 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6415 firstTime = FALSE;
\r
6418 cc.lStructSize = sizeof(cc);
\r
6419 cc.hwndOwner = hwnd;
\r
6420 cc.hInstance = NULL;
\r
6421 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6422 cc.lpCustColors = (LPDWORD) customColors;
\r
6423 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6425 if (!ChooseColor(&cc)) return FALSE;
\r
6427 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6428 if (newcolor == *which) return FALSE;
\r
6429 *which = newcolor;
\r
6433 InitDrawingColors();
\r
6434 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6439 MyLoadSound(MySound *ms)
\r
6445 if (ms->data) free(ms->data);
\r
6448 switch (ms->name[0]) {
\r
6454 /* System sound from Control Panel. Don't preload here. */
\r
6458 if (ms->name[1] == NULLCHAR) {
\r
6459 /* "!" alone = silence */
\r
6462 /* Builtin wave resource. Error if not found. */
\r
6463 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6464 if (h == NULL) break;
\r
6465 ms->data = (void *)LoadResource(hInst, h);
\r
6466 if (h == NULL) break;
\r
6471 /* .wav file. Error if not found. */
\r
6472 f = fopen(ms->name, "rb");
\r
6473 if (f == NULL) break;
\r
6474 if (fstat(fileno(f), &st) < 0) break;
\r
6475 ms->data = malloc(st.st_size);
\r
6476 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6482 char buf[MSG_SIZ];
\r
6483 sprintf(buf, "Error loading sound %s", ms->name);
\r
6484 DisplayError(buf, GetLastError());
\r
6490 MyPlaySound(MySound *ms)
\r
6492 BOOLEAN ok = FALSE;
\r
6493 switch (ms->name[0]) {
\r
6499 /* System sound from Control Panel (deprecated feature).
\r
6500 "$" alone or an unset sound name gets default beep (still in use). */
\r
6501 if (ms->name[1]) {
\r
6502 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6504 if (!ok) ok = MessageBeep(MB_OK);
\r
6507 /* Builtin wave resource, or "!" alone for silence */
\r
6508 if (ms->name[1]) {
\r
6509 if (ms->data == NULL) return FALSE;
\r
6510 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6516 /* .wav file. Error if not found. */
\r
6517 if (ms->data == NULL) return FALSE;
\r
6518 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6521 /* Don't print an error: this can happen innocently if the sound driver
\r
6522 is busy; for instance, if another instance of WinBoard is playing
\r
6523 a sound at about the same time. */
\r
6526 char buf[MSG_SIZ];
\r
6527 sprintf(buf, "Error playing sound %s", ms->name);
\r
6528 DisplayError(buf, GetLastError());
\r
6536 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6539 OPENFILENAME *ofn;
\r
6540 static UINT *number; /* gross that this is static */
\r
6542 switch (message) {
\r
6543 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6544 /* Center the dialog over the application window */
\r
6545 ofn = (OPENFILENAME *) lParam;
\r
6546 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6547 number = (UINT *) ofn->lCustData;
\r
6548 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6552 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6553 return FALSE; /* Allow for further processing */
\r
6556 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6557 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6559 return FALSE; /* Allow for further processing */
\r
6565 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6567 static UINT *number;
\r
6568 OPENFILENAME *ofname;
\r
6571 case WM_INITDIALOG:
\r
6572 ofname = (OPENFILENAME *)lParam;
\r
6573 number = (UINT *)(ofname->lCustData);
\r
6576 ofnot = (OFNOTIFY *)lParam;
\r
6577 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6578 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6587 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6588 char *nameFilt, char *dlgTitle, UINT *number,
\r
6589 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6591 OPENFILENAME openFileName;
\r
6592 char buf1[MSG_SIZ];
\r
6595 if (fileName == NULL) fileName = buf1;
\r
6596 if (defName == NULL) {
\r
6597 strcpy(fileName, "*.");
\r
6598 strcat(fileName, defExt);
\r
6600 strcpy(fileName, defName);
\r
6602 if (fileTitle) strcpy(fileTitle, "");
\r
6603 if (number) *number = 0;
\r
6605 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6606 openFileName.hwndOwner = hwnd;
\r
6607 openFileName.hInstance = (HANDLE) hInst;
\r
6608 openFileName.lpstrFilter = nameFilt;
\r
6609 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6610 openFileName.nMaxCustFilter = 0L;
\r
6611 openFileName.nFilterIndex = 1L;
\r
6612 openFileName.lpstrFile = fileName;
\r
6613 openFileName.nMaxFile = MSG_SIZ;
\r
6614 openFileName.lpstrFileTitle = fileTitle;
\r
6615 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6616 openFileName.lpstrInitialDir = NULL;
\r
6617 openFileName.lpstrTitle = dlgTitle;
\r
6618 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6619 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6620 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6621 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6622 openFileName.nFileOffset = 0;
\r
6623 openFileName.nFileExtension = 0;
\r
6624 openFileName.lpstrDefExt = defExt;
\r
6625 openFileName.lCustData = (LONG) number;
\r
6626 openFileName.lpfnHook = oldDialog ?
\r
6627 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6628 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6630 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6631 GetOpenFileName(&openFileName)) {
\r
6632 /* open the file */
\r
6633 f = fopen(openFileName.lpstrFile, write);
\r
6635 MessageBox(hwnd, "File open failed", NULL,
\r
6636 MB_OK|MB_ICONEXCLAMATION);
\r
6640 int err = CommDlgExtendedError();
\r
6641 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6650 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6652 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6655 * Get the first pop-up menu in the menu template. This is the
\r
6656 * menu that TrackPopupMenu displays.
\r
6658 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6660 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6663 * TrackPopup uses screen coordinates, so convert the
\r
6664 * coordinates of the mouse click to screen coordinates.
\r
6666 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6668 /* Draw and track the floating pop-up menu. */
\r
6669 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6670 pt.x, pt.y, 0, hwnd, NULL);
\r
6672 /* Destroy the menu.*/
\r
6673 DestroyMenu(hmenu);
\r
6678 int sizeX, sizeY, newSizeX, newSizeY;
\r
6680 } ResizeEditPlusButtonsClosure;
\r
6683 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6685 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6689 if (hChild == cl->hText) return TRUE;
\r
6690 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6691 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6692 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6693 ScreenToClient(cl->hDlg, &pt);
\r
6694 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6695 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6699 /* Resize a dialog that has a (rich) edit field filling most of
\r
6700 the top, with a row of buttons below */
\r
6702 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6705 int newTextHeight, newTextWidth;
\r
6706 ResizeEditPlusButtonsClosure cl;
\r
6708 /*if (IsIconic(hDlg)) return;*/
\r
6709 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6711 cl.hdwp = BeginDeferWindowPos(8);
\r
6713 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6714 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6715 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6716 if (newTextHeight < 0) {
\r
6717 newSizeY += -newTextHeight;
\r
6718 newTextHeight = 0;
\r
6720 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6721 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6727 cl.newSizeX = newSizeX;
\r
6728 cl.newSizeY = newSizeY;
\r
6729 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6731 EndDeferWindowPos(cl.hdwp);
\r
6734 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6736 RECT rChild, rParent;
\r
6737 int wChild, hChild, wParent, hParent;
\r
6738 int wScreen, hScreen, xNew, yNew;
\r
6741 /* Get the Height and Width of the child window */
\r
6742 GetWindowRect (hwndChild, &rChild);
\r
6743 wChild = rChild.right - rChild.left;
\r
6744 hChild = rChild.bottom - rChild.top;
\r
6746 /* Get the Height and Width of the parent window */
\r
6747 GetWindowRect (hwndParent, &rParent);
\r
6748 wParent = rParent.right - rParent.left;
\r
6749 hParent = rParent.bottom - rParent.top;
\r
6751 /* Get the display limits */
\r
6752 hdc = GetDC (hwndChild);
\r
6753 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6754 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6755 ReleaseDC(hwndChild, hdc);
\r
6757 /* Calculate new X position, then adjust for screen */
\r
6758 xNew = rParent.left + ((wParent - wChild) /2);
\r
6761 } else if ((xNew+wChild) > wScreen) {
\r
6762 xNew = wScreen - wChild;
\r
6765 /* Calculate new Y position, then adjust for screen */
\r
6767 yNew = rParent.top + ((hParent - hChild) /2);
\r
6770 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6775 } else if ((yNew+hChild) > hScreen) {
\r
6776 yNew = hScreen - hChild;
\r
6779 /* Set it, and return */
\r
6780 return SetWindowPos (hwndChild, NULL,
\r
6781 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6784 /* Center one window over another */
\r
6785 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6787 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6790 /*---------------------------------------------------------------------------*\
\r
6792 * Startup Dialog functions
\r
6794 \*---------------------------------------------------------------------------*/
\r
6796 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6798 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6800 while (*cd != NULL) {
\r
6801 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6807 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6809 char buf1[ARG_MAX];
\r
6812 if (str[0] == '@') {
\r
6813 FILE* f = fopen(str + 1, "r");
\r
6815 DisplayFatalError(str + 1, errno, 2);
\r
6818 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6820 buf1[len] = NULLCHAR;
\r
6824 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6827 char buf[MSG_SIZ];
\r
6828 char *end = strchr(str, '\n');
\r
6829 if (end == NULL) return;
\r
6830 memcpy(buf, str, end - str);
\r
6831 buf[end - str] = NULLCHAR;
\r
6832 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6838 SetStartupDialogEnables(HWND hDlg)
\r
6840 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6841 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6842 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6843 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6844 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6845 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6846 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6847 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6848 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6849 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6850 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6851 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6852 IsDlgButtonChecked(hDlg, OPT_View));
\r
6856 QuoteForFilename(char *filename)
\r
6858 int dquote, space;
\r
6859 dquote = strchr(filename, '"') != NULL;
\r
6860 space = strchr(filename, ' ') != NULL;
\r
6861 if (dquote || space) {
\r
6873 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6875 char buf[MSG_SIZ];
\r
6878 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6879 q = QuoteForFilename(nthcp);
\r
6880 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6881 if (*nthdir != NULLCHAR) {
\r
6882 q = QuoteForFilename(nthdir);
\r
6883 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6885 if (*nthcp == NULLCHAR) {
\r
6886 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6887 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6888 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6889 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6894 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6896 char buf[MSG_SIZ];
\r
6900 switch (message) {
\r
6901 case WM_INITDIALOG:
\r
6902 /* Center the dialog */
\r
6903 CenterWindow (hDlg, GetDesktopWindow());
\r
6904 /* Initialize the dialog items */
\r
6905 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6906 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6907 firstChessProgramNames);
\r
6908 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6909 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6910 secondChessProgramNames);
\r
6911 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6912 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6913 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6914 if (*appData.icsHelper != NULLCHAR) {
\r
6915 char *q = QuoteForFilename(appData.icsHelper);
\r
6916 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6918 if (*appData.icsHost == NULLCHAR) {
\r
6919 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6920 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6921 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6922 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6923 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6926 if (appData.icsActive) {
\r
6927 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6929 else if (appData.noChessProgram) {
\r
6930 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6933 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6936 SetStartupDialogEnables(hDlg);
\r
6940 switch (LOWORD(wParam)) {
\r
6942 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6943 strcpy(buf, "/fcp=");
\r
6944 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6946 ParseArgs(StringGet, &p);
\r
6947 strcpy(buf, "/scp=");
\r
6948 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6950 ParseArgs(StringGet, &p);
\r
6951 appData.noChessProgram = FALSE;
\r
6952 appData.icsActive = FALSE;
\r
6953 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6954 strcpy(buf, "/ics /icshost=");
\r
6955 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6957 ParseArgs(StringGet, &p);
\r
6958 if (appData.zippyPlay) {
\r
6959 strcpy(buf, "/fcp=");
\r
6960 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6962 ParseArgs(StringGet, &p);
\r
6964 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6965 appData.noChessProgram = TRUE;
\r
6966 appData.icsActive = FALSE;
\r
6968 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6969 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6972 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6973 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6975 ParseArgs(StringGet, &p);
\r
6977 EndDialog(hDlg, TRUE);
\r
6984 case IDM_HELPCONTENTS:
\r
6985 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6986 MessageBox (GetFocus(),
\r
6987 "Unable to activate help",
\r
6988 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6993 SetStartupDialogEnables(hDlg);
\r
7001 /*---------------------------------------------------------------------------*\
\r
7003 * About box dialog functions
\r
7005 \*---------------------------------------------------------------------------*/
\r
7007 /* Process messages for "About" dialog box */
\r
7009 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7011 switch (message) {
\r
7012 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7013 /* Center the dialog over the application window */
\r
7014 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7015 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7018 case WM_COMMAND: /* message: received a command */
\r
7019 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7020 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7021 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7029 /*---------------------------------------------------------------------------*\
\r
7031 * Comment Dialog functions
\r
7033 \*---------------------------------------------------------------------------*/
\r
7036 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7038 static HANDLE hwndText = NULL;
\r
7039 int len, newSizeX, newSizeY, flags;
\r
7040 static int sizeX, sizeY;
\r
7045 switch (message) {
\r
7046 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7047 /* Initialize the dialog items */
\r
7048 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7049 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7050 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7051 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7052 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7053 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7054 SetWindowText(hDlg, commentTitle);
\r
7055 if (editComment) {
\r
7056 SetFocus(hwndText);
\r
7058 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7060 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7061 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7062 MAKELPARAM(FALSE, 0));
\r
7063 /* Size and position the dialog */
\r
7064 if (!commentDialog) {
\r
7065 commentDialog = hDlg;
\r
7066 flags = SWP_NOZORDER;
\r
7067 GetClientRect(hDlg, &rect);
\r
7068 sizeX = rect.right;
\r
7069 sizeY = rect.bottom;
\r
7070 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7071 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7072 WINDOWPLACEMENT wp;
\r
7073 EnsureOnScreen(&commentX, &commentY);
\r
7074 wp.length = sizeof(WINDOWPLACEMENT);
\r
7076 wp.showCmd = SW_SHOW;
\r
7077 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7078 wp.rcNormalPosition.left = commentX;
\r
7079 wp.rcNormalPosition.right = commentX + commentW;
\r
7080 wp.rcNormalPosition.top = commentY;
\r
7081 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7082 SetWindowPlacement(hDlg, &wp);
\r
7084 GetClientRect(hDlg, &rect);
\r
7085 newSizeX = rect.right;
\r
7086 newSizeY = rect.bottom;
\r
7087 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7088 newSizeX, newSizeY);
\r
7095 case WM_COMMAND: /* message: received a command */
\r
7096 switch (LOWORD(wParam)) {
\r
7098 if (editComment) {
\r
7100 /* Read changed options from the dialog box */
\r
7101 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7102 len = GetWindowTextLength(hwndText);
\r
7103 str = (char *) malloc(len + 1);
\r
7104 GetWindowText(hwndText, str, len + 1);
\r
7113 ReplaceComment(commentIndex, str);
\r
7120 case OPT_CancelComment:
\r
7124 case OPT_ClearComment:
\r
7125 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7128 case OPT_EditComment:
\r
7129 EditCommentEvent();
\r
7138 newSizeX = LOWORD(lParam);
\r
7139 newSizeY = HIWORD(lParam);
\r
7140 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7145 case WM_GETMINMAXINFO:
\r
7146 /* Prevent resizing window too small */
\r
7147 mmi = (MINMAXINFO *) lParam;
\r
7148 mmi->ptMinTrackSize.x = 100;
\r
7149 mmi->ptMinTrackSize.y = 100;
\r
7156 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7161 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7163 if (str == NULL) str = "";
\r
7164 p = (char *) malloc(2 * strlen(str) + 2);
\r
7167 if (*str == '\n') *q++ = '\r';
\r
7171 if (commentText != NULL) free(commentText);
\r
7173 commentIndex = index;
\r
7174 commentTitle = title;
\r
7176 editComment = edit;
\r
7178 if (commentDialog) {
\r
7179 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7180 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7182 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7183 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7184 hwndMain, (DLGPROC)lpProc);
\r
7185 FreeProcInstance(lpProc);
\r
7187 commentDialogUp = TRUE;
\r
7191 /*---------------------------------------------------------------------------*\
\r
7193 * Type-in move dialog functions
\r
7195 \*---------------------------------------------------------------------------*/
\r
7198 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7200 char move[MSG_SIZ];
\r
7202 ChessMove moveType;
\r
7203 int fromX, fromY, toX, toY;
\r
7206 switch (message) {
\r
7207 case WM_INITDIALOG:
\r
7208 move[0] = (char) lParam;
\r
7209 move[1] = NULLCHAR;
\r
7210 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7211 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7212 SetWindowText(hInput, move);
\r
7214 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7218 switch (LOWORD(wParam)) {
\r
7220 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7221 gameMode != Training) {
\r
7222 DisplayMoveError("Displayed move is not current");
\r
7224 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7225 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7226 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7227 if (gameMode != Training)
\r
7228 forwardMostMove = currentMove;
\r
7229 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7231 DisplayMoveError("Could not parse move");
\r
7234 EndDialog(hDlg, TRUE);
\r
7237 EndDialog(hDlg, FALSE);
\r
7248 PopUpMoveDialog(char firstchar)
\r
7252 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7253 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7254 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7255 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7256 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7257 gameMode == Training) {
\r
7258 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7259 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7260 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7261 FreeProcInstance(lpProc);
\r
7265 /*---------------------------------------------------------------------------*\
\r
7267 * Type-in name dialog functions
\r
7269 \*---------------------------------------------------------------------------*/
\r
7272 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7274 char move[MSG_SIZ];
\r
7277 switch (message) {
\r
7278 case WM_INITDIALOG:
\r
7279 move[0] = (char) lParam;
\r
7280 move[1] = NULLCHAR;
\r
7281 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7282 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7283 SetWindowText(hInput, move);
\r
7285 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7289 switch (LOWORD(wParam)) {
\r
7291 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7292 appData.userName = strdup(move);
\r
7294 EndDialog(hDlg, TRUE);
\r
7297 EndDialog(hDlg, FALSE);
\r
7308 PopUpNameDialog(char firstchar)
\r
7312 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7313 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7314 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7315 FreeProcInstance(lpProc);
\r
7318 /*---------------------------------------------------------------------------*\
\r
7322 \*---------------------------------------------------------------------------*/
\r
7324 /* Nonmodal error box */
\r
7325 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7326 WPARAM wParam, LPARAM lParam);
\r
7329 ErrorPopUp(char *title, char *content)
\r
7333 BOOLEAN modal = hwndMain == NULL;
\r
7351 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7352 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7355 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7357 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7358 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7359 hwndMain, (DLGPROC)lpProc);
\r
7360 FreeProcInstance(lpProc);
\r
7367 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7368 if (errorDialog == NULL) return;
\r
7369 DestroyWindow(errorDialog);
\r
7370 errorDialog = NULL;
\r
7374 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7379 switch (message) {
\r
7380 case WM_INITDIALOG:
\r
7381 GetWindowRect(hDlg, &rChild);
\r
7384 SetWindowPos(hDlg, NULL, rChild.left,
\r
7385 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7386 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7390 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7391 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7392 and it doesn't work when you resize the dialog.
\r
7393 For now, just give it a default position.
\r
7395 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7397 errorDialog = hDlg;
\r
7398 SetWindowText(hDlg, errorTitle);
\r
7399 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7400 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7404 switch (LOWORD(wParam)) {
\r
7407 if (errorDialog == hDlg) errorDialog = NULL;
\r
7408 DestroyWindow(hDlg);
\r
7420 HWND gothicDialog = NULL;
\r
7423 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7427 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7429 switch (message) {
\r
7430 case WM_INITDIALOG:
\r
7431 GetWindowRect(hDlg, &rChild);
\r
7433 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7437 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7438 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7439 and it doesn't work when you resize the dialog.
\r
7440 For now, just give it a default position.
\r
7442 gothicDialog = hDlg;
\r
7443 SetWindowText(hDlg, errorTitle);
\r
7444 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7445 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7449 switch (LOWORD(wParam)) {
\r
7452 if (errorDialog == hDlg) errorDialog = NULL;
\r
7453 DestroyWindow(hDlg);
\r
7465 GothicPopUp(char *title, VariantClass variant)
\r
7468 static char *lastTitle;
\r
7470 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7471 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7473 if(lastTitle != title && gothicDialog != NULL) {
\r
7474 DestroyWindow(gothicDialog);
\r
7475 gothicDialog = NULL;
\r
7477 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7478 title = lastTitle;
\r
7479 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7480 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7481 hwndMain, (DLGPROC)lpProc);
\r
7482 FreeProcInstance(lpProc);
\r
7487 /*---------------------------------------------------------------------------*\
\r
7489 * Ics Interaction console functions
\r
7491 \*---------------------------------------------------------------------------*/
\r
7493 #define HISTORY_SIZE 64
\r
7494 static char *history[HISTORY_SIZE];
\r
7495 int histIn = 0, histP = 0;
\r
7498 SaveInHistory(char *cmd)
\r
7500 if (history[histIn] != NULL) {
\r
7501 free(history[histIn]);
\r
7502 history[histIn] = NULL;
\r
7504 if (*cmd == NULLCHAR) return;
\r
7505 history[histIn] = StrSave(cmd);
\r
7506 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7507 if (history[histIn] != NULL) {
\r
7508 free(history[histIn]);
\r
7509 history[histIn] = NULL;
\r
7515 PrevInHistory(char *cmd)
\r
7518 if (histP == histIn) {
\r
7519 if (history[histIn] != NULL) free(history[histIn]);
\r
7520 history[histIn] = StrSave(cmd);
\r
7522 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7523 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7525 return history[histP];
\r
7531 if (histP == histIn) return NULL;
\r
7532 histP = (histP + 1) % HISTORY_SIZE;
\r
7533 return history[histP];
\r
7540 BOOLEAN immediate;
\r
7541 } IcsTextMenuEntry;
\r
7542 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7543 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7546 ParseIcsTextMenu(char *icsTextMenuString)
\r
7549 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7550 char *p = icsTextMenuString;
\r
7551 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7554 if (e->command != NULL) {
\r
7556 e->command = NULL;
\r
7560 e = icsTextMenuEntry;
\r
7561 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7562 if (*p == ';' || *p == '\n') {
\r
7563 e->item = strdup("-");
\r
7564 e->command = NULL;
\r
7566 } else if (*p == '-') {
\r
7567 e->item = strdup("-");
\r
7568 e->command = NULL;
\r
7572 char *q, *r, *s, *t;
\r
7574 q = strchr(p, ',');
\r
7575 if (q == NULL) break;
\r
7577 r = strchr(q + 1, ',');
\r
7578 if (r == NULL) break;
\r
7580 s = strchr(r + 1, ',');
\r
7581 if (s == NULL) break;
\r
7584 t = strchr(s + 1, c);
\r
7587 t = strchr(s + 1, c);
\r
7589 if (t != NULL) *t = NULLCHAR;
\r
7590 e->item = strdup(p);
\r
7591 e->command = strdup(q + 1);
\r
7592 e->getname = *(r + 1) != '0';
\r
7593 e->immediate = *(s + 1) != '0';
\r
7597 if (t == NULL) break;
\r
7606 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7610 hmenu = LoadMenu(hInst, "TextMenu");
\r
7611 h = GetSubMenu(hmenu, 0);
\r
7613 if (strcmp(e->item, "-") == 0) {
\r
7614 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7616 if (e->item[0] == '|') {
\r
7617 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7618 IDM_CommandX + i, &e->item[1]);
\r
7620 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7629 WNDPROC consoleTextWindowProc;
\r
7632 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7634 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7635 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7639 SetWindowText(hInput, command);
\r
7641 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7643 sel.cpMin = 999999;
\r
7644 sel.cpMax = 999999;
\r
7645 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7650 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7651 if (sel.cpMin == sel.cpMax) {
\r
7652 /* Expand to surrounding word */
\r
7655 tr.chrg.cpMax = sel.cpMin;
\r
7656 tr.chrg.cpMin = --sel.cpMin;
\r
7657 if (sel.cpMin < 0) break;
\r
7658 tr.lpstrText = name;
\r
7659 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7660 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7664 tr.chrg.cpMin = sel.cpMax;
\r
7665 tr.chrg.cpMax = ++sel.cpMax;
\r
7666 tr.lpstrText = name;
\r
7667 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7668 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7671 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7672 MessageBeep(MB_ICONEXCLAMATION);
\r
7676 tr.lpstrText = name;
\r
7677 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7679 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7680 MessageBeep(MB_ICONEXCLAMATION);
\r
7683 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7686 sprintf(buf, "%s %s", command, name);
\r
7687 SetWindowText(hInput, buf);
\r
7688 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7690 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7691 SetWindowText(hInput, buf);
\r
7692 sel.cpMin = 999999;
\r
7693 sel.cpMax = 999999;
\r
7694 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7700 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7705 switch (message) {
\r
7707 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7710 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7713 sel.cpMin = 999999;
\r
7714 sel.cpMax = 999999;
\r
7715 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7716 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7721 if (wParam == '\t') {
\r
7722 if (GetKeyState(VK_SHIFT) < 0) {
\r
7724 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7725 if (buttonDesc[0].hwnd) {
\r
7726 SetFocus(buttonDesc[0].hwnd);
\r
7728 SetFocus(hwndMain);
\r
7732 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7735 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7737 SendMessage(hInput, message, wParam, lParam);
\r
7741 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7743 return SendMessage(hInput, message, wParam, lParam);
\r
7744 case WM_MBUTTONDOWN:
\r
7745 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7746 case WM_RBUTTONDOWN:
\r
7747 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7748 /* Move selection here if it was empty */
\r
7750 pt.x = LOWORD(lParam);
\r
7751 pt.y = HIWORD(lParam);
\r
7752 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7753 if (sel.cpMin == sel.cpMax) {
\r
7754 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7755 sel.cpMax = sel.cpMin;
\r
7756 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7758 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7761 case WM_RBUTTONUP:
\r
7762 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7763 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7764 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7767 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7768 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7769 if (sel.cpMin == sel.cpMax) {
\r
7770 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7771 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7773 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7774 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7776 pt.x = LOWORD(lParam);
\r
7777 pt.y = HIWORD(lParam);
\r
7778 MenuPopup(hwnd, pt, hmenu, -1);
\r
7782 switch (LOWORD(wParam)) {
\r
7783 case IDM_QuickPaste:
\r
7785 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7786 if (sel.cpMin == sel.cpMax) {
\r
7787 MessageBeep(MB_ICONEXCLAMATION);
\r
7790 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7791 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7792 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7797 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7800 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7803 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7807 int i = LOWORD(wParam) - IDM_CommandX;
\r
7808 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7809 icsTextMenuEntry[i].command != NULL) {
\r
7810 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7811 icsTextMenuEntry[i].getname,
\r
7812 icsTextMenuEntry[i].immediate);
\r
7820 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7823 WNDPROC consoleInputWindowProc;
\r
7826 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7828 char buf[MSG_SIZ];
\r
7830 static BOOL sendNextChar = FALSE;
\r
7831 static BOOL quoteNextChar = FALSE;
\r
7832 InputSource *is = consoleInputSource;
\r
7836 switch (message) {
\r
7838 if (!appData.localLineEditing || sendNextChar) {
\r
7839 is->buf[0] = (CHAR) wParam;
\r
7841 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7842 sendNextChar = FALSE;
\r
7845 if (quoteNextChar) {
\r
7846 buf[0] = (char) wParam;
\r
7847 buf[1] = NULLCHAR;
\r
7848 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7849 quoteNextChar = FALSE;
\r
7853 case '\r': /* Enter key */
\r
7854 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7855 if (consoleEcho) SaveInHistory(is->buf);
\r
7856 is->buf[is->count++] = '\n';
\r
7857 is->buf[is->count] = NULLCHAR;
\r
7858 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7859 if (consoleEcho) {
\r
7860 ConsoleOutput(is->buf, is->count, TRUE);
\r
7861 } else if (appData.localLineEditing) {
\r
7862 ConsoleOutput("\n", 1, TRUE);
\r
7865 case '\033': /* Escape key */
\r
7866 SetWindowText(hwnd, "");
\r
7867 cf.cbSize = sizeof(CHARFORMAT);
\r
7868 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7869 if (consoleEcho) {
\r
7870 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7872 cf.crTextColor = COLOR_ECHOOFF;
\r
7874 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7875 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7877 case '\t': /* Tab key */
\r
7878 if (GetKeyState(VK_SHIFT) < 0) {
\r
7880 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7883 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7884 if (buttonDesc[0].hwnd) {
\r
7885 SetFocus(buttonDesc[0].hwnd);
\r
7887 SetFocus(hwndMain);
\r
7891 case '\023': /* Ctrl+S */
\r
7892 sendNextChar = TRUE;
\r
7894 case '\021': /* Ctrl+Q */
\r
7895 quoteNextChar = TRUE;
\r
7904 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7905 p = PrevInHistory(buf);
\r
7907 SetWindowText(hwnd, p);
\r
7908 sel.cpMin = 999999;
\r
7909 sel.cpMax = 999999;
\r
7910 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7915 p = NextInHistory();
\r
7917 SetWindowText(hwnd, p);
\r
7918 sel.cpMin = 999999;
\r
7919 sel.cpMax = 999999;
\r
7920 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7926 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7930 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7934 case WM_MBUTTONDOWN:
\r
7935 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7936 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7938 case WM_RBUTTONUP:
\r
7939 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7940 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7941 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7945 hmenu = LoadMenu(hInst, "InputMenu");
\r
7946 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7947 if (sel.cpMin == sel.cpMax) {
\r
7948 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7949 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7951 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7952 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7954 pt.x = LOWORD(lParam);
\r
7955 pt.y = HIWORD(lParam);
\r
7956 MenuPopup(hwnd, pt, hmenu, -1);
\r
7960 switch (LOWORD(wParam)) {
\r
7962 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7964 case IDM_SelectAll:
\r
7966 sel.cpMax = -1; /*999999?*/
\r
7967 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7970 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7973 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7976 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7981 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7984 #define CO_MAX 100000
\r
7985 #define CO_TRIM 1000
\r
7988 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7990 static SnapData sd;
\r
7991 static HWND hText, hInput /*, hFocus*/;
\r
7992 // InputSource *is = consoleInputSource;
\r
7994 static int sizeX, sizeY;
\r
7995 int newSizeX, newSizeY;
\r
7998 switch (message) {
\r
7999 case WM_INITDIALOG: /* message: initialize dialog box */
\r
8000 hwndConsole = hDlg;
\r
8001 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8002 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8004 consoleTextWindowProc = (WNDPROC)
\r
8005 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8006 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8007 consoleInputWindowProc = (WNDPROC)
\r
8008 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8009 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8010 Colorize(ColorNormal, TRUE);
\r
8011 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8012 ChangedConsoleFont();
\r
8013 GetClientRect(hDlg, &rect);
\r
8014 sizeX = rect.right;
\r
8015 sizeY = rect.bottom;
\r
8016 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
8017 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
8018 WINDOWPLACEMENT wp;
\r
8019 EnsureOnScreen(&consoleX, &consoleY);
\r
8020 wp.length = sizeof(WINDOWPLACEMENT);
\r
8022 wp.showCmd = SW_SHOW;
\r
8023 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8024 wp.rcNormalPosition.left = consoleX;
\r
8025 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8026 wp.rcNormalPosition.top = consoleY;
\r
8027 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8028 SetWindowPlacement(hDlg, &wp);
\r
8031 // [HGM] Chessknight's change 2004-07-13
\r
8032 else { /* Determine Defaults */
\r
8033 WINDOWPLACEMENT wp;
\r
8034 consoleX = winWidth + 1;
\r
8035 consoleY = boardY;
\r
8036 consoleW = screenWidth - winWidth;
\r
8037 consoleH = winHeight;
\r
8038 EnsureOnScreen(&consoleX, &consoleY);
\r
8039 wp.length = sizeof(WINDOWPLACEMENT);
\r
8041 wp.showCmd = SW_SHOW;
\r
8042 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8043 wp.rcNormalPosition.left = consoleX;
\r
8044 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8045 wp.rcNormalPosition.top = consoleY;
\r
8046 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8047 SetWindowPlacement(hDlg, &wp);
\r
8062 if (IsIconic(hDlg)) break;
\r
8063 newSizeX = LOWORD(lParam);
\r
8064 newSizeY = HIWORD(lParam);
\r
8065 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8066 RECT rectText, rectInput;
\r
8068 int newTextHeight, newTextWidth;
\r
8069 GetWindowRect(hText, &rectText);
\r
8070 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8071 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8072 if (newTextHeight < 0) {
\r
8073 newSizeY += -newTextHeight;
\r
8074 newTextHeight = 0;
\r
8076 SetWindowPos(hText, NULL, 0, 0,
\r
8077 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8078 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8079 pt.x = rectInput.left;
\r
8080 pt.y = rectInput.top + newSizeY - sizeY;
\r
8081 ScreenToClient(hDlg, &pt);
\r
8082 SetWindowPos(hInput, NULL,
\r
8083 pt.x, pt.y, /* needs client coords */
\r
8084 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8085 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8091 case WM_GETMINMAXINFO:
\r
8092 /* Prevent resizing window too small */
\r
8093 mmi = (MINMAXINFO *) lParam;
\r
8094 mmi->ptMinTrackSize.x = 100;
\r
8095 mmi->ptMinTrackSize.y = 100;
\r
8098 /* [AS] Snapping */
\r
8099 case WM_ENTERSIZEMOVE:
\r
8100 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8103 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8106 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8108 case WM_EXITSIZEMOVE:
\r
8109 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8112 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8120 if (hwndConsole) return;
\r
8121 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8122 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8127 ConsoleOutput(char* data, int length, int forceVisible)
\r
8132 char buf[CO_MAX+1];
\r
8135 static int delayLF = 0;
\r
8136 CHARRANGE savesel, sel;
\r
8138 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8146 while (length--) {
\r
8154 } else if (*p == '\007') {
\r
8155 MyPlaySound(&sounds[(int)SoundBell]);
\r
8162 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8163 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8164 /* Save current selection */
\r
8165 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8166 exlen = GetWindowTextLength(hText);
\r
8167 /* Find out whether current end of text is visible */
\r
8168 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8169 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8170 /* Trim existing text if it's too long */
\r
8171 if (exlen + (q - buf) > CO_MAX) {
\r
8172 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8175 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8176 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8178 savesel.cpMin -= trim;
\r
8179 savesel.cpMax -= trim;
\r
8180 if (exlen < 0) exlen = 0;
\r
8181 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8182 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8184 /* Append the new text */
\r
8185 sel.cpMin = exlen;
\r
8186 sel.cpMax = exlen;
\r
8187 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8188 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8189 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8190 if (forceVisible || exlen == 0 ||
\r
8191 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8192 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8193 /* Scroll to make new end of text visible if old end of text
\r
8194 was visible or new text is an echo of user typein */
\r
8195 sel.cpMin = 9999999;
\r
8196 sel.cpMax = 9999999;
\r
8197 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8198 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8199 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8200 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8202 if (savesel.cpMax == exlen || forceVisible) {
\r
8203 /* Move insert point to new end of text if it was at the old
\r
8204 end of text or if the new text is an echo of user typein */
\r
8205 sel.cpMin = 9999999;
\r
8206 sel.cpMax = 9999999;
\r
8207 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8209 /* Restore previous selection */
\r
8210 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8212 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8219 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8223 COLORREF oldFg, oldBg;
\r
8227 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8229 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8230 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8231 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8234 rect.right = x + squareSize;
\r
8236 rect.bottom = y + squareSize;
\r
8239 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8240 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8241 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8242 &rect, str, strlen(str), NULL);
\r
8244 (void) SetTextColor(hdc, oldFg);
\r
8245 (void) SetBkColor(hdc, oldBg);
\r
8246 (void) SelectObject(hdc, oldFont);
\r
8250 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8251 RECT *rect, char *color, char *flagFell)
\r
8255 COLORREF oldFg, oldBg;
\r
8258 if (appData.clockMode) {
\r
8260 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8262 sprintf(buf, "%s:%c%s %s", color, (logoHeight>0 ? 0 : ' '), TimeString(timeRemaining), flagFell);
\r
8269 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8270 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8272 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8273 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8275 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8277 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8278 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8279 rect, str, strlen(str), NULL);
\r
8280 if(logoHeight > 0 && appData.clockMode) {
\r
8282 sprintf(buf, "%s %s", TimeString(timeRemaining), flagFell);
\r
8283 r.top = rect->top + logoHeight/2;
\r
8284 r.left = rect->left;
\r
8285 r.right = rect->right;
\r
8286 r.bottom = rect->bottom;
\r
8287 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8288 r.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8289 &r, str, strlen(str), NULL);
\r
8291 (void) SetTextColor(hdc, oldFg);
\r
8292 (void) SetBkColor(hdc, oldBg);
\r
8293 (void) SelectObject(hdc, oldFont);
\r
8298 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8304 if( count <= 0 ) {
\r
8305 if (appData.debugMode) {
\r
8306 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8309 return ERROR_INVALID_USER_BUFFER;
\r
8312 ResetEvent(ovl->hEvent);
\r
8313 ovl->Offset = ovl->OffsetHigh = 0;
\r
8314 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8318 err = GetLastError();
\r
8319 if (err == ERROR_IO_PENDING) {
\r
8320 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8324 err = GetLastError();
\r
8331 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8336 ResetEvent(ovl->hEvent);
\r
8337 ovl->Offset = ovl->OffsetHigh = 0;
\r
8338 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8342 err = GetLastError();
\r
8343 if (err == ERROR_IO_PENDING) {
\r
8344 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8348 err = GetLastError();
\r
8354 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8355 void CheckForInputBufferFull( InputSource * is )
\r
8357 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8358 /* Look for end of line */
\r
8359 char * p = is->buf;
\r
8361 while( p < is->next && *p != '\n' ) {
\r
8365 if( p >= is->next ) {
\r
8366 if (appData.debugMode) {
\r
8367 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8370 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8371 is->count = (DWORD) -1;
\r
8372 is->next = is->buf;
\r
8378 InputThread(LPVOID arg)
\r
8383 is = (InputSource *) arg;
\r
8384 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8385 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8386 while (is->hThread != NULL) {
\r
8387 is->error = DoReadFile(is->hFile, is->next,
\r
8388 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8389 &is->count, &ovl);
\r
8390 if (is->error == NO_ERROR) {
\r
8391 is->next += is->count;
\r
8393 if (is->error == ERROR_BROKEN_PIPE) {
\r
8394 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8397 is->count = (DWORD) -1;
\r
8398 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8403 CheckForInputBufferFull( is );
\r
8405 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8407 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8409 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8412 CloseHandle(ovl.hEvent);
\r
8413 CloseHandle(is->hFile);
\r
8415 if (appData.debugMode) {
\r
8416 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8423 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8425 NonOvlInputThread(LPVOID arg)
\r
8432 is = (InputSource *) arg;
\r
8433 while (is->hThread != NULL) {
\r
8434 is->error = ReadFile(is->hFile, is->next,
\r
8435 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8436 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8437 if (is->error == NO_ERROR) {
\r
8438 /* Change CRLF to LF */
\r
8439 if (is->next > is->buf) {
\r
8441 i = is->count + 1;
\r
8449 if (prev == '\r' && *p == '\n') {
\r
8461 if (is->error == ERROR_BROKEN_PIPE) {
\r
8462 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8465 is->count = (DWORD) -1;
\r
8469 CheckForInputBufferFull( is );
\r
8471 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8473 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8475 if (is->count < 0) break; /* Quit on error */
\r
8477 CloseHandle(is->hFile);
\r
8482 SocketInputThread(LPVOID arg)
\r
8486 is = (InputSource *) arg;
\r
8487 while (is->hThread != NULL) {
\r
8488 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8489 if ((int)is->count == SOCKET_ERROR) {
\r
8490 is->count = (DWORD) -1;
\r
8491 is->error = WSAGetLastError();
\r
8493 is->error = NO_ERROR;
\r
8494 is->next += is->count;
\r
8495 if (is->count == 0 && is->second == is) {
\r
8496 /* End of file on stderr; quit with no message */
\r
8500 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8502 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8504 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8510 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8514 is = (InputSource *) lParam;
\r
8515 if (is->lineByLine) {
\r
8516 /* Feed in lines one by one */
\r
8517 char *p = is->buf;
\r
8519 while (q < is->next) {
\r
8520 if (*q++ == '\n') {
\r
8521 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8526 /* Move any partial line to the start of the buffer */
\r
8528 while (p < is->next) {
\r
8533 if (is->error != NO_ERROR || is->count == 0) {
\r
8534 /* Notify backend of the error. Note: If there was a partial
\r
8535 line at the end, it is not flushed through. */
\r
8536 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8539 /* Feed in the whole chunk of input at once */
\r
8540 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8541 is->next = is->buf;
\r
8545 /*---------------------------------------------------------------------------*\
\r
8547 * Menu enables. Used when setting various modes.
\r
8549 \*---------------------------------------------------------------------------*/
\r
8557 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8559 while (enab->item > 0) {
\r
8560 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8565 Enables gnuEnables[] = {
\r
8566 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8567 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8568 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8569 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8570 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8571 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8572 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8573 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8574 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8575 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8579 Enables icsEnables[] = {
\r
8580 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8581 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8582 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8583 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8584 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8585 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8586 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8587 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8588 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8589 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8590 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8591 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8596 Enables zippyEnables[] = {
\r
8597 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8598 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8599 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8604 Enables ncpEnables[] = {
\r
8605 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8606 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8607 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8608 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8609 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8610 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8611 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8612 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8613 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8614 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8615 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8616 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8617 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8618 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8619 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8623 Enables trainingOnEnables[] = {
\r
8624 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8625 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8626 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8627 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8628 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8629 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8630 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8631 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8635 Enables trainingOffEnables[] = {
\r
8636 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8637 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8638 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8639 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8640 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8641 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8642 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8643 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8647 /* These modify either ncpEnables or gnuEnables */
\r
8648 Enables cmailEnables[] = {
\r
8649 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8650 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8651 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8652 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8653 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8654 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8655 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8659 Enables machineThinkingEnables[] = {
\r
8660 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8661 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8662 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8663 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8664 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8665 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8666 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8667 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8668 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8669 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8670 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8671 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8672 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8673 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8674 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8678 Enables userThinkingEnables[] = {
\r
8679 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8680 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8681 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8682 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8683 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8684 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8685 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8686 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8687 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8688 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8689 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8690 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8691 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8692 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8693 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8697 /*---------------------------------------------------------------------------*\
\r
8699 * Front-end interface functions exported by XBoard.
\r
8700 * Functions appear in same order as prototypes in frontend.h.
\r
8702 \*---------------------------------------------------------------------------*/
\r
8706 static UINT prevChecked = 0;
\r
8707 static int prevPausing = 0;
\r
8710 if (pausing != prevPausing) {
\r
8711 prevPausing = pausing;
\r
8712 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8713 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8714 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8717 switch (gameMode) {
\r
8718 case BeginningOfGame:
\r
8719 if (appData.icsActive)
\r
8720 nowChecked = IDM_IcsClient;
\r
8721 else if (appData.noChessProgram)
\r
8722 nowChecked = IDM_EditGame;
\r
8724 nowChecked = IDM_MachineBlack;
\r
8726 case MachinePlaysBlack:
\r
8727 nowChecked = IDM_MachineBlack;
\r
8729 case MachinePlaysWhite:
\r
8730 nowChecked = IDM_MachineWhite;
\r
8732 case TwoMachinesPlay:
\r
8733 nowChecked = IDM_TwoMachines;
\r
8736 nowChecked = IDM_AnalysisMode;
\r
8739 nowChecked = IDM_AnalyzeFile;
\r
8742 nowChecked = IDM_EditGame;
\r
8744 case PlayFromGameFile:
\r
8745 nowChecked = IDM_LoadGame;
\r
8747 case EditPosition:
\r
8748 nowChecked = IDM_EditPosition;
\r
8751 nowChecked = IDM_Training;
\r
8753 case IcsPlayingWhite:
\r
8754 case IcsPlayingBlack:
\r
8755 case IcsObserving:
\r
8757 nowChecked = IDM_IcsClient;
\r
8764 if (prevChecked != 0)
\r
8765 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8766 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8767 if (nowChecked != 0)
\r
8768 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8769 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8771 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8772 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8773 MF_BYCOMMAND|MF_ENABLED);
\r
8775 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8776 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8779 prevChecked = nowChecked;
\r
8781 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8782 if (appData.icsActive) {
\r
8783 if (appData.icsEngineAnalyze) {
\r
8784 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8785 MF_BYCOMMAND|MF_CHECKED);
\r
8787 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8788 MF_BYCOMMAND|MF_UNCHECKED);
\r
8796 HMENU hmenu = GetMenu(hwndMain);
\r
8797 SetMenuEnables(hmenu, icsEnables);
\r
8798 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8799 MF_BYPOSITION|MF_ENABLED);
\r
8801 if (appData.zippyPlay) {
\r
8802 SetMenuEnables(hmenu, zippyEnables);
\r
8803 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8804 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8805 MF_BYCOMMAND|MF_ENABLED);
\r
8813 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8819 HMENU hmenu = GetMenu(hwndMain);
\r
8820 SetMenuEnables(hmenu, ncpEnables);
\r
8821 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8822 MF_BYPOSITION|MF_GRAYED);
\r
8823 DrawMenuBar(hwndMain);
\r
8829 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8833 SetTrainingModeOn()
\r
8836 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8837 for (i = 0; i < N_BUTTONS; i++) {
\r
8838 if (buttonDesc[i].hwnd != NULL)
\r
8839 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8844 VOID SetTrainingModeOff()
\r
8847 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8848 for (i = 0; i < N_BUTTONS; i++) {
\r
8849 if (buttonDesc[i].hwnd != NULL)
\r
8850 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8856 SetUserThinkingEnables()
\r
8858 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8862 SetMachineThinkingEnables()
\r
8864 HMENU hMenu = GetMenu(hwndMain);
\r
8865 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8867 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8869 if (gameMode == MachinePlaysBlack) {
\r
8870 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8871 } else if (gameMode == MachinePlaysWhite) {
\r
8872 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8873 } else if (gameMode == TwoMachinesPlay) {
\r
8874 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8880 DisplayTitle(char *str)
\r
8882 char title[MSG_SIZ], *host;
\r
8883 if (str[0] != NULLCHAR) {
\r
8884 strcpy(title, str);
\r
8885 } else if (appData.icsActive) {
\r
8886 if (appData.icsCommPort[0] != NULLCHAR)
\r
8889 host = appData.icsHost;
\r
8890 sprintf(title, "%s: %s", szTitle, host);
\r
8891 } else if (appData.noChessProgram) {
\r
8892 strcpy(title, szTitle);
\r
8894 strcpy(title, szTitle);
\r
8895 strcat(title, ": ");
\r
8896 strcat(title, first.tidy);
\r
8898 SetWindowText(hwndMain, title);
\r
8903 DisplayMessage(char *str1, char *str2)
\r
8907 int remain = MESSAGE_TEXT_MAX - 1;
\r
8910 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8911 messageText[0] = NULLCHAR;
\r
8913 len = strlen(str1);
\r
8914 if (len > remain) len = remain;
\r
8915 strncpy(messageText, str1, len);
\r
8916 messageText[len] = NULLCHAR;
\r
8919 if (*str2 && remain >= 2) {
\r
8921 strcat(messageText, " ");
\r
8924 len = strlen(str2);
\r
8925 if (len > remain) len = remain;
\r
8926 strncat(messageText, str2, len);
\r
8928 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8930 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8931 hdc = GetDC(hwndMain);
\r
8932 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8933 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8934 &messageRect, messageText, strlen(messageText), NULL);
\r
8935 (void) SelectObject(hdc, oldFont);
\r
8936 (void) ReleaseDC(hwndMain, hdc);
\r
8940 DisplayError(char *str, int error)
\r
8942 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8948 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8949 NULL, error, LANG_NEUTRAL,
\r
8950 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8952 sprintf(buf, "%s:\n%s", str, buf2);
\r
8954 ErrorMap *em = errmap;
\r
8955 while (em->err != 0 && em->err != error) em++;
\r
8956 if (em->err != 0) {
\r
8957 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8959 sprintf(buf, "%s:\nError code %d", str, error);
\r
8964 ErrorPopUp("Error", buf);
\r
8969 DisplayMoveError(char *str)
\r
8971 fromX = fromY = -1;
\r
8972 ClearHighlights();
\r
8973 DrawPosition(FALSE, NULL);
\r
8974 if (appData.popupMoveErrors) {
\r
8975 ErrorPopUp("Error", str);
\r
8977 DisplayMessage(str, "");
\r
8978 moveErrorMessageUp = TRUE;
\r
8983 DisplayFatalError(char *str, int error, int exitStatus)
\r
8985 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8987 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8990 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8991 NULL, error, LANG_NEUTRAL,
\r
8992 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8994 sprintf(buf, "%s:\n%s", str, buf2);
\r
8996 ErrorMap *em = errmap;
\r
8997 while (em->err != 0 && em->err != error) em++;
\r
8998 if (em->err != 0) {
\r
8999 sprintf(buf, "%s:\n%s", str, em->msg);
\r
9001 sprintf(buf, "%s:\nError code %d", str, error);
\r
9006 if (appData.debugMode) {
\r
9007 fprintf(debugFP, "%s: %s\n", label, str);
\r
9009 if (appData.popupExitMessage) {
\r
9010 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9011 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9013 ExitEvent(exitStatus);
\r
9018 DisplayInformation(char *str)
\r
9020 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9025 DisplayNote(char *str)
\r
9027 ErrorPopUp("Note", str);
\r
9032 char *title, *question, *replyPrefix;
\r
9037 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9039 static QuestionParams *qp;
\r
9040 char reply[MSG_SIZ];
\r
9043 switch (message) {
\r
9044 case WM_INITDIALOG:
\r
9045 qp = (QuestionParams *) lParam;
\r
9046 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9047 SetWindowText(hDlg, qp->title);
\r
9048 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9049 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9053 switch (LOWORD(wParam)) {
\r
9055 strcpy(reply, qp->replyPrefix);
\r
9056 if (*reply) strcat(reply, " ");
\r
9057 len = strlen(reply);
\r
9058 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9059 strcat(reply, "\n");
\r
9060 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9061 EndDialog(hDlg, TRUE);
\r
9062 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9065 EndDialog(hDlg, FALSE);
\r
9076 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9078 QuestionParams qp;
\r
9082 qp.question = question;
\r
9083 qp.replyPrefix = replyPrefix;
\r
9085 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9086 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9087 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9088 FreeProcInstance(lpProc);
\r
9091 /* [AS] Pick FRC position */
\r
9092 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9094 static int * lpIndexFRC;
\r
9100 case WM_INITDIALOG:
\r
9101 lpIndexFRC = (int *) lParam;
\r
9103 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9105 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9106 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9107 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9108 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9113 switch( LOWORD(wParam) ) {
\r
9115 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9116 EndDialog( hDlg, 0 );
\r
9117 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9120 EndDialog( hDlg, 1 );
\r
9122 case IDC_NFG_Edit:
\r
9123 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9124 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9126 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9129 case IDC_NFG_Random:
\r
9130 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9131 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9144 int index = appData.defaultFrcPosition;
\r
9145 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9147 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9149 if( result == 0 ) {
\r
9150 appData.defaultFrcPosition = index;
\r
9156 /* [AS] Game list options */
\r
9162 static GLT_Item GLT_ItemInfo[] = {
\r
9163 { GLT_EVENT, "Event" },
\r
9164 { GLT_SITE, "Site" },
\r
9165 { GLT_DATE, "Date" },
\r
9166 { GLT_ROUND, "Round" },
\r
9167 { GLT_PLAYERS, "Players" },
\r
9168 { GLT_RESULT, "Result" },
\r
9169 { GLT_WHITE_ELO, "White Rating" },
\r
9170 { GLT_BLACK_ELO, "Black Rating" },
\r
9171 { GLT_TIME_CONTROL,"Time Control" },
\r
9172 { GLT_VARIANT, "Variant" },
\r
9173 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9177 const char * GLT_FindItem( char id )
\r
9179 const char * result = 0;
\r
9181 GLT_Item * list = GLT_ItemInfo;
\r
9183 while( list->id != 0 ) {
\r
9184 if( list->id == id ) {
\r
9185 result = list->name;
\r
9195 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9197 const char * name = GLT_FindItem( id );
\r
9200 if( index >= 0 ) {
\r
9201 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9204 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9209 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9213 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9216 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9220 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9222 pc = GLT_ALL_TAGS;
\r
9225 if( strchr( tags, *pc ) == 0 ) {
\r
9226 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9231 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9234 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9236 char result = '\0';
\r
9239 GLT_Item * list = GLT_ItemInfo;
\r
9241 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9242 while( list->id != 0 ) {
\r
9243 if( strcmp( list->name, name ) == 0 ) {
\r
9244 result = list->id;
\r
9255 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9257 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9258 int idx2 = idx1 + delta;
\r
9259 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9261 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9264 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9265 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9266 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9267 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9271 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9273 static char glt[64];
\r
9274 static char * lpUserGLT;
\r
9278 case WM_INITDIALOG:
\r
9279 lpUserGLT = (char *) lParam;
\r
9281 strcpy( glt, lpUserGLT );
\r
9283 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9285 /* Initialize list */
\r
9286 GLT_TagsToList( hDlg, glt );
\r
9288 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9293 switch( LOWORD(wParam) ) {
\r
9296 char * pc = lpUserGLT;
\r
9298 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9302 id = GLT_ListItemToTag( hDlg, idx );
\r
9306 } while( id != '\0' );
\r
9308 EndDialog( hDlg, 0 );
\r
9311 EndDialog( hDlg, 1 );
\r
9314 case IDC_GLT_Default:
\r
9315 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9316 GLT_TagsToList( hDlg, glt );
\r
9319 case IDC_GLT_Restore:
\r
9320 strcpy( glt, lpUserGLT );
\r
9321 GLT_TagsToList( hDlg, glt );
\r
9325 GLT_MoveSelection( hDlg, -1 );
\r
9328 case IDC_GLT_Down:
\r
9329 GLT_MoveSelection( hDlg, +1 );
\r
9339 int GameListOptions()
\r
9343 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9345 strcpy( glt, appData.gameListTags );
\r
9347 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9349 if( result == 0 ) {
\r
9350 /* [AS] Memory leak here! */
\r
9351 appData.gameListTags = strdup( glt );
\r
9359 DisplayIcsInteractionTitle(char *str)
\r
9361 char consoleTitle[MSG_SIZ];
\r
9363 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9364 SetWindowText(hwndConsole, consoleTitle);
\r
9368 DrawPosition(int fullRedraw, Board board)
\r
9370 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9377 fromX = fromY = -1;
\r
9378 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9379 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9380 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9381 dragInfo.lastpos = dragInfo.pos;
\r
9382 dragInfo.start.x = dragInfo.start.y = -1;
\r
9383 dragInfo.from = dragInfo.start;
\r
9385 DrawPosition(TRUE, NULL);
\r
9391 CommentPopUp(char *title, char *str)
\r
9393 HWND hwnd = GetActiveWindow();
\r
9394 EitherCommentPopUp(0, title, str, FALSE);
\r
9395 SetActiveWindow(hwnd);
\r
9399 CommentPopDown(void)
\r
9401 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9402 if (commentDialog) {
\r
9403 ShowWindow(commentDialog, SW_HIDE);
\r
9405 commentDialogUp = FALSE;
\r
9409 EditCommentPopUp(int index, char *title, char *str)
\r
9411 EitherCommentPopUp(index, title, str, TRUE);
\r
9418 MyPlaySound(&sounds[(int)SoundMove]);
\r
9421 VOID PlayIcsWinSound()
\r
9423 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9426 VOID PlayIcsLossSound()
\r
9428 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9431 VOID PlayIcsDrawSound()
\r
9433 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9436 VOID PlayIcsUnfinishedSound()
\r
9438 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9444 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9452 consoleEcho = TRUE;
\r
9453 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9454 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9455 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9464 consoleEcho = FALSE;
\r
9465 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9466 /* This works OK: set text and background both to the same color */
\r
9468 cf.crTextColor = COLOR_ECHOOFF;
\r
9469 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9470 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9473 /* No Raw()...? */
\r
9475 void Colorize(ColorClass cc, int continuation)
\r
9477 currentColorClass = cc;
\r
9478 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9479 consoleCF.crTextColor = textAttribs[cc].color;
\r
9480 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9481 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9487 static char buf[MSG_SIZ];
\r
9488 DWORD bufsiz = MSG_SIZ;
\r
9490 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9491 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9493 if (!GetUserName(buf, &bufsiz)) {
\r
9494 /*DisplayError("Error getting user name", GetLastError());*/
\r
9495 strcpy(buf, "User");
\r
9503 static char buf[MSG_SIZ];
\r
9504 DWORD bufsiz = MSG_SIZ;
\r
9506 if (!GetComputerName(buf, &bufsiz)) {
\r
9507 /*DisplayError("Error getting host name", GetLastError());*/
\r
9508 strcpy(buf, "Unknown");
\r
9515 ClockTimerRunning()
\r
9517 return clockTimerEvent != 0;
\r
9523 if (clockTimerEvent == 0) return FALSE;
\r
9524 KillTimer(hwndMain, clockTimerEvent);
\r
9525 clockTimerEvent = 0;
\r
9530 StartClockTimer(long millisec)
\r
9532 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9533 (UINT) millisec, NULL);
\r
9537 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9540 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9542 if(appData.noGUI) return;
\r
9543 hdc = GetDC(hwndMain);
\r
9544 if (!IsIconic(hwndMain)) {
\r
9545 DisplayAClock(hdc, timeRemaining, highlight,
\r
9546 flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9548 if (highlight && iconCurrent == iconBlack) {
\r
9549 iconCurrent = iconWhite;
\r
9550 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9551 if (IsIconic(hwndMain)) {
\r
9552 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9555 (void) ReleaseDC(hwndMain, hdc);
\r
9557 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9561 DisplayBlackClock(long timeRemaining, int highlight)
\r
9564 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9566 if(appData.noGUI) return;
\r
9567 hdc = GetDC(hwndMain);
\r
9568 if (!IsIconic(hwndMain)) {
\r
9569 DisplayAClock(hdc, timeRemaining, highlight,
\r
9570 flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9572 if (highlight && iconCurrent == iconWhite) {
\r
9573 iconCurrent = iconBlack;
\r
9574 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9575 if (IsIconic(hwndMain)) {
\r
9576 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9579 (void) ReleaseDC(hwndMain, hdc);
\r
9581 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9586 LoadGameTimerRunning()
\r
9588 return loadGameTimerEvent != 0;
\r
9592 StopLoadGameTimer()
\r
9594 if (loadGameTimerEvent == 0) return FALSE;
\r
9595 KillTimer(hwndMain, loadGameTimerEvent);
\r
9596 loadGameTimerEvent = 0;
\r
9601 StartLoadGameTimer(long millisec)
\r
9603 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9604 (UINT) millisec, NULL);
\r
9612 char fileTitle[MSG_SIZ];
\r
9614 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9615 f = OpenFileDialog(hwndMain, "a", defName,
\r
9616 appData.oldSaveStyle ? "gam" : "pgn",
\r
9618 "Save Game to File", NULL, fileTitle, NULL);
\r
9620 SaveGame(f, 0, "");
\r
9627 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9629 if (delayedTimerEvent != 0) {
\r
9630 if (appData.debugMode) {
\r
9631 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9633 KillTimer(hwndMain, delayedTimerEvent);
\r
9634 delayedTimerEvent = 0;
\r
9635 delayedTimerCallback();
\r
9637 delayedTimerCallback = cb;
\r
9638 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9639 (UINT) millisec, NULL);
\r
9642 DelayedEventCallback
\r
9645 if (delayedTimerEvent) {
\r
9646 return delayedTimerCallback;
\r
9653 CancelDelayedEvent()
\r
9655 if (delayedTimerEvent) {
\r
9656 KillTimer(hwndMain, delayedTimerEvent);
\r
9657 delayedTimerEvent = 0;
\r
9661 DWORD GetWin32Priority(int nice)
\r
9662 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9664 REALTIME_PRIORITY_CLASS 0x00000100
\r
9665 HIGH_PRIORITY_CLASS 0x00000080
\r
9666 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9667 NORMAL_PRIORITY_CLASS 0x00000020
\r
9668 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9669 IDLE_PRIORITY_CLASS 0x00000040
\r
9671 if (nice < -15) return 0x00000080;
\r
9672 if (nice < 0) return 0x00008000;
\r
9673 if (nice == 0) return 0x00000020;
\r
9674 if (nice < 15) return 0x00004000;
\r
9675 return 0x00000040;
\r
9678 /* Start a child process running the given program.
\r
9679 The process's standard output can be read from "from", and its
\r
9680 standard input can be written to "to".
\r
9681 Exit with fatal error if anything goes wrong.
\r
9682 Returns an opaque pointer that can be used to destroy the process
\r
9686 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9688 #define BUFSIZE 4096
\r
9690 HANDLE hChildStdinRd, hChildStdinWr,
\r
9691 hChildStdoutRd, hChildStdoutWr;
\r
9692 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9693 SECURITY_ATTRIBUTES saAttr;
\r
9695 PROCESS_INFORMATION piProcInfo;
\r
9696 STARTUPINFO siStartInfo;
\r
9698 char buf[MSG_SIZ];
\r
9701 if (appData.debugMode) {
\r
9702 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9707 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9708 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9709 saAttr.bInheritHandle = TRUE;
\r
9710 saAttr.lpSecurityDescriptor = NULL;
\r
9713 * The steps for redirecting child's STDOUT:
\r
9714 * 1. Create anonymous pipe to be STDOUT for child.
\r
9715 * 2. Create a noninheritable duplicate of read handle,
\r
9716 * and close the inheritable read handle.
\r
9719 /* Create a pipe for the child's STDOUT. */
\r
9720 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9721 return GetLastError();
\r
9724 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9725 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9726 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9727 FALSE, /* not inherited */
\r
9728 DUPLICATE_SAME_ACCESS);
\r
9730 return GetLastError();
\r
9732 CloseHandle(hChildStdoutRd);
\r
9735 * The steps for redirecting child's STDIN:
\r
9736 * 1. Create anonymous pipe to be STDIN for child.
\r
9737 * 2. Create a noninheritable duplicate of write handle,
\r
9738 * and close the inheritable write handle.
\r
9741 /* Create a pipe for the child's STDIN. */
\r
9742 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9743 return GetLastError();
\r
9746 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9747 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9748 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9749 FALSE, /* not inherited */
\r
9750 DUPLICATE_SAME_ACCESS);
\r
9752 return GetLastError();
\r
9754 CloseHandle(hChildStdinWr);
\r
9756 /* Arrange to (1) look in dir for the child .exe file, and
\r
9757 * (2) have dir be the child's working directory. Interpret
\r
9758 * dir relative to the directory WinBoard loaded from. */
\r
9759 GetCurrentDirectory(MSG_SIZ, buf);
\r
9760 SetCurrentDirectory(installDir);
\r
9761 SetCurrentDirectory(dir);
\r
9763 /* Now create the child process. */
\r
9765 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9766 siStartInfo.lpReserved = NULL;
\r
9767 siStartInfo.lpDesktop = NULL;
\r
9768 siStartInfo.lpTitle = NULL;
\r
9769 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9770 siStartInfo.cbReserved2 = 0;
\r
9771 siStartInfo.lpReserved2 = NULL;
\r
9772 siStartInfo.hStdInput = hChildStdinRd;
\r
9773 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9774 siStartInfo.hStdError = hChildStdoutWr;
\r
9776 fSuccess = CreateProcess(NULL,
\r
9777 cmdLine, /* command line */
\r
9778 NULL, /* process security attributes */
\r
9779 NULL, /* primary thread security attrs */
\r
9780 TRUE, /* handles are inherited */
\r
9781 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9782 NULL, /* use parent's environment */
\r
9784 &siStartInfo, /* STARTUPINFO pointer */
\r
9785 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9787 err = GetLastError();
\r
9788 SetCurrentDirectory(buf); /* return to prev directory */
\r
9793 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9794 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9795 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9798 /* Close the handles we don't need in the parent */
\r
9799 CloseHandle(piProcInfo.hThread);
\r
9800 CloseHandle(hChildStdinRd);
\r
9801 CloseHandle(hChildStdoutWr);
\r
9803 /* Prepare return value */
\r
9804 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9805 cp->kind = CPReal;
\r
9806 cp->hProcess = piProcInfo.hProcess;
\r
9807 cp->pid = piProcInfo.dwProcessId;
\r
9808 cp->hFrom = hChildStdoutRdDup;
\r
9809 cp->hTo = hChildStdinWrDup;
\r
9811 *pr = (void *) cp;
\r
9813 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9814 2000 where engines sometimes don't see the initial command(s)
\r
9815 from WinBoard and hang. I don't understand how that can happen,
\r
9816 but the Sleep is harmless, so I've put it in. Others have also
\r
9817 reported what may be the same problem, so hopefully this will fix
\r
9818 it for them too. */
\r
9826 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9828 ChildProc *cp; int result;
\r
9830 cp = (ChildProc *) pr;
\r
9831 if (cp == NULL) return;
\r
9833 switch (cp->kind) {
\r
9835 /* TerminateProcess is considered harmful, so... */
\r
9836 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9837 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9838 /* The following doesn't work because the chess program
\r
9839 doesn't "have the same console" as WinBoard. Maybe
\r
9840 we could arrange for this even though neither WinBoard
\r
9841 nor the chess program uses a console for stdio? */
\r
9842 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9844 /* [AS] Special termination modes for misbehaving programs... */
\r
9845 if( signal == 9 ) {
\r
9846 result = TerminateProcess( cp->hProcess, 0 );
\r
9848 if ( appData.debugMode) {
\r
9849 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9852 else if( signal == 10 ) {
\r
9853 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9855 if( dw != WAIT_OBJECT_0 ) {
\r
9856 result = TerminateProcess( cp->hProcess, 0 );
\r
9858 if ( appData.debugMode) {
\r
9859 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9865 CloseHandle(cp->hProcess);
\r
9869 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9873 closesocket(cp->sock);
\r
9878 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9879 closesocket(cp->sock);
\r
9880 closesocket(cp->sock2);
\r
9888 InterruptChildProcess(ProcRef pr)
\r
9892 cp = (ChildProc *) pr;
\r
9893 if (cp == NULL) return;
\r
9894 switch (cp->kind) {
\r
9896 /* The following doesn't work because the chess program
\r
9897 doesn't "have the same console" as WinBoard. Maybe
\r
9898 we could arrange for this even though neither WinBoard
\r
9899 nor the chess program uses a console for stdio */
\r
9900 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9905 /* Can't interrupt */
\r
9909 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9916 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9918 char cmdLine[MSG_SIZ];
\r
9920 if (port[0] == NULLCHAR) {
\r
9921 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9923 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9925 return StartChildProcess(cmdLine, "", pr);
\r
9929 /* Code to open TCP sockets */
\r
9932 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9937 struct sockaddr_in sa, mysa;
\r
9938 struct hostent FAR *hp;
\r
9939 unsigned short uport;
\r
9940 WORD wVersionRequested;
\r
9943 /* Initialize socket DLL */
\r
9944 wVersionRequested = MAKEWORD(1, 1);
\r
9945 err = WSAStartup(wVersionRequested, &wsaData);
\r
9946 if (err != 0) return err;
\r
9949 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9950 err = WSAGetLastError();
\r
9955 /* Bind local address using (mostly) don't-care values.
\r
9957 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9958 mysa.sin_family = AF_INET;
\r
9959 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9960 uport = (unsigned short) 0;
\r
9961 mysa.sin_port = htons(uport);
\r
9962 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9963 == SOCKET_ERROR) {
\r
9964 err = WSAGetLastError();
\r
9969 /* Resolve remote host name */
\r
9970 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9971 if (!(hp = gethostbyname(host))) {
\r
9972 unsigned int b0, b1, b2, b3;
\r
9974 err = WSAGetLastError();
\r
9976 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9977 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9978 hp->h_addrtype = AF_INET;
\r
9980 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9981 hp->h_addr_list[0] = (char *) malloc(4);
\r
9982 hp->h_addr_list[0][0] = (char) b0;
\r
9983 hp->h_addr_list[0][1] = (char) b1;
\r
9984 hp->h_addr_list[0][2] = (char) b2;
\r
9985 hp->h_addr_list[0][3] = (char) b3;
\r
9991 sa.sin_family = hp->h_addrtype;
\r
9992 uport = (unsigned short) atoi(port);
\r
9993 sa.sin_port = htons(uport);
\r
9994 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9996 /* Make connection */
\r
9997 if (connect(s, (struct sockaddr *) &sa,
\r
9998 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9999 err = WSAGetLastError();
\r
10004 /* Prepare return value */
\r
10005 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10006 cp->kind = CPSock;
\r
10008 *pr = (ProcRef *) cp;
\r
10014 OpenCommPort(char *name, ProcRef *pr)
\r
10019 char fullname[MSG_SIZ];
\r
10021 if (*name != '\\')
\r
10022 sprintf(fullname, "\\\\.\\%s", name);
\r
10024 strcpy(fullname, name);
\r
10026 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10027 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10028 if (h == (HANDLE) -1) {
\r
10029 return GetLastError();
\r
10033 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10035 /* Accumulate characters until a 100ms pause, then parse */
\r
10036 ct.ReadIntervalTimeout = 100;
\r
10037 ct.ReadTotalTimeoutMultiplier = 0;
\r
10038 ct.ReadTotalTimeoutConstant = 0;
\r
10039 ct.WriteTotalTimeoutMultiplier = 0;
\r
10040 ct.WriteTotalTimeoutConstant = 0;
\r
10041 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10043 /* Prepare return value */
\r
10044 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10045 cp->kind = CPComm;
\r
10048 *pr = (ProcRef *) cp;
\r
10054 OpenLoopback(ProcRef *pr)
\r
10056 DisplayFatalError("Not implemented", 0, 1);
\r
10062 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10066 SOCKET s, s2, s3;
\r
10067 struct sockaddr_in sa, mysa;
\r
10068 struct hostent FAR *hp;
\r
10069 unsigned short uport;
\r
10070 WORD wVersionRequested;
\r
10073 char stderrPortStr[MSG_SIZ];
\r
10075 /* Initialize socket DLL */
\r
10076 wVersionRequested = MAKEWORD(1, 1);
\r
10077 err = WSAStartup(wVersionRequested, &wsaData);
\r
10078 if (err != 0) return err;
\r
10080 /* Resolve remote host name */
\r
10081 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10082 if (!(hp = gethostbyname(host))) {
\r
10083 unsigned int b0, b1, b2, b3;
\r
10085 err = WSAGetLastError();
\r
10087 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10088 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10089 hp->h_addrtype = AF_INET;
\r
10090 hp->h_length = 4;
\r
10091 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10092 hp->h_addr_list[0] = (char *) malloc(4);
\r
10093 hp->h_addr_list[0][0] = (char) b0;
\r
10094 hp->h_addr_list[0][1] = (char) b1;
\r
10095 hp->h_addr_list[0][2] = (char) b2;
\r
10096 hp->h_addr_list[0][3] = (char) b3;
\r
10102 sa.sin_family = hp->h_addrtype;
\r
10103 uport = (unsigned short) 514;
\r
10104 sa.sin_port = htons(uport);
\r
10105 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10107 /* Bind local socket to unused "privileged" port address
\r
10109 s = INVALID_SOCKET;
\r
10110 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10111 mysa.sin_family = AF_INET;
\r
10112 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10113 for (fromPort = 1023;; fromPort--) {
\r
10114 if (fromPort < 0) {
\r
10116 return WSAEADDRINUSE;
\r
10118 if (s == INVALID_SOCKET) {
\r
10119 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10120 err = WSAGetLastError();
\r
10125 uport = (unsigned short) fromPort;
\r
10126 mysa.sin_port = htons(uport);
\r
10127 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10128 == SOCKET_ERROR) {
\r
10129 err = WSAGetLastError();
\r
10130 if (err == WSAEADDRINUSE) continue;
\r
10134 if (connect(s, (struct sockaddr *) &sa,
\r
10135 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10136 err = WSAGetLastError();
\r
10137 if (err == WSAEADDRINUSE) {
\r
10148 /* Bind stderr local socket to unused "privileged" port address
\r
10150 s2 = INVALID_SOCKET;
\r
10151 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10152 mysa.sin_family = AF_INET;
\r
10153 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10154 for (fromPort = 1023;; fromPort--) {
\r
10155 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10156 if (fromPort < 0) {
\r
10157 (void) closesocket(s);
\r
10159 return WSAEADDRINUSE;
\r
10161 if (s2 == INVALID_SOCKET) {
\r
10162 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10163 err = WSAGetLastError();
\r
10169 uport = (unsigned short) fromPort;
\r
10170 mysa.sin_port = htons(uport);
\r
10171 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10172 == SOCKET_ERROR) {
\r
10173 err = WSAGetLastError();
\r
10174 if (err == WSAEADDRINUSE) continue;
\r
10175 (void) closesocket(s);
\r
10179 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10180 err = WSAGetLastError();
\r
10181 if (err == WSAEADDRINUSE) {
\r
10183 s2 = INVALID_SOCKET;
\r
10186 (void) closesocket(s);
\r
10187 (void) closesocket(s2);
\r
10193 prevStderrPort = fromPort; // remember port used
\r
10194 sprintf(stderrPortStr, "%d", fromPort);
\r
10196 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10197 err = WSAGetLastError();
\r
10198 (void) closesocket(s);
\r
10199 (void) closesocket(s2);
\r
10204 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10205 err = WSAGetLastError();
\r
10206 (void) closesocket(s);
\r
10207 (void) closesocket(s2);
\r
10211 if (*user == NULLCHAR) user = UserName();
\r
10212 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10213 err = WSAGetLastError();
\r
10214 (void) closesocket(s);
\r
10215 (void) closesocket(s2);
\r
10219 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10220 err = WSAGetLastError();
\r
10221 (void) closesocket(s);
\r
10222 (void) closesocket(s2);
\r
10227 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10228 err = WSAGetLastError();
\r
10229 (void) closesocket(s);
\r
10230 (void) closesocket(s2);
\r
10234 (void) closesocket(s2); /* Stop listening */
\r
10236 /* Prepare return value */
\r
10237 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10238 cp->kind = CPRcmd;
\r
10241 *pr = (ProcRef *) cp;
\r
10248 AddInputSource(ProcRef pr, int lineByLine,
\r
10249 InputCallback func, VOIDSTAR closure)
\r
10251 InputSource *is, *is2 = NULL;
\r
10252 ChildProc *cp = (ChildProc *) pr;
\r
10254 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10255 is->lineByLine = lineByLine;
\r
10257 is->closure = closure;
\r
10258 is->second = NULL;
\r
10259 is->next = is->buf;
\r
10260 if (pr == NoProc) {
\r
10261 is->kind = CPReal;
\r
10262 consoleInputSource = is;
\r
10264 is->kind = cp->kind;
\r
10266 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10267 we create all threads suspended so that the is->hThread variable can be
\r
10268 safely assigned, then let the threads start with ResumeThread.
\r
10270 switch (cp->kind) {
\r
10272 is->hFile = cp->hFrom;
\r
10273 cp->hFrom = NULL; /* now owned by InputThread */
\r
10275 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10276 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10280 is->hFile = cp->hFrom;
\r
10281 cp->hFrom = NULL; /* now owned by InputThread */
\r
10283 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10284 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10288 is->sock = cp->sock;
\r
10290 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10291 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10295 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10297 is->sock = cp->sock;
\r
10298 is->second = is2;
\r
10299 is2->sock = cp->sock2;
\r
10300 is2->second = is2;
\r
10302 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10303 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10305 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10306 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10310 if( is->hThread != NULL ) {
\r
10311 ResumeThread( is->hThread );
\r
10314 if( is2 != NULL && is2->hThread != NULL ) {
\r
10315 ResumeThread( is2->hThread );
\r
10319 return (InputSourceRef) is;
\r
10323 RemoveInputSource(InputSourceRef isr)
\r
10327 is = (InputSource *) isr;
\r
10328 is->hThread = NULL; /* tell thread to stop */
\r
10329 CloseHandle(is->hThread);
\r
10330 if (is->second != NULL) {
\r
10331 is->second->hThread = NULL;
\r
10332 CloseHandle(is->second->hThread);
\r
10338 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10341 int outCount = SOCKET_ERROR;
\r
10342 ChildProc *cp = (ChildProc *) pr;
\r
10343 static OVERLAPPED ovl;
\r
10345 if (pr == NoProc) {
\r
10346 ConsoleOutput(message, count, FALSE);
\r
10350 if (ovl.hEvent == NULL) {
\r
10351 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10353 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10355 switch (cp->kind) {
\r
10358 outCount = send(cp->sock, message, count, 0);
\r
10359 if (outCount == SOCKET_ERROR) {
\r
10360 *outError = WSAGetLastError();
\r
10362 *outError = NO_ERROR;
\r
10367 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10368 &dOutCount, NULL)) {
\r
10369 *outError = NO_ERROR;
\r
10370 outCount = (int) dOutCount;
\r
10372 *outError = GetLastError();
\r
10377 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10378 &dOutCount, &ovl);
\r
10379 if (*outError == NO_ERROR) {
\r
10380 outCount = (int) dOutCount;
\r
10388 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10391 /* Ignore delay, not implemented for WinBoard */
\r
10392 return OutputToProcess(pr, message, count, outError);
\r
10397 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10398 char *buf, int count, int error)
\r
10400 DisplayFatalError("Not implemented", 0, 1);
\r
10403 /* see wgamelist.c for Game List functions */
\r
10404 /* see wedittags.c for Edit Tags functions */
\r
10411 char buf[MSG_SIZ];
\r
10414 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10415 f = fopen(buf, "r");
\r
10417 ProcessICSInitScript(f);
\r
10425 StartAnalysisClock()
\r
10427 if (analysisTimerEvent) return;
\r
10428 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10429 (UINT) 2000, NULL);
\r
10433 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10435 static HANDLE hwndText;
\r
10437 static int sizeX, sizeY;
\r
10438 int newSizeX, newSizeY, flags;
\r
10441 switch (message) {
\r
10442 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10443 /* Initialize the dialog items */
\r
10444 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10445 SetWindowText(hDlg, analysisTitle);
\r
10446 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10447 /* Size and position the dialog */
\r
10448 if (!analysisDialog) {
\r
10449 analysisDialog = hDlg;
\r
10450 flags = SWP_NOZORDER;
\r
10451 GetClientRect(hDlg, &rect);
\r
10452 sizeX = rect.right;
\r
10453 sizeY = rect.bottom;
\r
10454 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10455 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10456 WINDOWPLACEMENT wp;
\r
10457 EnsureOnScreen(&analysisX, &analysisY);
\r
10458 wp.length = sizeof(WINDOWPLACEMENT);
\r
10460 wp.showCmd = SW_SHOW;
\r
10461 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10462 wp.rcNormalPosition.left = analysisX;
\r
10463 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10464 wp.rcNormalPosition.top = analysisY;
\r
10465 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10466 SetWindowPlacement(hDlg, &wp);
\r
10468 GetClientRect(hDlg, &rect);
\r
10469 newSizeX = rect.right;
\r
10470 newSizeY = rect.bottom;
\r
10471 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10472 newSizeX, newSizeY);
\r
10473 sizeX = newSizeX;
\r
10474 sizeY = newSizeY;
\r
10479 case WM_COMMAND: /* message: received a command */
\r
10480 switch (LOWORD(wParam)) {
\r
10482 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10483 ExitAnalyzeMode();
\r
10495 newSizeX = LOWORD(lParam);
\r
10496 newSizeY = HIWORD(lParam);
\r
10497 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10498 sizeX = newSizeX;
\r
10499 sizeY = newSizeY;
\r
10502 case WM_GETMINMAXINFO:
\r
10503 /* Prevent resizing window too small */
\r
10504 mmi = (MINMAXINFO *) lParam;
\r
10505 mmi->ptMinTrackSize.x = 100;
\r
10506 mmi->ptMinTrackSize.y = 100;
\r
10513 AnalysisPopUp(char* title, char* str)
\r
10519 EngineOutputPopUp();
\r
10522 if (str == NULL) str = "";
\r
10523 p = (char *) malloc(2 * strlen(str) + 2);
\r
10526 if (*str == '\n') *q++ = '\r';
\r
10530 if (analysisText != NULL) free(analysisText);
\r
10531 analysisText = p;
\r
10533 if (analysisDialog) {
\r
10534 SetWindowText(analysisDialog, title);
\r
10535 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10536 ShowWindow(analysisDialog, SW_SHOW);
\r
10538 analysisTitle = title;
\r
10539 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10540 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10541 hwndMain, (DLGPROC)lpProc);
\r
10542 FreeProcInstance(lpProc);
\r
10544 analysisDialogUp = TRUE;
\r
10548 AnalysisPopDown()
\r
10550 if (analysisDialog) {
\r
10551 ShowWindow(analysisDialog, SW_HIDE);
\r
10553 analysisDialogUp = FALSE;
\r
10558 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10560 highlightInfo.sq[0].x = fromX;
\r
10561 highlightInfo.sq[0].y = fromY;
\r
10562 highlightInfo.sq[1].x = toX;
\r
10563 highlightInfo.sq[1].y = toY;
\r
10567 ClearHighlights()
\r
10569 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10570 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10574 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10576 premoveHighlightInfo.sq[0].x = fromX;
\r
10577 premoveHighlightInfo.sq[0].y = fromY;
\r
10578 premoveHighlightInfo.sq[1].x = toX;
\r
10579 premoveHighlightInfo.sq[1].y = toY;
\r
10583 ClearPremoveHighlights()
\r
10585 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10586 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10590 ShutDownFrontEnd()
\r
10592 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10593 DeleteClipboardTempFiles();
\r
10599 if (IsIconic(hwndMain))
\r
10600 ShowWindow(hwndMain, SW_RESTORE);
\r
10602 SetActiveWindow(hwndMain);
\r
10606 * Prototypes for animation support routines
\r
10608 static void ScreenSquare(int column, int row, POINT * pt);
\r
10609 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10610 POINT frames[], int * nFrames);
\r
10614 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10615 { // [HGM] atomic: animate blast wave
\r
10617 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10618 explodeInfo.fromX = fromX;
\r
10619 explodeInfo.fromY = fromY;
\r
10620 explodeInfo.toX = toX;
\r
10621 explodeInfo.toY = toY;
\r
10622 for(i=1; i<nFrames; i++) {
\r
10623 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10624 DrawPosition(FALSE, NULL);
\r
10625 Sleep(appData.animSpeed);
\r
10627 explodeInfo.radius = 0;
\r
10628 DrawPosition(TRUE, NULL);
\r
10631 #define kFactor 4
\r
10634 AnimateMove(board, fromX, fromY, toX, toY)
\r
10641 ChessSquare piece;
\r
10642 POINT start, finish, mid;
\r
10643 POINT frames[kFactor * 2 + 1];
\r
10646 if (!appData.animate) return;
\r
10647 if (doingSizing) return;
\r
10648 if (fromY < 0 || fromX < 0) return;
\r
10649 piece = board[fromY][fromX];
\r
10650 if (piece >= EmptySquare) return;
\r
10652 ScreenSquare(fromX, fromY, &start);
\r
10653 ScreenSquare(toX, toY, &finish);
\r
10655 /* All pieces except knights move in straight line */
\r
10656 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10657 mid.x = start.x + (finish.x - start.x) / 2;
\r
10658 mid.y = start.y + (finish.y - start.y) / 2;
\r
10660 /* Knight: make diagonal movement then straight */
\r
10661 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10662 mid.x = start.x + (finish.x - start.x) / 2;
\r
10663 mid.y = finish.y;
\r
10665 mid.x = finish.x;
\r
10666 mid.y = start.y + (finish.y - start.y) / 2;
\r
10670 /* Don't use as many frames for very short moves */
\r
10671 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10672 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10674 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10676 animInfo.from.x = fromX;
\r
10677 animInfo.from.y = fromY;
\r
10678 animInfo.to.x = toX;
\r
10679 animInfo.to.y = toY;
\r
10680 animInfo.lastpos = start;
\r
10681 animInfo.piece = piece;
\r
10682 for (n = 0; n < nFrames; n++) {
\r
10683 animInfo.pos = frames[n];
\r
10684 DrawPosition(FALSE, NULL);
\r
10685 animInfo.lastpos = animInfo.pos;
\r
10686 Sleep(appData.animSpeed);
\r
10688 animInfo.pos = finish;
\r
10689 DrawPosition(FALSE, NULL);
\r
10690 animInfo.piece = EmptySquare;
\r
10691 if(gameInfo.variant == VariantAtomic &&
\r
10692 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10693 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10696 /* Convert board position to corner of screen rect and color */
\r
10699 ScreenSquare(column, row, pt)
\r
10700 int column; int row; POINT * pt;
\r
10703 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10704 pt->y = lineGap + row * (squareSize + lineGap);
\r
10706 pt->x = lineGap + column * (squareSize + lineGap);
\r
10707 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10711 /* Generate a series of frame coords from start->mid->finish.
\r
10712 The movement rate doubles until the half way point is
\r
10713 reached, then halves back down to the final destination,
\r
10714 which gives a nice slow in/out effect. The algorithmn
\r
10715 may seem to generate too many intermediates for short
\r
10716 moves, but remember that the purpose is to attract the
\r
10717 viewers attention to the piece about to be moved and
\r
10718 then to where it ends up. Too few frames would be less
\r
10722 Tween(start, mid, finish, factor, frames, nFrames)
\r
10723 POINT * start; POINT * mid;
\r
10724 POINT * finish; int factor;
\r
10725 POINT frames[]; int * nFrames;
\r
10727 int n, fraction = 1, count = 0;
\r
10729 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10730 for (n = 0; n < factor; n++)
\r
10732 for (n = 0; n < factor; n++) {
\r
10733 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10734 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10736 fraction = fraction / 2;
\r
10740 frames[count] = *mid;
\r
10743 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10745 for (n = 0; n < factor; n++) {
\r
10746 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10747 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10749 fraction = fraction * 2;
\r
10751 *nFrames = count;
\r
10755 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10760 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10761 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10763 OutputDebugString( buf );
\r
10766 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10768 EvalGraphSet( first, last, current, pvInfoList );
\r
10771 void SetProgramStats( FrontEndProgramStats * stats )
\r
10776 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10777 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10779 OutputDebugString( buf );
\r
10782 EngineOutputUpdate( stats );
\r