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) {
\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 blackRect.left = leftLogoRect.right;
\r
3154 blackRect.right = rightLogoRect.left;
\r
3155 blackRect.top = OUTER_MARGIN;
\r
3156 blackRect.bottom = blackRect.top + clockSize.cy;
\r
3158 whiteRect.left = blackRect.left ;
\r
3159 whiteRect.right = blackRect.right;
\r
3160 whiteRect.top = blackRect.bottom;
\r
3161 whiteRect.bottom = leftLogoRect.bottom;
\r
3163 whiteRect.left = OUTER_MARGIN;
\r
3164 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3165 whiteRect.top = OUTER_MARGIN + logoHeight;
\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((logoHeight > 0 ? flipView: 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(!(logoHeight > 0 ? flipView: 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((logoHeight > 0 ? flipView: flipClock), 1);
\r
5137 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5138 if (gameMode == EditGame) AdjustClock(!(logoHeight > 0 ? flipView: 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
5946 case IDM_GeneralOptions:
\r
5947 GeneralOptionsPopup(hwnd);
\r
5948 DrawPosition(TRUE, NULL);
\r
5951 case IDM_BoardOptions:
\r
5952 BoardOptionsPopup(hwnd);
\r
5955 case IDM_EnginePlayOptions:
\r
5956 EnginePlayOptionsPopup(hwnd);
\r
5959 case IDM_OptionsUCI:
\r
5960 UciOptionsPopup(hwnd);
\r
5963 case IDM_IcsOptions:
\r
5964 IcsOptionsPopup(hwnd);
\r
5968 FontsOptionsPopup(hwnd);
\r
5972 SoundOptionsPopup(hwnd);
\r
5975 case IDM_CommPort:
\r
5976 CommPortOptionsPopup(hwnd);
\r
5979 case IDM_LoadOptions:
\r
5980 LoadOptionsPopup(hwnd);
\r
5983 case IDM_SaveOptions:
\r
5984 SaveOptionsPopup(hwnd);
\r
5987 case IDM_TimeControl:
\r
5988 TimeControlOptionsPopup(hwnd);
\r
5991 case IDM_SaveSettings:
\r
5992 SaveSettings(settingsFileName);
\r
5995 case IDM_SaveSettingsOnExit:
\r
5996 saveSettingsOnExit = !saveSettingsOnExit;
\r
5997 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5998 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5999 MF_CHECKED : MF_UNCHECKED));
\r
6010 case IDM_AboutGame:
\r
6015 appData.debugMode = !appData.debugMode;
\r
6016 if (appData.debugMode) {
\r
6017 char dir[MSG_SIZ];
\r
6018 GetCurrentDirectory(MSG_SIZ, dir);
\r
6019 SetCurrentDirectory(installDir);
\r
6020 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6021 SetCurrentDirectory(dir);
\r
6022 setbuf(debugFP, NULL);
\r
6029 case IDM_HELPCONTENTS:
\r
6030 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6031 MessageBox (GetFocus(),
\r
6032 "Unable to activate help",
\r
6033 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6037 case IDM_HELPSEARCH:
\r
6038 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
6039 MessageBox (GetFocus(),
\r
6040 "Unable to activate help",
\r
6041 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6045 case IDM_HELPHELP:
\r
6046 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6047 MessageBox (GetFocus(),
\r
6048 "Unable to activate help",
\r
6049 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6054 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6056 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6057 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6058 FreeProcInstance(lpProc);
\r
6061 case IDM_DirectCommand1:
\r
6062 AskQuestionEvent("Direct Command",
\r
6063 "Send to chess program:", "", "1");
\r
6065 case IDM_DirectCommand2:
\r
6066 AskQuestionEvent("Direct Command",
\r
6067 "Send to second chess program:", "", "2");
\r
6070 case EP_WhitePawn:
\r
6071 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6072 fromX = fromY = -1;
\r
6075 case EP_WhiteKnight:
\r
6076 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6077 fromX = fromY = -1;
\r
6080 case EP_WhiteBishop:
\r
6081 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6082 fromX = fromY = -1;
\r
6085 case EP_WhiteRook:
\r
6086 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6087 fromX = fromY = -1;
\r
6090 case EP_WhiteQueen:
\r
6091 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6092 fromX = fromY = -1;
\r
6095 case EP_WhiteFerz:
\r
6096 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6097 fromX = fromY = -1;
\r
6100 case EP_WhiteWazir:
\r
6101 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6102 fromX = fromY = -1;
\r
6105 case EP_WhiteAlfil:
\r
6106 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6107 fromX = fromY = -1;
\r
6110 case EP_WhiteCannon:
\r
6111 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6112 fromX = fromY = -1;
\r
6115 case EP_WhiteCardinal:
\r
6116 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6117 fromX = fromY = -1;
\r
6120 case EP_WhiteMarshall:
\r
6121 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6122 fromX = fromY = -1;
\r
6125 case EP_WhiteKing:
\r
6126 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6127 fromX = fromY = -1;
\r
6130 case EP_BlackPawn:
\r
6131 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6132 fromX = fromY = -1;
\r
6135 case EP_BlackKnight:
\r
6136 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6137 fromX = fromY = -1;
\r
6140 case EP_BlackBishop:
\r
6141 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6142 fromX = fromY = -1;
\r
6145 case EP_BlackRook:
\r
6146 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6147 fromX = fromY = -1;
\r
6150 case EP_BlackQueen:
\r
6151 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6152 fromX = fromY = -1;
\r
6155 case EP_BlackFerz:
\r
6156 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6157 fromX = fromY = -1;
\r
6160 case EP_BlackWazir:
\r
6161 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6162 fromX = fromY = -1;
\r
6165 case EP_BlackAlfil:
\r
6166 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6167 fromX = fromY = -1;
\r
6170 case EP_BlackCannon:
\r
6171 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6172 fromX = fromY = -1;
\r
6175 case EP_BlackCardinal:
\r
6176 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6177 fromX = fromY = -1;
\r
6180 case EP_BlackMarshall:
\r
6181 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6182 fromX = fromY = -1;
\r
6185 case EP_BlackKing:
\r
6186 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6187 fromX = fromY = -1;
\r
6190 case EP_EmptySquare:
\r
6191 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6192 fromX = fromY = -1;
\r
6195 case EP_ClearBoard:
\r
6196 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6197 fromX = fromY = -1;
\r
6201 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6202 fromX = fromY = -1;
\r
6206 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6207 fromX = fromY = -1;
\r
6211 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6212 fromX = fromY = -1;
\r
6216 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6217 fromX = fromY = -1;
\r
6221 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6222 fromX = fromY = -1;
\r
6226 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6227 fromX = fromY = -1;
\r
6231 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6232 fromX = fromY = -1;
\r
6236 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6237 fromX = fromY = -1;
\r
6241 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6242 fromX = fromY = -1;
\r
6246 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6252 case CLOCK_TIMER_ID:
\r
6253 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6254 clockTimerEvent = 0;
\r
6255 DecrementClocks(); /* call into back end */
\r
6257 case LOAD_GAME_TIMER_ID:
\r
6258 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6259 loadGameTimerEvent = 0;
\r
6260 AutoPlayGameLoop(); /* call into back end */
\r
6262 case ANALYSIS_TIMER_ID:
\r
6263 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6264 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6265 AnalysisPeriodicEvent(0);
\r
6267 KillTimer(hwnd, analysisTimerEvent);
\r
6268 analysisTimerEvent = 0;
\r
6271 case DELAYED_TIMER_ID:
\r
6272 KillTimer(hwnd, delayedTimerEvent);
\r
6273 delayedTimerEvent = 0;
\r
6274 delayedTimerCallback();
\r
6279 case WM_USER_Input:
\r
6280 InputEvent(hwnd, message, wParam, lParam);
\r
6283 /* [AS] Also move "attached" child windows */
\r
6284 case WM_WINDOWPOSCHANGING:
\r
6286 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6287 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6289 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6290 /* Window is moving */
\r
6293 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6294 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6295 rcMain.right = boardX + winWidth;
\r
6296 rcMain.top = boardY;
\r
6297 rcMain.bottom = boardY + winHeight;
\r
6299 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6300 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6301 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6308 /* [AS] Snapping */
\r
6309 case WM_ENTERSIZEMOVE:
\r
6310 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6311 if (hwnd == hwndMain) {
\r
6312 doingSizing = TRUE;
\r
6315 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6319 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6320 if (hwnd == hwndMain) {
\r
6321 lastSizing = wParam;
\r
6326 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6327 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6329 case WM_EXITSIZEMOVE:
\r
6330 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6331 if (hwnd == hwndMain) {
\r
6333 doingSizing = FALSE;
\r
6334 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6335 GetClientRect(hwnd, &client);
\r
6336 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6338 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6340 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6343 case WM_DESTROY: /* message: window being destroyed */
\r
6344 PostQuitMessage(0);
\r
6348 if (hwnd == hwndMain) {
\r
6353 default: /* Passes it on if unprocessed */
\r
6354 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6359 /*---------------------------------------------------------------------------*\
\r
6361 * Misc utility routines
\r
6363 \*---------------------------------------------------------------------------*/
\r
6366 * Decent random number generator, at least not as bad as Windows
\r
6367 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6369 unsigned int randstate;
\r
6374 randstate = randstate * 1664525 + 1013904223;
\r
6375 return (int) randstate & 0x7fffffff;
\r
6379 mysrandom(unsigned int seed)
\r
6386 * returns TRUE if user selects a different color, FALSE otherwise
\r
6390 ChangeColor(HWND hwnd, COLORREF *which)
\r
6392 static BOOL firstTime = TRUE;
\r
6393 static DWORD customColors[16];
\r
6395 COLORREF newcolor;
\r
6400 /* Make initial colors in use available as custom colors */
\r
6401 /* Should we put the compiled-in defaults here instead? */
\r
6403 customColors[i++] = lightSquareColor & 0xffffff;
\r
6404 customColors[i++] = darkSquareColor & 0xffffff;
\r
6405 customColors[i++] = whitePieceColor & 0xffffff;
\r
6406 customColors[i++] = blackPieceColor & 0xffffff;
\r
6407 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6408 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6410 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6411 customColors[i++] = textAttribs[ccl].color;
\r
6413 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6414 firstTime = FALSE;
\r
6417 cc.lStructSize = sizeof(cc);
\r
6418 cc.hwndOwner = hwnd;
\r
6419 cc.hInstance = NULL;
\r
6420 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6421 cc.lpCustColors = (LPDWORD) customColors;
\r
6422 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6424 if (!ChooseColor(&cc)) return FALSE;
\r
6426 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6427 if (newcolor == *which) return FALSE;
\r
6428 *which = newcolor;
\r
6432 InitDrawingColors();
\r
6433 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6438 MyLoadSound(MySound *ms)
\r
6444 if (ms->data) free(ms->data);
\r
6447 switch (ms->name[0]) {
\r
6453 /* System sound from Control Panel. Don't preload here. */
\r
6457 if (ms->name[1] == NULLCHAR) {
\r
6458 /* "!" alone = silence */
\r
6461 /* Builtin wave resource. Error if not found. */
\r
6462 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6463 if (h == NULL) break;
\r
6464 ms->data = (void *)LoadResource(hInst, h);
\r
6465 if (h == NULL) break;
\r
6470 /* .wav file. Error if not found. */
\r
6471 f = fopen(ms->name, "rb");
\r
6472 if (f == NULL) break;
\r
6473 if (fstat(fileno(f), &st) < 0) break;
\r
6474 ms->data = malloc(st.st_size);
\r
6475 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6481 char buf[MSG_SIZ];
\r
6482 sprintf(buf, "Error loading sound %s", ms->name);
\r
6483 DisplayError(buf, GetLastError());
\r
6489 MyPlaySound(MySound *ms)
\r
6491 BOOLEAN ok = FALSE;
\r
6492 switch (ms->name[0]) {
\r
6498 /* System sound from Control Panel (deprecated feature).
\r
6499 "$" alone or an unset sound name gets default beep (still in use). */
\r
6500 if (ms->name[1]) {
\r
6501 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6503 if (!ok) ok = MessageBeep(MB_OK);
\r
6506 /* Builtin wave resource, or "!" alone for silence */
\r
6507 if (ms->name[1]) {
\r
6508 if (ms->data == NULL) return FALSE;
\r
6509 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6515 /* .wav file. Error if not found. */
\r
6516 if (ms->data == NULL) return FALSE;
\r
6517 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6520 /* Don't print an error: this can happen innocently if the sound driver
\r
6521 is busy; for instance, if another instance of WinBoard is playing
\r
6522 a sound at about the same time. */
\r
6525 char buf[MSG_SIZ];
\r
6526 sprintf(buf, "Error playing sound %s", ms->name);
\r
6527 DisplayError(buf, GetLastError());
\r
6535 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6538 OPENFILENAME *ofn;
\r
6539 static UINT *number; /* gross that this is static */
\r
6541 switch (message) {
\r
6542 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6543 /* Center the dialog over the application window */
\r
6544 ofn = (OPENFILENAME *) lParam;
\r
6545 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6546 number = (UINT *) ofn->lCustData;
\r
6547 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6551 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6552 return FALSE; /* Allow for further processing */
\r
6555 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6556 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6558 return FALSE; /* Allow for further processing */
\r
6564 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6566 static UINT *number;
\r
6567 OPENFILENAME *ofname;
\r
6570 case WM_INITDIALOG:
\r
6571 ofname = (OPENFILENAME *)lParam;
\r
6572 number = (UINT *)(ofname->lCustData);
\r
6575 ofnot = (OFNOTIFY *)lParam;
\r
6576 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6577 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6586 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6587 char *nameFilt, char *dlgTitle, UINT *number,
\r
6588 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6590 OPENFILENAME openFileName;
\r
6591 char buf1[MSG_SIZ];
\r
6594 if (fileName == NULL) fileName = buf1;
\r
6595 if (defName == NULL) {
\r
6596 strcpy(fileName, "*.");
\r
6597 strcat(fileName, defExt);
\r
6599 strcpy(fileName, defName);
\r
6601 if (fileTitle) strcpy(fileTitle, "");
\r
6602 if (number) *number = 0;
\r
6604 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6605 openFileName.hwndOwner = hwnd;
\r
6606 openFileName.hInstance = (HANDLE) hInst;
\r
6607 openFileName.lpstrFilter = nameFilt;
\r
6608 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6609 openFileName.nMaxCustFilter = 0L;
\r
6610 openFileName.nFilterIndex = 1L;
\r
6611 openFileName.lpstrFile = fileName;
\r
6612 openFileName.nMaxFile = MSG_SIZ;
\r
6613 openFileName.lpstrFileTitle = fileTitle;
\r
6614 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6615 openFileName.lpstrInitialDir = NULL;
\r
6616 openFileName.lpstrTitle = dlgTitle;
\r
6617 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6618 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6619 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6620 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6621 openFileName.nFileOffset = 0;
\r
6622 openFileName.nFileExtension = 0;
\r
6623 openFileName.lpstrDefExt = defExt;
\r
6624 openFileName.lCustData = (LONG) number;
\r
6625 openFileName.lpfnHook = oldDialog ?
\r
6626 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6627 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6629 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6630 GetOpenFileName(&openFileName)) {
\r
6631 /* open the file */
\r
6632 f = fopen(openFileName.lpstrFile, write);
\r
6634 MessageBox(hwnd, "File open failed", NULL,
\r
6635 MB_OK|MB_ICONEXCLAMATION);
\r
6639 int err = CommDlgExtendedError();
\r
6640 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6649 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6651 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6654 * Get the first pop-up menu in the menu template. This is the
\r
6655 * menu that TrackPopupMenu displays.
\r
6657 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6659 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6662 * TrackPopup uses screen coordinates, so convert the
\r
6663 * coordinates of the mouse click to screen coordinates.
\r
6665 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6667 /* Draw and track the floating pop-up menu. */
\r
6668 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6669 pt.x, pt.y, 0, hwnd, NULL);
\r
6671 /* Destroy the menu.*/
\r
6672 DestroyMenu(hmenu);
\r
6677 int sizeX, sizeY, newSizeX, newSizeY;
\r
6679 } ResizeEditPlusButtonsClosure;
\r
6682 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6684 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6688 if (hChild == cl->hText) return TRUE;
\r
6689 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6690 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6691 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6692 ScreenToClient(cl->hDlg, &pt);
\r
6693 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6694 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6698 /* Resize a dialog that has a (rich) edit field filling most of
\r
6699 the top, with a row of buttons below */
\r
6701 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6704 int newTextHeight, newTextWidth;
\r
6705 ResizeEditPlusButtonsClosure cl;
\r
6707 /*if (IsIconic(hDlg)) return;*/
\r
6708 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6710 cl.hdwp = BeginDeferWindowPos(8);
\r
6712 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6713 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6714 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6715 if (newTextHeight < 0) {
\r
6716 newSizeY += -newTextHeight;
\r
6717 newTextHeight = 0;
\r
6719 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6720 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6726 cl.newSizeX = newSizeX;
\r
6727 cl.newSizeY = newSizeY;
\r
6728 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6730 EndDeferWindowPos(cl.hdwp);
\r
6733 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6735 RECT rChild, rParent;
\r
6736 int wChild, hChild, wParent, hParent;
\r
6737 int wScreen, hScreen, xNew, yNew;
\r
6740 /* Get the Height and Width of the child window */
\r
6741 GetWindowRect (hwndChild, &rChild);
\r
6742 wChild = rChild.right - rChild.left;
\r
6743 hChild = rChild.bottom - rChild.top;
\r
6745 /* Get the Height and Width of the parent window */
\r
6746 GetWindowRect (hwndParent, &rParent);
\r
6747 wParent = rParent.right - rParent.left;
\r
6748 hParent = rParent.bottom - rParent.top;
\r
6750 /* Get the display limits */
\r
6751 hdc = GetDC (hwndChild);
\r
6752 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6753 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6754 ReleaseDC(hwndChild, hdc);
\r
6756 /* Calculate new X position, then adjust for screen */
\r
6757 xNew = rParent.left + ((wParent - wChild) /2);
\r
6760 } else if ((xNew+wChild) > wScreen) {
\r
6761 xNew = wScreen - wChild;
\r
6764 /* Calculate new Y position, then adjust for screen */
\r
6766 yNew = rParent.top + ((hParent - hChild) /2);
\r
6769 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6774 } else if ((yNew+hChild) > hScreen) {
\r
6775 yNew = hScreen - hChild;
\r
6778 /* Set it, and return */
\r
6779 return SetWindowPos (hwndChild, NULL,
\r
6780 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6783 /* Center one window over another */
\r
6784 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6786 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6789 /*---------------------------------------------------------------------------*\
\r
6791 * Startup Dialog functions
\r
6793 \*---------------------------------------------------------------------------*/
\r
6795 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6797 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6799 while (*cd != NULL) {
\r
6800 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6806 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6808 char buf1[ARG_MAX];
\r
6811 if (str[0] == '@') {
\r
6812 FILE* f = fopen(str + 1, "r");
\r
6814 DisplayFatalError(str + 1, errno, 2);
\r
6817 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6819 buf1[len] = NULLCHAR;
\r
6823 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6826 char buf[MSG_SIZ];
\r
6827 char *end = strchr(str, '\n');
\r
6828 if (end == NULL) return;
\r
6829 memcpy(buf, str, end - str);
\r
6830 buf[end - str] = NULLCHAR;
\r
6831 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6837 SetStartupDialogEnables(HWND hDlg)
\r
6839 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6840 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6841 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6842 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6843 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6844 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6845 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6846 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6847 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6848 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6849 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6850 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6851 IsDlgButtonChecked(hDlg, OPT_View));
\r
6855 QuoteForFilename(char *filename)
\r
6857 int dquote, space;
\r
6858 dquote = strchr(filename, '"') != NULL;
\r
6859 space = strchr(filename, ' ') != NULL;
\r
6860 if (dquote || space) {
\r
6872 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6874 char buf[MSG_SIZ];
\r
6877 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6878 q = QuoteForFilename(nthcp);
\r
6879 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6880 if (*nthdir != NULLCHAR) {
\r
6881 q = QuoteForFilename(nthdir);
\r
6882 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6884 if (*nthcp == NULLCHAR) {
\r
6885 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6886 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6887 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6888 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6893 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6895 char buf[MSG_SIZ];
\r
6899 switch (message) {
\r
6900 case WM_INITDIALOG:
\r
6901 /* Center the dialog */
\r
6902 CenterWindow (hDlg, GetDesktopWindow());
\r
6903 /* Initialize the dialog items */
\r
6904 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6905 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6906 firstChessProgramNames);
\r
6907 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6908 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6909 secondChessProgramNames);
\r
6910 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6911 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6912 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6913 if (*appData.icsHelper != NULLCHAR) {
\r
6914 char *q = QuoteForFilename(appData.icsHelper);
\r
6915 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6917 if (*appData.icsHost == NULLCHAR) {
\r
6918 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6919 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6920 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6921 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6922 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6925 if (appData.icsActive) {
\r
6926 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6928 else if (appData.noChessProgram) {
\r
6929 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6932 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6935 SetStartupDialogEnables(hDlg);
\r
6939 switch (LOWORD(wParam)) {
\r
6941 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6942 strcpy(buf, "/fcp=");
\r
6943 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6945 ParseArgs(StringGet, &p);
\r
6946 strcpy(buf, "/scp=");
\r
6947 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6949 ParseArgs(StringGet, &p);
\r
6950 appData.noChessProgram = FALSE;
\r
6951 appData.icsActive = FALSE;
\r
6952 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6953 strcpy(buf, "/ics /icshost=");
\r
6954 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6956 ParseArgs(StringGet, &p);
\r
6957 if (appData.zippyPlay) {
\r
6958 strcpy(buf, "/fcp=");
\r
6959 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6961 ParseArgs(StringGet, &p);
\r
6963 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6964 appData.noChessProgram = TRUE;
\r
6965 appData.icsActive = FALSE;
\r
6967 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6968 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6971 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6972 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6974 ParseArgs(StringGet, &p);
\r
6976 EndDialog(hDlg, TRUE);
\r
6983 case IDM_HELPCONTENTS:
\r
6984 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6985 MessageBox (GetFocus(),
\r
6986 "Unable to activate help",
\r
6987 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6992 SetStartupDialogEnables(hDlg);
\r
7000 /*---------------------------------------------------------------------------*\
\r
7002 * About box dialog functions
\r
7004 \*---------------------------------------------------------------------------*/
\r
7006 /* Process messages for "About" dialog box */
\r
7008 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7010 switch (message) {
\r
7011 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7012 /* Center the dialog over the application window */
\r
7013 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7014 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7017 case WM_COMMAND: /* message: received a command */
\r
7018 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7019 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7020 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7028 /*---------------------------------------------------------------------------*\
\r
7030 * Comment Dialog functions
\r
7032 \*---------------------------------------------------------------------------*/
\r
7035 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7037 static HANDLE hwndText = NULL;
\r
7038 int len, newSizeX, newSizeY, flags;
\r
7039 static int sizeX, sizeY;
\r
7044 switch (message) {
\r
7045 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7046 /* Initialize the dialog items */
\r
7047 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7048 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7049 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7050 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7051 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7052 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7053 SetWindowText(hDlg, commentTitle);
\r
7054 if (editComment) {
\r
7055 SetFocus(hwndText);
\r
7057 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7059 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7060 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7061 MAKELPARAM(FALSE, 0));
\r
7062 /* Size and position the dialog */
\r
7063 if (!commentDialog) {
\r
7064 commentDialog = hDlg;
\r
7065 flags = SWP_NOZORDER;
\r
7066 GetClientRect(hDlg, &rect);
\r
7067 sizeX = rect.right;
\r
7068 sizeY = rect.bottom;
\r
7069 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7070 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7071 WINDOWPLACEMENT wp;
\r
7072 EnsureOnScreen(&commentX, &commentY);
\r
7073 wp.length = sizeof(WINDOWPLACEMENT);
\r
7075 wp.showCmd = SW_SHOW;
\r
7076 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7077 wp.rcNormalPosition.left = commentX;
\r
7078 wp.rcNormalPosition.right = commentX + commentW;
\r
7079 wp.rcNormalPosition.top = commentY;
\r
7080 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7081 SetWindowPlacement(hDlg, &wp);
\r
7083 GetClientRect(hDlg, &rect);
\r
7084 newSizeX = rect.right;
\r
7085 newSizeY = rect.bottom;
\r
7086 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7087 newSizeX, newSizeY);
\r
7094 case WM_COMMAND: /* message: received a command */
\r
7095 switch (LOWORD(wParam)) {
\r
7097 if (editComment) {
\r
7099 /* Read changed options from the dialog box */
\r
7100 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7101 len = GetWindowTextLength(hwndText);
\r
7102 str = (char *) malloc(len + 1);
\r
7103 GetWindowText(hwndText, str, len + 1);
\r
7112 ReplaceComment(commentIndex, str);
\r
7119 case OPT_CancelComment:
\r
7123 case OPT_ClearComment:
\r
7124 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7127 case OPT_EditComment:
\r
7128 EditCommentEvent();
\r
7137 newSizeX = LOWORD(lParam);
\r
7138 newSizeY = HIWORD(lParam);
\r
7139 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7144 case WM_GETMINMAXINFO:
\r
7145 /* Prevent resizing window too small */
\r
7146 mmi = (MINMAXINFO *) lParam;
\r
7147 mmi->ptMinTrackSize.x = 100;
\r
7148 mmi->ptMinTrackSize.y = 100;
\r
7155 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7160 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7162 if (str == NULL) str = "";
\r
7163 p = (char *) malloc(2 * strlen(str) + 2);
\r
7166 if (*str == '\n') *q++ = '\r';
\r
7170 if (commentText != NULL) free(commentText);
\r
7172 commentIndex = index;
\r
7173 commentTitle = title;
\r
7175 editComment = edit;
\r
7177 if (commentDialog) {
\r
7178 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7179 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7181 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7182 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7183 hwndMain, (DLGPROC)lpProc);
\r
7184 FreeProcInstance(lpProc);
\r
7186 commentDialogUp = TRUE;
\r
7190 /*---------------------------------------------------------------------------*\
\r
7192 * Type-in move dialog functions
\r
7194 \*---------------------------------------------------------------------------*/
\r
7197 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7199 char move[MSG_SIZ];
\r
7201 ChessMove moveType;
\r
7202 int fromX, fromY, toX, toY;
\r
7205 switch (message) {
\r
7206 case WM_INITDIALOG:
\r
7207 move[0] = (char) lParam;
\r
7208 move[1] = NULLCHAR;
\r
7209 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7210 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7211 SetWindowText(hInput, move);
\r
7213 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7217 switch (LOWORD(wParam)) {
\r
7219 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7220 gameMode != Training) {
\r
7221 DisplayMoveError("Displayed move is not current");
\r
7223 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7224 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7225 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7226 if (gameMode != Training)
\r
7227 forwardMostMove = currentMove;
\r
7228 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7230 DisplayMoveError("Could not parse move");
\r
7233 EndDialog(hDlg, TRUE);
\r
7236 EndDialog(hDlg, FALSE);
\r
7247 PopUpMoveDialog(char firstchar)
\r
7251 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7252 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7253 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7254 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7255 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7256 gameMode == Training) {
\r
7257 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7258 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7259 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7260 FreeProcInstance(lpProc);
\r
7264 /*---------------------------------------------------------------------------*\
\r
7266 * Type-in name dialog functions
\r
7268 \*---------------------------------------------------------------------------*/
\r
7271 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7273 char move[MSG_SIZ];
\r
7276 switch (message) {
\r
7277 case WM_INITDIALOG:
\r
7278 move[0] = (char) lParam;
\r
7279 move[1] = NULLCHAR;
\r
7280 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7281 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7282 SetWindowText(hInput, move);
\r
7284 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7288 switch (LOWORD(wParam)) {
\r
7290 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7291 appData.userName = strdup(move);
\r
7293 EndDialog(hDlg, TRUE);
\r
7296 EndDialog(hDlg, FALSE);
\r
7307 PopUpNameDialog(char firstchar)
\r
7311 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7312 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7313 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7314 FreeProcInstance(lpProc);
\r
7317 /*---------------------------------------------------------------------------*\
\r
7321 \*---------------------------------------------------------------------------*/
\r
7323 /* Nonmodal error box */
\r
7324 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7325 WPARAM wParam, LPARAM lParam);
\r
7328 ErrorPopUp(char *title, char *content)
\r
7332 BOOLEAN modal = hwndMain == NULL;
\r
7350 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7351 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7354 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7356 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7357 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7358 hwndMain, (DLGPROC)lpProc);
\r
7359 FreeProcInstance(lpProc);
\r
7366 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7367 if (errorDialog == NULL) return;
\r
7368 DestroyWindow(errorDialog);
\r
7369 errorDialog = NULL;
\r
7373 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7378 switch (message) {
\r
7379 case WM_INITDIALOG:
\r
7380 GetWindowRect(hDlg, &rChild);
\r
7383 SetWindowPos(hDlg, NULL, rChild.left,
\r
7384 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7385 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7389 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7390 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7391 and it doesn't work when you resize the dialog.
\r
7392 For now, just give it a default position.
\r
7394 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7396 errorDialog = hDlg;
\r
7397 SetWindowText(hDlg, errorTitle);
\r
7398 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7399 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7403 switch (LOWORD(wParam)) {
\r
7406 if (errorDialog == hDlg) errorDialog = NULL;
\r
7407 DestroyWindow(hDlg);
\r
7419 HWND gothicDialog = NULL;
\r
7422 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7426 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7428 switch (message) {
\r
7429 case WM_INITDIALOG:
\r
7430 GetWindowRect(hDlg, &rChild);
\r
7432 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7436 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7437 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7438 and it doesn't work when you resize the dialog.
\r
7439 For now, just give it a default position.
\r
7441 gothicDialog = hDlg;
\r
7442 SetWindowText(hDlg, errorTitle);
\r
7443 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7444 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7448 switch (LOWORD(wParam)) {
\r
7451 if (errorDialog == hDlg) errorDialog = NULL;
\r
7452 DestroyWindow(hDlg);
\r
7464 GothicPopUp(char *title, VariantClass variant)
\r
7467 static char *lastTitle;
\r
7469 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7470 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7472 if(lastTitle != title && gothicDialog != NULL) {
\r
7473 DestroyWindow(gothicDialog);
\r
7474 gothicDialog = NULL;
\r
7476 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7477 title = lastTitle;
\r
7478 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7479 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7480 hwndMain, (DLGPROC)lpProc);
\r
7481 FreeProcInstance(lpProc);
\r
7486 /*---------------------------------------------------------------------------*\
\r
7488 * Ics Interaction console functions
\r
7490 \*---------------------------------------------------------------------------*/
\r
7492 #define HISTORY_SIZE 64
\r
7493 static char *history[HISTORY_SIZE];
\r
7494 int histIn = 0, histP = 0;
\r
7497 SaveInHistory(char *cmd)
\r
7499 if (history[histIn] != NULL) {
\r
7500 free(history[histIn]);
\r
7501 history[histIn] = NULL;
\r
7503 if (*cmd == NULLCHAR) return;
\r
7504 history[histIn] = StrSave(cmd);
\r
7505 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7506 if (history[histIn] != NULL) {
\r
7507 free(history[histIn]);
\r
7508 history[histIn] = NULL;
\r
7514 PrevInHistory(char *cmd)
\r
7517 if (histP == histIn) {
\r
7518 if (history[histIn] != NULL) free(history[histIn]);
\r
7519 history[histIn] = StrSave(cmd);
\r
7521 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7522 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7524 return history[histP];
\r
7530 if (histP == histIn) return NULL;
\r
7531 histP = (histP + 1) % HISTORY_SIZE;
\r
7532 return history[histP];
\r
7539 BOOLEAN immediate;
\r
7540 } IcsTextMenuEntry;
\r
7541 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7542 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7545 ParseIcsTextMenu(char *icsTextMenuString)
\r
7548 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7549 char *p = icsTextMenuString;
\r
7550 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7553 if (e->command != NULL) {
\r
7555 e->command = NULL;
\r
7559 e = icsTextMenuEntry;
\r
7560 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7561 if (*p == ';' || *p == '\n') {
\r
7562 e->item = strdup("-");
\r
7563 e->command = NULL;
\r
7565 } else if (*p == '-') {
\r
7566 e->item = strdup("-");
\r
7567 e->command = NULL;
\r
7571 char *q, *r, *s, *t;
\r
7573 q = strchr(p, ',');
\r
7574 if (q == NULL) break;
\r
7576 r = strchr(q + 1, ',');
\r
7577 if (r == NULL) break;
\r
7579 s = strchr(r + 1, ',');
\r
7580 if (s == NULL) break;
\r
7583 t = strchr(s + 1, c);
\r
7586 t = strchr(s + 1, c);
\r
7588 if (t != NULL) *t = NULLCHAR;
\r
7589 e->item = strdup(p);
\r
7590 e->command = strdup(q + 1);
\r
7591 e->getname = *(r + 1) != '0';
\r
7592 e->immediate = *(s + 1) != '0';
\r
7596 if (t == NULL) break;
\r
7605 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7609 hmenu = LoadMenu(hInst, "TextMenu");
\r
7610 h = GetSubMenu(hmenu, 0);
\r
7612 if (strcmp(e->item, "-") == 0) {
\r
7613 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7615 if (e->item[0] == '|') {
\r
7616 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7617 IDM_CommandX + i, &e->item[1]);
\r
7619 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7628 WNDPROC consoleTextWindowProc;
\r
7631 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7633 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7634 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7638 SetWindowText(hInput, command);
\r
7640 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7642 sel.cpMin = 999999;
\r
7643 sel.cpMax = 999999;
\r
7644 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7649 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7650 if (sel.cpMin == sel.cpMax) {
\r
7651 /* Expand to surrounding word */
\r
7654 tr.chrg.cpMax = sel.cpMin;
\r
7655 tr.chrg.cpMin = --sel.cpMin;
\r
7656 if (sel.cpMin < 0) break;
\r
7657 tr.lpstrText = name;
\r
7658 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7659 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7663 tr.chrg.cpMin = sel.cpMax;
\r
7664 tr.chrg.cpMax = ++sel.cpMax;
\r
7665 tr.lpstrText = name;
\r
7666 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7667 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7670 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7671 MessageBeep(MB_ICONEXCLAMATION);
\r
7675 tr.lpstrText = name;
\r
7676 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7678 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7679 MessageBeep(MB_ICONEXCLAMATION);
\r
7682 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7685 sprintf(buf, "%s %s", command, name);
\r
7686 SetWindowText(hInput, buf);
\r
7687 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7689 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7690 SetWindowText(hInput, buf);
\r
7691 sel.cpMin = 999999;
\r
7692 sel.cpMax = 999999;
\r
7693 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7699 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7704 switch (message) {
\r
7706 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7709 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7712 sel.cpMin = 999999;
\r
7713 sel.cpMax = 999999;
\r
7714 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7715 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7720 if (wParam == '\t') {
\r
7721 if (GetKeyState(VK_SHIFT) < 0) {
\r
7723 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7724 if (buttonDesc[0].hwnd) {
\r
7725 SetFocus(buttonDesc[0].hwnd);
\r
7727 SetFocus(hwndMain);
\r
7731 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7734 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7736 SendMessage(hInput, message, wParam, lParam);
\r
7740 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7742 return SendMessage(hInput, message, wParam, lParam);
\r
7743 case WM_MBUTTONDOWN:
\r
7744 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7745 case WM_RBUTTONDOWN:
\r
7746 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7747 /* Move selection here if it was empty */
\r
7749 pt.x = LOWORD(lParam);
\r
7750 pt.y = HIWORD(lParam);
\r
7751 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7752 if (sel.cpMin == sel.cpMax) {
\r
7753 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7754 sel.cpMax = sel.cpMin;
\r
7755 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7757 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7760 case WM_RBUTTONUP:
\r
7761 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7762 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7763 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7766 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7767 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7768 if (sel.cpMin == sel.cpMax) {
\r
7769 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7770 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7772 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7773 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7775 pt.x = LOWORD(lParam);
\r
7776 pt.y = HIWORD(lParam);
\r
7777 MenuPopup(hwnd, pt, hmenu, -1);
\r
7781 switch (LOWORD(wParam)) {
\r
7782 case IDM_QuickPaste:
\r
7784 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7785 if (sel.cpMin == sel.cpMax) {
\r
7786 MessageBeep(MB_ICONEXCLAMATION);
\r
7789 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7790 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7791 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7796 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7799 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7802 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7806 int i = LOWORD(wParam) - IDM_CommandX;
\r
7807 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7808 icsTextMenuEntry[i].command != NULL) {
\r
7809 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7810 icsTextMenuEntry[i].getname,
\r
7811 icsTextMenuEntry[i].immediate);
\r
7819 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7822 WNDPROC consoleInputWindowProc;
\r
7825 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7827 char buf[MSG_SIZ];
\r
7829 static BOOL sendNextChar = FALSE;
\r
7830 static BOOL quoteNextChar = FALSE;
\r
7831 InputSource *is = consoleInputSource;
\r
7835 switch (message) {
\r
7837 if (!appData.localLineEditing || sendNextChar) {
\r
7838 is->buf[0] = (CHAR) wParam;
\r
7840 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7841 sendNextChar = FALSE;
\r
7844 if (quoteNextChar) {
\r
7845 buf[0] = (char) wParam;
\r
7846 buf[1] = NULLCHAR;
\r
7847 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7848 quoteNextChar = FALSE;
\r
7852 case '\r': /* Enter key */
\r
7853 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7854 if (consoleEcho) SaveInHistory(is->buf);
\r
7855 is->buf[is->count++] = '\n';
\r
7856 is->buf[is->count] = NULLCHAR;
\r
7857 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7858 if (consoleEcho) {
\r
7859 ConsoleOutput(is->buf, is->count, TRUE);
\r
7860 } else if (appData.localLineEditing) {
\r
7861 ConsoleOutput("\n", 1, TRUE);
\r
7864 case '\033': /* Escape key */
\r
7865 SetWindowText(hwnd, "");
\r
7866 cf.cbSize = sizeof(CHARFORMAT);
\r
7867 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7868 if (consoleEcho) {
\r
7869 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7871 cf.crTextColor = COLOR_ECHOOFF;
\r
7873 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7874 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7876 case '\t': /* Tab key */
\r
7877 if (GetKeyState(VK_SHIFT) < 0) {
\r
7879 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7882 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7883 if (buttonDesc[0].hwnd) {
\r
7884 SetFocus(buttonDesc[0].hwnd);
\r
7886 SetFocus(hwndMain);
\r
7890 case '\023': /* Ctrl+S */
\r
7891 sendNextChar = TRUE;
\r
7893 case '\021': /* Ctrl+Q */
\r
7894 quoteNextChar = TRUE;
\r
7903 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7904 p = PrevInHistory(buf);
\r
7906 SetWindowText(hwnd, p);
\r
7907 sel.cpMin = 999999;
\r
7908 sel.cpMax = 999999;
\r
7909 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7914 p = NextInHistory();
\r
7916 SetWindowText(hwnd, p);
\r
7917 sel.cpMin = 999999;
\r
7918 sel.cpMax = 999999;
\r
7919 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7925 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7929 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7933 case WM_MBUTTONDOWN:
\r
7934 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7935 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7937 case WM_RBUTTONUP:
\r
7938 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7939 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7940 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7944 hmenu = LoadMenu(hInst, "InputMenu");
\r
7945 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7946 if (sel.cpMin == sel.cpMax) {
\r
7947 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7948 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7950 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7951 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7953 pt.x = LOWORD(lParam);
\r
7954 pt.y = HIWORD(lParam);
\r
7955 MenuPopup(hwnd, pt, hmenu, -1);
\r
7959 switch (LOWORD(wParam)) {
\r
7961 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7963 case IDM_SelectAll:
\r
7965 sel.cpMax = -1; /*999999?*/
\r
7966 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7969 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7972 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7975 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7980 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7983 #define CO_MAX 100000
\r
7984 #define CO_TRIM 1000
\r
7987 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7989 static SnapData sd;
\r
7990 static HWND hText, hInput /*, hFocus*/;
\r
7991 // InputSource *is = consoleInputSource;
\r
7993 static int sizeX, sizeY;
\r
7994 int newSizeX, newSizeY;
\r
7997 switch (message) {
\r
7998 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7999 hwndConsole = hDlg;
\r
8000 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
8001 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
8003 consoleTextWindowProc = (WNDPROC)
\r
8004 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8005 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8006 consoleInputWindowProc = (WNDPROC)
\r
8007 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8008 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8009 Colorize(ColorNormal, TRUE);
\r
8010 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8011 ChangedConsoleFont();
\r
8012 GetClientRect(hDlg, &rect);
\r
8013 sizeX = rect.right;
\r
8014 sizeY = rect.bottom;
\r
8015 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
8016 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
8017 WINDOWPLACEMENT wp;
\r
8018 EnsureOnScreen(&consoleX, &consoleY);
\r
8019 wp.length = sizeof(WINDOWPLACEMENT);
\r
8021 wp.showCmd = SW_SHOW;
\r
8022 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8023 wp.rcNormalPosition.left = consoleX;
\r
8024 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8025 wp.rcNormalPosition.top = consoleY;
\r
8026 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8027 SetWindowPlacement(hDlg, &wp);
\r
8030 // [HGM] Chessknight's change 2004-07-13
\r
8031 else { /* Determine Defaults */
\r
8032 WINDOWPLACEMENT wp;
\r
8033 consoleX = winWidth + 1;
\r
8034 consoleY = boardY;
\r
8035 consoleW = screenWidth - winWidth;
\r
8036 consoleH = winHeight;
\r
8037 EnsureOnScreen(&consoleX, &consoleY);
\r
8038 wp.length = sizeof(WINDOWPLACEMENT);
\r
8040 wp.showCmd = SW_SHOW;
\r
8041 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8042 wp.rcNormalPosition.left = consoleX;
\r
8043 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8044 wp.rcNormalPosition.top = consoleY;
\r
8045 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8046 SetWindowPlacement(hDlg, &wp);
\r
8061 if (IsIconic(hDlg)) break;
\r
8062 newSizeX = LOWORD(lParam);
\r
8063 newSizeY = HIWORD(lParam);
\r
8064 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8065 RECT rectText, rectInput;
\r
8067 int newTextHeight, newTextWidth;
\r
8068 GetWindowRect(hText, &rectText);
\r
8069 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8070 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8071 if (newTextHeight < 0) {
\r
8072 newSizeY += -newTextHeight;
\r
8073 newTextHeight = 0;
\r
8075 SetWindowPos(hText, NULL, 0, 0,
\r
8076 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8077 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8078 pt.x = rectInput.left;
\r
8079 pt.y = rectInput.top + newSizeY - sizeY;
\r
8080 ScreenToClient(hDlg, &pt);
\r
8081 SetWindowPos(hInput, NULL,
\r
8082 pt.x, pt.y, /* needs client coords */
\r
8083 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8084 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8090 case WM_GETMINMAXINFO:
\r
8091 /* Prevent resizing window too small */
\r
8092 mmi = (MINMAXINFO *) lParam;
\r
8093 mmi->ptMinTrackSize.x = 100;
\r
8094 mmi->ptMinTrackSize.y = 100;
\r
8097 /* [AS] Snapping */
\r
8098 case WM_ENTERSIZEMOVE:
\r
8099 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8102 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8105 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8107 case WM_EXITSIZEMOVE:
\r
8108 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8111 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8119 if (hwndConsole) return;
\r
8120 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8121 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8126 ConsoleOutput(char* data, int length, int forceVisible)
\r
8131 char buf[CO_MAX+1];
\r
8134 static int delayLF = 0;
\r
8135 CHARRANGE savesel, sel;
\r
8137 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8145 while (length--) {
\r
8153 } else if (*p == '\007') {
\r
8154 MyPlaySound(&sounds[(int)SoundBell]);
\r
8161 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8162 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8163 /* Save current selection */
\r
8164 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8165 exlen = GetWindowTextLength(hText);
\r
8166 /* Find out whether current end of text is visible */
\r
8167 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8168 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8169 /* Trim existing text if it's too long */
\r
8170 if (exlen + (q - buf) > CO_MAX) {
\r
8171 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8174 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8175 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8177 savesel.cpMin -= trim;
\r
8178 savesel.cpMax -= trim;
\r
8179 if (exlen < 0) exlen = 0;
\r
8180 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8181 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8183 /* Append the new text */
\r
8184 sel.cpMin = exlen;
\r
8185 sel.cpMax = exlen;
\r
8186 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8187 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8188 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8189 if (forceVisible || exlen == 0 ||
\r
8190 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8191 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8192 /* Scroll to make new end of text visible if old end of text
\r
8193 was visible or new text is an echo of user typein */
\r
8194 sel.cpMin = 9999999;
\r
8195 sel.cpMax = 9999999;
\r
8196 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8197 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8198 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8199 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8201 if (savesel.cpMax == exlen || forceVisible) {
\r
8202 /* Move insert point to new end of text if it was at the old
\r
8203 end of text or if the new text is an echo of user typein */
\r
8204 sel.cpMin = 9999999;
\r
8205 sel.cpMax = 9999999;
\r
8206 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8208 /* Restore previous selection */
\r
8209 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8211 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8218 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8222 COLORREF oldFg, oldBg;
\r
8226 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8228 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8229 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8230 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8233 rect.right = x + squareSize;
\r
8235 rect.bottom = y + squareSize;
\r
8238 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8239 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8240 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8241 &rect, str, strlen(str), NULL);
\r
8243 (void) SetTextColor(hdc, oldFg);
\r
8244 (void) SetBkColor(hdc, oldBg);
\r
8245 (void) SelectObject(hdc, oldFont);
\r
8249 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8250 RECT *rect, char *color, char *flagFell)
\r
8254 COLORREF oldFg, oldBg;
\r
8257 if (appData.clockMode) {
\r
8259 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8261 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
8268 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8269 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8271 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8272 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8274 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8276 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8277 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8278 rect, str, strlen(str), NULL);
\r
8280 (void) SetTextColor(hdc, oldFg);
\r
8281 (void) SetBkColor(hdc, oldBg);
\r
8282 (void) SelectObject(hdc, oldFont);
\r
8287 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8293 if( count <= 0 ) {
\r
8294 if (appData.debugMode) {
\r
8295 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8298 return ERROR_INVALID_USER_BUFFER;
\r
8301 ResetEvent(ovl->hEvent);
\r
8302 ovl->Offset = ovl->OffsetHigh = 0;
\r
8303 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8307 err = GetLastError();
\r
8308 if (err == ERROR_IO_PENDING) {
\r
8309 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8313 err = GetLastError();
\r
8320 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8325 ResetEvent(ovl->hEvent);
\r
8326 ovl->Offset = ovl->OffsetHigh = 0;
\r
8327 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8331 err = GetLastError();
\r
8332 if (err == ERROR_IO_PENDING) {
\r
8333 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8337 err = GetLastError();
\r
8343 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8344 void CheckForInputBufferFull( InputSource * is )
\r
8346 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8347 /* Look for end of line */
\r
8348 char * p = is->buf;
\r
8350 while( p < is->next && *p != '\n' ) {
\r
8354 if( p >= is->next ) {
\r
8355 if (appData.debugMode) {
\r
8356 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8359 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8360 is->count = (DWORD) -1;
\r
8361 is->next = is->buf;
\r
8367 InputThread(LPVOID arg)
\r
8372 is = (InputSource *) arg;
\r
8373 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8374 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8375 while (is->hThread != NULL) {
\r
8376 is->error = DoReadFile(is->hFile, is->next,
\r
8377 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8378 &is->count, &ovl);
\r
8379 if (is->error == NO_ERROR) {
\r
8380 is->next += is->count;
\r
8382 if (is->error == ERROR_BROKEN_PIPE) {
\r
8383 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8386 is->count = (DWORD) -1;
\r
8387 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8392 CheckForInputBufferFull( is );
\r
8394 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8396 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8398 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8401 CloseHandle(ovl.hEvent);
\r
8402 CloseHandle(is->hFile);
\r
8404 if (appData.debugMode) {
\r
8405 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8412 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8414 NonOvlInputThread(LPVOID arg)
\r
8421 is = (InputSource *) arg;
\r
8422 while (is->hThread != NULL) {
\r
8423 is->error = ReadFile(is->hFile, is->next,
\r
8424 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8425 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8426 if (is->error == NO_ERROR) {
\r
8427 /* Change CRLF to LF */
\r
8428 if (is->next > is->buf) {
\r
8430 i = is->count + 1;
\r
8438 if (prev == '\r' && *p == '\n') {
\r
8450 if (is->error == ERROR_BROKEN_PIPE) {
\r
8451 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8454 is->count = (DWORD) -1;
\r
8458 CheckForInputBufferFull( is );
\r
8460 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8462 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8464 if (is->count < 0) break; /* Quit on error */
\r
8466 CloseHandle(is->hFile);
\r
8471 SocketInputThread(LPVOID arg)
\r
8475 is = (InputSource *) arg;
\r
8476 while (is->hThread != NULL) {
\r
8477 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8478 if ((int)is->count == SOCKET_ERROR) {
\r
8479 is->count = (DWORD) -1;
\r
8480 is->error = WSAGetLastError();
\r
8482 is->error = NO_ERROR;
\r
8483 is->next += is->count;
\r
8484 if (is->count == 0 && is->second == is) {
\r
8485 /* End of file on stderr; quit with no message */
\r
8489 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8491 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8493 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8499 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8503 is = (InputSource *) lParam;
\r
8504 if (is->lineByLine) {
\r
8505 /* Feed in lines one by one */
\r
8506 char *p = is->buf;
\r
8508 while (q < is->next) {
\r
8509 if (*q++ == '\n') {
\r
8510 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8515 /* Move any partial line to the start of the buffer */
\r
8517 while (p < is->next) {
\r
8522 if (is->error != NO_ERROR || is->count == 0) {
\r
8523 /* Notify backend of the error. Note: If there was a partial
\r
8524 line at the end, it is not flushed through. */
\r
8525 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8528 /* Feed in the whole chunk of input at once */
\r
8529 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8530 is->next = is->buf;
\r
8534 /*---------------------------------------------------------------------------*\
\r
8536 * Menu enables. Used when setting various modes.
\r
8538 \*---------------------------------------------------------------------------*/
\r
8546 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8548 while (enab->item > 0) {
\r
8549 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8554 Enables gnuEnables[] = {
\r
8555 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8556 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8557 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8558 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8559 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8560 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8561 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8562 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8563 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8564 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8568 Enables icsEnables[] = {
\r
8569 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8570 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8571 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8572 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8573 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8574 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8575 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8576 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8577 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8578 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8579 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8580 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8585 Enables zippyEnables[] = {
\r
8586 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8587 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8588 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8593 Enables ncpEnables[] = {
\r
8594 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8595 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8596 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8597 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8598 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8599 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8600 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8601 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8602 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8603 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8604 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8605 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8606 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8607 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8608 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8612 Enables trainingOnEnables[] = {
\r
8613 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8614 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8615 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8616 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8617 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8618 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8619 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8620 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8624 Enables trainingOffEnables[] = {
\r
8625 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8626 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8627 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8628 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8629 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8630 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8631 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8632 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8636 /* These modify either ncpEnables or gnuEnables */
\r
8637 Enables cmailEnables[] = {
\r
8638 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8639 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8640 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8641 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8642 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8643 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8644 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8648 Enables machineThinkingEnables[] = {
\r
8649 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8650 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8651 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8652 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8653 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8654 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8655 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8656 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8657 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8658 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8659 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8660 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8661 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8662 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8663 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8667 Enables userThinkingEnables[] = {
\r
8668 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8669 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8670 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8671 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8672 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8673 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8674 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8675 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8676 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8677 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8678 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8679 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8680 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8681 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8682 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8686 /*---------------------------------------------------------------------------*\
\r
8688 * Front-end interface functions exported by XBoard.
\r
8689 * Functions appear in same order as prototypes in frontend.h.
\r
8691 \*---------------------------------------------------------------------------*/
\r
8695 static UINT prevChecked = 0;
\r
8696 static int prevPausing = 0;
\r
8699 if (pausing != prevPausing) {
\r
8700 prevPausing = pausing;
\r
8701 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8702 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8703 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8706 switch (gameMode) {
\r
8707 case BeginningOfGame:
\r
8708 if (appData.icsActive)
\r
8709 nowChecked = IDM_IcsClient;
\r
8710 else if (appData.noChessProgram)
\r
8711 nowChecked = IDM_EditGame;
\r
8713 nowChecked = IDM_MachineBlack;
\r
8715 case MachinePlaysBlack:
\r
8716 nowChecked = IDM_MachineBlack;
\r
8718 case MachinePlaysWhite:
\r
8719 nowChecked = IDM_MachineWhite;
\r
8721 case TwoMachinesPlay:
\r
8722 nowChecked = IDM_TwoMachines;
\r
8725 nowChecked = IDM_AnalysisMode;
\r
8728 nowChecked = IDM_AnalyzeFile;
\r
8731 nowChecked = IDM_EditGame;
\r
8733 case PlayFromGameFile:
\r
8734 nowChecked = IDM_LoadGame;
\r
8736 case EditPosition:
\r
8737 nowChecked = IDM_EditPosition;
\r
8740 nowChecked = IDM_Training;
\r
8742 case IcsPlayingWhite:
\r
8743 case IcsPlayingBlack:
\r
8744 case IcsObserving:
\r
8746 nowChecked = IDM_IcsClient;
\r
8753 if (prevChecked != 0)
\r
8754 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8755 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8756 if (nowChecked != 0)
\r
8757 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8758 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8760 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8761 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8762 MF_BYCOMMAND|MF_ENABLED);
\r
8764 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8765 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8768 prevChecked = nowChecked;
\r
8770 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8771 if (appData.icsActive) {
\r
8772 if (appData.icsEngineAnalyze) {
\r
8773 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8774 MF_BYCOMMAND|MF_CHECKED);
\r
8776 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8777 MF_BYCOMMAND|MF_UNCHECKED);
\r
8785 HMENU hmenu = GetMenu(hwndMain);
\r
8786 SetMenuEnables(hmenu, icsEnables);
\r
8787 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8788 MF_BYPOSITION|MF_ENABLED);
\r
8790 if (appData.zippyPlay) {
\r
8791 SetMenuEnables(hmenu, zippyEnables);
\r
8792 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8793 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8794 MF_BYCOMMAND|MF_ENABLED);
\r
8802 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8808 HMENU hmenu = GetMenu(hwndMain);
\r
8809 SetMenuEnables(hmenu, ncpEnables);
\r
8810 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8811 MF_BYPOSITION|MF_GRAYED);
\r
8812 DrawMenuBar(hwndMain);
\r
8818 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8822 SetTrainingModeOn()
\r
8825 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8826 for (i = 0; i < N_BUTTONS; i++) {
\r
8827 if (buttonDesc[i].hwnd != NULL)
\r
8828 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8833 VOID SetTrainingModeOff()
\r
8836 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8837 for (i = 0; i < N_BUTTONS; i++) {
\r
8838 if (buttonDesc[i].hwnd != NULL)
\r
8839 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8845 SetUserThinkingEnables()
\r
8847 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8851 SetMachineThinkingEnables()
\r
8853 HMENU hMenu = GetMenu(hwndMain);
\r
8854 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8856 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8858 if (gameMode == MachinePlaysBlack) {
\r
8859 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8860 } else if (gameMode == MachinePlaysWhite) {
\r
8861 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8862 } else if (gameMode == TwoMachinesPlay) {
\r
8863 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8869 DisplayTitle(char *str)
\r
8871 char title[MSG_SIZ], *host;
\r
8872 if (str[0] != NULLCHAR) {
\r
8873 strcpy(title, str);
\r
8874 } else if (appData.icsActive) {
\r
8875 if (appData.icsCommPort[0] != NULLCHAR)
\r
8878 host = appData.icsHost;
\r
8879 sprintf(title, "%s: %s", szTitle, host);
\r
8880 } else if (appData.noChessProgram) {
\r
8881 strcpy(title, szTitle);
\r
8883 strcpy(title, szTitle);
\r
8884 strcat(title, ": ");
\r
8885 strcat(title, first.tidy);
\r
8887 SetWindowText(hwndMain, title);
\r
8892 DisplayMessage(char *str1, char *str2)
\r
8896 int remain = MESSAGE_TEXT_MAX - 1;
\r
8899 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8900 messageText[0] = NULLCHAR;
\r
8902 len = strlen(str1);
\r
8903 if (len > remain) len = remain;
\r
8904 strncpy(messageText, str1, len);
\r
8905 messageText[len] = NULLCHAR;
\r
8908 if (*str2 && remain >= 2) {
\r
8910 strcat(messageText, " ");
\r
8913 len = strlen(str2);
\r
8914 if (len > remain) len = remain;
\r
8915 strncat(messageText, str2, len);
\r
8917 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8919 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8920 hdc = GetDC(hwndMain);
\r
8921 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8922 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8923 &messageRect, messageText, strlen(messageText), NULL);
\r
8924 (void) SelectObject(hdc, oldFont);
\r
8925 (void) ReleaseDC(hwndMain, hdc);
\r
8929 DisplayError(char *str, int error)
\r
8931 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8937 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8938 NULL, error, LANG_NEUTRAL,
\r
8939 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8941 sprintf(buf, "%s:\n%s", str, buf2);
\r
8943 ErrorMap *em = errmap;
\r
8944 while (em->err != 0 && em->err != error) em++;
\r
8945 if (em->err != 0) {
\r
8946 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8948 sprintf(buf, "%s:\nError code %d", str, error);
\r
8953 ErrorPopUp("Error", buf);
\r
8958 DisplayMoveError(char *str)
\r
8960 fromX = fromY = -1;
\r
8961 ClearHighlights();
\r
8962 DrawPosition(FALSE, NULL);
\r
8963 if (appData.popupMoveErrors) {
\r
8964 ErrorPopUp("Error", str);
\r
8966 DisplayMessage(str, "");
\r
8967 moveErrorMessageUp = TRUE;
\r
8972 DisplayFatalError(char *str, int error, int exitStatus)
\r
8974 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8976 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8979 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8980 NULL, error, LANG_NEUTRAL,
\r
8981 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8983 sprintf(buf, "%s:\n%s", str, buf2);
\r
8985 ErrorMap *em = errmap;
\r
8986 while (em->err != 0 && em->err != error) em++;
\r
8987 if (em->err != 0) {
\r
8988 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8990 sprintf(buf, "%s:\nError code %d", str, error);
\r
8995 if (appData.debugMode) {
\r
8996 fprintf(debugFP, "%s: %s\n", label, str);
\r
8998 if (appData.popupExitMessage) {
\r
8999 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
9000 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
9002 ExitEvent(exitStatus);
\r
9007 DisplayInformation(char *str)
\r
9009 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9014 DisplayNote(char *str)
\r
9016 ErrorPopUp("Note", str);
\r
9021 char *title, *question, *replyPrefix;
\r
9026 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9028 static QuestionParams *qp;
\r
9029 char reply[MSG_SIZ];
\r
9032 switch (message) {
\r
9033 case WM_INITDIALOG:
\r
9034 qp = (QuestionParams *) lParam;
\r
9035 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9036 SetWindowText(hDlg, qp->title);
\r
9037 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9038 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9042 switch (LOWORD(wParam)) {
\r
9044 strcpy(reply, qp->replyPrefix);
\r
9045 if (*reply) strcat(reply, " ");
\r
9046 len = strlen(reply);
\r
9047 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9048 strcat(reply, "\n");
\r
9049 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9050 EndDialog(hDlg, TRUE);
\r
9051 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9054 EndDialog(hDlg, FALSE);
\r
9065 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9067 QuestionParams qp;
\r
9071 qp.question = question;
\r
9072 qp.replyPrefix = replyPrefix;
\r
9074 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9075 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9076 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9077 FreeProcInstance(lpProc);
\r
9080 /* [AS] Pick FRC position */
\r
9081 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9083 static int * lpIndexFRC;
\r
9089 case WM_INITDIALOG:
\r
9090 lpIndexFRC = (int *) lParam;
\r
9092 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9094 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9095 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9096 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9097 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9102 switch( LOWORD(wParam) ) {
\r
9104 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9105 EndDialog( hDlg, 0 );
\r
9106 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9109 EndDialog( hDlg, 1 );
\r
9111 case IDC_NFG_Edit:
\r
9112 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9113 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9115 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9118 case IDC_NFG_Random:
\r
9119 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9120 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9133 int index = appData.defaultFrcPosition;
\r
9134 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9136 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9138 if( result == 0 ) {
\r
9139 appData.defaultFrcPosition = index;
\r
9145 /* [AS] Game list options */
\r
9151 static GLT_Item GLT_ItemInfo[] = {
\r
9152 { GLT_EVENT, "Event" },
\r
9153 { GLT_SITE, "Site" },
\r
9154 { GLT_DATE, "Date" },
\r
9155 { GLT_ROUND, "Round" },
\r
9156 { GLT_PLAYERS, "Players" },
\r
9157 { GLT_RESULT, "Result" },
\r
9158 { GLT_WHITE_ELO, "White Rating" },
\r
9159 { GLT_BLACK_ELO, "Black Rating" },
\r
9160 { GLT_TIME_CONTROL,"Time Control" },
\r
9161 { GLT_VARIANT, "Variant" },
\r
9162 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9166 const char * GLT_FindItem( char id )
\r
9168 const char * result = 0;
\r
9170 GLT_Item * list = GLT_ItemInfo;
\r
9172 while( list->id != 0 ) {
\r
9173 if( list->id == id ) {
\r
9174 result = list->name;
\r
9184 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9186 const char * name = GLT_FindItem( id );
\r
9189 if( index >= 0 ) {
\r
9190 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9193 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9198 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9202 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9205 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9209 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9211 pc = GLT_ALL_TAGS;
\r
9214 if( strchr( tags, *pc ) == 0 ) {
\r
9215 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9220 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9223 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9225 char result = '\0';
\r
9228 GLT_Item * list = GLT_ItemInfo;
\r
9230 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9231 while( list->id != 0 ) {
\r
9232 if( strcmp( list->name, name ) == 0 ) {
\r
9233 result = list->id;
\r
9244 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9246 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9247 int idx2 = idx1 + delta;
\r
9248 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9250 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9253 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9254 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9255 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9256 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9260 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9262 static char glt[64];
\r
9263 static char * lpUserGLT;
\r
9267 case WM_INITDIALOG:
\r
9268 lpUserGLT = (char *) lParam;
\r
9270 strcpy( glt, lpUserGLT );
\r
9272 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9274 /* Initialize list */
\r
9275 GLT_TagsToList( hDlg, glt );
\r
9277 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9282 switch( LOWORD(wParam) ) {
\r
9285 char * pc = lpUserGLT;
\r
9287 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9291 id = GLT_ListItemToTag( hDlg, idx );
\r
9295 } while( id != '\0' );
\r
9297 EndDialog( hDlg, 0 );
\r
9300 EndDialog( hDlg, 1 );
\r
9303 case IDC_GLT_Default:
\r
9304 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9305 GLT_TagsToList( hDlg, glt );
\r
9308 case IDC_GLT_Restore:
\r
9309 strcpy( glt, lpUserGLT );
\r
9310 GLT_TagsToList( hDlg, glt );
\r
9314 GLT_MoveSelection( hDlg, -1 );
\r
9317 case IDC_GLT_Down:
\r
9318 GLT_MoveSelection( hDlg, +1 );
\r
9328 int GameListOptions()
\r
9332 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9334 strcpy( glt, appData.gameListTags );
\r
9336 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9338 if( result == 0 ) {
\r
9339 /* [AS] Memory leak here! */
\r
9340 appData.gameListTags = strdup( glt );
\r
9348 DisplayIcsInteractionTitle(char *str)
\r
9350 char consoleTitle[MSG_SIZ];
\r
9352 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9353 SetWindowText(hwndConsole, consoleTitle);
\r
9357 DrawPosition(int fullRedraw, Board board)
\r
9359 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9366 fromX = fromY = -1;
\r
9367 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9368 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9369 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9370 dragInfo.lastpos = dragInfo.pos;
\r
9371 dragInfo.start.x = dragInfo.start.y = -1;
\r
9372 dragInfo.from = dragInfo.start;
\r
9374 DrawPosition(TRUE, NULL);
\r
9380 CommentPopUp(char *title, char *str)
\r
9382 HWND hwnd = GetActiveWindow();
\r
9383 EitherCommentPopUp(0, title, str, FALSE);
\r
9384 SetActiveWindow(hwnd);
\r
9388 CommentPopDown(void)
\r
9390 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9391 if (commentDialog) {
\r
9392 ShowWindow(commentDialog, SW_HIDE);
\r
9394 commentDialogUp = FALSE;
\r
9398 EditCommentPopUp(int index, char *title, char *str)
\r
9400 EitherCommentPopUp(index, title, str, TRUE);
\r
9407 MyPlaySound(&sounds[(int)SoundMove]);
\r
9410 VOID PlayIcsWinSound()
\r
9412 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9415 VOID PlayIcsLossSound()
\r
9417 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9420 VOID PlayIcsDrawSound()
\r
9422 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9425 VOID PlayIcsUnfinishedSound()
\r
9427 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9433 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9441 consoleEcho = TRUE;
\r
9442 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9443 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9444 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9453 consoleEcho = FALSE;
\r
9454 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9455 /* This works OK: set text and background both to the same color */
\r
9457 cf.crTextColor = COLOR_ECHOOFF;
\r
9458 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9459 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9462 /* No Raw()...? */
\r
9464 void Colorize(ColorClass cc, int continuation)
\r
9466 currentColorClass = cc;
\r
9467 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9468 consoleCF.crTextColor = textAttribs[cc].color;
\r
9469 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9470 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9476 static char buf[MSG_SIZ];
\r
9477 DWORD bufsiz = MSG_SIZ;
\r
9479 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9480 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9482 if (!GetUserName(buf, &bufsiz)) {
\r
9483 /*DisplayError("Error getting user name", GetLastError());*/
\r
9484 strcpy(buf, "User");
\r
9492 static char buf[MSG_SIZ];
\r
9493 DWORD bufsiz = MSG_SIZ;
\r
9495 if (!GetComputerName(buf, &bufsiz)) {
\r
9496 /*DisplayError("Error getting host name", GetLastError());*/
\r
9497 strcpy(buf, "Unknown");
\r
9504 ClockTimerRunning()
\r
9506 return clockTimerEvent != 0;
\r
9512 if (clockTimerEvent == 0) return FALSE;
\r
9513 KillTimer(hwndMain, clockTimerEvent);
\r
9514 clockTimerEvent = 0;
\r
9519 StartClockTimer(long millisec)
\r
9521 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9522 (UINT) millisec, NULL);
\r
9526 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9529 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9531 if(appData.noGUI) return;
\r
9532 hdc = GetDC(hwndMain);
\r
9533 if (!IsIconic(hwndMain)) {
\r
9534 DisplayAClock(hdc, timeRemaining, highlight,
\r
9535 (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);
\r
9537 if (highlight && iconCurrent == iconBlack) {
\r
9538 iconCurrent = iconWhite;
\r
9539 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9540 if (IsIconic(hwndMain)) {
\r
9541 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9544 (void) ReleaseDC(hwndMain, hdc);
\r
9546 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9550 DisplayBlackClock(long timeRemaining, int highlight)
\r
9553 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9555 if(appData.noGUI) return;
\r
9556 hdc = GetDC(hwndMain);
\r
9557 if (!IsIconic(hwndMain)) {
\r
9558 DisplayAClock(hdc, timeRemaining, highlight,
\r
9559 (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);
\r
9561 if (highlight && iconCurrent == iconWhite) {
\r
9562 iconCurrent = iconBlack;
\r
9563 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9564 if (IsIconic(hwndMain)) {
\r
9565 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9568 (void) ReleaseDC(hwndMain, hdc);
\r
9570 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9575 LoadGameTimerRunning()
\r
9577 return loadGameTimerEvent != 0;
\r
9581 StopLoadGameTimer()
\r
9583 if (loadGameTimerEvent == 0) return FALSE;
\r
9584 KillTimer(hwndMain, loadGameTimerEvent);
\r
9585 loadGameTimerEvent = 0;
\r
9590 StartLoadGameTimer(long millisec)
\r
9592 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9593 (UINT) millisec, NULL);
\r
9601 char fileTitle[MSG_SIZ];
\r
9603 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9604 f = OpenFileDialog(hwndMain, "a", defName,
\r
9605 appData.oldSaveStyle ? "gam" : "pgn",
\r
9607 "Save Game to File", NULL, fileTitle, NULL);
\r
9609 SaveGame(f, 0, "");
\r
9616 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9618 if (delayedTimerEvent != 0) {
\r
9619 if (appData.debugMode) {
\r
9620 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9622 KillTimer(hwndMain, delayedTimerEvent);
\r
9623 delayedTimerEvent = 0;
\r
9624 delayedTimerCallback();
\r
9626 delayedTimerCallback = cb;
\r
9627 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9628 (UINT) millisec, NULL);
\r
9631 DelayedEventCallback
\r
9634 if (delayedTimerEvent) {
\r
9635 return delayedTimerCallback;
\r
9642 CancelDelayedEvent()
\r
9644 if (delayedTimerEvent) {
\r
9645 KillTimer(hwndMain, delayedTimerEvent);
\r
9646 delayedTimerEvent = 0;
\r
9650 DWORD GetWin32Priority(int nice)
\r
9651 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9653 REALTIME_PRIORITY_CLASS 0x00000100
\r
9654 HIGH_PRIORITY_CLASS 0x00000080
\r
9655 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9656 NORMAL_PRIORITY_CLASS 0x00000020
\r
9657 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9658 IDLE_PRIORITY_CLASS 0x00000040
\r
9660 if (nice < -15) return 0x00000080;
\r
9661 if (nice < 0) return 0x00008000;
\r
9662 if (nice == 0) return 0x00000020;
\r
9663 if (nice < 15) return 0x00004000;
\r
9664 return 0x00000040;
\r
9667 /* Start a child process running the given program.
\r
9668 The process's standard output can be read from "from", and its
\r
9669 standard input can be written to "to".
\r
9670 Exit with fatal error if anything goes wrong.
\r
9671 Returns an opaque pointer that can be used to destroy the process
\r
9675 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9677 #define BUFSIZE 4096
\r
9679 HANDLE hChildStdinRd, hChildStdinWr,
\r
9680 hChildStdoutRd, hChildStdoutWr;
\r
9681 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9682 SECURITY_ATTRIBUTES saAttr;
\r
9684 PROCESS_INFORMATION piProcInfo;
\r
9685 STARTUPINFO siStartInfo;
\r
9687 char buf[MSG_SIZ];
\r
9690 if (appData.debugMode) {
\r
9691 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9696 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9697 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9698 saAttr.bInheritHandle = TRUE;
\r
9699 saAttr.lpSecurityDescriptor = NULL;
\r
9702 * The steps for redirecting child's STDOUT:
\r
9703 * 1. Create anonymous pipe to be STDOUT for child.
\r
9704 * 2. Create a noninheritable duplicate of read handle,
\r
9705 * and close the inheritable read handle.
\r
9708 /* Create a pipe for the child's STDOUT. */
\r
9709 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9710 return GetLastError();
\r
9713 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9714 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9715 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9716 FALSE, /* not inherited */
\r
9717 DUPLICATE_SAME_ACCESS);
\r
9719 return GetLastError();
\r
9721 CloseHandle(hChildStdoutRd);
\r
9724 * The steps for redirecting child's STDIN:
\r
9725 * 1. Create anonymous pipe to be STDIN for child.
\r
9726 * 2. Create a noninheritable duplicate of write handle,
\r
9727 * and close the inheritable write handle.
\r
9730 /* Create a pipe for the child's STDIN. */
\r
9731 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9732 return GetLastError();
\r
9735 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9736 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9737 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9738 FALSE, /* not inherited */
\r
9739 DUPLICATE_SAME_ACCESS);
\r
9741 return GetLastError();
\r
9743 CloseHandle(hChildStdinWr);
\r
9745 /* Arrange to (1) look in dir for the child .exe file, and
\r
9746 * (2) have dir be the child's working directory. Interpret
\r
9747 * dir relative to the directory WinBoard loaded from. */
\r
9748 GetCurrentDirectory(MSG_SIZ, buf);
\r
9749 SetCurrentDirectory(installDir);
\r
9750 SetCurrentDirectory(dir);
\r
9752 /* Now create the child process. */
\r
9754 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9755 siStartInfo.lpReserved = NULL;
\r
9756 siStartInfo.lpDesktop = NULL;
\r
9757 siStartInfo.lpTitle = NULL;
\r
9758 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9759 siStartInfo.cbReserved2 = 0;
\r
9760 siStartInfo.lpReserved2 = NULL;
\r
9761 siStartInfo.hStdInput = hChildStdinRd;
\r
9762 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9763 siStartInfo.hStdError = hChildStdoutWr;
\r
9765 fSuccess = CreateProcess(NULL,
\r
9766 cmdLine, /* command line */
\r
9767 NULL, /* process security attributes */
\r
9768 NULL, /* primary thread security attrs */
\r
9769 TRUE, /* handles are inherited */
\r
9770 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9771 NULL, /* use parent's environment */
\r
9773 &siStartInfo, /* STARTUPINFO pointer */
\r
9774 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9776 err = GetLastError();
\r
9777 SetCurrentDirectory(buf); /* return to prev directory */
\r
9782 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9783 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9784 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9787 /* Close the handles we don't need in the parent */
\r
9788 CloseHandle(piProcInfo.hThread);
\r
9789 CloseHandle(hChildStdinRd);
\r
9790 CloseHandle(hChildStdoutWr);
\r
9792 /* Prepare return value */
\r
9793 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9794 cp->kind = CPReal;
\r
9795 cp->hProcess = piProcInfo.hProcess;
\r
9796 cp->pid = piProcInfo.dwProcessId;
\r
9797 cp->hFrom = hChildStdoutRdDup;
\r
9798 cp->hTo = hChildStdinWrDup;
\r
9800 *pr = (void *) cp;
\r
9802 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9803 2000 where engines sometimes don't see the initial command(s)
\r
9804 from WinBoard and hang. I don't understand how that can happen,
\r
9805 but the Sleep is harmless, so I've put it in. Others have also
\r
9806 reported what may be the same problem, so hopefully this will fix
\r
9807 it for them too. */
\r
9815 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9817 ChildProc *cp; int result;
\r
9819 cp = (ChildProc *) pr;
\r
9820 if (cp == NULL) return;
\r
9822 switch (cp->kind) {
\r
9824 /* TerminateProcess is considered harmful, so... */
\r
9825 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9826 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9827 /* The following doesn't work because the chess program
\r
9828 doesn't "have the same console" as WinBoard. Maybe
\r
9829 we could arrange for this even though neither WinBoard
\r
9830 nor the chess program uses a console for stdio? */
\r
9831 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9833 /* [AS] Special termination modes for misbehaving programs... */
\r
9834 if( signal == 9 ) {
\r
9835 result = TerminateProcess( cp->hProcess, 0 );
\r
9837 if ( appData.debugMode) {
\r
9838 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9841 else if( signal == 10 ) {
\r
9842 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9844 if( dw != WAIT_OBJECT_0 ) {
\r
9845 result = TerminateProcess( cp->hProcess, 0 );
\r
9847 if ( appData.debugMode) {
\r
9848 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9854 CloseHandle(cp->hProcess);
\r
9858 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9862 closesocket(cp->sock);
\r
9867 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9868 closesocket(cp->sock);
\r
9869 closesocket(cp->sock2);
\r
9877 InterruptChildProcess(ProcRef pr)
\r
9881 cp = (ChildProc *) pr;
\r
9882 if (cp == NULL) return;
\r
9883 switch (cp->kind) {
\r
9885 /* The following doesn't work because the chess program
\r
9886 doesn't "have the same console" as WinBoard. Maybe
\r
9887 we could arrange for this even though neither WinBoard
\r
9888 nor the chess program uses a console for stdio */
\r
9889 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9894 /* Can't interrupt */
\r
9898 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9905 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9907 char cmdLine[MSG_SIZ];
\r
9909 if (port[0] == NULLCHAR) {
\r
9910 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9912 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9914 return StartChildProcess(cmdLine, "", pr);
\r
9918 /* Code to open TCP sockets */
\r
9921 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9926 struct sockaddr_in sa, mysa;
\r
9927 struct hostent FAR *hp;
\r
9928 unsigned short uport;
\r
9929 WORD wVersionRequested;
\r
9932 /* Initialize socket DLL */
\r
9933 wVersionRequested = MAKEWORD(1, 1);
\r
9934 err = WSAStartup(wVersionRequested, &wsaData);
\r
9935 if (err != 0) return err;
\r
9938 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9939 err = WSAGetLastError();
\r
9944 /* Bind local address using (mostly) don't-care values.
\r
9946 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9947 mysa.sin_family = AF_INET;
\r
9948 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9949 uport = (unsigned short) 0;
\r
9950 mysa.sin_port = htons(uport);
\r
9951 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9952 == SOCKET_ERROR) {
\r
9953 err = WSAGetLastError();
\r
9958 /* Resolve remote host name */
\r
9959 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9960 if (!(hp = gethostbyname(host))) {
\r
9961 unsigned int b0, b1, b2, b3;
\r
9963 err = WSAGetLastError();
\r
9965 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9966 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9967 hp->h_addrtype = AF_INET;
\r
9969 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9970 hp->h_addr_list[0] = (char *) malloc(4);
\r
9971 hp->h_addr_list[0][0] = (char) b0;
\r
9972 hp->h_addr_list[0][1] = (char) b1;
\r
9973 hp->h_addr_list[0][2] = (char) b2;
\r
9974 hp->h_addr_list[0][3] = (char) b3;
\r
9980 sa.sin_family = hp->h_addrtype;
\r
9981 uport = (unsigned short) atoi(port);
\r
9982 sa.sin_port = htons(uport);
\r
9983 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9985 /* Make connection */
\r
9986 if (connect(s, (struct sockaddr *) &sa,
\r
9987 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9988 err = WSAGetLastError();
\r
9993 /* Prepare return value */
\r
9994 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9995 cp->kind = CPSock;
\r
9997 *pr = (ProcRef *) cp;
\r
10003 OpenCommPort(char *name, ProcRef *pr)
\r
10008 char fullname[MSG_SIZ];
\r
10010 if (*name != '\\')
\r
10011 sprintf(fullname, "\\\\.\\%s", name);
\r
10013 strcpy(fullname, name);
\r
10015 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10016 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10017 if (h == (HANDLE) -1) {
\r
10018 return GetLastError();
\r
10022 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10024 /* Accumulate characters until a 100ms pause, then parse */
\r
10025 ct.ReadIntervalTimeout = 100;
\r
10026 ct.ReadTotalTimeoutMultiplier = 0;
\r
10027 ct.ReadTotalTimeoutConstant = 0;
\r
10028 ct.WriteTotalTimeoutMultiplier = 0;
\r
10029 ct.WriteTotalTimeoutConstant = 0;
\r
10030 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10032 /* Prepare return value */
\r
10033 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10034 cp->kind = CPComm;
\r
10037 *pr = (ProcRef *) cp;
\r
10043 OpenLoopback(ProcRef *pr)
\r
10045 DisplayFatalError("Not implemented", 0, 1);
\r
10051 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10055 SOCKET s, s2, s3;
\r
10056 struct sockaddr_in sa, mysa;
\r
10057 struct hostent FAR *hp;
\r
10058 unsigned short uport;
\r
10059 WORD wVersionRequested;
\r
10062 char stderrPortStr[MSG_SIZ];
\r
10064 /* Initialize socket DLL */
\r
10065 wVersionRequested = MAKEWORD(1, 1);
\r
10066 err = WSAStartup(wVersionRequested, &wsaData);
\r
10067 if (err != 0) return err;
\r
10069 /* Resolve remote host name */
\r
10070 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10071 if (!(hp = gethostbyname(host))) {
\r
10072 unsigned int b0, b1, b2, b3;
\r
10074 err = WSAGetLastError();
\r
10076 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10077 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10078 hp->h_addrtype = AF_INET;
\r
10079 hp->h_length = 4;
\r
10080 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10081 hp->h_addr_list[0] = (char *) malloc(4);
\r
10082 hp->h_addr_list[0][0] = (char) b0;
\r
10083 hp->h_addr_list[0][1] = (char) b1;
\r
10084 hp->h_addr_list[0][2] = (char) b2;
\r
10085 hp->h_addr_list[0][3] = (char) b3;
\r
10091 sa.sin_family = hp->h_addrtype;
\r
10092 uport = (unsigned short) 514;
\r
10093 sa.sin_port = htons(uport);
\r
10094 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10096 /* Bind local socket to unused "privileged" port address
\r
10098 s = INVALID_SOCKET;
\r
10099 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10100 mysa.sin_family = AF_INET;
\r
10101 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10102 for (fromPort = 1023;; fromPort--) {
\r
10103 if (fromPort < 0) {
\r
10105 return WSAEADDRINUSE;
\r
10107 if (s == INVALID_SOCKET) {
\r
10108 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10109 err = WSAGetLastError();
\r
10114 uport = (unsigned short) fromPort;
\r
10115 mysa.sin_port = htons(uport);
\r
10116 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10117 == SOCKET_ERROR) {
\r
10118 err = WSAGetLastError();
\r
10119 if (err == WSAEADDRINUSE) continue;
\r
10123 if (connect(s, (struct sockaddr *) &sa,
\r
10124 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10125 err = WSAGetLastError();
\r
10126 if (err == WSAEADDRINUSE) {
\r
10137 /* Bind stderr local socket to unused "privileged" port address
\r
10139 s2 = INVALID_SOCKET;
\r
10140 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10141 mysa.sin_family = AF_INET;
\r
10142 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10143 for (fromPort = 1023;; fromPort--) {
\r
10144 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10145 if (fromPort < 0) {
\r
10146 (void) closesocket(s);
\r
10148 return WSAEADDRINUSE;
\r
10150 if (s2 == INVALID_SOCKET) {
\r
10151 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10152 err = WSAGetLastError();
\r
10158 uport = (unsigned short) fromPort;
\r
10159 mysa.sin_port = htons(uport);
\r
10160 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10161 == SOCKET_ERROR) {
\r
10162 err = WSAGetLastError();
\r
10163 if (err == WSAEADDRINUSE) continue;
\r
10164 (void) closesocket(s);
\r
10168 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10169 err = WSAGetLastError();
\r
10170 if (err == WSAEADDRINUSE) {
\r
10172 s2 = INVALID_SOCKET;
\r
10175 (void) closesocket(s);
\r
10176 (void) closesocket(s2);
\r
10182 prevStderrPort = fromPort; // remember port used
\r
10183 sprintf(stderrPortStr, "%d", fromPort);
\r
10185 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10186 err = WSAGetLastError();
\r
10187 (void) closesocket(s);
\r
10188 (void) closesocket(s2);
\r
10193 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10194 err = WSAGetLastError();
\r
10195 (void) closesocket(s);
\r
10196 (void) closesocket(s2);
\r
10200 if (*user == NULLCHAR) user = UserName();
\r
10201 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10202 err = WSAGetLastError();
\r
10203 (void) closesocket(s);
\r
10204 (void) closesocket(s2);
\r
10208 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10209 err = WSAGetLastError();
\r
10210 (void) closesocket(s);
\r
10211 (void) closesocket(s2);
\r
10216 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10217 err = WSAGetLastError();
\r
10218 (void) closesocket(s);
\r
10219 (void) closesocket(s2);
\r
10223 (void) closesocket(s2); /* Stop listening */
\r
10225 /* Prepare return value */
\r
10226 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10227 cp->kind = CPRcmd;
\r
10230 *pr = (ProcRef *) cp;
\r
10237 AddInputSource(ProcRef pr, int lineByLine,
\r
10238 InputCallback func, VOIDSTAR closure)
\r
10240 InputSource *is, *is2 = NULL;
\r
10241 ChildProc *cp = (ChildProc *) pr;
\r
10243 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10244 is->lineByLine = lineByLine;
\r
10246 is->closure = closure;
\r
10247 is->second = NULL;
\r
10248 is->next = is->buf;
\r
10249 if (pr == NoProc) {
\r
10250 is->kind = CPReal;
\r
10251 consoleInputSource = is;
\r
10253 is->kind = cp->kind;
\r
10255 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10256 we create all threads suspended so that the is->hThread variable can be
\r
10257 safely assigned, then let the threads start with ResumeThread.
\r
10259 switch (cp->kind) {
\r
10261 is->hFile = cp->hFrom;
\r
10262 cp->hFrom = NULL; /* now owned by InputThread */
\r
10264 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10265 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10269 is->hFile = cp->hFrom;
\r
10270 cp->hFrom = NULL; /* now owned by InputThread */
\r
10272 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10273 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10277 is->sock = cp->sock;
\r
10279 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10280 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10284 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10286 is->sock = cp->sock;
\r
10287 is->second = is2;
\r
10288 is2->sock = cp->sock2;
\r
10289 is2->second = is2;
\r
10291 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10292 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10294 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10295 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10299 if( is->hThread != NULL ) {
\r
10300 ResumeThread( is->hThread );
\r
10303 if( is2 != NULL && is2->hThread != NULL ) {
\r
10304 ResumeThread( is2->hThread );
\r
10308 return (InputSourceRef) is;
\r
10312 RemoveInputSource(InputSourceRef isr)
\r
10316 is = (InputSource *) isr;
\r
10317 is->hThread = NULL; /* tell thread to stop */
\r
10318 CloseHandle(is->hThread);
\r
10319 if (is->second != NULL) {
\r
10320 is->second->hThread = NULL;
\r
10321 CloseHandle(is->second->hThread);
\r
10327 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10330 int outCount = SOCKET_ERROR;
\r
10331 ChildProc *cp = (ChildProc *) pr;
\r
10332 static OVERLAPPED ovl;
\r
10334 if (pr == NoProc) {
\r
10335 ConsoleOutput(message, count, FALSE);
\r
10339 if (ovl.hEvent == NULL) {
\r
10340 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10342 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10344 switch (cp->kind) {
\r
10347 outCount = send(cp->sock, message, count, 0);
\r
10348 if (outCount == SOCKET_ERROR) {
\r
10349 *outError = WSAGetLastError();
\r
10351 *outError = NO_ERROR;
\r
10356 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10357 &dOutCount, NULL)) {
\r
10358 *outError = NO_ERROR;
\r
10359 outCount = (int) dOutCount;
\r
10361 *outError = GetLastError();
\r
10366 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10367 &dOutCount, &ovl);
\r
10368 if (*outError == NO_ERROR) {
\r
10369 outCount = (int) dOutCount;
\r
10377 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10380 /* Ignore delay, not implemented for WinBoard */
\r
10381 return OutputToProcess(pr, message, count, outError);
\r
10386 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10387 char *buf, int count, int error)
\r
10389 DisplayFatalError("Not implemented", 0, 1);
\r
10392 /* see wgamelist.c for Game List functions */
\r
10393 /* see wedittags.c for Edit Tags functions */
\r
10400 char buf[MSG_SIZ];
\r
10403 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10404 f = fopen(buf, "r");
\r
10406 ProcessICSInitScript(f);
\r
10414 StartAnalysisClock()
\r
10416 if (analysisTimerEvent) return;
\r
10417 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10418 (UINT) 2000, NULL);
\r
10422 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10424 static HANDLE hwndText;
\r
10426 static int sizeX, sizeY;
\r
10427 int newSizeX, newSizeY, flags;
\r
10430 switch (message) {
\r
10431 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10432 /* Initialize the dialog items */
\r
10433 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10434 SetWindowText(hDlg, analysisTitle);
\r
10435 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10436 /* Size and position the dialog */
\r
10437 if (!analysisDialog) {
\r
10438 analysisDialog = hDlg;
\r
10439 flags = SWP_NOZORDER;
\r
10440 GetClientRect(hDlg, &rect);
\r
10441 sizeX = rect.right;
\r
10442 sizeY = rect.bottom;
\r
10443 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10444 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10445 WINDOWPLACEMENT wp;
\r
10446 EnsureOnScreen(&analysisX, &analysisY);
\r
10447 wp.length = sizeof(WINDOWPLACEMENT);
\r
10449 wp.showCmd = SW_SHOW;
\r
10450 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10451 wp.rcNormalPosition.left = analysisX;
\r
10452 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10453 wp.rcNormalPosition.top = analysisY;
\r
10454 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10455 SetWindowPlacement(hDlg, &wp);
\r
10457 GetClientRect(hDlg, &rect);
\r
10458 newSizeX = rect.right;
\r
10459 newSizeY = rect.bottom;
\r
10460 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10461 newSizeX, newSizeY);
\r
10462 sizeX = newSizeX;
\r
10463 sizeY = newSizeY;
\r
10468 case WM_COMMAND: /* message: received a command */
\r
10469 switch (LOWORD(wParam)) {
\r
10471 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10472 ExitAnalyzeMode();
\r
10484 newSizeX = LOWORD(lParam);
\r
10485 newSizeY = HIWORD(lParam);
\r
10486 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10487 sizeX = newSizeX;
\r
10488 sizeY = newSizeY;
\r
10491 case WM_GETMINMAXINFO:
\r
10492 /* Prevent resizing window too small */
\r
10493 mmi = (MINMAXINFO *) lParam;
\r
10494 mmi->ptMinTrackSize.x = 100;
\r
10495 mmi->ptMinTrackSize.y = 100;
\r
10502 AnalysisPopUp(char* title, char* str)
\r
10508 EngineOutputPopUp();
\r
10511 if (str == NULL) str = "";
\r
10512 p = (char *) malloc(2 * strlen(str) + 2);
\r
10515 if (*str == '\n') *q++ = '\r';
\r
10519 if (analysisText != NULL) free(analysisText);
\r
10520 analysisText = p;
\r
10522 if (analysisDialog) {
\r
10523 SetWindowText(analysisDialog, title);
\r
10524 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10525 ShowWindow(analysisDialog, SW_SHOW);
\r
10527 analysisTitle = title;
\r
10528 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10529 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10530 hwndMain, (DLGPROC)lpProc);
\r
10531 FreeProcInstance(lpProc);
\r
10533 analysisDialogUp = TRUE;
\r
10537 AnalysisPopDown()
\r
10539 if (analysisDialog) {
\r
10540 ShowWindow(analysisDialog, SW_HIDE);
\r
10542 analysisDialogUp = FALSE;
\r
10547 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10549 highlightInfo.sq[0].x = fromX;
\r
10550 highlightInfo.sq[0].y = fromY;
\r
10551 highlightInfo.sq[1].x = toX;
\r
10552 highlightInfo.sq[1].y = toY;
\r
10556 ClearHighlights()
\r
10558 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10559 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10563 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10565 premoveHighlightInfo.sq[0].x = fromX;
\r
10566 premoveHighlightInfo.sq[0].y = fromY;
\r
10567 premoveHighlightInfo.sq[1].x = toX;
\r
10568 premoveHighlightInfo.sq[1].y = toY;
\r
10572 ClearPremoveHighlights()
\r
10574 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10575 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10579 ShutDownFrontEnd()
\r
10581 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10582 DeleteClipboardTempFiles();
\r
10588 if (IsIconic(hwndMain))
\r
10589 ShowWindow(hwndMain, SW_RESTORE);
\r
10591 SetActiveWindow(hwndMain);
\r
10595 * Prototypes for animation support routines
\r
10597 static void ScreenSquare(int column, int row, POINT * pt);
\r
10598 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10599 POINT frames[], int * nFrames);
\r
10603 AnimateAtomicCapture(int fromX, int fromY, int toX, int toY, int nFrames)
\r
10604 { // [HGM] atomic: animate blast wave
\r
10606 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10607 explodeInfo.fromX = fromX;
\r
10608 explodeInfo.fromY = fromY;
\r
10609 explodeInfo.toX = toX;
\r
10610 explodeInfo.toY = toY;
\r
10611 for(i=1; i<nFrames; i++) {
\r
10612 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10613 DrawPosition(FALSE, NULL);
\r
10614 Sleep(appData.animSpeed);
\r
10616 explodeInfo.radius = 0;
\r
10617 DrawPosition(TRUE, NULL);
\r
10620 #define kFactor 4
\r
10623 AnimateMove(board, fromX, fromY, toX, toY)
\r
10630 ChessSquare piece;
\r
10631 POINT start, finish, mid;
\r
10632 POINT frames[kFactor * 2 + 1];
\r
10635 if (!appData.animate) return;
\r
10636 if (doingSizing) return;
\r
10637 if (fromY < 0 || fromX < 0) return;
\r
10638 piece = board[fromY][fromX];
\r
10639 if (piece >= EmptySquare) return;
\r
10641 ScreenSquare(fromX, fromY, &start);
\r
10642 ScreenSquare(toX, toY, &finish);
\r
10644 /* All pieces except knights move in straight line */
\r
10645 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10646 mid.x = start.x + (finish.x - start.x) / 2;
\r
10647 mid.y = start.y + (finish.y - start.y) / 2;
\r
10649 /* Knight: make diagonal movement then straight */
\r
10650 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10651 mid.x = start.x + (finish.x - start.x) / 2;
\r
10652 mid.y = finish.y;
\r
10654 mid.x = finish.x;
\r
10655 mid.y = start.y + (finish.y - start.y) / 2;
\r
10659 /* Don't use as many frames for very short moves */
\r
10660 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10661 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10663 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10665 animInfo.from.x = fromX;
\r
10666 animInfo.from.y = fromY;
\r
10667 animInfo.to.x = toX;
\r
10668 animInfo.to.y = toY;
\r
10669 animInfo.lastpos = start;
\r
10670 animInfo.piece = piece;
\r
10671 for (n = 0; n < nFrames; n++) {
\r
10672 animInfo.pos = frames[n];
\r
10673 DrawPosition(FALSE, NULL);
\r
10674 animInfo.lastpos = animInfo.pos;
\r
10675 Sleep(appData.animSpeed);
\r
10677 animInfo.pos = finish;
\r
10678 DrawPosition(FALSE, NULL);
\r
10679 animInfo.piece = EmptySquare;
\r
10680 if(gameInfo.variant == VariantAtomic &&
\r
10681 (board[toY][toX] != EmptySquare || fromX != toX && (piece == WhitePawn || piece == BlackPawn) ) )
\r
10682 AnimateAtomicCapture(fromX, fromY, toX, toY, 2*nFrames);
\r
10685 /* Convert board position to corner of screen rect and color */
\r
10688 ScreenSquare(column, row, pt)
\r
10689 int column; int row; POINT * pt;
\r
10692 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10693 pt->y = lineGap + row * (squareSize + lineGap);
\r
10695 pt->x = lineGap + column * (squareSize + lineGap);
\r
10696 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10700 /* Generate a series of frame coords from start->mid->finish.
\r
10701 The movement rate doubles until the half way point is
\r
10702 reached, then halves back down to the final destination,
\r
10703 which gives a nice slow in/out effect. The algorithmn
\r
10704 may seem to generate too many intermediates for short
\r
10705 moves, but remember that the purpose is to attract the
\r
10706 viewers attention to the piece about to be moved and
\r
10707 then to where it ends up. Too few frames would be less
\r
10711 Tween(start, mid, finish, factor, frames, nFrames)
\r
10712 POINT * start; POINT * mid;
\r
10713 POINT * finish; int factor;
\r
10714 POINT frames[]; int * nFrames;
\r
10716 int n, fraction = 1, count = 0;
\r
10718 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10719 for (n = 0; n < factor; n++)
\r
10721 for (n = 0; n < factor; n++) {
\r
10722 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10723 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10725 fraction = fraction / 2;
\r
10729 frames[count] = *mid;
\r
10732 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10734 for (n = 0; n < factor; n++) {
\r
10735 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10736 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10738 fraction = fraction * 2;
\r
10740 *nFrames = count;
\r
10744 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10749 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10750 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10752 OutputDebugString( buf );
\r
10755 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10757 EvalGraphSet( first, last, current, pvInfoList );
\r
10760 void SetProgramStats( FrontEndProgramStats * stats )
\r
10765 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10766 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10768 OutputDebugString( buf );
\r
10771 EngineOutputUpdate( stats );
\r