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 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
138 static ExplodeInfo explodeInfo = {0, 0, 0};
\r
140 /* Window class names */
\r
141 char szAppName[] = "WinBoard";
\r
142 char szConsoleName[] = "WBConsole";
\r
144 /* Title bar text */
\r
145 char szTitle[] = "WinBoard";
\r
146 char szConsoleTitle[] = "ICS Interaction";
\r
149 char *settingsFileName;
\r
150 BOOLEAN saveSettingsOnExit;
\r
151 char installDir[MSG_SIZ];
\r
153 BoardSize boardSize;
\r
154 BOOLEAN chessProgram;
\r
155 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
156 static int squareSize, lineGap, minorSize;
\r
157 static int winWidth, winHeight;
\r
158 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
159 static int logoHeight = 0;
\r
160 static char messageText[MESSAGE_TEXT_MAX];
\r
161 static int clockTimerEvent = 0;
\r
162 static int loadGameTimerEvent = 0;
\r
163 static int analysisTimerEvent = 0;
\r
164 static DelayedEventCallback delayedTimerCallback;
\r
165 static int delayedTimerEvent = 0;
\r
166 static int buttonCount = 2;
\r
167 char *icsTextMenuString;
\r
169 char *firstChessProgramNames;
\r
170 char *secondChessProgramNames;
\r
172 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
174 #define PALETTESIZE 256
\r
176 HINSTANCE hInst; /* current instance */
\r
177 HWND hwndMain = NULL; /* root window*/
\r
178 HWND hwndConsole = NULL;
\r
179 BOOLEAN alwaysOnTop = FALSE;
\r
181 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
182 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
184 ColorClass currentColorClass;
\r
186 HWND hCommPort = NULL; /* currently open comm port */
\r
187 static HWND hwndPause; /* pause button */
\r
188 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
189 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
190 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
191 explodeBrush, /* [HGM] atomic */
\r
192 whitePieceBrush, blackPieceBrush, iconBkgndBrush /*, outlineBrush*/;
\r
193 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
194 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
195 static HPEN gridPen = NULL;
\r
196 static HPEN highlightPen = NULL;
\r
197 static HPEN premovePen = NULL;
\r
198 static NPLOGPALETTE pLogPal;
\r
199 static BOOL paletteChanged = FALSE;
\r
200 static HICON iconWhite, iconBlack, iconCurrent;
\r
201 static int doingSizing = FALSE;
\r
202 static int lastSizing = 0;
\r
203 static int prevStderrPort;
\r
205 /* [AS] Support for background textures */
\r
206 #define BACK_TEXTURE_MODE_DISABLED 0
\r
207 #define BACK_TEXTURE_MODE_PLAIN 1
\r
208 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
210 static HBITMAP liteBackTexture = NULL;
\r
211 static HBITMAP darkBackTexture = NULL;
\r
212 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
213 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
214 static int backTextureSquareSize = 0;
\r
215 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
217 #if __GNUC__ && !defined(_winmajor)
\r
218 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
220 #define oldDialog (_winmajor < 4)
\r
223 char *defaultTextAttribs[] =
\r
225 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
226 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
236 int cliWidth, cliHeight;
\r
239 SizeInfo sizeInfo[] =
\r
241 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
242 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
243 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
244 { "petite", 33, 1, 1, 1, 0, 0 },
\r
245 { "slim", 37, 2, 1, 0, 0, 0 },
\r
246 { "small", 40, 2, 1, 0, 0, 0 },
\r
247 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
248 { "middling", 49, 2, 0, 0, 0, 0 },
\r
249 { "average", 54, 2, 0, 0, 0, 0 },
\r
250 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
251 { "medium", 64, 3, 0, 0, 0, 0 },
\r
252 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
253 { "large", 80, 3, 0, 0, 0, 0 },
\r
254 { "big", 87, 3, 0, 0, 0, 0 },
\r
255 { "huge", 95, 3, 0, 0, 0, 0 },
\r
256 { "giant", 108, 3, 0, 0, 0, 0 },
\r
257 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
258 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
259 { NULL, 0, 0, 0, 0, 0, 0 }
\r
262 #define MF(x) {x, {{0,}, 0. }, {0, }, 0}
\r
263 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
265 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
266 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
267 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
268 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
269 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
270 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
271 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
272 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
273 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
274 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
275 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
276 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
277 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
278 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
279 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
280 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
281 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
282 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
285 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
294 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
295 #define N_BUTTONS 5
\r
297 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
299 {"<<", IDM_ToStart, NULL, NULL},
\r
300 {"<", IDM_Backward, NULL, NULL},
\r
301 {"P", IDM_Pause, NULL, NULL},
\r
302 {">", IDM_Forward, NULL, NULL},
\r
303 {">>", IDM_ToEnd, NULL, NULL},
\r
306 int tinyLayout = 0, smallLayout = 0;
\r
307 #define MENU_BAR_ITEMS 6
\r
308 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
309 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
310 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
314 MySound sounds[(int)NSoundClasses];
\r
315 MyTextAttribs textAttribs[(int)NColorClasses];
\r
317 MyColorizeAttribs colorizeAttribs[] = {
\r
318 { (COLORREF)0, 0, "Shout Text" },
\r
319 { (COLORREF)0, 0, "SShout/CShout" },
\r
320 { (COLORREF)0, 0, "Channel 1 Text" },
\r
321 { (COLORREF)0, 0, "Channel Text" },
\r
322 { (COLORREF)0, 0, "Kibitz Text" },
\r
323 { (COLORREF)0, 0, "Tell Text" },
\r
324 { (COLORREF)0, 0, "Challenge Text" },
\r
325 { (COLORREF)0, 0, "Request Text" },
\r
326 { (COLORREF)0, 0, "Seek Text" },
\r
327 { (COLORREF)0, 0, "Normal Text" },
\r
328 { (COLORREF)0, 0, "None" }
\r
333 static char *commentTitle;
\r
334 static char *commentText;
\r
335 static int commentIndex;
\r
336 static Boolean editComment = FALSE;
\r
337 HWND commentDialog = NULL;
\r
338 BOOLEAN commentDialogUp = FALSE;
\r
339 static int commentX, commentY, commentH, commentW;
\r
341 static char *analysisTitle;
\r
342 static char *analysisText;
\r
343 HWND analysisDialog = NULL;
\r
344 BOOLEAN analysisDialogUp = FALSE;
\r
345 static int analysisX, analysisY, analysisH, analysisW;
\r
347 char errorTitle[MSG_SIZ];
\r
348 char errorMessage[2*MSG_SIZ];
\r
349 HWND errorDialog = NULL;
\r
350 BOOLEAN moveErrorMessageUp = FALSE;
\r
351 BOOLEAN consoleEcho = TRUE;
\r
352 CHARFORMAT consoleCF;
\r
353 COLORREF consoleBackgroundColor;
\r
355 char *programVersion;
\r
361 typedef int CPKind;
\r
370 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
373 #define INPUT_SOURCE_BUF_SIZE 4096
\r
375 typedef struct _InputSource {
\r
382 char buf[INPUT_SOURCE_BUF_SIZE];
\r
386 InputCallback func;
\r
387 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
391 InputSource *consoleInputSource;
\r
396 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
397 VOID ConsoleCreate();
\r
399 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
400 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
401 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
402 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
404 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
405 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
406 void ParseIcsTextMenu(char *icsTextMenuString);
\r
407 VOID PopUpMoveDialog(char firstchar);
\r
408 VOID PopUpNameDialog(char firstchar);
\r
409 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
413 int GameListOptions();
\r
415 HWND moveHistoryDialog = NULL;
\r
416 BOOLEAN moveHistoryDialogUp = FALSE;
\r
418 WindowPlacement wpMoveHistory;
\r
420 HWND evalGraphDialog = NULL;
\r
421 BOOLEAN evalGraphDialogUp = FALSE;
\r
423 WindowPlacement wpEvalGraph;
\r
425 HWND engineOutputDialog = NULL;
\r
426 BOOLEAN engineOutputDialogUp = FALSE;
\r
428 WindowPlacement wpEngineOutput;
\r
430 VOID MoveHistoryPopUp();
\r
431 VOID MoveHistoryPopDown();
\r
432 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
433 BOOL MoveHistoryIsUp();
\r
435 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
436 VOID EvalGraphPopUp();
\r
437 VOID EvalGraphPopDown();
\r
438 BOOL EvalGraphIsUp();
\r
440 VOID EngineOutputPopUp();
\r
441 VOID EngineOutputPopDown();
\r
442 BOOL EngineOutputIsUp();
\r
443 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
445 VOID GothicPopUp(char *title, VariantClass variant);
\r
447 * Setting "frozen" should disable all user input other than deleting
\r
448 * the window. We do this while engines are initializing themselves.
\r
450 static int frozen = 0;
\r
451 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
457 if (frozen) return;
\r
459 hmenu = GetMenu(hwndMain);
\r
460 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
461 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
463 DrawMenuBar(hwndMain);
\r
466 /* Undo a FreezeUI */
\r
472 if (!frozen) return;
\r
474 hmenu = GetMenu(hwndMain);
\r
475 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
476 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
478 DrawMenuBar(hwndMain);
\r
481 /*---------------------------------------------------------------------------*\
\r
485 \*---------------------------------------------------------------------------*/
\r
488 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
489 LPSTR lpCmdLine, int nCmdShow)
\r
492 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
493 // INITCOMMONCONTROLSEX ex;
\r
497 LoadLibrary("RICHED32.DLL");
\r
498 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
500 if (!InitApplication(hInstance)) {
\r
503 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
507 // InitCommonControlsEx(&ex);
\r
508 InitCommonControls();
\r
510 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
511 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
512 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
514 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
516 while (GetMessage(&msg, /* message structure */
\r
517 NULL, /* handle of window receiving the message */
\r
518 0, /* lowest message to examine */
\r
519 0)) /* highest message to examine */
\r
521 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
522 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
523 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
524 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
525 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
526 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
527 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
528 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
529 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
530 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
531 TranslateMessage(&msg); /* Translates virtual key codes */
\r
532 DispatchMessage(&msg); /* Dispatches message to window */
\r
537 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
540 /*---------------------------------------------------------------------------*\
\r
542 * Initialization functions
\r
544 \*---------------------------------------------------------------------------*/
\r
547 InitApplication(HINSTANCE hInstance)
\r
551 /* Fill in window class structure with parameters that describe the */
\r
554 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
555 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
556 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
557 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
558 wc.hInstance = hInstance; /* Owner of this class */
\r
559 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
560 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
561 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
562 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
563 wc.lpszClassName = szAppName; /* Name to register as */
\r
565 /* Register the window class and return success/failure code. */
\r
566 if (!RegisterClass(&wc)) return FALSE;
\r
568 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
569 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
571 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
572 wc.hInstance = hInstance;
\r
573 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
574 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
575 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
576 wc.lpszMenuName = NULL;
\r
577 wc.lpszClassName = szConsoleName;
\r
579 if (!RegisterClass(&wc)) return FALSE;
\r
584 /* Set by InitInstance, used by EnsureOnScreen */
\r
585 int screenHeight, screenWidth;
\r
588 EnsureOnScreen(int *x, int *y)
\r
590 // int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
591 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
592 if (*x > screenWidth - 32) *x = 0;
\r
593 if (*y > screenHeight - 32) *y = 0;
\r
594 if (*x < 0) *x = 0;
\r
595 if (*y < 0) *y = 0;
\r
596 // if (*x < 10) *x = 10;
\r
597 // if (*y < gap) *y = gap;
\r
601 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
603 HWND hwnd; /* Main window handle. */
\r
605 WINDOWPLACEMENT wp;
\r
608 hInst = hInstance; /* Store instance handle in our global variable */
\r
610 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
611 *filepart = NULLCHAR;
\r
613 GetCurrentDirectory(MSG_SIZ, installDir);
\r
615 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
616 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
617 if (appData.debugMode) {
\r
618 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
619 setbuf(debugFP, NULL);
\r
624 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
625 // InitEngineUCI( installDir, &second );
\r
627 /* Create a main window for this application instance. */
\r
628 hwnd = CreateWindow(szAppName, szTitle,
\r
629 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
630 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
631 NULL, NULL, hInstance, NULL);
\r
634 /* If window could not be created, return "failure" */
\r
639 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
640 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
641 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
643 if (first.programLogo == NULL && appData.debugMode) {
\r
644 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
646 } else if(appData.autoLogo) {
\r
647 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
649 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
650 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
654 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
655 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
657 if (second.programLogo == NULL && appData.debugMode) {
\r
658 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
660 } else if(appData.autoLogo) {
\r
661 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
663 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
664 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
668 iconWhite = LoadIcon(hInstance, "icon_white");
\r
669 iconBlack = LoadIcon(hInstance, "icon_black");
\r
670 iconCurrent = iconWhite;
\r
671 InitDrawingColors();
\r
672 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
673 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
674 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
675 /* Compute window size for each board size, and use the largest
\r
676 size that fits on this screen as the default. */
\r
677 InitDrawingSizes((BoardSize)ibs, 0);
\r
678 if (boardSize == (BoardSize)-1 &&
\r
679 winHeight <= screenHeight
\r
680 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
681 && winWidth <= screenWidth) {
\r
682 boardSize = (BoardSize)ibs;
\r
686 InitDrawingSizes(boardSize, 0);
\r
688 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
690 /* [AS] Load textures if specified */
\r
691 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
693 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
694 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
695 liteBackTextureMode = appData.liteBackTextureMode;
\r
697 if (liteBackTexture == NULL && appData.debugMode) {
\r
698 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
702 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
703 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
704 darkBackTextureMode = appData.darkBackTextureMode;
\r
706 if (darkBackTexture == NULL && appData.debugMode) {
\r
707 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
711 mysrandom( (unsigned) time(NULL) );
\r
713 /* [AS] Restore layout */
\r
714 if( wpMoveHistory.visible ) {
\r
715 MoveHistoryPopUp();
\r
718 if( wpEvalGraph.visible ) {
\r
722 if( wpEngineOutput.visible ) {
\r
723 EngineOutputPopUp();
\r
728 /* Make the window visible; update its client area; and return "success" */
\r
729 EnsureOnScreen(&boardX, &boardY);
\r
730 wp.length = sizeof(WINDOWPLACEMENT);
\r
732 wp.showCmd = nCmdShow;
\r
733 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
734 wp.rcNormalPosition.left = boardX;
\r
735 wp.rcNormalPosition.right = boardX + winWidth;
\r
736 wp.rcNormalPosition.top = boardY;
\r
737 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
738 SetWindowPlacement(hwndMain, &wp);
\r
740 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
741 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
744 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
745 if( gameInfo.variant != VariantFischeRandom ) {
\r
746 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
751 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
752 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
754 ShowWindow(hwndConsole, nCmdShow);
\r
756 UpdateWindow(hwnd);
\r
764 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
765 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
766 ArgSettingsFilename
\r
774 String *pString; // ArgString
\r
775 int *pInt; // ArgInt
\r
776 float *pFloat; // ArgFloat
\r
777 Boolean *pBoolean; // ArgBoolean
\r
778 COLORREF *pColor; // ArgColor
\r
779 ColorClass cc; // ArgAttribs
\r
780 String *pFilename; // ArgFilename
\r
781 BoardSize *pBoardSize; // ArgBoardSize
\r
782 int whichFont; // ArgFont
\r
783 DCB *pDCB; // ArgCommSettings
\r
784 String *pFilename; // ArgSettingsFilename
\r
792 ArgDescriptor argDescriptors[] = {
\r
793 /* positional arguments */
\r
794 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
795 { "", ArgNone, NULL },
\r
796 /* keyword arguments */
\r
797 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
798 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
799 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
800 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
801 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
802 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
803 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
804 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
805 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
806 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
807 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
808 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
809 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
810 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
811 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
812 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
813 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
814 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
816 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
818 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
820 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
821 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
823 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
824 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
825 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
826 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
827 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
828 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
829 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
830 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
831 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
832 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
833 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
834 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
835 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
836 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
837 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
838 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
839 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
840 /*!!bitmapDirectory?*/
\r
841 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
842 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
843 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
844 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
845 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
846 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
847 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
848 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
849 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
850 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
851 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
852 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
853 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
854 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
855 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
856 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
857 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
858 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
859 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
860 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
861 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
862 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
863 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
864 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
865 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
866 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
867 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
868 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
869 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
870 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
871 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
872 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
873 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
874 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
875 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
876 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
877 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
878 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
879 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
880 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
881 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
882 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
883 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
884 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
885 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
886 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
887 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
888 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
889 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
890 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
891 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
892 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
893 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
894 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
895 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
896 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
897 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
898 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
899 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
900 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
901 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
902 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
903 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
904 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
905 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
906 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
907 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
908 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
909 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
910 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
911 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
912 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
913 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
914 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
915 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
916 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
917 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
918 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
919 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
920 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
921 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
922 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
923 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
924 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
925 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
926 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
927 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
928 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
929 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
930 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
931 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
932 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
933 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
934 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
935 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
936 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
937 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
938 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
939 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
940 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
941 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
942 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
943 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
944 TRUE }, /* must come after all fonts */
\r
945 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
946 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
947 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
948 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
949 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
950 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
951 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
952 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
953 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
954 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
955 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
956 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
957 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
958 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
959 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
960 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
961 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
962 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
963 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
964 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
965 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
966 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
967 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
968 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
969 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
970 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
971 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
972 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
973 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
974 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
975 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
977 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
978 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
980 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
981 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
982 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
983 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
984 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
985 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
986 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
987 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
988 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
989 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
990 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
991 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
992 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
993 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
994 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
995 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
996 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
997 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
998 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
999 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
1000 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
1001 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
1002 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1003 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
1004 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
1005 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
1006 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1007 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
1008 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
1009 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
1010 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
1011 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1012 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
1013 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
1014 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
1015 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
1016 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1017 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
1018 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
1019 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1020 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
1021 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1022 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1023 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1024 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1025 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1026 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1027 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1028 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1029 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1030 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1031 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1032 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1033 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1034 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1035 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1036 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1037 { "highlightLastMove", ArgBoolean,
\r
1038 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1039 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1040 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1041 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1042 { "highlightDragging", ArgBoolean,
\r
1043 (LPVOID) &appData.highlightDragging, TRUE },
\r
1044 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1045 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1046 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1047 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1048 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1049 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1050 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1051 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1052 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1053 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1054 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1055 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1056 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1057 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1058 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1059 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1060 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1061 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1062 { "soundShout", ArgFilename,
\r
1063 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1064 { "soundSShout", ArgFilename,
\r
1065 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1066 { "soundChannel1", ArgFilename,
\r
1067 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1068 { "soundChannel", ArgFilename,
\r
1069 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1070 { "soundKibitz", ArgFilename,
\r
1071 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1072 { "soundTell", ArgFilename,
\r
1073 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1074 { "soundChallenge", ArgFilename,
\r
1075 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1076 { "soundRequest", ArgFilename,
\r
1077 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1078 { "soundSeek", ArgFilename,
\r
1079 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1080 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1081 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1082 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1083 { "soundIcsLoss", ArgFilename,
\r
1084 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1085 { "soundIcsDraw", ArgFilename,
\r
1086 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1087 { "soundIcsUnfinished", ArgFilename,
\r
1088 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1089 { "soundIcsAlarm", ArgFilename,
\r
1090 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1091 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1092 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1093 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1094 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1095 { "reuseChessPrograms", ArgBoolean,
\r
1096 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1097 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1098 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1099 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1100 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1101 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1102 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1103 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1104 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1105 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1106 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1107 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1108 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1109 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1110 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1111 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1112 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1113 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1114 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1115 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1116 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1117 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1118 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1119 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1120 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1121 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1122 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1123 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1124 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1125 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1126 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1127 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1128 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1129 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1130 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1131 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1132 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1133 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1135 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1137 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1138 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1139 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1140 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1141 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1142 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1143 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1144 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1145 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1146 /* [AS] New features */
\r
1147 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1148 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1149 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1150 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1151 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1152 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1153 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1154 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1155 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1156 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1157 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1158 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1159 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1160 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1161 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1162 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1163 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1164 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1165 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1166 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1167 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1168 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1169 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1170 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1171 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1172 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1173 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1174 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1175 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1176 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1177 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1178 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1179 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1180 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1181 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1182 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1183 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1184 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1185 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1186 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1187 { "firstXBook", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1188 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1189 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1190 { "secondXBook", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1191 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1192 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1193 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1194 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1195 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1196 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1198 /* [AS] Layout stuff */
\r
1199 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1200 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1201 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1202 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1203 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1205 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1206 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1207 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1208 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1209 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1211 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1212 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1213 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1214 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1215 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1217 /* [HGM] board-size, adjudication and misc. options */
\r
1218 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1219 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1220 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1221 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1222 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1223 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1224 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1225 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1226 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1227 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1228 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1229 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1230 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1231 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1232 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1233 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1234 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1235 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1236 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1237 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1238 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1239 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1240 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1241 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1242 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1243 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1244 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1245 { "firstOptions", ArgString, (LPVOID) &appData.firstOptions, FALSE },
\r
1246 { "secondOptions", ArgString, (LPVOID) &appData.secondOptions, FALSE },
\r
1247 { "firstNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride1, FALSE },
\r
1248 { "secondNeedsNoncompliantFEN", ArgString, (LPVOID) &appData.fenOverride2, FALSE },
\r
1251 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1252 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1253 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1254 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1255 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1256 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1257 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1258 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1259 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1260 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1261 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1262 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1263 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1265 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1266 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1267 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1268 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1269 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1270 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1271 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1273 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1274 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1275 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1276 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1277 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1278 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1279 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1280 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1281 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1282 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1283 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1284 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1285 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1286 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1287 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1288 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1289 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1290 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1292 /* [HGM] options for broadcasting and time odds */
\r
1293 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1294 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1295 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1296 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1297 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1298 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1299 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1300 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1301 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1302 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1303 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1304 { NULL, ArgNone, NULL, FALSE }
\r
1308 /* Kludge for indirection files on command line */
\r
1309 char* lastIndirectionFilename;
\r
1310 ArgDescriptor argDescriptorIndirection =
\r
1311 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1315 ExitArgError(char *msg, char *badArg)
\r
1317 char buf[MSG_SIZ];
\r
1319 sprintf(buf, "%s %s", msg, badArg);
\r
1320 DisplayFatalError(buf, 0, 2);
\r
1324 /* Command line font name parser. NULL name means do nothing.
\r
1325 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1326 For backward compatibility, syntax without the colon is also
\r
1327 accepted, but font names with digits in them won't work in that case.
\r
1330 ParseFontName(char *name, MyFontParams *mfp)
\r
1333 if (name == NULL) return;
\r
1335 q = strchr(p, ':');
\r
1337 if (q - p >= sizeof(mfp->faceName))
\r
1338 ExitArgError("Font name too long:", name);
\r
1339 memcpy(mfp->faceName, p, q - p);
\r
1340 mfp->faceName[q - p] = NULLCHAR;
\r
1343 q = mfp->faceName;
\r
1344 while (*p && !isdigit(*p)) {
\r
1346 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1347 ExitArgError("Font name too long:", name);
\r
1349 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1352 if (!*p) ExitArgError("Font point size missing:", name);
\r
1353 mfp->pointSize = (float) atof(p);
\r
1354 mfp->bold = (strchr(p, 'b') != NULL);
\r
1355 mfp->italic = (strchr(p, 'i') != NULL);
\r
1356 mfp->underline = (strchr(p, 'u') != NULL);
\r
1357 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1360 /* Color name parser.
\r
1361 X version accepts X color names, but this one
\r
1362 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1364 ParseColorName(char *name)
\r
1366 int red, green, blue, count;
\r
1367 char buf[MSG_SIZ];
\r
1369 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1371 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1372 &red, &green, &blue);
\r
1375 sprintf(buf, "Can't parse color name %s", name);
\r
1376 DisplayError(buf, 0);
\r
1377 return RGB(0, 0, 0);
\r
1379 return PALETTERGB(red, green, blue);
\r
1383 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1385 char *e = argValue;
\r
1389 if (*e == 'b') eff |= CFE_BOLD;
\r
1390 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1391 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1392 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1393 else if (*e == '#' || isdigit(*e)) break;
\r
1397 *color = ParseColorName(e);
\r
1402 ParseBoardSize(char *name)
\r
1404 BoardSize bs = SizeTiny;
\r
1405 while (sizeInfo[bs].name != NULL) {
\r
1406 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1409 ExitArgError("Unrecognized board size value", name);
\r
1410 return bs; /* not reached */
\r
1415 StringGet(void *getClosure)
\r
1417 char **p = (char **) getClosure;
\r
1422 FileGet(void *getClosure)
\r
1425 FILE* f = (FILE*) getClosure;
\r
1428 if (c == '\r') c = getc(f); // work around DOS format files by bypassing the '\r' completely
\r
1435 /* Parse settings file named "name". If file found, return the
\r
1436 full name in fullname and return TRUE; else return FALSE */
\r
1438 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1442 int ok; char buf[MSG_SIZ];
\r
1444 ok = SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy);
\r
1445 if(!ok && strchr(name, '.') == NULL) { // [HGM] append default file-name extension '.ini' when needed
\r
1446 sprintf(buf, "%s.ini", name);
\r
1447 ok = SearchPath(installDir, buf, NULL, MSG_SIZ, fullname, &dummy);
\r
1450 f = fopen(fullname, "r");
\r
1452 ParseArgs(FileGet, f);
\r
1461 ParseArgs(GetFunc get, void *cl)
\r
1463 char argName[ARG_MAX];
\r
1464 char argValue[ARG_MAX];
\r
1465 ArgDescriptor *ad;
\r
1474 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1475 if (ch == NULLCHAR) break;
\r
1477 /* Comment to end of line */
\r
1479 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1481 } else if (ch == '/' || ch == '-') {
\r
1484 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1485 ch != '\n' && ch != '\t') {
\r
1491 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1492 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1494 if (ad->argName == NULL)
\r
1495 ExitArgError("Unrecognized argument", argName);
\r
1497 } else if (ch == '@') {
\r
1498 /* Indirection file */
\r
1499 ad = &argDescriptorIndirection;
\r
1502 /* Positional argument */
\r
1503 ad = &argDescriptors[posarg++];
\r
1504 strcpy(argName, ad->argName);
\r
1507 if (ad->argType == ArgTrue) {
\r
1508 *(Boolean *) ad->argLoc = TRUE;
\r
1511 if (ad->argType == ArgFalse) {
\r
1512 *(Boolean *) ad->argLoc = FALSE;
\r
1516 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1517 if (ch == NULLCHAR || ch == '\n') {
\r
1518 ExitArgError("No value provided for argument", argName);
\r
1522 // Quoting with { }. No characters have to (or can) be escaped.
\r
1523 // Thus the string cannot contain a '}' character.
\r
1543 } else if (ch == '\'' || ch == '"') {
\r
1544 // Quoting with ' ' or " ", with \ as escape character.
\r
1545 // Inconvenient for long strings that may contain Windows filenames.
\r
1562 if (ch == start) {
\r
1571 if (ad->argType == ArgFilename
\r
1572 || ad->argType == ArgSettingsFilename) {
\r
1578 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1602 for (i = 0; i < 3; i++) {
\r
1603 if (ch >= '0' && ch <= '7') {
\r
1604 octval = octval*8 + (ch - '0');
\r
1611 *q++ = (char) octval;
\r
1622 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1629 switch (ad->argType) {
\r
1631 *(int *) ad->argLoc = atoi(argValue);
\r
1635 *(float *) ad->argLoc = (float) atof(argValue);
\r
1640 *(char **) ad->argLoc = strdup(argValue);
\r
1643 case ArgSettingsFilename:
\r
1645 char fullname[MSG_SIZ];
\r
1646 if (ParseSettingsFile(argValue, fullname)) {
\r
1647 if (ad->argLoc != NULL) {
\r
1648 *(char **) ad->argLoc = strdup(fullname);
\r
1651 if (ad->argLoc != NULL) {
\r
1653 ExitArgError("Failed to open indirection file", argValue);
\r
1660 switch (argValue[0]) {
\r
1663 *(Boolean *) ad->argLoc = TRUE;
\r
1667 *(Boolean *) ad->argLoc = FALSE;
\r
1670 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1676 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1679 case ArgAttribs: {
\r
1680 ColorClass cc = (ColorClass)ad->argLoc;
\r
1681 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1685 case ArgBoardSize:
\r
1686 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1690 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1693 case ArgCommSettings:
\r
1694 ParseCommSettings(argValue, &dcb);
\r
1698 ExitArgError("Unrecognized argument", argValue);
\r
1707 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1709 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1710 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1713 lf->lfEscapement = 0;
\r
1714 lf->lfOrientation = 0;
\r
1715 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1716 lf->lfItalic = mfp->italic;
\r
1717 lf->lfUnderline = mfp->underline;
\r
1718 lf->lfStrikeOut = mfp->strikeout;
\r
1719 lf->lfCharSet = DEFAULT_CHARSET;
\r
1720 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1721 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1722 lf->lfQuality = DEFAULT_QUALITY;
\r
1723 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1724 strcpy(lf->lfFaceName, mfp->faceName);
\r
1728 CreateFontInMF(MyFont *mf)
\r
1730 LFfromMFP(&mf->lf, &mf->mfp);
\r
1731 if (mf->hf) DeleteObject(mf->hf);
\r
1732 mf->hf = CreateFontIndirect(&mf->lf);
\r
1736 SetDefaultTextAttribs()
\r
1739 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1740 ParseAttribs(&textAttribs[cc].color,
\r
1741 &textAttribs[cc].effects,
\r
1742 defaultTextAttribs[cc]);
\r
1747 SetDefaultSounds()
\r
1751 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1752 textAttribs[cc].sound.name = strdup("");
\r
1753 textAttribs[cc].sound.data = NULL;
\r
1755 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1756 sounds[sc].name = strdup("");
\r
1757 sounds[sc].data = NULL;
\r
1759 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1767 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1768 MyLoadSound(&textAttribs[cc].sound);
\r
1770 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1771 MyLoadSound(&sounds[sc]);
\r
1776 InitAppData(LPSTR lpCmdLine)
\r
1779 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1782 programName = szAppName;
\r
1784 /* Initialize to defaults */
\r
1785 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1786 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1787 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1788 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1789 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1790 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1791 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1792 SetDefaultTextAttribs();
\r
1793 SetDefaultSounds();
\r
1794 appData.movesPerSession = MOVES_PER_SESSION;
\r
1795 appData.initString = INIT_STRING;
\r
1796 appData.secondInitString = INIT_STRING;
\r
1797 appData.firstComputerString = COMPUTER_STRING;
\r
1798 appData.secondComputerString = COMPUTER_STRING;
\r
1799 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1800 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1801 appData.firstPlaysBlack = FALSE;
\r
1802 appData.noChessProgram = FALSE;
\r
1803 chessProgram = FALSE;
\r
1804 appData.firstHost = FIRST_HOST;
\r
1805 appData.secondHost = SECOND_HOST;
\r
1806 appData.firstDirectory = FIRST_DIRECTORY;
\r
1807 appData.secondDirectory = SECOND_DIRECTORY;
\r
1808 appData.bitmapDirectory = "";
\r
1809 appData.remoteShell = REMOTE_SHELL;
\r
1810 appData.remoteUser = "";
\r
1811 appData.timeDelay = TIME_DELAY;
\r
1812 appData.timeControl = TIME_CONTROL;
\r
1813 appData.timeIncrement = TIME_INCREMENT;
\r
1814 appData.icsActive = FALSE;
\r
1815 appData.icsHost = "";
\r
1816 appData.icsPort = ICS_PORT;
\r
1817 appData.icsCommPort = ICS_COMM_PORT;
\r
1818 appData.icsLogon = ICS_LOGON;
\r
1819 appData.icsHelper = "";
\r
1820 appData.useTelnet = FALSE;
\r
1821 appData.telnetProgram = TELNET_PROGRAM;
\r
1822 appData.gateway = "";
\r
1823 appData.loadGameFile = "";
\r
1824 appData.loadGameIndex = 0;
\r
1825 appData.saveGameFile = "";
\r
1826 appData.autoSaveGames = FALSE;
\r
1827 appData.loadPositionFile = "";
\r
1828 appData.loadPositionIndex = 1;
\r
1829 appData.savePositionFile = "";
\r
1830 appData.matchMode = FALSE;
\r
1831 appData.matchGames = 0;
\r
1832 appData.monoMode = FALSE;
\r
1833 appData.debugMode = FALSE;
\r
1834 appData.clockMode = TRUE;
\r
1835 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1836 appData.Iconic = FALSE; /*unused*/
\r
1837 appData.searchTime = "";
\r
1838 appData.searchDepth = 0;
\r
1839 appData.showCoords = FALSE;
\r
1840 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1841 appData.autoCallFlag = FALSE;
\r
1842 appData.flipView = FALSE;
\r
1843 appData.autoFlipView = TRUE;
\r
1844 appData.cmailGameName = "";
\r
1845 appData.alwaysPromoteToQueen = FALSE;
\r
1846 appData.oldSaveStyle = FALSE;
\r
1847 appData.quietPlay = FALSE;
\r
1848 appData.showThinking = FALSE;
\r
1849 appData.ponderNextMove = TRUE;
\r
1850 appData.periodicUpdates = TRUE;
\r
1851 appData.popupExitMessage = TRUE;
\r
1852 appData.popupMoveErrors = FALSE;
\r
1853 appData.autoObserve = FALSE;
\r
1854 appData.autoComment = FALSE;
\r
1855 appData.animate = TRUE;
\r
1856 appData.animSpeed = 10;
\r
1857 appData.animateDragging = TRUE;
\r
1858 appData.highlightLastMove = TRUE;
\r
1859 appData.getMoveList = TRUE;
\r
1860 appData.testLegality = TRUE;
\r
1861 appData.premove = TRUE;
\r
1862 appData.premoveWhite = FALSE;
\r
1863 appData.premoveWhiteText = "";
\r
1864 appData.premoveBlack = FALSE;
\r
1865 appData.premoveBlackText = "";
\r
1866 appData.icsAlarm = TRUE;
\r
1867 appData.icsAlarmTime = 5000;
\r
1868 appData.autoRaiseBoard = TRUE;
\r
1869 appData.localLineEditing = TRUE;
\r
1870 appData.colorize = TRUE;
\r
1871 appData.reuseFirst = TRUE;
\r
1872 appData.reuseSecond = TRUE;
\r
1873 appData.blindfold = FALSE;
\r
1874 appData.icsEngineAnalyze = FALSE;
\r
1875 memset(&dcb, 0, sizeof(DCB)); // required by VS 2002 +
\r
1876 dcb.DCBlength = sizeof(DCB);
\r
1877 dcb.BaudRate = 9600;
\r
1878 dcb.fBinary = TRUE;
\r
1879 dcb.fParity = FALSE;
\r
1880 dcb.fOutxCtsFlow = FALSE;
\r
1881 dcb.fOutxDsrFlow = FALSE;
\r
1882 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1883 dcb.fDsrSensitivity = FALSE;
\r
1884 dcb.fTXContinueOnXoff = TRUE;
\r
1885 dcb.fOutX = FALSE;
\r
1887 dcb.fNull = FALSE;
\r
1888 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1889 dcb.fAbortOnError = FALSE;
\r
1891 dcb.Parity = SPACEPARITY;
\r
1892 dcb.StopBits = ONESTOPBIT;
\r
1893 settingsFileName = SETTINGS_FILE;
\r
1894 saveSettingsOnExit = TRUE;
\r
1895 boardX = CW_USEDEFAULT;
\r
1896 boardY = CW_USEDEFAULT;
\r
1897 consoleX = CW_USEDEFAULT;
\r
1898 consoleY = CW_USEDEFAULT;
\r
1899 consoleW = CW_USEDEFAULT;
\r
1900 consoleH = CW_USEDEFAULT;
\r
1901 analysisX = CW_USEDEFAULT;
\r
1902 analysisY = CW_USEDEFAULT;
\r
1903 analysisW = CW_USEDEFAULT;
\r
1904 analysisH = CW_USEDEFAULT;
\r
1905 commentX = CW_USEDEFAULT;
\r
1906 commentY = CW_USEDEFAULT;
\r
1907 commentW = CW_USEDEFAULT;
\r
1908 commentH = CW_USEDEFAULT;
\r
1909 editTagsX = CW_USEDEFAULT;
\r
1910 editTagsY = CW_USEDEFAULT;
\r
1911 editTagsW = CW_USEDEFAULT;
\r
1912 editTagsH = CW_USEDEFAULT;
\r
1913 gameListX = CW_USEDEFAULT;
\r
1914 gameListY = CW_USEDEFAULT;
\r
1915 gameListW = CW_USEDEFAULT;
\r
1916 gameListH = CW_USEDEFAULT;
\r
1917 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1918 icsNames = ICS_NAMES;
\r
1919 firstChessProgramNames = FCP_NAMES;
\r
1920 secondChessProgramNames = SCP_NAMES;
\r
1921 appData.initialMode = "";
\r
1922 appData.variant = "normal";
\r
1923 appData.firstProtocolVersion = PROTOVER;
\r
1924 appData.secondProtocolVersion = PROTOVER;
\r
1925 appData.showButtonBar = TRUE;
\r
1927 /* [AS] New properties (see comments in header file) */
\r
1928 appData.firstScoreIsAbsolute = FALSE;
\r
1929 appData.secondScoreIsAbsolute = FALSE;
\r
1930 appData.saveExtendedInfoInPGN = FALSE;
\r
1931 appData.hideThinkingFromHuman = FALSE;
\r
1932 appData.liteBackTextureFile = "";
\r
1933 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1934 appData.darkBackTextureFile = "";
\r
1935 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1936 appData.renderPiecesWithFont = "";
\r
1937 appData.fontToPieceTable = "";
\r
1938 appData.fontBackColorWhite = 0;
\r
1939 appData.fontForeColorWhite = 0;
\r
1940 appData.fontBackColorBlack = 0;
\r
1941 appData.fontForeColorBlack = 0;
\r
1942 appData.fontPieceSize = 80;
\r
1943 appData.overrideLineGap = 1;
\r
1944 appData.adjudicateLossThreshold = 0;
\r
1945 appData.delayBeforeQuit = 0;
\r
1946 appData.delayAfterQuit = 0;
\r
1947 appData.nameOfDebugFile = "winboard.debug";
\r
1948 appData.pgnEventHeader = "Computer Chess Game";
\r
1949 appData.defaultFrcPosition = -1;
\r
1950 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1951 appData.saveOutOfBookInfo = TRUE;
\r
1952 appData.showEvalInMoveHistory = TRUE;
\r
1953 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1954 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1955 appData.highlightMoveWithArrow = FALSE;
\r
1956 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1957 appData.useStickyWindows = TRUE;
\r
1958 appData.adjudicateDrawMoves = 0;
\r
1959 appData.autoDisplayComment = TRUE;
\r
1960 appData.autoDisplayTags = TRUE;
\r
1961 appData.firstIsUCI = FALSE;
\r
1962 appData.secondIsUCI = FALSE;
\r
1963 appData.firstHasOwnBookUCI = TRUE;
\r
1964 appData.secondHasOwnBookUCI = TRUE;
\r
1965 appData.polyglotDir = "";
\r
1966 appData.usePolyglotBook = FALSE;
\r
1967 appData.polyglotBook = "";
\r
1968 appData.defaultHashSize = 64;
\r
1969 appData.defaultCacheSizeEGTB = 4;
\r
1970 appData.defaultPathEGTB = "c:\\egtb";
\r
1971 appData.firstOptions = "";
\r
1972 appData.secondOptions = "";
\r
1974 InitWindowPlacement( &wpMoveHistory );
\r
1975 InitWindowPlacement( &wpEvalGraph );
\r
1976 InitWindowPlacement( &wpEngineOutput );
\r
1978 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1979 appData.NrFiles = -1;
\r
1980 appData.NrRanks = -1;
\r
1981 appData.holdingsSize = -1;
\r
1982 appData.testClaims = FALSE;
\r
1983 appData.checkMates = FALSE;
\r
1984 appData.materialDraws= FALSE;
\r
1985 appData.trivialDraws = FALSE;
\r
1986 appData.ruleMoves = 51;
\r
1987 appData.drawRepeats = 6;
\r
1988 appData.matchPause = 10000;
\r
1989 appData.alphaRank = FALSE;
\r
1990 appData.allWhite = FALSE;
\r
1991 appData.upsideDown = FALSE;
\r
1992 appData.serverPause = 15;
\r
1993 appData.serverMovesName = NULL;
\r
1994 appData.suppressLoadMoves = FALSE;
\r
1995 appData.firstTimeOdds = 1;
\r
1996 appData.secondTimeOdds = 1;
\r
1997 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
1998 appData.secondAccumulateTC = 1;
\r
1999 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
2000 appData.secondNPS = -1;
\r
2001 appData.engineComments = 1;
\r
2002 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
2003 appData.egtFormats = "";
\r
2006 appData.zippyTalk = ZIPPY_TALK;
\r
2007 appData.zippyPlay = ZIPPY_PLAY;
\r
2008 appData.zippyLines = ZIPPY_LINES;
\r
2009 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
2010 appData.zippyPassword = ZIPPY_PASSWORD;
\r
2011 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
2012 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
2013 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
2014 appData.zippyUseI = ZIPPY_USE_I;
\r
2015 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
2016 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
2017 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
2018 appData.zippyGameStart = ZIPPY_GAME_START;
\r
2019 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
2020 appData.zippyAbort = ZIPPY_ABORT;
\r
2021 appData.zippyVariants = ZIPPY_VARIANTS;
\r
2022 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
2023 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
2026 /* Point font array elements to structures and
\r
2027 parse default font names */
\r
2028 for (i=0; i<NUM_FONTS; i++) {
\r
2029 for (j=0; j<NUM_SIZES; j++) {
\r
2030 font[j][i] = &fontRec[j][i];
\r
2031 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2035 /* Parse default settings file if any */
\r
2036 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2037 settingsFileName = strdup(buf);
\r
2040 /* Parse command line */
\r
2041 ParseArgs(StringGet, &lpCmdLine);
\r
2043 /* [HGM] make sure board size is acceptable */
\r
2044 if(appData.NrFiles > BOARD_SIZE ||
\r
2045 appData.NrRanks > BOARD_SIZE )
\r
2046 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2048 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2049 * with options from the command line, we now make an even higher priority
\r
2050 * overrule by WB options attached to the engine command line. This so that
\r
2051 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2054 if(appData.firstChessProgram != NULL) {
\r
2055 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2056 static char *f = "first";
\r
2057 char buf[MSG_SIZ], *q = buf;
\r
2058 if(p != NULL) { // engine command line contains WinBoard options
\r
2059 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2060 ParseArgs(StringGet, &q);
\r
2061 p[-1] = 0; // cut them offengine command line
\r
2064 // now do same for second chess program
\r
2065 if(appData.secondChessProgram != NULL) {
\r
2066 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2067 static char *s = "second";
\r
2068 char buf[MSG_SIZ], *q = buf;
\r
2069 if(p != NULL) { // engine command line contains WinBoard options
\r
2070 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2071 ParseArgs(StringGet, &q);
\r
2072 p[-1] = 0; // cut them offengine command line
\r
2077 /* Propagate options that affect others */
\r
2078 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2079 if (appData.icsActive || appData.noChessProgram) {
\r
2080 chessProgram = FALSE; /* not local chess program mode */
\r
2083 /* Open startup dialog if needed */
\r
2084 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2085 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2086 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2087 *appData.secondChessProgram == NULLCHAR))) {
\r
2090 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2091 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2092 FreeProcInstance(lpProc);
\r
2095 /* Make sure save files land in the right (?) directory */
\r
2096 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2097 appData.saveGameFile = strdup(buf);
\r
2099 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2100 appData.savePositionFile = strdup(buf);
\r
2103 /* Finish initialization for fonts and sounds */
\r
2104 for (i=0; i<NUM_FONTS; i++) {
\r
2105 for (j=0; j<NUM_SIZES; j++) {
\r
2106 CreateFontInMF(font[j][i]);
\r
2109 /* xboard, and older WinBoards, controlled the move sound with the
\r
2110 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2111 always turn the option on (so that the backend will call us),
\r
2112 then let the user turn the sound off by setting it to silence if
\r
2113 desired. To accommodate old winboard.ini files saved by old
\r
2114 versions of WinBoard, we also turn off the sound if the option
\r
2115 was initially set to false. */
\r
2116 if (!appData.ringBellAfterMoves) {
\r
2117 sounds[(int)SoundMove].name = strdup("");
\r
2118 appData.ringBellAfterMoves = TRUE;
\r
2120 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2121 SetCurrentDirectory(installDir);
\r
2123 SetCurrentDirectory(currDir);
\r
2125 p = icsTextMenuString;
\r
2126 if (p[0] == '@') {
\r
2127 FILE* f = fopen(p + 1, "r");
\r
2129 DisplayFatalError(p + 1, errno, 2);
\r
2132 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2134 buf[i] = NULLCHAR;
\r
2137 ParseIcsTextMenu(strdup(p));
\r
2144 HMENU hmenu = GetMenu(hwndMain);
\r
2146 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2147 MF_BYCOMMAND|((appData.icsActive &&
\r
2148 *appData.icsCommPort != NULLCHAR) ?
\r
2149 MF_ENABLED : MF_GRAYED));
\r
2150 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2151 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2152 MF_CHECKED : MF_UNCHECKED));
\r
2157 SaveSettings(char* name)
\r
2160 ArgDescriptor *ad;
\r
2161 WINDOWPLACEMENT wp;
\r
2162 char dir[MSG_SIZ];
\r
2164 if (!hwndMain) return;
\r
2166 GetCurrentDirectory(MSG_SIZ, dir);
\r
2167 SetCurrentDirectory(installDir);
\r
2168 f = fopen(name, "w");
\r
2169 SetCurrentDirectory(dir);
\r
2171 DisplayError(name, errno);
\r
2174 fprintf(f, ";\n");
\r
2175 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2176 fprintf(f, ";\n");
\r
2177 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2178 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2179 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2180 fprintf(f, ";\n");
\r
2182 wp.length = sizeof(WINDOWPLACEMENT);
\r
2183 GetWindowPlacement(hwndMain, &wp);
\r
2184 boardX = wp.rcNormalPosition.left;
\r
2185 boardY = wp.rcNormalPosition.top;
\r
2187 if (hwndConsole) {
\r
2188 GetWindowPlacement(hwndConsole, &wp);
\r
2189 consoleX = wp.rcNormalPosition.left;
\r
2190 consoleY = wp.rcNormalPosition.top;
\r
2191 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2192 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2195 if (analysisDialog) {
\r
2196 GetWindowPlacement(analysisDialog, &wp);
\r
2197 analysisX = wp.rcNormalPosition.left;
\r
2198 analysisY = wp.rcNormalPosition.top;
\r
2199 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2200 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2203 if (commentDialog) {
\r
2204 GetWindowPlacement(commentDialog, &wp);
\r
2205 commentX = wp.rcNormalPosition.left;
\r
2206 commentY = wp.rcNormalPosition.top;
\r
2207 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2208 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2211 if (editTagsDialog) {
\r
2212 GetWindowPlacement(editTagsDialog, &wp);
\r
2213 editTagsX = wp.rcNormalPosition.left;
\r
2214 editTagsY = wp.rcNormalPosition.top;
\r
2215 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2216 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2219 if (gameListDialog) {
\r
2220 GetWindowPlacement(gameListDialog, &wp);
\r
2221 gameListX = wp.rcNormalPosition.left;
\r
2222 gameListY = wp.rcNormalPosition.top;
\r
2223 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2224 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2227 /* [AS] Move history */
\r
2228 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2230 if( moveHistoryDialog ) {
\r
2231 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2232 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2233 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2234 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2235 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2238 /* [AS] Eval graph */
\r
2239 wpEvalGraph.visible = EvalGraphIsUp();
\r
2241 if( evalGraphDialog ) {
\r
2242 GetWindowPlacement(evalGraphDialog, &wp);
\r
2243 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2244 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2245 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2246 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2249 /* [AS] Engine output */
\r
2250 wpEngineOutput.visible = EngineOutputIsUp();
\r
2252 if( engineOutputDialog ) {
\r
2253 GetWindowPlacement(engineOutputDialog, &wp);
\r
2254 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2255 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2256 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2257 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2260 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2261 if (!ad->save) continue;
\r
2262 switch (ad->argType) {
\r
2265 char *p = *(char **)ad->argLoc;
\r
2266 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2267 /* Quote multiline values or \-containing values
\r
2268 with { } if possible */
\r
2269 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2271 /* Else quote with " " */
\r
2272 fprintf(f, "/%s=\"", ad->argName);
\r
2274 if (*p == '\n') fprintf(f, "\n");
\r
2275 else if (*p == '\r') fprintf(f, "\\r");
\r
2276 else if (*p == '\t') fprintf(f, "\\t");
\r
2277 else if (*p == '\b') fprintf(f, "\\b");
\r
2278 else if (*p == '\f') fprintf(f, "\\f");
\r
2279 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2280 else if (*p == '\"') fprintf(f, "\\\"");
\r
2281 else if (*p == '\\') fprintf(f, "\\\\");
\r
2285 fprintf(f, "\"\n");
\r
2290 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2293 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2296 fprintf(f, "/%s=%s\n", ad->argName,
\r
2297 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2300 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2303 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2307 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2308 fprintf(f, "/%s=#%02lx%02lx%02lx\n", ad->argName,
\r
2309 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2314 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2315 fprintf(f, "/%s=\"%s%s%s%s%s#%02lx%02lx%02lx\"\n", ad->argName,
\r
2316 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2317 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2318 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2319 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2320 (ta->effects) ? " " : "",
\r
2321 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2325 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2326 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2328 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2331 case ArgBoardSize:
\r
2332 fprintf(f, "/%s=%s\n", ad->argName,
\r
2333 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2338 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2339 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2340 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2341 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2342 ad->argName, mfp->faceName, mfp->pointSize,
\r
2343 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2344 mfp->bold ? "b" : "",
\r
2345 mfp->italic ? "i" : "",
\r
2346 mfp->underline ? "u" : "",
\r
2347 mfp->strikeout ? "s" : "");
\r
2351 case ArgCommSettings:
\r
2352 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2354 case ArgSettingsFilename: ;
\r
2362 /*---------------------------------------------------------------------------*\
\r
2364 * GDI board drawing routines
\r
2366 \*---------------------------------------------------------------------------*/
\r
2368 /* [AS] Draw square using background texture */
\r
2369 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2374 return; /* Should never happen! */
\r
2377 SetGraphicsMode( dst, GM_ADVANCED );
\r
2384 /* X reflection */
\r
2389 x.eDx = (FLOAT) dw + dx - 1;
\r
2392 SetWorldTransform( dst, &x );
\r
2395 /* Y reflection */
\r
2401 x.eDy = (FLOAT) dh + dy - 1;
\r
2403 SetWorldTransform( dst, &x );
\r
2411 x.eDx = (FLOAT) dx;
\r
2412 x.eDy = (FLOAT) dy;
\r
2415 SetWorldTransform( dst, &x );
\r
2419 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2427 SetWorldTransform( dst, &x );
\r
2429 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2432 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2434 PM_WP = (int) WhitePawn,
\r
2435 PM_WN = (int) WhiteKnight,
\r
2436 PM_WB = (int) WhiteBishop,
\r
2437 PM_WR = (int) WhiteRook,
\r
2438 PM_WQ = (int) WhiteQueen,
\r
2439 PM_WF = (int) WhiteFerz,
\r
2440 PM_WW = (int) WhiteWazir,
\r
2441 PM_WE = (int) WhiteAlfil,
\r
2442 PM_WM = (int) WhiteMan,
\r
2443 PM_WO = (int) WhiteCannon,
\r
2444 PM_WU = (int) WhiteUnicorn,
\r
2445 PM_WH = (int) WhiteNightrider,
\r
2446 PM_WA = (int) WhiteAngel,
\r
2447 PM_WC = (int) WhiteMarshall,
\r
2448 PM_WAB = (int) WhiteCardinal,
\r
2449 PM_WD = (int) WhiteDragon,
\r
2450 PM_WL = (int) WhiteLance,
\r
2451 PM_WS = (int) WhiteCobra,
\r
2452 PM_WV = (int) WhiteFalcon,
\r
2453 PM_WSG = (int) WhiteSilver,
\r
2454 PM_WG = (int) WhiteGrasshopper,
\r
2455 PM_WK = (int) WhiteKing,
\r
2456 PM_BP = (int) BlackPawn,
\r
2457 PM_BN = (int) BlackKnight,
\r
2458 PM_BB = (int) BlackBishop,
\r
2459 PM_BR = (int) BlackRook,
\r
2460 PM_BQ = (int) BlackQueen,
\r
2461 PM_BF = (int) BlackFerz,
\r
2462 PM_BW = (int) BlackWazir,
\r
2463 PM_BE = (int) BlackAlfil,
\r
2464 PM_BM = (int) BlackMan,
\r
2465 PM_BO = (int) BlackCannon,
\r
2466 PM_BU = (int) BlackUnicorn,
\r
2467 PM_BH = (int) BlackNightrider,
\r
2468 PM_BA = (int) BlackAngel,
\r
2469 PM_BC = (int) BlackMarshall,
\r
2470 PM_BG = (int) BlackGrasshopper,
\r
2471 PM_BAB = (int) BlackCardinal,
\r
2472 PM_BD = (int) BlackDragon,
\r
2473 PM_BL = (int) BlackLance,
\r
2474 PM_BS = (int) BlackCobra,
\r
2475 PM_BV = (int) BlackFalcon,
\r
2476 PM_BSG = (int) BlackSilver,
\r
2477 PM_BK = (int) BlackKing
\r
2480 static HFONT hPieceFont = NULL;
\r
2481 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2482 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2483 static int fontBitmapSquareSize = 0;
\r
2484 static char pieceToFontChar[(int) EmptySquare] =
\r
2485 { 'p', 'n', 'b', 'r', 'q',
\r
2486 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2487 'k', 'o', 'm', 'v', 't', 'w',
\r
2488 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2491 extern BOOL SetCharTable( char *table, const char * map );
\r
2492 /* [HGM] moved to backend.c */
\r
2494 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2497 BYTE r1 = GetRValue( color );
\r
2498 BYTE g1 = GetGValue( color );
\r
2499 BYTE b1 = GetBValue( color );
\r
2505 /* Create a uniform background first */
\r
2506 hbrush = CreateSolidBrush( color );
\r
2507 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2508 FillRect( hdc, &rc, hbrush );
\r
2509 DeleteObject( hbrush );
\r
2512 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2513 int steps = squareSize / 2;
\r
2516 for( i=0; i<steps; i++ ) {
\r
2517 BYTE r = r1 - (r1-r2) * i / steps;
\r
2518 BYTE g = g1 - (g1-g2) * i / steps;
\r
2519 BYTE b = b1 - (b1-b2) * i / steps;
\r
2521 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2522 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2523 FillRect( hdc, &rc, hbrush );
\r
2524 DeleteObject(hbrush);
\r
2527 else if( mode == 2 ) {
\r
2528 /* Diagonal gradient, good more or less for every piece */
\r
2529 POINT triangle[3];
\r
2530 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2531 HBRUSH hbrush_old;
\r
2532 int steps = squareSize;
\r
2535 triangle[0].x = squareSize - steps;
\r
2536 triangle[0].y = squareSize;
\r
2537 triangle[1].x = squareSize;
\r
2538 triangle[1].y = squareSize;
\r
2539 triangle[2].x = squareSize;
\r
2540 triangle[2].y = squareSize - steps;
\r
2542 for( i=0; i<steps; i++ ) {
\r
2543 BYTE r = r1 - (r1-r2) * i / steps;
\r
2544 BYTE g = g1 - (g1-g2) * i / steps;
\r
2545 BYTE b = b1 - (b1-b2) * i / steps;
\r
2547 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2548 hbrush_old = SelectObject( hdc, hbrush );
\r
2549 Polygon( hdc, triangle, 3 );
\r
2550 SelectObject( hdc, hbrush_old );
\r
2551 DeleteObject(hbrush);
\r
2556 SelectObject( hdc, hpen );
\r
2561 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2562 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2563 piece: follow the steps as explained below.
\r
2565 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2569 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2573 int backColor = whitePieceColor;
\r
2574 int foreColor = blackPieceColor;
\r
2576 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2577 backColor = appData.fontBackColorWhite;
\r
2578 foreColor = appData.fontForeColorWhite;
\r
2580 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2581 backColor = appData.fontBackColorBlack;
\r
2582 foreColor = appData.fontForeColorBlack;
\r
2586 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2588 hbm_old = SelectObject( hdc, hbm );
\r
2592 rc.right = squareSize;
\r
2593 rc.bottom = squareSize;
\r
2595 /* Step 1: background is now black */
\r
2596 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2598 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2600 pt.x = (squareSize - sz.cx) / 2;
\r
2601 pt.y = (squareSize - sz.cy) / 2;
\r
2603 SetBkMode( hdc, TRANSPARENT );
\r
2604 SetTextColor( hdc, chroma );
\r
2605 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2606 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2608 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2609 /* Step 3: the area outside the piece is filled with white */
\r
2610 // FloodFill( hdc, 0, 0, chroma );
\r
2611 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2612 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2613 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2614 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2615 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2617 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2618 but if the start point is not inside the piece we're lost!
\r
2619 There should be a better way to do this... if we could create a region or path
\r
2620 from the fill operation we would be fine for example.
\r
2622 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2623 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2625 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2626 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2627 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2629 SelectObject( dc2, bm2 );
\r
2630 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2631 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2632 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2633 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2634 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2637 DeleteObject( bm2 );
\r
2640 SetTextColor( hdc, 0 );
\r
2642 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2643 draw the piece again in black for safety.
\r
2645 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2647 SelectObject( hdc, hbm_old );
\r
2649 if( hPieceMask[index] != NULL ) {
\r
2650 DeleteObject( hPieceMask[index] );
\r
2653 hPieceMask[index] = hbm;
\r
2656 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2658 SelectObject( hdc, hbm );
\r
2661 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2662 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2663 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2665 SelectObject( dc1, hPieceMask[index] );
\r
2666 SelectObject( dc2, bm2 );
\r
2667 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2668 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2671 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2672 the piece background and deletes (makes transparent) the rest.
\r
2673 Thanks to that mask, we are free to paint the background with the greates
\r
2674 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2675 We use this, to make gradients and give the pieces a "roundish" look.
\r
2677 SetPieceBackground( hdc, backColor, 2 );
\r
2678 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2682 DeleteObject( bm2 );
\r
2685 SetTextColor( hdc, foreColor );
\r
2686 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2688 SelectObject( hdc, hbm_old );
\r
2690 if( hPieceFace[index] != NULL ) {
\r
2691 DeleteObject( hPieceFace[index] );
\r
2694 hPieceFace[index] = hbm;
\r
2697 static int TranslatePieceToFontPiece( int piece )
\r
2727 case BlackMarshall:
\r
2731 case BlackNightrider:
\r
2737 case BlackUnicorn:
\r
2741 case BlackGrasshopper:
\r
2753 case BlackCardinal:
\r
2760 case WhiteMarshall:
\r
2764 case WhiteNightrider:
\r
2770 case WhiteUnicorn:
\r
2774 case WhiteGrasshopper:
\r
2786 case WhiteCardinal:
\r
2795 void CreatePiecesFromFont()
\r
2798 HDC hdc_window = NULL;
\r
2804 if( fontBitmapSquareSize < 0 ) {
\r
2805 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2809 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2810 fontBitmapSquareSize = -1;
\r
2814 if( fontBitmapSquareSize != squareSize ) {
\r
2815 hdc_window = GetDC( hwndMain );
\r
2816 hdc = CreateCompatibleDC( hdc_window );
\r
2818 if( hPieceFont != NULL ) {
\r
2819 DeleteObject( hPieceFont );
\r
2822 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2823 hPieceMask[i] = NULL;
\r
2824 hPieceFace[i] = NULL;
\r
2830 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2831 fontHeight = appData.fontPieceSize;
\r
2834 fontHeight = (fontHeight * squareSize) / 100;
\r
2836 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2838 lf.lfEscapement = 0;
\r
2839 lf.lfOrientation = 0;
\r
2840 lf.lfWeight = FW_NORMAL;
\r
2842 lf.lfUnderline = 0;
\r
2843 lf.lfStrikeOut = 0;
\r
2844 lf.lfCharSet = DEFAULT_CHARSET;
\r
2845 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2846 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2847 lf.lfQuality = PROOF_QUALITY;
\r
2848 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2849 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2850 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2852 hPieceFont = CreateFontIndirect( &lf );
\r
2854 if( hPieceFont == NULL ) {
\r
2855 fontBitmapSquareSize = -2;
\r
2858 /* Setup font-to-piece character table */
\r
2859 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2860 /* No (or wrong) global settings, try to detect the font */
\r
2861 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2863 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2865 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2866 /* DiagramTT* family */
\r
2867 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2869 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2870 /* Fairy symbols */
\r
2871 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2873 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2874 /* Good Companion (Some characters get warped as literal :-( */
\r
2875 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2876 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2877 SetCharTable(pieceToFontChar, s);
\r
2880 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2881 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2885 /* Create bitmaps */
\r
2886 hfont_old = SelectObject( hdc, hPieceFont );
\r
2888 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2889 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2890 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2891 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2892 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2893 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2894 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2895 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2896 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2897 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2898 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2899 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2901 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2902 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2903 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2904 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2905 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2906 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2907 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2908 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2909 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2910 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2911 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
2912 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
2913 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
2914 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
2915 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
2916 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
2917 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2918 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2919 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2920 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2921 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2922 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2923 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2924 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2925 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2926 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2927 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
2928 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
2929 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
2930 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
2931 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
2932 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
2934 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2935 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2936 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2938 SelectObject( hdc, hfont_old );
\r
2940 fontBitmapSquareSize = squareSize;
\r
2944 if( hdc != NULL ) {
\r
2948 if( hdc_window != NULL ) {
\r
2949 ReleaseDC( hwndMain, hdc_window );
\r
2954 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2958 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2959 if (gameInfo.event &&
\r
2960 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2961 strcmp(name, "k80s") == 0) {
\r
2962 strcpy(name, "tim");
\r
2964 return LoadBitmap(hinst, name);
\r
2968 /* Insert a color into the program's logical palette
\r
2969 structure. This code assumes the given color is
\r
2970 the result of the RGB or PALETTERGB macro, and it
\r
2971 knows how those macros work (which is documented).
\r
2974 InsertInPalette(COLORREF color)
\r
2976 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2978 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2979 DisplayFatalError("Too many colors", 0, 1);
\r
2980 pLogPal->palNumEntries--;
\r
2984 pe->peFlags = (char) 0;
\r
2985 pe->peRed = (char) (0xFF & color);
\r
2986 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2987 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2993 InitDrawingColors()
\r
2995 if (pLogPal == NULL) {
\r
2996 /* Allocate enough memory for a logical palette with
\r
2997 * PALETTESIZE entries and set the size and version fields
\r
2998 * of the logical palette structure.
\r
3000 pLogPal = (NPLOGPALETTE)
\r
3001 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
3002 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
3003 pLogPal->palVersion = 0x300;
\r
3005 pLogPal->palNumEntries = 0;
\r
3007 InsertInPalette(lightSquareColor);
\r
3008 InsertInPalette(darkSquareColor);
\r
3009 InsertInPalette(whitePieceColor);
\r
3010 InsertInPalette(blackPieceColor);
\r
3011 InsertInPalette(highlightSquareColor);
\r
3012 InsertInPalette(premoveHighlightColor);
\r
3014 /* create a logical color palette according the information
\r
3015 * in the LOGPALETTE structure.
\r
3017 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
3019 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
3020 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
3021 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
3022 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
3023 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
3024 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
3025 explodeBrush = CreateSolidBrush(highlightSquareColor); // [HGM] atomic
\r
3026 /* [AS] Force rendering of the font-based pieces */
\r
3027 if( fontBitmapSquareSize > 0 ) {
\r
3028 fontBitmapSquareSize = 0;
\r
3034 BoardWidth(int boardSize, int n)
\r
3035 { /* [HGM] argument n added to allow different width and height */
\r
3036 int lineGap = sizeInfo[boardSize].lineGap;
\r
3038 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3039 lineGap = appData.overrideLineGap;
\r
3042 return (n + 1) * lineGap +
\r
3043 n * sizeInfo[boardSize].squareSize;
\r
3046 /* Respond to board resize by dragging edge */
\r
3048 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3050 BoardSize newSize = NUM_SIZES - 1;
\r
3051 static int recurse = 0;
\r
3052 if (IsIconic(hwndMain)) return;
\r
3053 if (recurse > 0) return;
\r
3055 while (newSize > 0) {
\r
3056 InitDrawingSizes(newSize+1000, 0); // [HGM] kludge to update sizeInfo without visible effects
\r
3057 if(newSizeX >= sizeInfo[newSize].cliWidth &&
\r
3058 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3061 boardSize = newSize;
\r
3062 InitDrawingSizes(boardSize, flags);
\r
3069 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3071 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3072 ChessSquare piece;
\r
3073 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3075 SIZE clockSize, messageSize;
\r
3077 char buf[MSG_SIZ];
\r
3079 HMENU hmenu = GetMenu(hwndMain);
\r
3080 RECT crect, wrect;
\r
3082 LOGBRUSH logbrush;
\r
3084 int suppressVisibleEffects = 0; // [HGM] kludge to request updating sizeInfo only
\r
3085 if((int)boardSize >= 1000 ) { boardSize -= 1000; suppressVisibleEffects = 1; }
\r
3087 /* [HGM] call with -2 uses old size (for if nr of files, ranks changes) */
\r
3088 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3090 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3091 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3092 squareSize = sizeInfo[boardSize].squareSize;
\r
3093 lineGap = sizeInfo[boardSize].lineGap;
\r
3094 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3096 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3097 lineGap = appData.overrideLineGap;
\r
3100 if (tinyLayout != oldTinyLayout) {
\r
3101 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3103 style &= ~WS_SYSMENU;
\r
3104 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3105 "&Minimize\tCtrl+F4");
\r
3107 style |= WS_SYSMENU;
\r
3108 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3110 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3112 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3113 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3114 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3116 DrawMenuBar(hwndMain);
\r
3119 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3120 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3122 /* Get text area sizes */
\r
3123 hdc = GetDC(hwndMain);
\r
3124 if (appData.clockMode) {
\r
3125 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3127 sprintf(buf, "White");
\r
3129 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3130 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3131 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3132 str = "We only care about the height here";
\r
3133 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3134 SelectObject(hdc, oldFont);
\r
3135 ReleaseDC(hwndMain, hdc);
\r
3137 /* Compute where everything goes */
\r
3138 if(first.programLogo || second.programLogo) {
\r
3139 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3140 logoHeight = 2*clockSize.cy;
\r
3141 leftLogoRect.left = OUTER_MARGIN;
\r
3142 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3143 leftLogoRect.top = OUTER_MARGIN;
\r
3144 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3146 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3147 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3148 rightLogoRect.top = OUTER_MARGIN;
\r
3149 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3152 blackRect.left = leftLogoRect.right;
\r
3153 blackRect.right = rightLogoRect.left;
\r
3154 blackRect.top = OUTER_MARGIN;
\r
3155 blackRect.bottom = blackRect.top + clockSize.cy;
\r
3157 whiteRect.left = blackRect.left ;
\r
3158 whiteRect.right = blackRect.right;
\r
3159 whiteRect.top = blackRect.bottom;
\r
3160 whiteRect.bottom = leftLogoRect.bottom;
\r
3162 whiteRect.left = OUTER_MARGIN;
\r
3163 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3164 whiteRect.top = OUTER_MARGIN + logoHeight;
\r
3165 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3167 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3168 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3169 blackRect.top = whiteRect.top;
\r
3170 blackRect.bottom = whiteRect.bottom;
\r
3173 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3174 if (appData.showButtonBar) {
\r
3175 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3176 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3178 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3180 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3181 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3183 boardRect.left = OUTER_MARGIN;
\r
3184 boardRect.right = boardRect.left + boardWidth;
\r
3185 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3186 boardRect.bottom = boardRect.top + boardHeight;
\r
3188 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3189 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3190 if(suppressVisibleEffects) return; // [HGM] when called for filling sizeInfo only
\r
3191 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3192 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3193 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3194 GetWindowRect(hwndMain, &wrect);
\r
3195 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3196 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3197 /* compensate if menu bar wrapped */
\r
3198 GetClientRect(hwndMain, &crect);
\r
3199 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3200 winHeight += offby;
\r
3202 case WMSZ_TOPLEFT:
\r
3203 SetWindowPos(hwndMain, NULL,
\r
3204 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3205 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3208 case WMSZ_TOPRIGHT:
\r
3210 SetWindowPos(hwndMain, NULL,
\r
3211 wrect.left, wrect.bottom - winHeight,
\r
3212 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3215 case WMSZ_BOTTOMLEFT:
\r
3217 SetWindowPos(hwndMain, NULL,
\r
3218 wrect.right - winWidth, wrect.top,
\r
3219 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3222 case WMSZ_BOTTOMRIGHT:
\r
3226 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3227 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3232 for (i = 0; i < N_BUTTONS; i++) {
\r
3233 if (buttonDesc[i].hwnd != NULL) {
\r
3234 DestroyWindow(buttonDesc[i].hwnd);
\r
3235 buttonDesc[i].hwnd = NULL;
\r
3237 if (appData.showButtonBar) {
\r
3238 buttonDesc[i].hwnd =
\r
3239 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3240 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3241 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3242 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3243 (HMENU) buttonDesc[i].id,
\r
3244 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3246 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3247 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3248 MAKELPARAM(FALSE, 0));
\r
3250 if (buttonDesc[i].id == IDM_Pause)
\r
3251 hwndPause = buttonDesc[i].hwnd;
\r
3252 buttonDesc[i].wndproc = (WNDPROC)
\r
3253 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3256 if (gridPen != NULL) DeleteObject(gridPen);
\r
3257 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3258 if (premovePen != NULL) DeleteObject(premovePen);
\r
3259 if (lineGap != 0) {
\r
3260 logbrush.lbStyle = BS_SOLID;
\r
3261 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3263 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3264 lineGap, &logbrush, 0, NULL);
\r
3265 logbrush.lbColor = highlightSquareColor;
\r
3267 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3268 lineGap, &logbrush, 0, NULL);
\r
3270 logbrush.lbColor = premoveHighlightColor;
\r
3272 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3273 lineGap, &logbrush, 0, NULL);
\r
3275 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3276 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3277 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3278 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3279 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3280 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3281 BOARD_WIDTH * (squareSize + lineGap);
\r
3282 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3284 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3285 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3286 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3287 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3288 lineGap / 2 + (i * (squareSize + lineGap));
\r
3289 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3290 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3291 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3295 /* [HGM] Licensing requirement */
\r
3297 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3300 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3302 GothicPopUp( "", VariantNormal);
\r
3305 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3306 oldBoardSize = boardSize;
\r
3307 oldTinyLayout = tinyLayout;
\r
3309 /* Load piece bitmaps for this board size */
\r
3310 for (i=0; i<=2; i++) {
\r
3311 for (piece = WhitePawn;
\r
3312 (int) piece < (int) BlackPawn;
\r
3313 piece = (ChessSquare) ((int) piece + 1)) {
\r
3314 if (pieceBitmap[i][piece] != NULL)
\r
3315 DeleteObject(pieceBitmap[i][piece]);
\r
3319 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3320 // Orthodox Chess pieces
\r
3321 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3322 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3323 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3324 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3325 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3326 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3327 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3328 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3329 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3330 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3331 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3332 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3333 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3334 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3335 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3336 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3337 // in Shogi, Hijack the unused Queen for Lance
\r
3338 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3339 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3340 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3342 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3343 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3344 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3347 if(squareSize <= 72 && squareSize >= 33) {
\r
3348 /* A & C are available in most sizes now */
\r
3349 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3350 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3351 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3352 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3353 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3354 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3355 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3356 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3357 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3358 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3359 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3360 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3361 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3362 } else { // Smirf-like
\r
3363 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3364 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3365 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3367 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3368 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3369 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3370 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3371 } else { // WinBoard standard
\r
3372 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3373 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3374 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3379 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3380 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3381 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3382 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3383 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3384 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3385 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3386 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3387 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3388 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3389 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3390 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3391 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3392 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3393 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3394 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3395 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3396 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3397 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3398 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3399 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3400 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3401 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3402 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3403 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3404 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3405 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3406 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3407 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3408 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3409 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3411 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3412 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3413 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3414 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3415 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3416 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3417 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3418 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3419 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3420 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3421 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3422 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3423 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3425 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3426 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3427 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3428 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3429 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3430 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3431 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3432 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3433 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3434 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3435 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3436 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3439 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3440 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3441 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3442 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3443 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3444 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3445 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3446 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3447 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3448 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3449 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3450 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3451 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3452 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3453 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3457 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3458 /* special Shogi support in this size */
\r
3459 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3460 for (piece = WhitePawn;
\r
3461 (int) piece < (int) BlackPawn;
\r
3462 piece = (ChessSquare) ((int) piece + 1)) {
\r
3463 if (pieceBitmap[i][piece] != NULL)
\r
3464 DeleteObject(pieceBitmap[i][piece]);
\r
3467 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3468 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3469 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3470 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3471 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3472 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3473 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3474 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3475 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3476 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3477 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3478 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3479 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3480 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3481 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3482 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3483 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3484 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3485 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3486 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3487 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3488 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3489 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3490 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3491 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3492 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3493 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3494 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3495 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3496 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3497 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3498 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3499 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3500 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3501 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3502 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3503 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3504 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3505 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3506 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3507 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3508 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3514 PieceBitmap(ChessSquare p, int kind)
\r
3516 if ((int) p >= (int) BlackPawn)
\r
3517 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3519 return pieceBitmap[kind][(int) p];
\r
3522 /***************************************************************/
\r
3524 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3525 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3527 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3528 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3532 SquareToPos(int row, int column, int * x, int * y)
\r
3535 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3536 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3538 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3539 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3544 DrawCoordsOnDC(HDC hdc)
\r
3546 static char files[24] = {'0', '1','2','3','4','5','6','7','8','9','0','1','1','0','9','8','7','6','5','4','3','2','1','0'};
\r
3547 static char ranks[24] = {'l', 'k','j','i','h','g','f','e','d','c','b','a','a','b','c','d','e','f','g','h','i','j','k','l'};
\r
3548 char str[2] = { NULLCHAR, NULLCHAR };
\r
3549 int oldMode, oldAlign, x, y, start, i;
\r
3553 if (!appData.showCoords)
\r
3556 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3558 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3559 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3560 oldAlign = GetTextAlign(hdc);
\r
3561 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3563 y = boardRect.top + lineGap;
\r
3564 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3566 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3567 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3568 str[0] = files[start + i];
\r
3569 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3570 y += squareSize + lineGap;
\r
3573 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3575 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3576 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3577 str[0] = ranks[start + i];
\r
3578 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3579 x += squareSize + lineGap;
\r
3582 SelectObject(hdc, oldBrush);
\r
3583 SetBkMode(hdc, oldMode);
\r
3584 SetTextAlign(hdc, oldAlign);
\r
3585 SelectObject(hdc, oldFont);
\r
3589 DrawGridOnDC(HDC hdc)
\r
3593 if (lineGap != 0) {
\r
3594 oldPen = SelectObject(hdc, gridPen);
\r
3595 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3596 SelectObject(hdc, oldPen);
\r
3600 #define HIGHLIGHT_PEN 0
\r
3601 #define PREMOVE_PEN 1
\r
3604 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3607 HPEN oldPen, hPen;
\r
3608 if (lineGap == 0) return;
\r
3610 x1 = boardRect.left +
\r
3611 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3612 y1 = boardRect.top +
\r
3613 lineGap/2 + y * (squareSize + lineGap);
\r
3615 x1 = boardRect.left +
\r
3616 lineGap/2 + x * (squareSize + lineGap);
\r
3617 y1 = boardRect.top +
\r
3618 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3620 hPen = pen ? premovePen : highlightPen;
\r
3621 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3622 MoveToEx(hdc, x1, y1, NULL);
\r
3623 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3624 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3625 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3626 LineTo(hdc, x1, y1);
\r
3627 SelectObject(hdc, oldPen);
\r
3631 DrawHighlightsOnDC(HDC hdc)
\r
3634 for (i=0; i<2; i++) {
\r
3635 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3636 DrawHighlightOnDC(hdc, TRUE,
\r
3637 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3640 for (i=0; i<2; i++) {
\r
3641 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3642 premoveHighlightInfo.sq[i].y >= 0) {
\r
3643 DrawHighlightOnDC(hdc, TRUE,
\r
3644 premoveHighlightInfo.sq[i].x,
\r
3645 premoveHighlightInfo.sq[i].y,
\r
3651 /* Note: sqcolor is used only in monoMode */
\r
3652 /* Note that this code is largely duplicated in woptions.c,
\r
3653 function DrawSampleSquare, so that needs to be updated too */
\r
3655 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3657 HBITMAP oldBitmap;
\r
3661 if (appData.blindfold) return;
\r
3663 /* [AS] Use font-based pieces if needed */
\r
3664 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3665 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3666 CreatePiecesFromFont();
\r
3668 if( fontBitmapSquareSize == squareSize ) {
\r
3669 int index = TranslatePieceToFontPiece(piece);
\r
3671 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3675 squareSize, squareSize,
\r
3680 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3684 squareSize, squareSize,
\r
3693 if (appData.monoMode) {
\r
3694 SelectObject(tmphdc, PieceBitmap(piece,
\r
3695 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3696 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3697 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3699 tmpSize = squareSize;
\r
3701 ((piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper) ||
\r
3702 (piece >= (int)BlackNightrider && piece <= BlackGrasshopper)) ) {
\r
3703 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3704 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3705 x += (squareSize - minorSize)>>1;
\r
3706 y += squareSize - minorSize - 2;
\r
3707 tmpSize = minorSize;
\r
3709 if (color || appData.allWhite ) {
\r
3710 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3712 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3713 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3714 if(appData.upsideDown && color==flipView)
\r
3715 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3717 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3719 /* Use black piece color for outline of white pieces */
\r
3720 /* Not sure this looks really good (though xboard does it).
\r
3721 Maybe better to have another selectable color, default black */
\r
3722 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3723 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3724 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3726 /* Use black for outline of white pieces */
\r
3727 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3728 if(appData.upsideDown && color==flipView)
\r
3729 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3731 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3735 /* Use white piece color for details of black pieces */
\r
3736 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3737 WHITE_PIECE ones aren't always the right shape. */
\r
3738 /* Not sure this looks really good (though xboard does it).
\r
3739 Maybe better to have another selectable color, default medium gray? */
\r
3740 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3741 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3742 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3743 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3744 SelectObject(hdc, blackPieceBrush);
\r
3745 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3747 /* Use square color for details of black pieces */
\r
3748 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3749 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3750 if(appData.upsideDown && !flipView)
\r
3751 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3753 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3756 SelectObject(hdc, oldBrush);
\r
3757 SelectObject(tmphdc, oldBitmap);
\r
3761 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3762 int GetBackTextureMode( int algo )
\r
3764 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3768 case BACK_TEXTURE_MODE_PLAIN:
\r
3769 result = 1; /* Always use identity map */
\r
3771 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3772 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3780 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3781 to handle redraws cleanly (as random numbers would always be different).
\r
3783 VOID RebuildTextureSquareInfo()
\r
3793 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3795 if( liteBackTexture != NULL ) {
\r
3796 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3797 lite_w = bi.bmWidth;
\r
3798 lite_h = bi.bmHeight;
\r
3802 if( darkBackTexture != NULL ) {
\r
3803 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3804 dark_w = bi.bmWidth;
\r
3805 dark_h = bi.bmHeight;
\r
3809 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3810 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3811 if( (col + row) & 1 ) {
\r
3813 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3814 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3815 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3816 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3821 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3822 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3823 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3824 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3831 /* [AS] Arrow highlighting support */
\r
3833 static int A_WIDTH = 5; /* Width of arrow body */
\r
3835 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3836 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3838 static double Sqr( double x )
\r
3843 static int Round( double x )
\r
3845 return (int) (x + 0.5);
\r
3848 /* Draw an arrow between two points using current settings */
\r
3849 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3852 double dx, dy, j, k, x, y;
\r
3854 if( d_x == s_x ) {
\r
3855 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3857 arrow[0].x = s_x + A_WIDTH;
\r
3860 arrow[1].x = s_x + A_WIDTH;
\r
3861 arrow[1].y = d_y - h;
\r
3863 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3864 arrow[2].y = d_y - h;
\r
3869 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3870 arrow[4].y = d_y - h;
\r
3872 arrow[5].x = s_x - A_WIDTH;
\r
3873 arrow[5].y = d_y - h;
\r
3875 arrow[6].x = s_x - A_WIDTH;
\r
3878 else if( d_y == s_y ) {
\r
3879 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3882 arrow[0].y = s_y + A_WIDTH;
\r
3884 arrow[1].x = d_x - w;
\r
3885 arrow[1].y = s_y + A_WIDTH;
\r
3887 arrow[2].x = d_x - w;
\r
3888 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3893 arrow[4].x = d_x - w;
\r
3894 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3896 arrow[5].x = d_x - w;
\r
3897 arrow[5].y = s_y - A_WIDTH;
\r
3900 arrow[6].y = s_y - A_WIDTH;
\r
3903 /* [AS] Needed a lot of paper for this! :-) */
\r
3904 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3905 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3907 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3909 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3914 arrow[0].x = Round(x - j);
\r
3915 arrow[0].y = Round(y + j*dx);
\r
3917 arrow[1].x = Round(x + j);
\r
3918 arrow[1].y = Round(y - j*dx);
\r
3921 x = (double) d_x - k;
\r
3922 y = (double) d_y - k*dy;
\r
3925 x = (double) d_x + k;
\r
3926 y = (double) d_y + k*dy;
\r
3929 arrow[2].x = Round(x + j);
\r
3930 arrow[2].y = Round(y - j*dx);
\r
3932 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3933 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3938 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3939 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3941 arrow[6].x = Round(x - j);
\r
3942 arrow[6].y = Round(y + j*dx);
\r
3945 Polygon( hdc, arrow, 7 );
\r
3948 /* [AS] Draw an arrow between two squares */
\r
3949 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3951 int s_x, s_y, d_x, d_y;
\r
3958 if( s_col == d_col && s_row == d_row ) {
\r
3962 /* Get source and destination points */
\r
3963 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3964 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3967 d_y += squareSize / 4;
\r
3969 else if( d_y < s_y ) {
\r
3970 d_y += 3 * squareSize / 4;
\r
3973 d_y += squareSize / 2;
\r
3977 d_x += squareSize / 4;
\r
3979 else if( d_x < s_x ) {
\r
3980 d_x += 3 * squareSize / 4;
\r
3983 d_x += squareSize / 2;
\r
3986 s_x += squareSize / 2;
\r
3987 s_y += squareSize / 2;
\r
3989 /* Adjust width */
\r
3990 A_WIDTH = squareSize / 14;
\r
3993 stLB.lbStyle = BS_SOLID;
\r
3994 stLB.lbColor = appData.highlightArrowColor;
\r
3997 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3998 holdpen = SelectObject( hdc, hpen );
\r
3999 hbrush = CreateBrushIndirect( &stLB );
\r
4000 holdbrush = SelectObject( hdc, hbrush );
\r
4002 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
4004 SelectObject( hdc, holdpen );
\r
4005 SelectObject( hdc, holdbrush );
\r
4006 DeleteObject( hpen );
\r
4007 DeleteObject( hbrush );
\r
4010 BOOL HasHighlightInfo()
\r
4012 BOOL result = FALSE;
\r
4014 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
4015 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
4023 BOOL IsDrawArrowEnabled()
\r
4025 BOOL result = FALSE;
\r
4027 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
4034 VOID DrawArrowHighlight( HDC hdc )
\r
4036 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4037 DrawArrowBetweenSquares( hdc,
\r
4038 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4039 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4043 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4045 HRGN result = NULL;
\r
4047 if( HasHighlightInfo() ) {
\r
4048 int x1, y1, x2, y2;
\r
4049 int sx, sy, dx, dy;
\r
4051 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4052 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4054 sx = MIN( x1, x2 );
\r
4055 sy = MIN( y1, y2 );
\r
4056 dx = MAX( x1, x2 ) + squareSize;
\r
4057 dy = MAX( y1, y2 ) + squareSize;
\r
4059 result = CreateRectRgn( sx, sy, dx, dy );
\r
4066 Warning: this function modifies the behavior of several other functions.
\r
4068 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4069 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4070 repaint is scattered all over the place, which is not good for features such as
\r
4071 "arrow highlighting" that require a full repaint of the board.
\r
4073 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4074 user interaction, when speed is not so important) but especially to avoid errors
\r
4075 in the displayed graphics.
\r
4077 In such patched places, I always try refer to this function so there is a single
\r
4078 place to maintain knowledge.
\r
4080 To restore the original behavior, just return FALSE unconditionally.
\r
4082 BOOL IsFullRepaintPreferrable()
\r
4084 BOOL result = FALSE;
\r
4086 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4087 /* Arrow may appear on the board */
\r
4095 This function is called by DrawPosition to know whether a full repaint must
\r
4098 Only DrawPosition may directly call this function, which makes use of
\r
4099 some state information. Other function should call DrawPosition specifying
\r
4100 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4102 BOOL DrawPositionNeedsFullRepaint()
\r
4104 BOOL result = FALSE;
\r
4107 Probably a slightly better policy would be to trigger a full repaint
\r
4108 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4109 but animation is fast enough that it's difficult to notice.
\r
4111 if( animInfo.piece == EmptySquare ) {
\r
4112 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4121 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4123 int row, column, x, y, square_color, piece_color;
\r
4124 ChessSquare piece;
\r
4126 HDC texture_hdc = NULL;
\r
4128 /* [AS] Initialize background textures if needed */
\r
4129 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4130 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4131 if( backTextureSquareSize != squareSize
\r
4132 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4133 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4134 backTextureSquareSize = squareSize;
\r
4135 RebuildTextureSquareInfo();
\r
4138 texture_hdc = CreateCompatibleDC( hdc );
\r
4141 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4142 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4144 SquareToPos(row, column, &x, &y);
\r
4146 piece = board[row][column];
\r
4148 square_color = ((column + row) % 2) == 1;
\r
4149 if( gameInfo.variant == VariantXiangqi ) {
\r
4150 square_color = !InPalace(row, column);
\r
4151 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4152 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4154 piece_color = (int) piece < (int) BlackPawn;
\r
4157 /* [HGM] holdings file: light square or black */
\r
4158 if(column == BOARD_LEFT-2) {
\r
4159 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4162 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4166 if(column == BOARD_RGHT + 1 ) {
\r
4167 if( row < gameInfo.holdingsSize )
\r
4170 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4174 if(column == BOARD_LEFT-1 ) /* left align */
\r
4175 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4176 else if( column == BOARD_RGHT) /* right align */
\r
4177 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4179 if (appData.monoMode) {
\r
4180 if (piece == EmptySquare) {
\r
4181 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4182 square_color ? WHITENESS : BLACKNESS);
\r
4184 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4187 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4188 /* [AS] Draw the square using a texture bitmap */
\r
4189 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4190 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4191 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4194 squareSize, squareSize,
\r
4197 backTextureSquareInfo[r][c].mode,
\r
4198 backTextureSquareInfo[r][c].x,
\r
4199 backTextureSquareInfo[r][c].y );
\r
4201 SelectObject( texture_hdc, hbm );
\r
4203 if (piece != EmptySquare) {
\r
4204 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4208 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4210 oldBrush = SelectObject(hdc, brush );
\r
4211 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4212 SelectObject(hdc, oldBrush);
\r
4213 if (piece != EmptySquare)
\r
4214 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4219 if( texture_hdc != NULL ) {
\r
4220 DeleteDC( texture_hdc );
\r
4224 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4225 void fputDW(FILE *f, int x)
\r
4227 fputc(x & 255, f);
\r
4228 fputc(x>>8 & 255, f);
\r
4229 fputc(x>>16 & 255, f);
\r
4230 fputc(x>>24 & 255, f);
\r
4233 #define MAX_CLIPS 200 /* more than enough */
\r
4236 DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)
\r
4238 // HBITMAP bufferBitmap;
\r
4243 int w = 100, h = 50;
\r
4245 if(cps->programLogo == NULL) return;
\r
4246 // GetClientRect(hwndMain, &Rect);
\r
4247 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4248 // Rect.bottom-Rect.top+1);
\r
4249 tmphdc = CreateCompatibleDC(hdc);
\r
4250 hbm = SelectObject(tmphdc, (HBITMAP) cps->programLogo);
\r
4251 if( GetObject( cps->programLogo, sizeof(bi), &bi ) > 0 ) {
\r
4255 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4256 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4257 SelectObject(tmphdc, hbm);
\r
4262 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4264 static Board lastReq, lastDrawn;
\r
4265 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4266 static int lastDrawnFlipView = 0;
\r
4267 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4268 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4271 HBITMAP bufferBitmap;
\r
4272 HBITMAP oldBitmap;
\r
4274 HRGN clips[MAX_CLIPS];
\r
4275 ChessSquare dragged_piece = EmptySquare;
\r
4277 /* I'm undecided on this - this function figures out whether a full
\r
4278 * repaint is necessary on its own, so there's no real reason to have the
\r
4279 * caller tell it that. I think this can safely be set to FALSE - but
\r
4280 * if we trust the callers not to request full repaints unnessesarily, then
\r
4281 * we could skip some clipping work. In other words, only request a full
\r
4282 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4283 * gamestart and similar) --Hawk
\r
4285 Boolean fullrepaint = repaint;
\r
4287 if( DrawPositionNeedsFullRepaint() ) {
\r
4288 fullrepaint = TRUE;
\r
4292 if( fullrepaint ) {
\r
4293 static int repaint_count = 0;
\r
4297 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4298 OutputDebugString( buf );
\r
4302 if (board == NULL) {
\r
4303 if (!lastReqValid) {
\r
4308 CopyBoard(lastReq, board);
\r
4312 if (doingSizing) {
\r
4316 if (IsIconic(hwndMain)) {
\r
4320 if (hdc == NULL) {
\r
4321 hdc = GetDC(hwndMain);
\r
4322 if (!appData.monoMode) {
\r
4323 SelectPalette(hdc, hPal, FALSE);
\r
4324 RealizePalette(hdc);
\r
4328 releaseDC = FALSE;
\r
4332 fprintf(debugFP, "*******************************\n"
\r
4334 "dragInfo.from (%d,%d)\n"
\r
4335 "dragInfo.start (%d,%d)\n"
\r
4336 "dragInfo.pos (%d,%d)\n"
\r
4337 "dragInfo.lastpos (%d,%d)\n",
\r
4338 repaint ? "TRUE" : "FALSE",
\r
4339 dragInfo.from.x, dragInfo.from.y,
\r
4340 dragInfo.start.x, dragInfo.start.y,
\r
4341 dragInfo.pos.x, dragInfo.pos.y,
\r
4342 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4343 fprintf(debugFP, "prev: ");
\r
4344 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4345 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4346 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4349 fprintf(debugFP, "\n");
\r
4350 fprintf(debugFP, "board: ");
\r
4351 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4352 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4353 fprintf(debugFP, "%d ", board[row][column]);
\r
4356 fprintf(debugFP, "\n");
\r
4360 /* Create some work-DCs */
\r
4361 hdcmem = CreateCompatibleDC(hdc);
\r
4362 tmphdc = CreateCompatibleDC(hdc);
\r
4364 /* If dragging is in progress, we temporarely remove the piece */
\r
4365 /* [HGM] or temporarily decrease count if stacked */
\r
4366 /* !! Moved to before board compare !! */
\r
4367 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4368 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4369 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4370 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4371 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4373 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4374 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4375 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4377 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4380 /* Figure out which squares need updating by comparing the
\r
4381 * newest board with the last drawn board and checking if
\r
4382 * flipping has changed.
\r
4384 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4385 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4386 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4387 if (lastDrawn[row][column] != board[row][column]) {
\r
4388 SquareToPos(row, column, &x, &y);
\r
4389 clips[num_clips++] =
\r
4390 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4394 for (i=0; i<2; i++) {
\r
4395 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4396 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4397 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4398 lastDrawnHighlight.sq[i].y >= 0) {
\r
4399 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4400 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4401 clips[num_clips++] =
\r
4402 CreateRectRgn(x - lineGap, y - lineGap,
\r
4403 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4405 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4406 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4407 clips[num_clips++] =
\r
4408 CreateRectRgn(x - lineGap, y - lineGap,
\r
4409 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4413 for (i=0; i<2; i++) {
\r
4414 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4415 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4416 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4417 lastDrawnPremove.sq[i].y >= 0) {
\r
4418 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4419 lastDrawnPremove.sq[i].x, &x, &y);
\r
4420 clips[num_clips++] =
\r
4421 CreateRectRgn(x - lineGap, y - lineGap,
\r
4422 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4424 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4425 premoveHighlightInfo.sq[i].y >= 0) {
\r
4426 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4427 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4428 clips[num_clips++] =
\r
4429 CreateRectRgn(x - lineGap, y - lineGap,
\r
4430 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4435 fullrepaint = TRUE;
\r
4438 /* Create a buffer bitmap - this is the actual bitmap
\r
4439 * being written to. When all the work is done, we can
\r
4440 * copy it to the real DC (the screen). This avoids
\r
4441 * the problems with flickering.
\r
4443 GetClientRect(hwndMain, &Rect);
\r
4444 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4445 Rect.bottom-Rect.top+1);
\r
4446 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4447 if (!appData.monoMode) {
\r
4448 SelectPalette(hdcmem, hPal, FALSE);
\r
4451 /* Create clips for dragging */
\r
4452 if (!fullrepaint) {
\r
4453 if (dragInfo.from.x >= 0) {
\r
4454 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4455 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4457 if (dragInfo.start.x >= 0) {
\r
4458 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4459 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4461 if (dragInfo.pos.x >= 0) {
\r
4462 x = dragInfo.pos.x - squareSize / 2;
\r
4463 y = dragInfo.pos.y - squareSize / 2;
\r
4464 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4466 if (dragInfo.lastpos.x >= 0) {
\r
4467 x = dragInfo.lastpos.x - squareSize / 2;
\r
4468 y = dragInfo.lastpos.y - squareSize / 2;
\r
4469 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4473 /* Are we animating a move?
\r
4475 * - remove the piece from the board (temporarely)
\r
4476 * - calculate the clipping region
\r
4478 if (!fullrepaint) {
\r
4479 if (animInfo.piece != EmptySquare) {
\r
4480 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4481 x = boardRect.left + animInfo.lastpos.x;
\r
4482 y = boardRect.top + animInfo.lastpos.y;
\r
4483 x2 = boardRect.left + animInfo.pos.x;
\r
4484 y2 = boardRect.top + animInfo.pos.y;
\r
4485 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4486 /* Slight kludge. The real problem is that after AnimateMove is
\r
4487 done, the position on the screen does not match lastDrawn.
\r
4488 This currently causes trouble only on e.p. captures in
\r
4489 atomic, where the piece moves to an empty square and then
\r
4490 explodes. The old and new positions both had an empty square
\r
4491 at the destination, but animation has drawn a piece there and
\r
4492 we have to remember to erase it. [HGM] moved until after setting lastDrawn */
\r
4493 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4497 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4498 if (num_clips == 0)
\r
4499 fullrepaint = TRUE;
\r
4501 /* Set clipping on the memory DC */
\r
4502 if (!fullrepaint) {
\r
4503 SelectClipRgn(hdcmem, clips[0]);
\r
4504 for (x = 1; x < num_clips; x++) {
\r
4505 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4506 abort(); // this should never ever happen!
\r
4510 /* Do all the drawing to the memory DC */
\r
4511 if(explodeInfo.radius) { // [HGM] atomic
\r
4513 int x, y, r=(explodeInfo.radius * squareSize)/100;
\r
4514 SquareToPos(explodeInfo.y, explodeInfo.x, &x, &y);
\r
4515 x += squareSize/2;
\r
4516 y += squareSize/2;
\r
4517 if(!fullrepaint) {
\r
4518 clips[num_clips] = CreateRectRgn(x-r, y-r, x+r, y+r);
\r
4519 ExtSelectClipRgn(hdcmem, clips[num_clips++], RGN_OR);
\r
4521 DrawGridOnDC(hdcmem);
\r
4522 DrawHighlightsOnDC(hdcmem);
\r
4523 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4524 oldBrush = SelectObject(hdcmem, explodeBrush);
\r
4525 Ellipse(hdcmem, x-r, y-r, x+r, y+r);
\r
4526 SelectObject(hdcmem, oldBrush);
\r
4528 DrawGridOnDC(hdcmem);
\r
4529 DrawHighlightsOnDC(hdcmem);
\r
4530 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4533 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);
\r
4534 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);
\r
4537 if( appData.highlightMoveWithArrow ) {
\r
4538 DrawArrowHighlight(hdcmem);
\r
4541 DrawCoordsOnDC(hdcmem);
\r
4543 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4544 /* to make sure lastDrawn contains what is actually drawn */
\r
4546 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4547 if (dragged_piece != EmptySquare) {
\r
4548 /* [HGM] or restack */
\r
4549 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4550 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4552 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4553 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4554 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4555 x = dragInfo.pos.x - squareSize / 2;
\r
4556 y = dragInfo.pos.y - squareSize / 2;
\r
4557 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4558 ((int) dragged_piece < (int) BlackPawn),
\r
4559 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4562 /* Put the animated piece back into place and draw it */
\r
4563 if (animInfo.piece != EmptySquare) {
\r
4564 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4565 x = boardRect.left + animInfo.pos.x;
\r
4566 y = boardRect.top + animInfo.pos.y;
\r
4567 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4568 ((int) animInfo.piece < (int) BlackPawn),
\r
4569 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4572 /* Release the bufferBitmap by selecting in the old bitmap
\r
4573 * and delete the memory DC
\r
4575 SelectObject(hdcmem, oldBitmap);
\r
4578 /* Set clipping on the target DC */
\r
4579 if (!fullrepaint) {
\r
4580 SelectClipRgn(hdc, clips[0]);
\r
4581 for (x = 1; x < num_clips; x++) {
\r
4582 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4583 abort(); // this should never ever happen!
\r
4587 /* Copy the new bitmap onto the screen in one go.
\r
4588 * This way we avoid any flickering
\r
4590 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4591 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4592 boardRect.right - boardRect.left,
\r
4593 boardRect.bottom - boardRect.top,
\r
4594 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4595 if(saveDiagFlag) {
\r
4596 BITMAP b; int i, j=0, m, w, wb, fac=0; char pData[1000000];
\r
4597 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4599 GetObject(bufferBitmap, sizeof(b), &b);
\r
4600 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4601 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4602 bih.biWidth = b.bmWidth;
\r
4603 bih.biHeight = b.bmHeight;
\r
4605 bih.biBitCount = b.bmBitsPixel;
\r
4606 bih.biCompression = 0;
\r
4607 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4608 bih.biXPelsPerMeter = 0;
\r
4609 bih.biYPelsPerMeter = 0;
\r
4610 bih.biClrUsed = 0;
\r
4611 bih.biClrImportant = 0;
\r
4612 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4613 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4614 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4615 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4618 wb = b.bmWidthBytes;
\r
4620 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4621 int k = ((int*) pData)[i];
\r
4622 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4623 if(j >= 16) break;
\r
4625 if(j >= nrColors) nrColors = j+1;
\r
4627 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4629 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4630 for(w=0; w<(wb>>2); w+=2) {
\r
4631 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4632 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4633 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4634 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4635 pData[p++] = m | j<<4;
\r
4637 while(p&3) pData[p++] = 0;
\r
4640 wb = ((wb+31)>>5)<<2;
\r
4642 // write BITMAPFILEHEADER
\r
4643 fprintf(diagFile, "BM");
\r
4644 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4645 fputDW(diagFile, 0);
\r
4646 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4647 // write BITMAPINFOHEADER
\r
4648 fputDW(diagFile, 40);
\r
4649 fputDW(diagFile, b.bmWidth);
\r
4650 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4651 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4652 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4653 fputDW(diagFile, 0);
\r
4654 fputDW(diagFile, 0);
\r
4655 fputDW(diagFile, 0);
\r
4656 fputDW(diagFile, 0);
\r
4657 fputDW(diagFile, 0);
\r
4658 fputDW(diagFile, 0);
\r
4659 // write color table
\r
4661 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4662 // write bitmap data
\r
4663 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4664 fputc(pData[i], diagFile);
\r
4669 SelectObject(tmphdc, oldBitmap);
\r
4671 /* Massive cleanup */
\r
4672 for (x = 0; x < num_clips; x++)
\r
4673 DeleteObject(clips[x]);
\r
4676 DeleteObject(bufferBitmap);
\r
4679 ReleaseDC(hwndMain, hdc);
\r
4681 if (lastDrawnFlipView != flipView) {
\r
4683 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4685 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4688 /* CopyBoard(lastDrawn, board);*/
\r
4689 lastDrawnHighlight = highlightInfo;
\r
4690 lastDrawnPremove = premoveHighlightInfo;
\r
4691 lastDrawnFlipView = flipView;
\r
4692 lastDrawnValid = 1;
\r
4695 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4700 saveDiagFlag = 1; diagFile = f;
\r
4701 HDCDrawPosition(NULL, TRUE, NULL);
\r
4705 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4712 /*---------------------------------------------------------------------------*\
\r
4713 | CLIENT PAINT PROCEDURE
\r
4714 | This is the main event-handler for the WM_PAINT message.
\r
4716 \*---------------------------------------------------------------------------*/
\r
4718 PaintProc(HWND hwnd)
\r
4724 if((hdc = BeginPaint(hwnd, &ps))) {
\r
4725 if (IsIconic(hwnd)) {
\r
4726 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4728 if (!appData.monoMode) {
\r
4729 SelectPalette(hdc, hPal, FALSE);
\r
4730 RealizePalette(hdc);
\r
4732 HDCDrawPosition(hdc, 1, NULL);
\r
4734 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4735 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4736 ETO_CLIPPED|ETO_OPAQUE,
\r
4737 &messageRect, messageText, strlen(messageText), NULL);
\r
4738 SelectObject(hdc, oldFont);
\r
4739 DisplayBothClocks();
\r
4741 EndPaint(hwnd,&ps);
\r
4749 * If the user selects on a border boundary, return -1; if off the board,
\r
4750 * return -2. Otherwise map the event coordinate to the square.
\r
4751 * The offset boardRect.left or boardRect.top must already have been
\r
4752 * subtracted from x.
\r
4755 EventToSquare(int x)
\r
4762 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4764 x /= (squareSize + lineGap);
\r
4765 if (x >= BOARD_SIZE)
\r
4776 DropEnable dropEnables[] = {
\r
4777 { 'P', DP_Pawn, "Pawn" },
\r
4778 { 'N', DP_Knight, "Knight" },
\r
4779 { 'B', DP_Bishop, "Bishop" },
\r
4780 { 'R', DP_Rook, "Rook" },
\r
4781 { 'Q', DP_Queen, "Queen" },
\r
4785 SetupDropMenu(HMENU hmenu)
\r
4787 int i, count, enable;
\r
4789 extern char white_holding[], black_holding[];
\r
4790 char item[MSG_SIZ];
\r
4792 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4793 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4794 dropEnables[i].piece);
\r
4796 while (p && *p++ == dropEnables[i].piece) count++;
\r
4797 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4798 enable = count > 0 || !appData.testLegality
\r
4799 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4800 && !appData.icsActive);
\r
4801 ModifyMenu(hmenu, dropEnables[i].command,
\r
4802 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4803 dropEnables[i].command, item);
\r
4807 static int fromX = -1, fromY = -1, toX, toY;
\r
4809 /* Event handler for mouse messages */
\r
4811 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4815 static int recursive = 0;
\r
4817 // BOOLEAN needsRedraw = FALSE;
\r
4818 BOOLEAN saveAnimate;
\r
4819 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4820 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4821 ChessMove moveType;
\r
4824 if (message == WM_MBUTTONUP) {
\r
4825 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4826 to the middle button: we simulate pressing the left button too!
\r
4828 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4829 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4835 pt.x = LOWORD(lParam);
\r
4836 pt.y = HIWORD(lParam);
\r
4837 x = EventToSquare(pt.x - boardRect.left);
\r
4838 y = EventToSquare(pt.y - boardRect.top);
\r
4839 if (!flipView && y >= 0) {
\r
4840 y = BOARD_HEIGHT - 1 - y;
\r
4842 if (flipView && x >= 0) {
\r
4843 x = BOARD_WIDTH - 1 - x;
\r
4846 switch (message) {
\r
4847 case WM_LBUTTONDOWN:
\r
4848 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4849 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4850 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4851 if(gameInfo.holdingsWidth &&
\r
4852 (WhiteOnMove(currentMove)
\r
4853 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4854 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4855 // click in right holdings, for determining promotion piece
\r
4856 ChessSquare p = boards[currentMove][y][x];
\r
4857 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4858 if(p != EmptySquare) {
\r
4859 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4860 fromX = fromY = -1;
\r
4864 DrawPosition(FALSE, boards[currentMove]);
\r
4868 sameAgain = FALSE;
\r
4870 /* Downclick vertically off board; check if on clock */
\r
4871 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4872 if (gameMode == EditPosition) {
\r
4873 SetWhiteToPlayEvent();
\r
4874 } else if (gameMode == IcsPlayingBlack ||
\r
4875 gameMode == MachinePlaysWhite) {
\r
4877 } else if (gameMode == EditGame) {
\r
4878 AdjustClock((logoHeight > 0 ? flipView: flipClock), -1);
\r
4880 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4881 if (gameMode == EditPosition) {
\r
4882 SetBlackToPlayEvent();
\r
4883 } else if (gameMode == IcsPlayingWhite ||
\r
4884 gameMode == MachinePlaysBlack) {
\r
4886 } else if (gameMode == EditGame) {
\r
4887 AdjustClock(!(logoHeight > 0 ? flipView: flipClock), -1);
\r
4890 if (!appData.highlightLastMove) {
\r
4891 ClearHighlights();
\r
4892 DrawPosition((int) (forceFullRepaint || FALSE), NULL);
\r
4894 fromX = fromY = -1;
\r
4895 dragInfo.start.x = dragInfo.start.y = -1;
\r
4896 dragInfo.from = dragInfo.start;
\r
4898 } else if (x < 0 || y < 0
\r
4899 /* [HGM] block clicks between board and holdings */
\r
4900 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4901 || (x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize)
\r
4902 || (x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize)
\r
4903 /* EditPosition, empty square, or different color piece;
\r
4904 click-click move is possible */
\r
4907 } else if (fromX == x && fromY == y) {
\r
4908 /* Downclick on same square again */
\r
4909 ClearHighlights();
\r
4910 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4911 sameAgain = TRUE;
\r
4912 } else if (fromX != -1 &&
\r
4913 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4915 /* Downclick on different square. */
\r
4916 /* [HGM] if on holdings file, should count as new first click ! */
\r
4917 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4920 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4921 to make sure move is legal before showing promotion popup */
\r
4922 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4923 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4924 fromX = fromY = -1;
\r
4925 ClearHighlights();
\r
4926 DrawPosition(FALSE, boards[currentMove]);
\r
4929 if(moveType != ImpossibleMove) {
\r
4930 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4931 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4932 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4933 appData.alwaysPromoteToQueen)) {
\r
4934 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4935 if (!appData.highlightLastMove) {
\r
4936 ClearHighlights();
\r
4937 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4940 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4941 SetHighlights(fromX, fromY, toX, toY);
\r
4942 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4943 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4944 If promotion to Q is legal, all are legal! */
\r
4945 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4946 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4947 // kludge to temporarily execute move on display, wthout promotng yet
\r
4948 promotionChoice = TRUE;
\r
4949 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4950 boards[currentMove][toY][toX] = p;
\r
4951 DrawPosition(FALSE, boards[currentMove]);
\r
4952 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4953 boards[currentMove][toY][toX] = q;
\r
4955 PromotionPopup(hwnd);
\r
4956 } else { /* not a promotion */
\r
4957 if (appData.animate || appData.highlightLastMove) {
\r
4958 SetHighlights(fromX, fromY, toX, toY);
\r
4960 ClearHighlights();
\r
4962 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4963 fromX = fromY = -1;
\r
4964 if (appData.animate && !appData.highlightLastMove) {
\r
4965 ClearHighlights();
\r
4966 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4972 /* [HGM] it seemed that braces were missing here */
\r
4973 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4974 fromX = fromY = -1;
\r
4978 ClearHighlights();
\r
4979 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4981 /* First downclick, or restart on a square with same color piece */
\r
4982 if (!frozen && OKToStartUserMove(x, y)) {
\r
4985 dragInfo.lastpos = pt;
\r
4986 dragInfo.from.x = fromX;
\r
4987 dragInfo.from.y = fromY;
\r
4988 dragInfo.start = dragInfo.from;
\r
4989 SetCapture(hwndMain);
\r
4991 fromX = fromY = -1;
\r
4992 dragInfo.start.x = dragInfo.start.y = -1;
\r
4993 dragInfo.from = dragInfo.start;
\r
4994 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4998 case WM_LBUTTONUP:
\r
5000 if (fromX == -1) break;
\r
5001 if (x == fromX && y == fromY) {
\r
5002 dragInfo.from.x = dragInfo.from.y = -1;
\r
5003 /* Upclick on same square */
\r
5005 /* Clicked same square twice: abort click-click move */
\r
5006 fromX = fromY = -1;
\r
5008 ClearPremoveHighlights();
\r
5010 /* First square clicked: start click-click move */
\r
5011 SetHighlights(fromX, fromY, -1, -1);
\r
5013 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5014 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
5015 /* Errant click; ignore */
\r
5018 /* Finish drag move. */
\r
5019 if (appData.debugMode) {
\r
5020 fprintf(debugFP, "release\n");
\r
5022 dragInfo.from.x = dragInfo.from.y = -1;
\r
5025 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
5026 appData.animate = appData.animate && !appData.animateDragging;
\r
5027 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
5028 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
5029 fromX = fromY = -1;
\r
5030 ClearHighlights();
\r
5031 DrawPosition(FALSE, boards[currentMove]);
\r
5034 if(moveType != ImpossibleMove) {
\r
5035 /* [HGM] use move type to determine if move is promotion.
\r
5036 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
5037 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
5038 ((moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
5039 appData.alwaysPromoteToQueen))
\r
5040 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
5042 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
5043 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5044 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
5045 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
5046 // kludge to temporarily execute move on display, wthout promotng yet
\r
5047 promotionChoice = TRUE;
\r
5048 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
5049 boards[currentMove][toY][toX] = p;
\r
5050 DrawPosition(FALSE, boards[currentMove]);
\r
5051 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
5052 boards[currentMove][toY][toX] = q;
\r
5055 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5057 if(saveAnimate /* ^$!%@#$!$ */ && gameInfo.variant == VariantAtomic
\r
5058 && boards[currentMove][toY][toX] != EmptySquare) AnimateAtomicCapture(toX, toY, 20);
\r
5059 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5062 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5063 appData.animate = saveAnimate;
\r
5064 fromX = fromY = -1;
\r
5065 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5066 ClearHighlights();
\r
5068 if (appData.animate || appData.animateDragging ||
\r
5069 appData.highlightDragging || gotPremove) {
\r
5070 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5073 dragInfo.start.x = dragInfo.start.y = -1;
\r
5074 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5077 case WM_MOUSEMOVE:
\r
5078 if ((appData.animateDragging || appData.highlightDragging)
\r
5079 && (wParam & MK_LBUTTON)
\r
5080 && dragInfo.from.x >= 0)
\r
5082 BOOL full_repaint = FALSE;
\r
5084 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5085 if (appData.animateDragging) {
\r
5086 dragInfo.pos = pt;
\r
5088 if (appData.highlightDragging) {
\r
5089 SetHighlights(fromX, fromY, x, y);
\r
5090 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5091 full_repaint = TRUE;
\r
5095 DrawPosition( full_repaint, NULL);
\r
5097 dragInfo.lastpos = dragInfo.pos;
\r
5101 case WM_MOUSEWHEEL: // [DM]
\r
5102 { static int lastDir = 0; // [HGM] build in some hysteresis to avoid spurious events
\r
5103 /* Mouse Wheel is being rolled forward
\r
5104 * Play moves forward
\r
5106 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove)
\r
5107 { if(lastDir == 1) ForwardEvent(); else lastDir = 1; } // [HGM] suppress first event in direction
\r
5108 /* Mouse Wheel is being rolled backward
\r
5109 * Play moves backward
\r
5111 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove)
\r
5112 { if(lastDir == -1) BackwardEvent(); else lastDir = -1; }
\r
5116 case WM_MBUTTONDOWN:
\r
5117 case WM_RBUTTONDOWN:
\r
5120 fromX = fromY = -1;
\r
5121 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5122 dragInfo.start.x = dragInfo.start.y = -1;
\r
5123 dragInfo.from = dragInfo.start;
\r
5124 dragInfo.lastpos = dragInfo.pos;
\r
5125 if (appData.highlightDragging) {
\r
5126 ClearHighlights();
\r
5129 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5130 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5131 if (gameMode == EditGame) AdjustClock((logoHeight > 0 ? flipView: flipClock), 1);
\r
5132 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5133 if (gameMode == EditGame) AdjustClock(!(logoHeight > 0 ? flipView: flipClock), 1);
\r
5136 DrawPosition(TRUE, NULL);
\r
5138 switch (gameMode) {
\r
5139 case EditPosition:
\r
5140 case IcsExamining:
\r
5141 if (x < 0 || y < 0) break;
\r
5144 if (message == WM_MBUTTONDOWN) {
\r
5145 buttonCount = 3; /* even if system didn't think so */
\r
5146 if (wParam & MK_SHIFT)
\r
5147 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5149 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5150 } else { /* message == WM_RBUTTONDOWN */
\r
5152 if (buttonCount == 3) {
\r
5153 if (wParam & MK_SHIFT)
\r
5154 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5156 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5158 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5161 /* Just have one menu, on the right button. Windows users don't
\r
5162 think to try the middle one, and sometimes other software steals
\r
5163 it, or it doesn't really exist. */
\r
5164 if(gameInfo.variant != VariantShogi)
\r
5165 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5167 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5171 case IcsPlayingWhite:
\r
5172 case IcsPlayingBlack:
\r
5174 case MachinePlaysWhite:
\r
5175 case MachinePlaysBlack:
\r
5176 if (appData.testLegality &&
\r
5177 gameInfo.variant != VariantBughouse &&
\r
5178 gameInfo.variant != VariantCrazyhouse) break;
\r
5179 if (x < 0 || y < 0) break;
\r
5182 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5183 SetupDropMenu(hmenu);
\r
5184 MenuPopup(hwnd, pt, hmenu, -1);
\r
5195 /* Preprocess messages for buttons in main window */
\r
5197 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5199 int id = GetWindowLong(hwnd, GWL_ID);
\r
5202 for (i=0; i<N_BUTTONS; i++) {
\r
5203 if (buttonDesc[i].id == id) break;
\r
5205 if (i == N_BUTTONS) return 0;
\r
5206 switch (message) {
\r
5211 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5212 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5219 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5222 if (appData.icsActive) {
\r
5223 if (GetKeyState(VK_SHIFT) < 0) {
\r
5225 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5226 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5230 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5231 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5238 if (appData.icsActive) {
\r
5239 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5240 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5242 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5244 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5245 PopUpMoveDialog((char)wParam);
\r
5251 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5254 /* Process messages for Promotion dialog box */
\r
5256 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5260 switch (message) {
\r
5261 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5262 /* Center the dialog over the application window */
\r
5263 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5264 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5265 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5266 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5267 SW_SHOW : SW_HIDE);
\r
5268 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5269 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5270 ((PieceToChar(WhiteAngel) >= 'A' &&
\r
5271 PieceToChar(WhiteAngel) != '~') ||
\r
5272 (PieceToChar(BlackAngel) >= 'A' &&
\r
5273 PieceToChar(BlackAngel) != '~') ) ?
\r
5274 SW_SHOW : SW_HIDE);
\r
5275 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5276 ((PieceToChar(WhiteMarshall) >= 'A' &&
\r
5277 PieceToChar(WhiteMarshall) != '~') ||
\r
5278 (PieceToChar(BlackMarshall) >= 'A' &&
\r
5279 PieceToChar(BlackMarshall) != '~') ) ?
\r
5280 SW_SHOW : SW_HIDE);
\r
5281 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5282 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5283 gameInfo.variant != VariantShogi ?
\r
5284 SW_SHOW : SW_HIDE);
\r
5285 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5286 gameInfo.variant != VariantShogi ?
\r
5287 SW_SHOW : SW_HIDE);
\r
5288 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5289 gameInfo.variant == VariantShogi ?
\r
5290 SW_SHOW : SW_HIDE);
\r
5291 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5292 gameInfo.variant == VariantShogi ?
\r
5293 SW_SHOW : SW_HIDE);
\r
5294 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5295 gameInfo.variant == VariantSuper ?
\r
5296 SW_SHOW : SW_HIDE);
\r
5299 case WM_COMMAND: /* message: received a command */
\r
5300 switch (LOWORD(wParam)) {
\r
5302 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5303 ClearHighlights();
\r
5304 DrawPosition(FALSE, NULL);
\r
5307 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5310 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5313 promoChar = PieceToChar(BlackRook);
\r
5316 promoChar = PieceToChar(BlackBishop);
\r
5318 case PB_Chancellor:
\r
5319 promoChar = PieceToChar(BlackMarshall);
\r
5321 case PB_Archbishop:
\r
5322 promoChar = PieceToChar(BlackAngel);
\r
5325 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5330 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5331 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5332 only show the popup when we are already sure the move is valid or
\r
5333 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5334 will figure out it is a promotion from the promoChar. */
\r
5335 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5336 if (!appData.highlightLastMove) {
\r
5337 ClearHighlights();
\r
5338 DrawPosition(FALSE, NULL);
\r
5345 /* Pop up promotion dialog */
\r
5347 PromotionPopup(HWND hwnd)
\r
5351 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5352 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5353 hwnd, (DLGPROC)lpProc);
\r
5354 FreeProcInstance(lpProc);
\r
5357 /* Toggle ShowThinking */
\r
5359 ToggleShowThinking()
\r
5361 appData.showThinking = !appData.showThinking;
\r
5362 ShowThinkingEvent();
\r
5366 LoadGameDialog(HWND hwnd, char* title)
\r
5370 char fileTitle[MSG_SIZ];
\r
5371 f = OpenFileDialog(hwnd, "rb", "",
\r
5372 appData.oldSaveStyle ? "gam" : "pgn",
\r
5374 title, &number, fileTitle, NULL);
\r
5376 cmailMsgLoaded = FALSE;
\r
5377 if (number == 0) {
\r
5378 int error = GameListBuild(f);
\r
5380 DisplayError("Cannot build game list", error);
\r
5381 } else if (!ListEmpty(&gameList) &&
\r
5382 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5383 GameListPopUp(f, fileTitle);
\r
5386 GameListDestroy();
\r
5389 LoadGame(f, number, fileTitle, FALSE);
\r
5394 ChangedConsoleFont()
\r
5397 CHARRANGE tmpsel, sel;
\r
5398 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5399 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5400 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5403 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5404 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5405 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5406 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5407 * size. This was undocumented in the version of MSVC++ that I had
\r
5408 * when I wrote the code, but is apparently documented now.
\r
5410 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5411 cfmt.bCharSet = f->lf.lfCharSet;
\r
5412 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5413 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5414 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5415 /* Why are the following seemingly needed too? */
\r
5416 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5417 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5418 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5420 tmpsel.cpMax = -1; /*999999?*/
\r
5421 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5422 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5423 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5424 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5426 paraf.cbSize = sizeof(paraf);
\r
5427 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5428 paraf.dxStartIndent = 0;
\r
5429 paraf.dxOffset = WRAP_INDENT;
\r
5430 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5431 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5434 /*---------------------------------------------------------------------------*\
\r
5436 * Window Proc for main window
\r
5438 \*---------------------------------------------------------------------------*/
\r
5440 /* Process messages for main window, etc. */
\r
5442 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5445 int wmId, wmEvent;
\r
5449 char fileTitle[MSG_SIZ];
\r
5450 char buf[MSG_SIZ];
\r
5451 static SnapData sd;
\r
5453 switch (message) {
\r
5455 case WM_PAINT: /* message: repaint portion of window */
\r
5459 case WM_ERASEBKGND:
\r
5460 if (IsIconic(hwnd)) {
\r
5461 /* Cheat; change the message */
\r
5462 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5464 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5468 case WM_LBUTTONDOWN:
\r
5469 case WM_MBUTTONDOWN:
\r
5470 case WM_RBUTTONDOWN:
\r
5471 case WM_LBUTTONUP:
\r
5472 case WM_MBUTTONUP:
\r
5473 case WM_RBUTTONUP:
\r
5474 case WM_MOUSEMOVE:
\r
5475 case WM_MOUSEWHEEL:
\r
5476 MouseEvent(hwnd, message, wParam, lParam);
\r
5481 if (appData.icsActive) {
\r
5482 if (wParam == '\t') {
\r
5483 if (GetKeyState(VK_SHIFT) < 0) {
\r
5485 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5486 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5490 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5491 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5495 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5496 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5498 SendMessage(h, message, wParam, lParam);
\r
5500 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5501 PopUpMoveDialog((char)wParam);
\r
5505 case WM_PALETTECHANGED:
\r
5506 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5508 HDC hdc = GetDC(hwndMain);
\r
5509 SelectPalette(hdc, hPal, TRUE);
\r
5510 nnew = RealizePalette(hdc);
\r
5512 paletteChanged = TRUE;
\r
5514 UpdateColors(hdc);
\r
5516 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5519 ReleaseDC(hwnd, hdc);
\r
5523 case WM_QUERYNEWPALETTE:
\r
5524 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5526 HDC hdc = GetDC(hwndMain);
\r
5527 paletteChanged = FALSE;
\r
5528 SelectPalette(hdc, hPal, FALSE);
\r
5529 nnew = RealizePalette(hdc);
\r
5531 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5533 ReleaseDC(hwnd, hdc);
\r
5538 case WM_COMMAND: /* message: command from application menu */
\r
5539 wmId = LOWORD(wParam);
\r
5540 wmEvent = HIWORD(wParam);
\r
5545 AnalysisPopDown();
\r
5548 case IDM_NewGameFRC:
\r
5549 if( NewGameFRC() == 0 ) {
\r
5551 AnalysisPopDown();
\r
5555 case IDM_NewVariant:
\r
5556 NewVariantPopup(hwnd);
\r
5559 case IDM_LoadGame:
\r
5560 LoadGameDialog(hwnd, "Load Game from File");
\r
5563 case IDM_LoadNextGame:
\r
5567 case IDM_LoadPrevGame:
\r
5571 case IDM_ReloadGame:
\r
5575 case IDM_LoadPosition:
\r
5576 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5577 Reset(FALSE, TRUE);
\r
5580 f = OpenFileDialog(hwnd, "rb", "",
\r
5581 appData.oldSaveStyle ? "pos" : "fen",
\r
5583 "Load Position from File", &number, fileTitle, NULL);
\r
5585 LoadPosition(f, number, fileTitle);
\r
5589 case IDM_LoadNextPosition:
\r
5590 ReloadPosition(1);
\r
5593 case IDM_LoadPrevPosition:
\r
5594 ReloadPosition(-1);
\r
5597 case IDM_ReloadPosition:
\r
5598 ReloadPosition(0);
\r
5601 case IDM_SaveGame:
\r
5602 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5603 f = OpenFileDialog(hwnd, "a", defName,
\r
5604 appData.oldSaveStyle ? "gam" : "pgn",
\r
5606 "Save Game to File", NULL, fileTitle, NULL);
\r
5608 SaveGame(f, 0, "");
\r
5612 case IDM_SavePosition:
\r
5613 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5614 f = OpenFileDialog(hwnd, "a", defName,
\r
5615 appData.oldSaveStyle ? "pos" : "fen",
\r
5617 "Save Position to File", NULL, fileTitle, NULL);
\r
5619 SavePosition(f, 0, "");
\r
5623 case IDM_SaveDiagram:
\r
5624 defName = "diagram";
\r
5625 f = OpenFileDialog(hwnd, "wb", defName,
\r
5628 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5634 case IDM_CopyGame:
\r
5635 CopyGameToClipboard();
\r
5638 case IDM_PasteGame:
\r
5639 PasteGameFromClipboard();
\r
5642 case IDM_CopyGameListToClipboard:
\r
5643 CopyGameListToClipboard();
\r
5646 /* [AS] Autodetect FEN or PGN data */
\r
5647 case IDM_PasteAny:
\r
5648 PasteGameOrFENFromClipboard();
\r
5651 /* [AS] Move history */
\r
5652 case IDM_ShowMoveHistory:
\r
5653 if( MoveHistoryIsUp() ) {
\r
5654 MoveHistoryPopDown();
\r
5657 MoveHistoryPopUp();
\r
5661 /* [AS] Eval graph */
\r
5662 case IDM_ShowEvalGraph:
\r
5663 if( EvalGraphIsUp() ) {
\r
5664 EvalGraphPopDown();
\r
5671 /* [AS] Engine output */
\r
5672 case IDM_ShowEngineOutput:
\r
5673 if( EngineOutputIsUp() ) {
\r
5674 EngineOutputPopDown();
\r
5677 EngineOutputPopUp();
\r
5681 /* [AS] User adjudication */
\r
5682 case IDM_UserAdjudication_White:
\r
5683 UserAdjudicationEvent( +1 );
\r
5686 case IDM_UserAdjudication_Black:
\r
5687 UserAdjudicationEvent( -1 );
\r
5690 case IDM_UserAdjudication_Draw:
\r
5691 UserAdjudicationEvent( 0 );
\r
5694 /* [AS] Game list options dialog */
\r
5695 case IDM_GameListOptions:
\r
5696 GameListOptions();
\r
5699 case IDM_CopyPosition:
\r
5700 CopyFENToClipboard();
\r
5703 case IDM_PastePosition:
\r
5704 PasteFENFromClipboard();
\r
5707 case IDM_MailMove:
\r
5711 case IDM_ReloadCMailMsg:
\r
5712 Reset(TRUE, TRUE);
\r
5713 ReloadCmailMsgEvent(FALSE);
\r
5716 case IDM_Minimize:
\r
5717 ShowWindow(hwnd, SW_MINIMIZE);
\r
5724 case IDM_MachineWhite:
\r
5725 MachineWhiteEvent();
\r
5727 * refresh the tags dialog only if it's visible
\r
5729 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5731 tags = PGNTags(&gameInfo);
\r
5732 TagsPopUp(tags, CmailMsg());
\r
5737 case IDM_MachineBlack:
\r
5738 MachineBlackEvent();
\r
5740 * refresh the tags dialog only if it's visible
\r
5742 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5744 tags = PGNTags(&gameInfo);
\r
5745 TagsPopUp(tags, CmailMsg());
\r
5750 case IDM_TwoMachines:
\r
5751 TwoMachinesEvent();
\r
5753 * refresh the tags dialog only if it's visible
\r
5755 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5757 tags = PGNTags(&gameInfo);
\r
5758 TagsPopUp(tags, CmailMsg());
\r
5763 case IDM_AnalysisMode:
\r
5764 if (!first.analysisSupport) {
\r
5765 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5766 DisplayError(buf, 0);
\r
5768 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5769 if (appData.icsActive) {
\r
5770 if (gameMode != IcsObserving) {
\r
5771 sprintf(buf, "You are not observing a game");
\r
5772 DisplayError(buf, 0);
\r
5773 /* secure check */
\r
5774 if (appData.icsEngineAnalyze) {
\r
5775 if (appData.debugMode)
\r
5776 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5777 ExitAnalyzeMode();
\r
5783 /* if enable, user want disable icsEngineAnalyze */
\r
5784 if (appData.icsEngineAnalyze) {
\r
5785 ExitAnalyzeMode();
\r
5789 appData.icsEngineAnalyze = TRUE;
\r
5790 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5793 if (!appData.showThinking) ToggleShowThinking();
\r
5794 AnalyzeModeEvent();
\r
5798 case IDM_AnalyzeFile:
\r
5799 if (!first.analysisSupport) {
\r
5800 char buf[MSG_SIZ];
\r
5801 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5802 DisplayError(buf, 0);
\r
5804 if (!appData.showThinking) ToggleShowThinking();
\r
5805 AnalyzeFileEvent();
\r
5806 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5807 AnalysisPeriodicEvent(1);
\r
5811 case IDM_IcsClient:
\r
5815 case IDM_EditGame:
\r
5819 case IDM_EditPosition:
\r
5820 EditPositionEvent();
\r
5823 case IDM_Training:
\r
5827 case IDM_ShowGameList:
\r
5828 ShowGameListProc();
\r
5831 case IDM_EditTags:
\r
5835 case IDM_EditComment:
\r
5836 if (commentDialogUp && editComment) {
\r
5839 EditCommentEvent();
\r
5859 case IDM_CallFlag:
\r
5879 case IDM_StopObserving:
\r
5880 StopObservingEvent();
\r
5883 case IDM_StopExamining:
\r
5884 StopExaminingEvent();
\r
5887 case IDM_TypeInMove:
\r
5888 PopUpMoveDialog('\000');
\r
5891 case IDM_TypeInName:
\r
5892 PopUpNameDialog('\000');
\r
5895 case IDM_Backward:
\r
5897 SetFocus(hwndMain);
\r
5902 SetFocus(hwndMain);
\r
5907 SetFocus(hwndMain);
\r
5912 SetFocus(hwndMain);
\r
5919 case IDM_TruncateGame:
\r
5920 TruncateGameEvent();
\r
5927 case IDM_RetractMove:
\r
5928 RetractMoveEvent();
\r
5931 case IDM_FlipView:
\r
5932 flipView = !flipView;
\r
5933 DrawPosition(FALSE, NULL);
\r
5936 case IDM_FlipClock:
\r
5937 flipClock = !flipClock;
\r
5938 DisplayBothClocks();
\r
5941 case IDM_GeneralOptions:
\r
5942 GeneralOptionsPopup(hwnd);
\r
5943 DrawPosition(TRUE, NULL);
\r
5946 case IDM_BoardOptions:
\r
5947 BoardOptionsPopup(hwnd);
\r
5950 case IDM_EnginePlayOptions:
\r
5951 EnginePlayOptionsPopup(hwnd);
\r
5954 case IDM_OptionsUCI:
\r
5955 UciOptionsPopup(hwnd);
\r
5958 case IDM_IcsOptions:
\r
5959 IcsOptionsPopup(hwnd);
\r
5963 FontsOptionsPopup(hwnd);
\r
5967 SoundOptionsPopup(hwnd);
\r
5970 case IDM_CommPort:
\r
5971 CommPortOptionsPopup(hwnd);
\r
5974 case IDM_LoadOptions:
\r
5975 LoadOptionsPopup(hwnd);
\r
5978 case IDM_SaveOptions:
\r
5979 SaveOptionsPopup(hwnd);
\r
5982 case IDM_TimeControl:
\r
5983 TimeControlOptionsPopup(hwnd);
\r
5986 case IDM_SaveSettings:
\r
5987 SaveSettings(settingsFileName);
\r
5990 case IDM_SaveSettingsOnExit:
\r
5991 saveSettingsOnExit = !saveSettingsOnExit;
\r
5992 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5993 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5994 MF_CHECKED : MF_UNCHECKED));
\r
6005 case IDM_AboutGame:
\r
6010 appData.debugMode = !appData.debugMode;
\r
6011 if (appData.debugMode) {
\r
6012 char dir[MSG_SIZ];
\r
6013 GetCurrentDirectory(MSG_SIZ, dir);
\r
6014 SetCurrentDirectory(installDir);
\r
6015 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
6016 SetCurrentDirectory(dir);
\r
6017 setbuf(debugFP, NULL);
\r
6024 case IDM_HELPCONTENTS:
\r
6025 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6026 MessageBox (GetFocus(),
\r
6027 "Unable to activate help",
\r
6028 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6032 case IDM_HELPSEARCH:
\r
6033 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
6034 MessageBox (GetFocus(),
\r
6035 "Unable to activate help",
\r
6036 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6040 case IDM_HELPHELP:
\r
6041 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
6042 MessageBox (GetFocus(),
\r
6043 "Unable to activate help",
\r
6044 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6049 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
6051 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
6052 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
6053 FreeProcInstance(lpProc);
\r
6056 case IDM_DirectCommand1:
\r
6057 AskQuestionEvent("Direct Command",
\r
6058 "Send to chess program:", "", "1");
\r
6060 case IDM_DirectCommand2:
\r
6061 AskQuestionEvent("Direct Command",
\r
6062 "Send to second chess program:", "", "2");
\r
6065 case EP_WhitePawn:
\r
6066 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6067 fromX = fromY = -1;
\r
6070 case EP_WhiteKnight:
\r
6071 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6072 fromX = fromY = -1;
\r
6075 case EP_WhiteBishop:
\r
6076 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6077 fromX = fromY = -1;
\r
6080 case EP_WhiteRook:
\r
6081 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6082 fromX = fromY = -1;
\r
6085 case EP_WhiteQueen:
\r
6086 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6087 fromX = fromY = -1;
\r
6090 case EP_WhiteFerz:
\r
6091 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6092 fromX = fromY = -1;
\r
6095 case EP_WhiteWazir:
\r
6096 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6097 fromX = fromY = -1;
\r
6100 case EP_WhiteAlfil:
\r
6101 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6102 fromX = fromY = -1;
\r
6105 case EP_WhiteCannon:
\r
6106 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6107 fromX = fromY = -1;
\r
6110 case EP_WhiteCardinal:
\r
6111 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6112 fromX = fromY = -1;
\r
6115 case EP_WhiteMarshall:
\r
6116 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6117 fromX = fromY = -1;
\r
6120 case EP_WhiteKing:
\r
6121 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6122 fromX = fromY = -1;
\r
6125 case EP_BlackPawn:
\r
6126 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6127 fromX = fromY = -1;
\r
6130 case EP_BlackKnight:
\r
6131 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6132 fromX = fromY = -1;
\r
6135 case EP_BlackBishop:
\r
6136 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6137 fromX = fromY = -1;
\r
6140 case EP_BlackRook:
\r
6141 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6142 fromX = fromY = -1;
\r
6145 case EP_BlackQueen:
\r
6146 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6147 fromX = fromY = -1;
\r
6150 case EP_BlackFerz:
\r
6151 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6152 fromX = fromY = -1;
\r
6155 case EP_BlackWazir:
\r
6156 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6157 fromX = fromY = -1;
\r
6160 case EP_BlackAlfil:
\r
6161 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6162 fromX = fromY = -1;
\r
6165 case EP_BlackCannon:
\r
6166 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6167 fromX = fromY = -1;
\r
6170 case EP_BlackCardinal:
\r
6171 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6172 fromX = fromY = -1;
\r
6175 case EP_BlackMarshall:
\r
6176 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6177 fromX = fromY = -1;
\r
6180 case EP_BlackKing:
\r
6181 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6182 fromX = fromY = -1;
\r
6185 case EP_EmptySquare:
\r
6186 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6187 fromX = fromY = -1;
\r
6190 case EP_ClearBoard:
\r
6191 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6192 fromX = fromY = -1;
\r
6196 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6197 fromX = fromY = -1;
\r
6201 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6202 fromX = fromY = -1;
\r
6206 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6207 fromX = fromY = -1;
\r
6211 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6212 fromX = fromY = -1;
\r
6216 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6217 fromX = fromY = -1;
\r
6221 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6222 fromX = fromY = -1;
\r
6226 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6227 fromX = fromY = -1;
\r
6231 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6232 fromX = fromY = -1;
\r
6236 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6237 fromX = fromY = -1;
\r
6241 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6247 case CLOCK_TIMER_ID:
\r
6248 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6249 clockTimerEvent = 0;
\r
6250 DecrementClocks(); /* call into back end */
\r
6252 case LOAD_GAME_TIMER_ID:
\r
6253 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6254 loadGameTimerEvent = 0;
\r
6255 AutoPlayGameLoop(); /* call into back end */
\r
6257 case ANALYSIS_TIMER_ID:
\r
6258 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6259 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6260 AnalysisPeriodicEvent(0);
\r
6262 KillTimer(hwnd, analysisTimerEvent);
\r
6263 analysisTimerEvent = 0;
\r
6266 case DELAYED_TIMER_ID:
\r
6267 KillTimer(hwnd, delayedTimerEvent);
\r
6268 delayedTimerEvent = 0;
\r
6269 delayedTimerCallback();
\r
6274 case WM_USER_Input:
\r
6275 InputEvent(hwnd, message, wParam, lParam);
\r
6278 /* [AS] Also move "attached" child windows */
\r
6279 case WM_WINDOWPOSCHANGING:
\r
6281 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6282 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6284 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6285 /* Window is moving */
\r
6288 // GetWindowRect( hwnd, &rcMain ); //[HGM] sticky: in XP this returned new position, not old
\r
6289 rcMain.left = boardX; // replace by these 4 lines to reconstruct old rect
\r
6290 rcMain.right = boardX + winWidth;
\r
6291 rcMain.top = boardY;
\r
6292 rcMain.bottom = boardY + winHeight;
\r
6294 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6295 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6296 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6303 /* [AS] Snapping */
\r
6304 case WM_ENTERSIZEMOVE:
\r
6305 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6306 if (hwnd == hwndMain) {
\r
6307 doingSizing = TRUE;
\r
6310 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6314 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6315 if (hwnd == hwndMain) {
\r
6316 lastSizing = wParam;
\r
6321 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6322 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6324 case WM_EXITSIZEMOVE:
\r
6325 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6326 if (hwnd == hwndMain) {
\r
6328 doingSizing = FALSE;
\r
6329 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6330 GetClientRect(hwnd, &client);
\r
6331 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6333 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6335 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6338 case WM_DESTROY: /* message: window being destroyed */
\r
6339 PostQuitMessage(0);
\r
6343 if (hwnd == hwndMain) {
\r
6348 default: /* Passes it on if unprocessed */
\r
6349 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6354 /*---------------------------------------------------------------------------*\
\r
6356 * Misc utility routines
\r
6358 \*---------------------------------------------------------------------------*/
\r
6361 * Decent random number generator, at least not as bad as Windows
\r
6362 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6364 unsigned int randstate;
\r
6369 randstate = randstate * 1664525 + 1013904223;
\r
6370 return (int) randstate & 0x7fffffff;
\r
6374 mysrandom(unsigned int seed)
\r
6381 * returns TRUE if user selects a different color, FALSE otherwise
\r
6385 ChangeColor(HWND hwnd, COLORREF *which)
\r
6387 static BOOL firstTime = TRUE;
\r
6388 static DWORD customColors[16];
\r
6390 COLORREF newcolor;
\r
6395 /* Make initial colors in use available as custom colors */
\r
6396 /* Should we put the compiled-in defaults here instead? */
\r
6398 customColors[i++] = lightSquareColor & 0xffffff;
\r
6399 customColors[i++] = darkSquareColor & 0xffffff;
\r
6400 customColors[i++] = whitePieceColor & 0xffffff;
\r
6401 customColors[i++] = blackPieceColor & 0xffffff;
\r
6402 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6403 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6405 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6406 customColors[i++] = textAttribs[ccl].color;
\r
6408 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6409 firstTime = FALSE;
\r
6412 cc.lStructSize = sizeof(cc);
\r
6413 cc.hwndOwner = hwnd;
\r
6414 cc.hInstance = NULL;
\r
6415 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6416 cc.lpCustColors = (LPDWORD) customColors;
\r
6417 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6419 if (!ChooseColor(&cc)) return FALSE;
\r
6421 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6422 if (newcolor == *which) return FALSE;
\r
6423 *which = newcolor;
\r
6427 InitDrawingColors();
\r
6428 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6433 MyLoadSound(MySound *ms)
\r
6439 if (ms->data) free(ms->data);
\r
6442 switch (ms->name[0]) {
\r
6448 /* System sound from Control Panel. Don't preload here. */
\r
6452 if (ms->name[1] == NULLCHAR) {
\r
6453 /* "!" alone = silence */
\r
6456 /* Builtin wave resource. Error if not found. */
\r
6457 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6458 if (h == NULL) break;
\r
6459 ms->data = (void *)LoadResource(hInst, h);
\r
6460 if (h == NULL) break;
\r
6465 /* .wav file. Error if not found. */
\r
6466 f = fopen(ms->name, "rb");
\r
6467 if (f == NULL) break;
\r
6468 if (fstat(fileno(f), &st) < 0) break;
\r
6469 ms->data = malloc(st.st_size);
\r
6470 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6476 char buf[MSG_SIZ];
\r
6477 sprintf(buf, "Error loading sound %s", ms->name);
\r
6478 DisplayError(buf, GetLastError());
\r
6484 MyPlaySound(MySound *ms)
\r
6486 BOOLEAN ok = FALSE;
\r
6487 switch (ms->name[0]) {
\r
6493 /* System sound from Control Panel (deprecated feature).
\r
6494 "$" alone or an unset sound name gets default beep (still in use). */
\r
6495 if (ms->name[1]) {
\r
6496 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6498 if (!ok) ok = MessageBeep(MB_OK);
\r
6501 /* Builtin wave resource, or "!" alone for silence */
\r
6502 if (ms->name[1]) {
\r
6503 if (ms->data == NULL) return FALSE;
\r
6504 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6510 /* .wav file. Error if not found. */
\r
6511 if (ms->data == NULL) return FALSE;
\r
6512 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6515 /* Don't print an error: this can happen innocently if the sound driver
\r
6516 is busy; for instance, if another instance of WinBoard is playing
\r
6517 a sound at about the same time. */
\r
6520 char buf[MSG_SIZ];
\r
6521 sprintf(buf, "Error playing sound %s", ms->name);
\r
6522 DisplayError(buf, GetLastError());
\r
6530 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6533 OPENFILENAME *ofn;
\r
6534 static UINT *number; /* gross that this is static */
\r
6536 switch (message) {
\r
6537 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6538 /* Center the dialog over the application window */
\r
6539 ofn = (OPENFILENAME *) lParam;
\r
6540 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6541 number = (UINT *) ofn->lCustData;
\r
6542 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6546 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6547 return FALSE; /* Allow for further processing */
\r
6550 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6551 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6553 return FALSE; /* Allow for further processing */
\r
6559 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6561 static UINT *number;
\r
6562 OPENFILENAME *ofname;
\r
6565 case WM_INITDIALOG:
\r
6566 ofname = (OPENFILENAME *)lParam;
\r
6567 number = (UINT *)(ofname->lCustData);
\r
6570 ofnot = (OFNOTIFY *)lParam;
\r
6571 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6572 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6581 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6582 char *nameFilt, char *dlgTitle, UINT *number,
\r
6583 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6585 OPENFILENAME openFileName;
\r
6586 char buf1[MSG_SIZ];
\r
6589 if (fileName == NULL) fileName = buf1;
\r
6590 if (defName == NULL) {
\r
6591 strcpy(fileName, "*.");
\r
6592 strcat(fileName, defExt);
\r
6594 strcpy(fileName, defName);
\r
6596 if (fileTitle) strcpy(fileTitle, "");
\r
6597 if (number) *number = 0;
\r
6599 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6600 openFileName.hwndOwner = hwnd;
\r
6601 openFileName.hInstance = (HANDLE) hInst;
\r
6602 openFileName.lpstrFilter = nameFilt;
\r
6603 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6604 openFileName.nMaxCustFilter = 0L;
\r
6605 openFileName.nFilterIndex = 1L;
\r
6606 openFileName.lpstrFile = fileName;
\r
6607 openFileName.nMaxFile = MSG_SIZ;
\r
6608 openFileName.lpstrFileTitle = fileTitle;
\r
6609 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6610 openFileName.lpstrInitialDir = NULL;
\r
6611 openFileName.lpstrTitle = dlgTitle;
\r
6612 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6613 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6614 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6615 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6616 openFileName.nFileOffset = 0;
\r
6617 openFileName.nFileExtension = 0;
\r
6618 openFileName.lpstrDefExt = defExt;
\r
6619 openFileName.lCustData = (LONG) number;
\r
6620 openFileName.lpfnHook = oldDialog ?
\r
6621 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6622 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6624 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6625 GetOpenFileName(&openFileName)) {
\r
6626 /* open the file */
\r
6627 f = fopen(openFileName.lpstrFile, write);
\r
6629 MessageBox(hwnd, "File open failed", NULL,
\r
6630 MB_OK|MB_ICONEXCLAMATION);
\r
6634 int err = CommDlgExtendedError();
\r
6635 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6644 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6646 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6649 * Get the first pop-up menu in the menu template. This is the
\r
6650 * menu that TrackPopupMenu displays.
\r
6652 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6654 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6657 * TrackPopup uses screen coordinates, so convert the
\r
6658 * coordinates of the mouse click to screen coordinates.
\r
6660 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6662 /* Draw and track the floating pop-up menu. */
\r
6663 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6664 pt.x, pt.y, 0, hwnd, NULL);
\r
6666 /* Destroy the menu.*/
\r
6667 DestroyMenu(hmenu);
\r
6672 int sizeX, sizeY, newSizeX, newSizeY;
\r
6674 } ResizeEditPlusButtonsClosure;
\r
6677 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6679 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6683 if (hChild == cl->hText) return TRUE;
\r
6684 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6685 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6686 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6687 ScreenToClient(cl->hDlg, &pt);
\r
6688 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6689 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6693 /* Resize a dialog that has a (rich) edit field filling most of
\r
6694 the top, with a row of buttons below */
\r
6696 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6699 int newTextHeight, newTextWidth;
\r
6700 ResizeEditPlusButtonsClosure cl;
\r
6702 /*if (IsIconic(hDlg)) return;*/
\r
6703 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6705 cl.hdwp = BeginDeferWindowPos(8);
\r
6707 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6708 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6709 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6710 if (newTextHeight < 0) {
\r
6711 newSizeY += -newTextHeight;
\r
6712 newTextHeight = 0;
\r
6714 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6715 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6721 cl.newSizeX = newSizeX;
\r
6722 cl.newSizeY = newSizeY;
\r
6723 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6725 EndDeferWindowPos(cl.hdwp);
\r
6728 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6730 RECT rChild, rParent;
\r
6731 int wChild, hChild, wParent, hParent;
\r
6732 int wScreen, hScreen, xNew, yNew;
\r
6735 /* Get the Height and Width of the child window */
\r
6736 GetWindowRect (hwndChild, &rChild);
\r
6737 wChild = rChild.right - rChild.left;
\r
6738 hChild = rChild.bottom - rChild.top;
\r
6740 /* Get the Height and Width of the parent window */
\r
6741 GetWindowRect (hwndParent, &rParent);
\r
6742 wParent = rParent.right - rParent.left;
\r
6743 hParent = rParent.bottom - rParent.top;
\r
6745 /* Get the display limits */
\r
6746 hdc = GetDC (hwndChild);
\r
6747 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6748 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6749 ReleaseDC(hwndChild, hdc);
\r
6751 /* Calculate new X position, then adjust for screen */
\r
6752 xNew = rParent.left + ((wParent - wChild) /2);
\r
6755 } else if ((xNew+wChild) > wScreen) {
\r
6756 xNew = wScreen - wChild;
\r
6759 /* Calculate new Y position, then adjust for screen */
\r
6761 yNew = rParent.top + ((hParent - hChild) /2);
\r
6764 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6769 } else if ((yNew+hChild) > hScreen) {
\r
6770 yNew = hScreen - hChild;
\r
6773 /* Set it, and return */
\r
6774 return SetWindowPos (hwndChild, NULL,
\r
6775 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6778 /* Center one window over another */
\r
6779 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6781 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6784 /*---------------------------------------------------------------------------*\
\r
6786 * Startup Dialog functions
\r
6788 \*---------------------------------------------------------------------------*/
\r
6790 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6792 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6794 while (*cd != NULL) {
\r
6795 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6801 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6803 char buf1[ARG_MAX];
\r
6806 if (str[0] == '@') {
\r
6807 FILE* f = fopen(str + 1, "r");
\r
6809 DisplayFatalError(str + 1, errno, 2);
\r
6812 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6814 buf1[len] = NULLCHAR;
\r
6818 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6821 char buf[MSG_SIZ];
\r
6822 char *end = strchr(str, '\n');
\r
6823 if (end == NULL) return;
\r
6824 memcpy(buf, str, end - str);
\r
6825 buf[end - str] = NULLCHAR;
\r
6826 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6832 SetStartupDialogEnables(HWND hDlg)
\r
6834 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6835 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6836 (appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer)));
\r
6837 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6838 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6839 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6840 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6841 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6842 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6843 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6844 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6845 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6846 IsDlgButtonChecked(hDlg, OPT_View));
\r
6850 QuoteForFilename(char *filename)
\r
6852 int dquote, space;
\r
6853 dquote = strchr(filename, '"') != NULL;
\r
6854 space = strchr(filename, ' ') != NULL;
\r
6855 if (dquote || space) {
\r
6867 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6869 char buf[MSG_SIZ];
\r
6872 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6873 q = QuoteForFilename(nthcp);
\r
6874 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6875 if (*nthdir != NULLCHAR) {
\r
6876 q = QuoteForFilename(nthdir);
\r
6877 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6879 if (*nthcp == NULLCHAR) {
\r
6880 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6881 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6882 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6883 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6888 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6890 char buf[MSG_SIZ];
\r
6894 switch (message) {
\r
6895 case WM_INITDIALOG:
\r
6896 /* Center the dialog */
\r
6897 CenterWindow (hDlg, GetDesktopWindow());
\r
6898 /* Initialize the dialog items */
\r
6899 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6900 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6901 firstChessProgramNames);
\r
6902 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6903 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6904 secondChessProgramNames);
\r
6905 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6906 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6907 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6908 if (*appData.icsHelper != NULLCHAR) {
\r
6909 char *q = QuoteForFilename(appData.icsHelper);
\r
6910 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6912 if (*appData.icsHost == NULLCHAR) {
\r
6913 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6914 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6915 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6916 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6917 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6920 if (appData.icsActive) {
\r
6921 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6923 else if (appData.noChessProgram) {
\r
6924 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6927 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6930 SetStartupDialogEnables(hDlg);
\r
6934 switch (LOWORD(wParam)) {
\r
6936 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6937 strcpy(buf, "/fcp=");
\r
6938 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6940 ParseArgs(StringGet, &p);
\r
6941 strcpy(buf, "/scp=");
\r
6942 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6944 ParseArgs(StringGet, &p);
\r
6945 appData.noChessProgram = FALSE;
\r
6946 appData.icsActive = FALSE;
\r
6947 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6948 strcpy(buf, "/ics /icshost=");
\r
6949 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6951 ParseArgs(StringGet, &p);
\r
6952 if (appData.zippyPlay) {
\r
6953 strcpy(buf, "/fcp=");
\r
6954 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6956 ParseArgs(StringGet, &p);
\r
6958 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6959 appData.noChessProgram = TRUE;
\r
6960 appData.icsActive = FALSE;
\r
6962 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6963 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6966 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6967 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6969 ParseArgs(StringGet, &p);
\r
6971 EndDialog(hDlg, TRUE);
\r
6978 case IDM_HELPCONTENTS:
\r
6979 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6980 MessageBox (GetFocus(),
\r
6981 "Unable to activate help",
\r
6982 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6987 SetStartupDialogEnables(hDlg);
\r
6995 /*---------------------------------------------------------------------------*\
\r
6997 * About box dialog functions
\r
6999 \*---------------------------------------------------------------------------*/
\r
7001 /* Process messages for "About" dialog box */
\r
7003 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7005 switch (message) {
\r
7006 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7007 /* Center the dialog over the application window */
\r
7008 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
7009 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
7012 case WM_COMMAND: /* message: received a command */
\r
7013 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
7014 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
7015 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
7023 /*---------------------------------------------------------------------------*\
\r
7025 * Comment Dialog functions
\r
7027 \*---------------------------------------------------------------------------*/
\r
7030 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7032 static HANDLE hwndText = NULL;
\r
7033 int len, newSizeX, newSizeY, flags;
\r
7034 static int sizeX, sizeY;
\r
7039 switch (message) {
\r
7040 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7041 /* Initialize the dialog items */
\r
7042 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7043 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
7044 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
7045 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
7046 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
7047 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
7048 SetWindowText(hDlg, commentTitle);
\r
7049 if (editComment) {
\r
7050 SetFocus(hwndText);
\r
7052 SetFocus(GetDlgItem(hDlg, IDOK));
\r
7054 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
7055 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
7056 MAKELPARAM(FALSE, 0));
\r
7057 /* Size and position the dialog */
\r
7058 if (!commentDialog) {
\r
7059 commentDialog = hDlg;
\r
7060 flags = SWP_NOZORDER;
\r
7061 GetClientRect(hDlg, &rect);
\r
7062 sizeX = rect.right;
\r
7063 sizeY = rect.bottom;
\r
7064 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
7065 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
7066 WINDOWPLACEMENT wp;
\r
7067 EnsureOnScreen(&commentX, &commentY);
\r
7068 wp.length = sizeof(WINDOWPLACEMENT);
\r
7070 wp.showCmd = SW_SHOW;
\r
7071 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7072 wp.rcNormalPosition.left = commentX;
\r
7073 wp.rcNormalPosition.right = commentX + commentW;
\r
7074 wp.rcNormalPosition.top = commentY;
\r
7075 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7076 SetWindowPlacement(hDlg, &wp);
\r
7078 GetClientRect(hDlg, &rect);
\r
7079 newSizeX = rect.right;
\r
7080 newSizeY = rect.bottom;
\r
7081 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7082 newSizeX, newSizeY);
\r
7089 case WM_COMMAND: /* message: received a command */
\r
7090 switch (LOWORD(wParam)) {
\r
7092 if (editComment) {
\r
7094 /* Read changed options from the dialog box */
\r
7095 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7096 len = GetWindowTextLength(hwndText);
\r
7097 str = (char *) malloc(len + 1);
\r
7098 GetWindowText(hwndText, str, len + 1);
\r
7107 ReplaceComment(commentIndex, str);
\r
7114 case OPT_CancelComment:
\r
7118 case OPT_ClearComment:
\r
7119 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7122 case OPT_EditComment:
\r
7123 EditCommentEvent();
\r
7132 newSizeX = LOWORD(lParam);
\r
7133 newSizeY = HIWORD(lParam);
\r
7134 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7139 case WM_GETMINMAXINFO:
\r
7140 /* Prevent resizing window too small */
\r
7141 mmi = (MINMAXINFO *) lParam;
\r
7142 mmi->ptMinTrackSize.x = 100;
\r
7143 mmi->ptMinTrackSize.y = 100;
\r
7150 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7155 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7157 if (str == NULL) str = "";
\r
7158 p = (char *) malloc(2 * strlen(str) + 2);
\r
7161 if (*str == '\n') *q++ = '\r';
\r
7165 if (commentText != NULL) free(commentText);
\r
7167 commentIndex = index;
\r
7168 commentTitle = title;
\r
7170 editComment = edit;
\r
7172 if (commentDialog) {
\r
7173 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7174 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7176 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7177 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7178 hwndMain, (DLGPROC)lpProc);
\r
7179 FreeProcInstance(lpProc);
\r
7181 commentDialogUp = TRUE;
\r
7185 /*---------------------------------------------------------------------------*\
\r
7187 * Type-in move dialog functions
\r
7189 \*---------------------------------------------------------------------------*/
\r
7192 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7194 char move[MSG_SIZ];
\r
7196 ChessMove moveType;
\r
7197 int fromX, fromY, toX, toY;
\r
7200 switch (message) {
\r
7201 case WM_INITDIALOG:
\r
7202 move[0] = (char) lParam;
\r
7203 move[1] = NULLCHAR;
\r
7204 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7205 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7206 SetWindowText(hInput, move);
\r
7208 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7212 switch (LOWORD(wParam)) {
\r
7214 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7215 gameMode != Training) {
\r
7216 DisplayMoveError("Displayed move is not current");
\r
7218 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7219 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7220 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7221 if (gameMode != Training)
\r
7222 forwardMostMove = currentMove;
\r
7223 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7225 DisplayMoveError("Could not parse move");
\r
7228 EndDialog(hDlg, TRUE);
\r
7231 EndDialog(hDlg, FALSE);
\r
7242 PopUpMoveDialog(char firstchar)
\r
7246 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7247 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7248 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7249 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7250 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7251 gameMode == Training) {
\r
7252 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7253 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7254 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7255 FreeProcInstance(lpProc);
\r
7259 /*---------------------------------------------------------------------------*\
\r
7261 * Type-in name dialog functions
\r
7263 \*---------------------------------------------------------------------------*/
\r
7266 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7268 char move[MSG_SIZ];
\r
7271 switch (message) {
\r
7272 case WM_INITDIALOG:
\r
7273 move[0] = (char) lParam;
\r
7274 move[1] = NULLCHAR;
\r
7275 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7276 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7277 SetWindowText(hInput, move);
\r
7279 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7283 switch (LOWORD(wParam)) {
\r
7285 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7286 appData.userName = strdup(move);
\r
7288 EndDialog(hDlg, TRUE);
\r
7291 EndDialog(hDlg, FALSE);
\r
7302 PopUpNameDialog(char firstchar)
\r
7306 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7307 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7308 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7309 FreeProcInstance(lpProc);
\r
7312 /*---------------------------------------------------------------------------*\
\r
7316 \*---------------------------------------------------------------------------*/
\r
7318 /* Nonmodal error box */
\r
7319 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7320 WPARAM wParam, LPARAM lParam);
\r
7323 ErrorPopUp(char *title, char *content)
\r
7327 BOOLEAN modal = hwndMain == NULL;
\r
7345 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7346 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7349 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7351 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7352 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7353 hwndMain, (DLGPROC)lpProc);
\r
7354 FreeProcInstance(lpProc);
\r
7361 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7362 if (errorDialog == NULL) return;
\r
7363 DestroyWindow(errorDialog);
\r
7364 errorDialog = NULL;
\r
7368 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7373 switch (message) {
\r
7374 case WM_INITDIALOG:
\r
7375 GetWindowRect(hDlg, &rChild);
\r
7378 SetWindowPos(hDlg, NULL, rChild.left,
\r
7379 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7380 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7384 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7385 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7386 and it doesn't work when you resize the dialog.
\r
7387 For now, just give it a default position.
\r
7389 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7391 errorDialog = hDlg;
\r
7392 SetWindowText(hDlg, errorTitle);
\r
7393 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7394 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7398 switch (LOWORD(wParam)) {
\r
7401 if (errorDialog == hDlg) errorDialog = NULL;
\r
7402 DestroyWindow(hDlg);
\r
7414 HWND gothicDialog = NULL;
\r
7417 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7421 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7423 switch (message) {
\r
7424 case WM_INITDIALOG:
\r
7425 GetWindowRect(hDlg, &rChild);
\r
7427 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7431 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7432 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7433 and it doesn't work when you resize the dialog.
\r
7434 For now, just give it a default position.
\r
7436 gothicDialog = hDlg;
\r
7437 SetWindowText(hDlg, errorTitle);
\r
7438 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7439 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7443 switch (LOWORD(wParam)) {
\r
7446 if (errorDialog == hDlg) errorDialog = NULL;
\r
7447 DestroyWindow(hDlg);
\r
7459 GothicPopUp(char *title, VariantClass variant)
\r
7462 static char *lastTitle;
\r
7464 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7465 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7467 if(lastTitle != title && gothicDialog != NULL) {
\r
7468 DestroyWindow(gothicDialog);
\r
7469 gothicDialog = NULL;
\r
7471 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7472 title = lastTitle;
\r
7473 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7474 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7475 hwndMain, (DLGPROC)lpProc);
\r
7476 FreeProcInstance(lpProc);
\r
7481 /*---------------------------------------------------------------------------*\
\r
7483 * Ics Interaction console functions
\r
7485 \*---------------------------------------------------------------------------*/
\r
7487 #define HISTORY_SIZE 64
\r
7488 static char *history[HISTORY_SIZE];
\r
7489 int histIn = 0, histP = 0;
\r
7492 SaveInHistory(char *cmd)
\r
7494 if (history[histIn] != NULL) {
\r
7495 free(history[histIn]);
\r
7496 history[histIn] = NULL;
\r
7498 if (*cmd == NULLCHAR) return;
\r
7499 history[histIn] = StrSave(cmd);
\r
7500 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7501 if (history[histIn] != NULL) {
\r
7502 free(history[histIn]);
\r
7503 history[histIn] = NULL;
\r
7509 PrevInHistory(char *cmd)
\r
7512 if (histP == histIn) {
\r
7513 if (history[histIn] != NULL) free(history[histIn]);
\r
7514 history[histIn] = StrSave(cmd);
\r
7516 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7517 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7519 return history[histP];
\r
7525 if (histP == histIn) return NULL;
\r
7526 histP = (histP + 1) % HISTORY_SIZE;
\r
7527 return history[histP];
\r
7534 BOOLEAN immediate;
\r
7535 } IcsTextMenuEntry;
\r
7536 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7537 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7540 ParseIcsTextMenu(char *icsTextMenuString)
\r
7543 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7544 char *p = icsTextMenuString;
\r
7545 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7548 if (e->command != NULL) {
\r
7550 e->command = NULL;
\r
7554 e = icsTextMenuEntry;
\r
7555 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7556 if (*p == ';' || *p == '\n') {
\r
7557 e->item = strdup("-");
\r
7558 e->command = NULL;
\r
7560 } else if (*p == '-') {
\r
7561 e->item = strdup("-");
\r
7562 e->command = NULL;
\r
7566 char *q, *r, *s, *t;
\r
7568 q = strchr(p, ',');
\r
7569 if (q == NULL) break;
\r
7571 r = strchr(q + 1, ',');
\r
7572 if (r == NULL) break;
\r
7574 s = strchr(r + 1, ',');
\r
7575 if (s == NULL) break;
\r
7578 t = strchr(s + 1, c);
\r
7581 t = strchr(s + 1, c);
\r
7583 if (t != NULL) *t = NULLCHAR;
\r
7584 e->item = strdup(p);
\r
7585 e->command = strdup(q + 1);
\r
7586 e->getname = *(r + 1) != '0';
\r
7587 e->immediate = *(s + 1) != '0';
\r
7591 if (t == NULL) break;
\r
7600 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7604 hmenu = LoadMenu(hInst, "TextMenu");
\r
7605 h = GetSubMenu(hmenu, 0);
\r
7607 if (strcmp(e->item, "-") == 0) {
\r
7608 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7610 if (e->item[0] == '|') {
\r
7611 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7612 IDM_CommandX + i, &e->item[1]);
\r
7614 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7623 WNDPROC consoleTextWindowProc;
\r
7626 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7628 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7629 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7633 SetWindowText(hInput, command);
\r
7635 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7637 sel.cpMin = 999999;
\r
7638 sel.cpMax = 999999;
\r
7639 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7644 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7645 if (sel.cpMin == sel.cpMax) {
\r
7646 /* Expand to surrounding word */
\r
7649 tr.chrg.cpMax = sel.cpMin;
\r
7650 tr.chrg.cpMin = --sel.cpMin;
\r
7651 if (sel.cpMin < 0) break;
\r
7652 tr.lpstrText = name;
\r
7653 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7654 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7658 tr.chrg.cpMin = sel.cpMax;
\r
7659 tr.chrg.cpMax = ++sel.cpMax;
\r
7660 tr.lpstrText = name;
\r
7661 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7662 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7665 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7666 MessageBeep(MB_ICONEXCLAMATION);
\r
7670 tr.lpstrText = name;
\r
7671 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7673 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7674 MessageBeep(MB_ICONEXCLAMATION);
\r
7677 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7680 sprintf(buf, "%s %s", command, name);
\r
7681 SetWindowText(hInput, buf);
\r
7682 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7684 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7685 SetWindowText(hInput, buf);
\r
7686 sel.cpMin = 999999;
\r
7687 sel.cpMax = 999999;
\r
7688 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7694 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7699 switch (message) {
\r
7701 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7704 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7707 sel.cpMin = 999999;
\r
7708 sel.cpMax = 999999;
\r
7709 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7710 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7715 if (wParam == '\t') {
\r
7716 if (GetKeyState(VK_SHIFT) < 0) {
\r
7718 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7719 if (buttonDesc[0].hwnd) {
\r
7720 SetFocus(buttonDesc[0].hwnd);
\r
7722 SetFocus(hwndMain);
\r
7726 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7729 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7731 SendMessage(hInput, message, wParam, lParam);
\r
7735 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7737 return SendMessage(hInput, message, wParam, lParam);
\r
7738 case WM_MBUTTONDOWN:
\r
7739 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7740 case WM_RBUTTONDOWN:
\r
7741 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7742 /* Move selection here if it was empty */
\r
7744 pt.x = LOWORD(lParam);
\r
7745 pt.y = HIWORD(lParam);
\r
7746 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7747 if (sel.cpMin == sel.cpMax) {
\r
7748 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7749 sel.cpMax = sel.cpMin;
\r
7750 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7752 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7755 case WM_RBUTTONUP:
\r
7756 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7757 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7758 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7761 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7762 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7763 if (sel.cpMin == sel.cpMax) {
\r
7764 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7765 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7767 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7768 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7770 pt.x = LOWORD(lParam);
\r
7771 pt.y = HIWORD(lParam);
\r
7772 MenuPopup(hwnd, pt, hmenu, -1);
\r
7776 switch (LOWORD(wParam)) {
\r
7777 case IDM_QuickPaste:
\r
7779 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7780 if (sel.cpMin == sel.cpMax) {
\r
7781 MessageBeep(MB_ICONEXCLAMATION);
\r
7784 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7785 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7786 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7791 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7794 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7797 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7801 int i = LOWORD(wParam) - IDM_CommandX;
\r
7802 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7803 icsTextMenuEntry[i].command != NULL) {
\r
7804 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7805 icsTextMenuEntry[i].getname,
\r
7806 icsTextMenuEntry[i].immediate);
\r
7814 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7817 WNDPROC consoleInputWindowProc;
\r
7820 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7822 char buf[MSG_SIZ];
\r
7824 static BOOL sendNextChar = FALSE;
\r
7825 static BOOL quoteNextChar = FALSE;
\r
7826 InputSource *is = consoleInputSource;
\r
7830 switch (message) {
\r
7832 if (!appData.localLineEditing || sendNextChar) {
\r
7833 is->buf[0] = (CHAR) wParam;
\r
7835 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7836 sendNextChar = FALSE;
\r
7839 if (quoteNextChar) {
\r
7840 buf[0] = (char) wParam;
\r
7841 buf[1] = NULLCHAR;
\r
7842 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7843 quoteNextChar = FALSE;
\r
7847 case '\r': /* Enter key */
\r
7848 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7849 if (consoleEcho) SaveInHistory(is->buf);
\r
7850 is->buf[is->count++] = '\n';
\r
7851 is->buf[is->count] = NULLCHAR;
\r
7852 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7853 if (consoleEcho) {
\r
7854 ConsoleOutput(is->buf, is->count, TRUE);
\r
7855 } else if (appData.localLineEditing) {
\r
7856 ConsoleOutput("\n", 1, TRUE);
\r
7859 case '\033': /* Escape key */
\r
7860 SetWindowText(hwnd, "");
\r
7861 cf.cbSize = sizeof(CHARFORMAT);
\r
7862 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7863 if (consoleEcho) {
\r
7864 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7866 cf.crTextColor = COLOR_ECHOOFF;
\r
7868 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7869 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7871 case '\t': /* Tab key */
\r
7872 if (GetKeyState(VK_SHIFT) < 0) {
\r
7874 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7877 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7878 if (buttonDesc[0].hwnd) {
\r
7879 SetFocus(buttonDesc[0].hwnd);
\r
7881 SetFocus(hwndMain);
\r
7885 case '\023': /* Ctrl+S */
\r
7886 sendNextChar = TRUE;
\r
7888 case '\021': /* Ctrl+Q */
\r
7889 quoteNextChar = TRUE;
\r
7898 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7899 p = PrevInHistory(buf);
\r
7901 SetWindowText(hwnd, p);
\r
7902 sel.cpMin = 999999;
\r
7903 sel.cpMax = 999999;
\r
7904 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7909 p = NextInHistory();
\r
7911 SetWindowText(hwnd, p);
\r
7912 sel.cpMin = 999999;
\r
7913 sel.cpMax = 999999;
\r
7914 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7920 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7924 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7928 case WM_MBUTTONDOWN:
\r
7929 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7930 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7932 case WM_RBUTTONUP:
\r
7933 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7934 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7935 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7939 hmenu = LoadMenu(hInst, "InputMenu");
\r
7940 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7941 if (sel.cpMin == sel.cpMax) {
\r
7942 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7943 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7945 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7946 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7948 pt.x = LOWORD(lParam);
\r
7949 pt.y = HIWORD(lParam);
\r
7950 MenuPopup(hwnd, pt, hmenu, -1);
\r
7954 switch (LOWORD(wParam)) {
\r
7956 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7958 case IDM_SelectAll:
\r
7960 sel.cpMax = -1; /*999999?*/
\r
7961 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7964 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7967 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7970 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7975 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7978 #define CO_MAX 100000
\r
7979 #define CO_TRIM 1000
\r
7982 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7984 static SnapData sd;
\r
7985 static HWND hText, hInput /*, hFocus*/;
\r
7986 // InputSource *is = consoleInputSource;
\r
7988 static int sizeX, sizeY;
\r
7989 int newSizeX, newSizeY;
\r
7992 switch (message) {
\r
7993 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7994 hwndConsole = hDlg;
\r
7995 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7996 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7998 consoleTextWindowProc = (WNDPROC)
\r
7999 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
8000 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8001 consoleInputWindowProc = (WNDPROC)
\r
8002 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
8003 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8004 Colorize(ColorNormal, TRUE);
\r
8005 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
8006 ChangedConsoleFont();
\r
8007 GetClientRect(hDlg, &rect);
\r
8008 sizeX = rect.right;
\r
8009 sizeY = rect.bottom;
\r
8010 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
8011 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
8012 WINDOWPLACEMENT wp;
\r
8013 EnsureOnScreen(&consoleX, &consoleY);
\r
8014 wp.length = sizeof(WINDOWPLACEMENT);
\r
8016 wp.showCmd = SW_SHOW;
\r
8017 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8018 wp.rcNormalPosition.left = consoleX;
\r
8019 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8020 wp.rcNormalPosition.top = consoleY;
\r
8021 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8022 SetWindowPlacement(hDlg, &wp);
\r
8025 // [HGM] Chessknight's change 2004-07-13
\r
8026 else { /* Determine Defaults */
\r
8027 WINDOWPLACEMENT wp;
\r
8028 consoleX = winWidth + 1;
\r
8029 consoleY = boardY;
\r
8030 consoleW = screenWidth - winWidth;
\r
8031 consoleH = winHeight;
\r
8032 EnsureOnScreen(&consoleX, &consoleY);
\r
8033 wp.length = sizeof(WINDOWPLACEMENT);
\r
8035 wp.showCmd = SW_SHOW;
\r
8036 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
8037 wp.rcNormalPosition.left = consoleX;
\r
8038 wp.rcNormalPosition.right = consoleX + consoleW;
\r
8039 wp.rcNormalPosition.top = consoleY;
\r
8040 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
8041 SetWindowPlacement(hDlg, &wp);
\r
8056 if (IsIconic(hDlg)) break;
\r
8057 newSizeX = LOWORD(lParam);
\r
8058 newSizeY = HIWORD(lParam);
\r
8059 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
8060 RECT rectText, rectInput;
\r
8062 int newTextHeight, newTextWidth;
\r
8063 GetWindowRect(hText, &rectText);
\r
8064 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
8065 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8066 if (newTextHeight < 0) {
\r
8067 newSizeY += -newTextHeight;
\r
8068 newTextHeight = 0;
\r
8070 SetWindowPos(hText, NULL, 0, 0,
\r
8071 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8072 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8073 pt.x = rectInput.left;
\r
8074 pt.y = rectInput.top + newSizeY - sizeY;
\r
8075 ScreenToClient(hDlg, &pt);
\r
8076 SetWindowPos(hInput, NULL,
\r
8077 pt.x, pt.y, /* needs client coords */
\r
8078 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8079 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8085 case WM_GETMINMAXINFO:
\r
8086 /* Prevent resizing window too small */
\r
8087 mmi = (MINMAXINFO *) lParam;
\r
8088 mmi->ptMinTrackSize.x = 100;
\r
8089 mmi->ptMinTrackSize.y = 100;
\r
8092 /* [AS] Snapping */
\r
8093 case WM_ENTERSIZEMOVE:
\r
8094 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8097 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8100 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8102 case WM_EXITSIZEMOVE:
\r
8103 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8106 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8114 if (hwndConsole) return;
\r
8115 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8116 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8121 ConsoleOutput(char* data, int length, int forceVisible)
\r
8126 char buf[CO_MAX+1];
\r
8129 static int delayLF = 0;
\r
8130 CHARRANGE savesel, sel;
\r
8132 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8140 while (length--) {
\r
8148 } else if (*p == '\007') {
\r
8149 MyPlaySound(&sounds[(int)SoundBell]);
\r
8156 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8157 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8158 /* Save current selection */
\r
8159 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8160 exlen = GetWindowTextLength(hText);
\r
8161 /* Find out whether current end of text is visible */
\r
8162 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8163 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8164 /* Trim existing text if it's too long */
\r
8165 if (exlen + (q - buf) > CO_MAX) {
\r
8166 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8169 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8170 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8172 savesel.cpMin -= trim;
\r
8173 savesel.cpMax -= trim;
\r
8174 if (exlen < 0) exlen = 0;
\r
8175 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8176 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8178 /* Append the new text */
\r
8179 sel.cpMin = exlen;
\r
8180 sel.cpMax = exlen;
\r
8181 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8182 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8183 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8184 if (forceVisible || exlen == 0 ||
\r
8185 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8186 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8187 /* Scroll to make new end of text visible if old end of text
\r
8188 was visible or new text is an echo of user typein */
\r
8189 sel.cpMin = 9999999;
\r
8190 sel.cpMax = 9999999;
\r
8191 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8192 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8193 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8194 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8196 if (savesel.cpMax == exlen || forceVisible) {
\r
8197 /* Move insert point to new end of text if it was at the old
\r
8198 end of text or if the new text is an echo of user typein */
\r
8199 sel.cpMin = 9999999;
\r
8200 sel.cpMax = 9999999;
\r
8201 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8203 /* Restore previous selection */
\r
8204 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8206 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8213 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8217 COLORREF oldFg, oldBg;
\r
8221 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8223 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8224 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8225 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8228 rect.right = x + squareSize;
\r
8230 rect.bottom = y + squareSize;
\r
8233 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8234 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8235 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8236 &rect, str, strlen(str), NULL);
\r
8238 (void) SetTextColor(hdc, oldFg);
\r
8239 (void) SetBkColor(hdc, oldBg);
\r
8240 (void) SelectObject(hdc, oldFont);
\r
8244 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8245 RECT *rect, char *color, char *flagFell)
\r
8249 COLORREF oldFg, oldBg;
\r
8252 if (appData.clockMode) {
\r
8254 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8256 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
8263 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8264 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8266 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8267 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8269 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8271 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8272 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8273 rect, str, strlen(str), NULL);
\r
8275 (void) SetTextColor(hdc, oldFg);
\r
8276 (void) SetBkColor(hdc, oldBg);
\r
8277 (void) SelectObject(hdc, oldFont);
\r
8282 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8288 if( count <= 0 ) {
\r
8289 if (appData.debugMode) {
\r
8290 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8293 return ERROR_INVALID_USER_BUFFER;
\r
8296 ResetEvent(ovl->hEvent);
\r
8297 ovl->Offset = ovl->OffsetHigh = 0;
\r
8298 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8302 err = GetLastError();
\r
8303 if (err == ERROR_IO_PENDING) {
\r
8304 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8308 err = GetLastError();
\r
8315 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8320 ResetEvent(ovl->hEvent);
\r
8321 ovl->Offset = ovl->OffsetHigh = 0;
\r
8322 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8326 err = GetLastError();
\r
8327 if (err == ERROR_IO_PENDING) {
\r
8328 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8332 err = GetLastError();
\r
8338 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8339 void CheckForInputBufferFull( InputSource * is )
\r
8341 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8342 /* Look for end of line */
\r
8343 char * p = is->buf;
\r
8345 while( p < is->next && *p != '\n' ) {
\r
8349 if( p >= is->next ) {
\r
8350 if (appData.debugMode) {
\r
8351 fprintf( debugFP, "Input line exceeded buffer size (source id=%lu)\n", is->id );
\r
8354 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8355 is->count = (DWORD) -1;
\r
8356 is->next = is->buf;
\r
8362 InputThread(LPVOID arg)
\r
8367 is = (InputSource *) arg;
\r
8368 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8369 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8370 while (is->hThread != NULL) {
\r
8371 is->error = DoReadFile(is->hFile, is->next,
\r
8372 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8373 &is->count, &ovl);
\r
8374 if (is->error == NO_ERROR) {
\r
8375 is->next += is->count;
\r
8377 if (is->error == ERROR_BROKEN_PIPE) {
\r
8378 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8381 is->count = (DWORD) -1;
\r
8382 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8387 CheckForInputBufferFull( is );
\r
8389 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8391 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8393 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8396 CloseHandle(ovl.hEvent);
\r
8397 CloseHandle(is->hFile);
\r
8399 if (appData.debugMode) {
\r
8400 fprintf( debugFP, "Input thread terminated (id=%lu, error=%d, count=%ld)\n", is->id, is->error, is->count );
\r
8407 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8409 NonOvlInputThread(LPVOID arg)
\r
8416 is = (InputSource *) arg;
\r
8417 while (is->hThread != NULL) {
\r
8418 is->error = ReadFile(is->hFile, is->next,
\r
8419 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8420 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8421 if (is->error == NO_ERROR) {
\r
8422 /* Change CRLF to LF */
\r
8423 if (is->next > is->buf) {
\r
8425 i = is->count + 1;
\r
8433 if (prev == '\r' && *p == '\n') {
\r
8445 if (is->error == ERROR_BROKEN_PIPE) {
\r
8446 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8449 is->count = (DWORD) -1;
\r
8453 CheckForInputBufferFull( is );
\r
8455 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8457 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8459 if (is->count < 0) break; /* Quit on error */
\r
8461 CloseHandle(is->hFile);
\r
8466 SocketInputThread(LPVOID arg)
\r
8470 is = (InputSource *) arg;
\r
8471 while (is->hThread != NULL) {
\r
8472 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8473 if ((int)is->count == SOCKET_ERROR) {
\r
8474 is->count = (DWORD) -1;
\r
8475 is->error = WSAGetLastError();
\r
8477 is->error = NO_ERROR;
\r
8478 is->next += is->count;
\r
8479 if (is->count == 0 && is->second == is) {
\r
8480 /* End of file on stderr; quit with no message */
\r
8484 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8486 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8488 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8494 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8498 is = (InputSource *) lParam;
\r
8499 if (is->lineByLine) {
\r
8500 /* Feed in lines one by one */
\r
8501 char *p = is->buf;
\r
8503 while (q < is->next) {
\r
8504 if (*q++ == '\n') {
\r
8505 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8510 /* Move any partial line to the start of the buffer */
\r
8512 while (p < is->next) {
\r
8517 if (is->error != NO_ERROR || is->count == 0) {
\r
8518 /* Notify backend of the error. Note: If there was a partial
\r
8519 line at the end, it is not flushed through. */
\r
8520 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8523 /* Feed in the whole chunk of input at once */
\r
8524 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8525 is->next = is->buf;
\r
8529 /*---------------------------------------------------------------------------*\
\r
8531 * Menu enables. Used when setting various modes.
\r
8533 \*---------------------------------------------------------------------------*/
\r
8541 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8543 while (enab->item > 0) {
\r
8544 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8549 Enables gnuEnables[] = {
\r
8550 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8551 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8552 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8553 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8554 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8555 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8556 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8557 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8558 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8559 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8563 Enables icsEnables[] = {
\r
8564 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8565 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8566 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8567 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8568 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8569 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8570 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8571 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8572 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8573 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8574 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8575 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8580 Enables zippyEnables[] = {
\r
8581 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8582 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8583 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8588 Enables ncpEnables[] = {
\r
8589 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8590 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8591 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8592 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8593 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8594 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8595 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8596 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8597 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8598 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8599 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8600 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8601 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8602 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8603 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8607 Enables trainingOnEnables[] = {
\r
8608 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8609 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8610 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8611 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8612 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8613 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8614 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8615 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8619 Enables trainingOffEnables[] = {
\r
8620 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8621 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8622 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8623 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8624 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8625 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8626 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8627 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8631 /* These modify either ncpEnables or gnuEnables */
\r
8632 Enables cmailEnables[] = {
\r
8633 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8634 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8635 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8636 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8637 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8638 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8639 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8643 Enables machineThinkingEnables[] = {
\r
8644 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8645 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8646 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8647 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8648 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8649 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8650 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8651 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8652 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8653 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8654 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8655 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8656 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8657 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8658 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8662 Enables userThinkingEnables[] = {
\r
8663 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8664 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8665 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8666 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8667 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8668 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8669 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8670 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8671 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8672 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8673 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8674 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8675 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8676 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8677 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8681 /*---------------------------------------------------------------------------*\
\r
8683 * Front-end interface functions exported by XBoard.
\r
8684 * Functions appear in same order as prototypes in frontend.h.
\r
8686 \*---------------------------------------------------------------------------*/
\r
8690 static UINT prevChecked = 0;
\r
8691 static int prevPausing = 0;
\r
8694 if (pausing != prevPausing) {
\r
8695 prevPausing = pausing;
\r
8696 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8697 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8698 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8701 switch (gameMode) {
\r
8702 case BeginningOfGame:
\r
8703 if (appData.icsActive)
\r
8704 nowChecked = IDM_IcsClient;
\r
8705 else if (appData.noChessProgram)
\r
8706 nowChecked = IDM_EditGame;
\r
8708 nowChecked = IDM_MachineBlack;
\r
8710 case MachinePlaysBlack:
\r
8711 nowChecked = IDM_MachineBlack;
\r
8713 case MachinePlaysWhite:
\r
8714 nowChecked = IDM_MachineWhite;
\r
8716 case TwoMachinesPlay:
\r
8717 nowChecked = IDM_TwoMachines;
\r
8720 nowChecked = IDM_AnalysisMode;
\r
8723 nowChecked = IDM_AnalyzeFile;
\r
8726 nowChecked = IDM_EditGame;
\r
8728 case PlayFromGameFile:
\r
8729 nowChecked = IDM_LoadGame;
\r
8731 case EditPosition:
\r
8732 nowChecked = IDM_EditPosition;
\r
8735 nowChecked = IDM_Training;
\r
8737 case IcsPlayingWhite:
\r
8738 case IcsPlayingBlack:
\r
8739 case IcsObserving:
\r
8741 nowChecked = IDM_IcsClient;
\r
8748 if (prevChecked != 0)
\r
8749 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8750 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8751 if (nowChecked != 0)
\r
8752 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8753 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8755 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8756 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8757 MF_BYCOMMAND|MF_ENABLED);
\r
8759 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8760 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8763 prevChecked = nowChecked;
\r
8765 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8766 if (appData.icsActive) {
\r
8767 if (appData.icsEngineAnalyze) {
\r
8768 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8769 MF_BYCOMMAND|MF_CHECKED);
\r
8771 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8772 MF_BYCOMMAND|MF_UNCHECKED);
\r
8780 HMENU hmenu = GetMenu(hwndMain);
\r
8781 SetMenuEnables(hmenu, icsEnables);
\r
8782 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8783 MF_BYPOSITION|MF_ENABLED);
\r
8785 if (appData.zippyPlay) {
\r
8786 SetMenuEnables(hmenu, zippyEnables);
\r
8787 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8788 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8789 MF_BYCOMMAND|MF_ENABLED);
\r
8797 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8803 HMENU hmenu = GetMenu(hwndMain);
\r
8804 SetMenuEnables(hmenu, ncpEnables);
\r
8805 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8806 MF_BYPOSITION|MF_GRAYED);
\r
8807 DrawMenuBar(hwndMain);
\r
8813 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8817 SetTrainingModeOn()
\r
8820 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8821 for (i = 0; i < N_BUTTONS; i++) {
\r
8822 if (buttonDesc[i].hwnd != NULL)
\r
8823 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8828 VOID SetTrainingModeOff()
\r
8831 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8832 for (i = 0; i < N_BUTTONS; i++) {
\r
8833 if (buttonDesc[i].hwnd != NULL)
\r
8834 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8840 SetUserThinkingEnables()
\r
8842 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8846 SetMachineThinkingEnables()
\r
8848 HMENU hMenu = GetMenu(hwndMain);
\r
8849 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8851 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8853 if (gameMode == MachinePlaysBlack) {
\r
8854 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8855 } else if (gameMode == MachinePlaysWhite) {
\r
8856 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8857 } else if (gameMode == TwoMachinesPlay) {
\r
8858 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8864 DisplayTitle(char *str)
\r
8866 char title[MSG_SIZ], *host;
\r
8867 if (str[0] != NULLCHAR) {
\r
8868 strcpy(title, str);
\r
8869 } else if (appData.icsActive) {
\r
8870 if (appData.icsCommPort[0] != NULLCHAR)
\r
8873 host = appData.icsHost;
\r
8874 sprintf(title, "%s: %s", szTitle, host);
\r
8875 } else if (appData.noChessProgram) {
\r
8876 strcpy(title, szTitle);
\r
8878 strcpy(title, szTitle);
\r
8879 strcat(title, ": ");
\r
8880 strcat(title, first.tidy);
\r
8882 SetWindowText(hwndMain, title);
\r
8887 DisplayMessage(char *str1, char *str2)
\r
8891 int remain = MESSAGE_TEXT_MAX - 1;
\r
8894 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8895 messageText[0] = NULLCHAR;
\r
8897 len = strlen(str1);
\r
8898 if (len > remain) len = remain;
\r
8899 strncpy(messageText, str1, len);
\r
8900 messageText[len] = NULLCHAR;
\r
8903 if (*str2 && remain >= 2) {
\r
8905 strcat(messageText, " ");
\r
8908 len = strlen(str2);
\r
8909 if (len > remain) len = remain;
\r
8910 strncat(messageText, str2, len);
\r
8912 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8914 if (hwndMain == NULL || IsIconic(hwndMain)) return;
\r
8915 hdc = GetDC(hwndMain);
\r
8916 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8917 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8918 &messageRect, messageText, strlen(messageText), NULL);
\r
8919 (void) SelectObject(hdc, oldFont);
\r
8920 (void) ReleaseDC(hwndMain, hdc);
\r
8924 DisplayError(char *str, int error)
\r
8926 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8932 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8933 NULL, error, LANG_NEUTRAL,
\r
8934 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8936 sprintf(buf, "%s:\n%s", str, buf2);
\r
8938 ErrorMap *em = errmap;
\r
8939 while (em->err != 0 && em->err != error) em++;
\r
8940 if (em->err != 0) {
\r
8941 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8943 sprintf(buf, "%s:\nError code %d", str, error);
\r
8948 ErrorPopUp("Error", buf);
\r
8953 DisplayMoveError(char *str)
\r
8955 fromX = fromY = -1;
\r
8956 ClearHighlights();
\r
8957 DrawPosition(FALSE, NULL);
\r
8958 if (appData.popupMoveErrors) {
\r
8959 ErrorPopUp("Error", str);
\r
8961 DisplayMessage(str, "");
\r
8962 moveErrorMessageUp = TRUE;
\r
8967 DisplayFatalError(char *str, int error, int exitStatus)
\r
8969 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8971 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8974 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8975 NULL, error, LANG_NEUTRAL,
\r
8976 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8978 sprintf(buf, "%s:\n%s", str, buf2);
\r
8980 ErrorMap *em = errmap;
\r
8981 while (em->err != 0 && em->err != error) em++;
\r
8982 if (em->err != 0) {
\r
8983 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8985 sprintf(buf, "%s:\nError code %d", str, error);
\r
8990 if (appData.debugMode) {
\r
8991 fprintf(debugFP, "%s: %s\n", label, str);
\r
8993 if (appData.popupExitMessage) {
\r
8994 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8995 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8997 ExitEvent(exitStatus);
\r
9002 DisplayInformation(char *str)
\r
9004 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
9009 DisplayNote(char *str)
\r
9011 ErrorPopUp("Note", str);
\r
9016 char *title, *question, *replyPrefix;
\r
9021 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9023 static QuestionParams *qp;
\r
9024 char reply[MSG_SIZ];
\r
9027 switch (message) {
\r
9028 case WM_INITDIALOG:
\r
9029 qp = (QuestionParams *) lParam;
\r
9030 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9031 SetWindowText(hDlg, qp->title);
\r
9032 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
9033 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
9037 switch (LOWORD(wParam)) {
\r
9039 strcpy(reply, qp->replyPrefix);
\r
9040 if (*reply) strcat(reply, " ");
\r
9041 len = strlen(reply);
\r
9042 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
9043 strcat(reply, "\n");
\r
9044 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
9045 EndDialog(hDlg, TRUE);
\r
9046 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
9049 EndDialog(hDlg, FALSE);
\r
9060 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
9062 QuestionParams qp;
\r
9066 qp.question = question;
\r
9067 qp.replyPrefix = replyPrefix;
\r
9069 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9070 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9071 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9072 FreeProcInstance(lpProc);
\r
9075 /* [AS] Pick FRC position */
\r
9076 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9078 static int * lpIndexFRC;
\r
9084 case WM_INITDIALOG:
\r
9085 lpIndexFRC = (int *) lParam;
\r
9087 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9089 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9090 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9091 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9092 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9097 switch( LOWORD(wParam) ) {
\r
9099 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9100 EndDialog( hDlg, 0 );
\r
9101 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9104 EndDialog( hDlg, 1 );
\r
9106 case IDC_NFG_Edit:
\r
9107 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9108 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9110 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9113 case IDC_NFG_Random:
\r
9114 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9115 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9128 int index = appData.defaultFrcPosition;
\r
9129 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9131 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9133 if( result == 0 ) {
\r
9134 appData.defaultFrcPosition = index;
\r
9140 /* [AS] Game list options */
\r
9146 static GLT_Item GLT_ItemInfo[] = {
\r
9147 { GLT_EVENT, "Event" },
\r
9148 { GLT_SITE, "Site" },
\r
9149 { GLT_DATE, "Date" },
\r
9150 { GLT_ROUND, "Round" },
\r
9151 { GLT_PLAYERS, "Players" },
\r
9152 { GLT_RESULT, "Result" },
\r
9153 { GLT_WHITE_ELO, "White Rating" },
\r
9154 { GLT_BLACK_ELO, "Black Rating" },
\r
9155 { GLT_TIME_CONTROL,"Time Control" },
\r
9156 { GLT_VARIANT, "Variant" },
\r
9157 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9161 const char * GLT_FindItem( char id )
\r
9163 const char * result = 0;
\r
9165 GLT_Item * list = GLT_ItemInfo;
\r
9167 while( list->id != 0 ) {
\r
9168 if( list->id == id ) {
\r
9169 result = list->name;
\r
9179 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9181 const char * name = GLT_FindItem( id );
\r
9184 if( index >= 0 ) {
\r
9185 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9188 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9193 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9197 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9200 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9204 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9206 pc = GLT_ALL_TAGS;
\r
9209 if( strchr( tags, *pc ) == 0 ) {
\r
9210 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9215 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9218 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9220 char result = '\0';
\r
9223 GLT_Item * list = GLT_ItemInfo;
\r
9225 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9226 while( list->id != 0 ) {
\r
9227 if( strcmp( list->name, name ) == 0 ) {
\r
9228 result = list->id;
\r
9239 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9241 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9242 int idx2 = idx1 + delta;
\r
9243 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9245 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9248 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9249 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9250 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9251 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9255 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9257 static char glt[64];
\r
9258 static char * lpUserGLT;
\r
9262 case WM_INITDIALOG:
\r
9263 lpUserGLT = (char *) lParam;
\r
9265 strcpy( glt, lpUserGLT );
\r
9267 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9269 /* Initialize list */
\r
9270 GLT_TagsToList( hDlg, glt );
\r
9272 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9277 switch( LOWORD(wParam) ) {
\r
9280 char * pc = lpUserGLT;
\r
9282 // int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9286 id = GLT_ListItemToTag( hDlg, idx );
\r
9290 } while( id != '\0' );
\r
9292 EndDialog( hDlg, 0 );
\r
9295 EndDialog( hDlg, 1 );
\r
9298 case IDC_GLT_Default:
\r
9299 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9300 GLT_TagsToList( hDlg, glt );
\r
9303 case IDC_GLT_Restore:
\r
9304 strcpy( glt, lpUserGLT );
\r
9305 GLT_TagsToList( hDlg, glt );
\r
9309 GLT_MoveSelection( hDlg, -1 );
\r
9312 case IDC_GLT_Down:
\r
9313 GLT_MoveSelection( hDlg, +1 );
\r
9323 int GameListOptions()
\r
9327 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9329 strcpy( glt, appData.gameListTags );
\r
9331 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9333 if( result == 0 ) {
\r
9334 /* [AS] Memory leak here! */
\r
9335 appData.gameListTags = strdup( glt );
\r
9343 DisplayIcsInteractionTitle(char *str)
\r
9345 char consoleTitle[MSG_SIZ];
\r
9347 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9348 SetWindowText(hwndConsole, consoleTitle);
\r
9352 DrawPosition(int fullRedraw, Board board)
\r
9354 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9361 fromX = fromY = -1;
\r
9362 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9363 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9364 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9365 dragInfo.lastpos = dragInfo.pos;
\r
9366 dragInfo.start.x = dragInfo.start.y = -1;
\r
9367 dragInfo.from = dragInfo.start;
\r
9369 DrawPosition(TRUE, NULL);
\r
9375 CommentPopUp(char *title, char *str)
\r
9377 HWND hwnd = GetActiveWindow();
\r
9378 EitherCommentPopUp(0, title, str, FALSE);
\r
9379 SetActiveWindow(hwnd);
\r
9383 CommentPopDown(void)
\r
9385 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9386 if (commentDialog) {
\r
9387 ShowWindow(commentDialog, SW_HIDE);
\r
9389 commentDialogUp = FALSE;
\r
9393 EditCommentPopUp(int index, char *title, char *str)
\r
9395 EitherCommentPopUp(index, title, str, TRUE);
\r
9402 MyPlaySound(&sounds[(int)SoundMove]);
\r
9405 VOID PlayIcsWinSound()
\r
9407 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9410 VOID PlayIcsLossSound()
\r
9412 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9415 VOID PlayIcsDrawSound()
\r
9417 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9420 VOID PlayIcsUnfinishedSound()
\r
9422 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9428 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9436 consoleEcho = TRUE;
\r
9437 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9438 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9439 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9448 consoleEcho = FALSE;
\r
9449 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9450 /* This works OK: set text and background both to the same color */
\r
9452 cf.crTextColor = COLOR_ECHOOFF;
\r
9453 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9454 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9457 /* No Raw()...? */
\r
9459 void Colorize(ColorClass cc, int continuation)
\r
9461 currentColorClass = cc;
\r
9462 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9463 consoleCF.crTextColor = textAttribs[cc].color;
\r
9464 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9465 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9471 static char buf[MSG_SIZ];
\r
9472 DWORD bufsiz = MSG_SIZ;
\r
9474 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9475 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9477 if (!GetUserName(buf, &bufsiz)) {
\r
9478 /*DisplayError("Error getting user name", GetLastError());*/
\r
9479 strcpy(buf, "User");
\r
9487 static char buf[MSG_SIZ];
\r
9488 DWORD bufsiz = MSG_SIZ;
\r
9490 if (!GetComputerName(buf, &bufsiz)) {
\r
9491 /*DisplayError("Error getting host name", GetLastError());*/
\r
9492 strcpy(buf, "Unknown");
\r
9499 ClockTimerRunning()
\r
9501 return clockTimerEvent != 0;
\r
9507 if (clockTimerEvent == 0) return FALSE;
\r
9508 KillTimer(hwndMain, clockTimerEvent);
\r
9509 clockTimerEvent = 0;
\r
9514 StartClockTimer(long millisec)
\r
9516 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9517 (UINT) millisec, NULL);
\r
9521 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9524 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9526 if(appData.noGUI) return;
\r
9527 hdc = GetDC(hwndMain);
\r
9528 if (!IsIconic(hwndMain)) {
\r
9529 DisplayAClock(hdc, timeRemaining, highlight,
\r
9530 (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);
\r
9532 if (highlight && iconCurrent == iconBlack) {
\r
9533 iconCurrent = iconWhite;
\r
9534 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9535 if (IsIconic(hwndMain)) {
\r
9536 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9539 (void) ReleaseDC(hwndMain, hdc);
\r
9541 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9545 DisplayBlackClock(long timeRemaining, int highlight)
\r
9548 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9550 if(appData.noGUI) return;
\r
9551 hdc = GetDC(hwndMain);
\r
9552 if (!IsIconic(hwndMain)) {
\r
9553 DisplayAClock(hdc, timeRemaining, highlight,
\r
9554 (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);
\r
9556 if (highlight && iconCurrent == iconWhite) {
\r
9557 iconCurrent = iconBlack;
\r
9558 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9559 if (IsIconic(hwndMain)) {
\r
9560 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9563 (void) ReleaseDC(hwndMain, hdc);
\r
9565 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9570 LoadGameTimerRunning()
\r
9572 return loadGameTimerEvent != 0;
\r
9576 StopLoadGameTimer()
\r
9578 if (loadGameTimerEvent == 0) return FALSE;
\r
9579 KillTimer(hwndMain, loadGameTimerEvent);
\r
9580 loadGameTimerEvent = 0;
\r
9585 StartLoadGameTimer(long millisec)
\r
9587 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9588 (UINT) millisec, NULL);
\r
9596 char fileTitle[MSG_SIZ];
\r
9598 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9599 f = OpenFileDialog(hwndMain, "a", defName,
\r
9600 appData.oldSaveStyle ? "gam" : "pgn",
\r
9602 "Save Game to File", NULL, fileTitle, NULL);
\r
9604 SaveGame(f, 0, "");
\r
9611 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9613 if (delayedTimerEvent != 0) {
\r
9614 if (appData.debugMode) {
\r
9615 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9617 KillTimer(hwndMain, delayedTimerEvent);
\r
9618 delayedTimerEvent = 0;
\r
9619 delayedTimerCallback();
\r
9621 delayedTimerCallback = cb;
\r
9622 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9623 (UINT) millisec, NULL);
\r
9626 DelayedEventCallback
\r
9629 if (delayedTimerEvent) {
\r
9630 return delayedTimerCallback;
\r
9637 CancelDelayedEvent()
\r
9639 if (delayedTimerEvent) {
\r
9640 KillTimer(hwndMain, delayedTimerEvent);
\r
9641 delayedTimerEvent = 0;
\r
9645 DWORD GetWin32Priority(int nice)
\r
9646 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9648 REALTIME_PRIORITY_CLASS 0x00000100
\r
9649 HIGH_PRIORITY_CLASS 0x00000080
\r
9650 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9651 NORMAL_PRIORITY_CLASS 0x00000020
\r
9652 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9653 IDLE_PRIORITY_CLASS 0x00000040
\r
9655 if (nice < -15) return 0x00000080;
\r
9656 if (nice < 0) return 0x00008000;
\r
9657 if (nice == 0) return 0x00000020;
\r
9658 if (nice < 15) return 0x00004000;
\r
9659 return 0x00000040;
\r
9662 /* Start a child process running the given program.
\r
9663 The process's standard output can be read from "from", and its
\r
9664 standard input can be written to "to".
\r
9665 Exit with fatal error if anything goes wrong.
\r
9666 Returns an opaque pointer that can be used to destroy the process
\r
9670 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9672 #define BUFSIZE 4096
\r
9674 HANDLE hChildStdinRd, hChildStdinWr,
\r
9675 hChildStdoutRd, hChildStdoutWr;
\r
9676 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9677 SECURITY_ATTRIBUTES saAttr;
\r
9679 PROCESS_INFORMATION piProcInfo;
\r
9680 STARTUPINFO siStartInfo;
\r
9682 char buf[MSG_SIZ];
\r
9685 if (appData.debugMode) {
\r
9686 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9691 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9692 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9693 saAttr.bInheritHandle = TRUE;
\r
9694 saAttr.lpSecurityDescriptor = NULL;
\r
9697 * The steps for redirecting child's STDOUT:
\r
9698 * 1. Create anonymous pipe to be STDOUT for child.
\r
9699 * 2. Create a noninheritable duplicate of read handle,
\r
9700 * and close the inheritable read handle.
\r
9703 /* Create a pipe for the child's STDOUT. */
\r
9704 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9705 return GetLastError();
\r
9708 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9709 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9710 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9711 FALSE, /* not inherited */
\r
9712 DUPLICATE_SAME_ACCESS);
\r
9714 return GetLastError();
\r
9716 CloseHandle(hChildStdoutRd);
\r
9719 * The steps for redirecting child's STDIN:
\r
9720 * 1. Create anonymous pipe to be STDIN for child.
\r
9721 * 2. Create a noninheritable duplicate of write handle,
\r
9722 * and close the inheritable write handle.
\r
9725 /* Create a pipe for the child's STDIN. */
\r
9726 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9727 return GetLastError();
\r
9730 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9731 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9732 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9733 FALSE, /* not inherited */
\r
9734 DUPLICATE_SAME_ACCESS);
\r
9736 return GetLastError();
\r
9738 CloseHandle(hChildStdinWr);
\r
9740 /* Arrange to (1) look in dir for the child .exe file, and
\r
9741 * (2) have dir be the child's working directory. Interpret
\r
9742 * dir relative to the directory WinBoard loaded from. */
\r
9743 GetCurrentDirectory(MSG_SIZ, buf);
\r
9744 SetCurrentDirectory(installDir);
\r
9745 SetCurrentDirectory(dir);
\r
9747 /* Now create the child process. */
\r
9749 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9750 siStartInfo.lpReserved = NULL;
\r
9751 siStartInfo.lpDesktop = NULL;
\r
9752 siStartInfo.lpTitle = NULL;
\r
9753 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9754 siStartInfo.cbReserved2 = 0;
\r
9755 siStartInfo.lpReserved2 = NULL;
\r
9756 siStartInfo.hStdInput = hChildStdinRd;
\r
9757 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9758 siStartInfo.hStdError = hChildStdoutWr;
\r
9760 fSuccess = CreateProcess(NULL,
\r
9761 cmdLine, /* command line */
\r
9762 NULL, /* process security attributes */
\r
9763 NULL, /* primary thread security attrs */
\r
9764 TRUE, /* handles are inherited */
\r
9765 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9766 NULL, /* use parent's environment */
\r
9768 &siStartInfo, /* STARTUPINFO pointer */
\r
9769 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9771 err = GetLastError();
\r
9772 SetCurrentDirectory(buf); /* return to prev directory */
\r
9777 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9778 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9779 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9782 /* Close the handles we don't need in the parent */
\r
9783 CloseHandle(piProcInfo.hThread);
\r
9784 CloseHandle(hChildStdinRd);
\r
9785 CloseHandle(hChildStdoutWr);
\r
9787 /* Prepare return value */
\r
9788 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9789 cp->kind = CPReal;
\r
9790 cp->hProcess = piProcInfo.hProcess;
\r
9791 cp->pid = piProcInfo.dwProcessId;
\r
9792 cp->hFrom = hChildStdoutRdDup;
\r
9793 cp->hTo = hChildStdinWrDup;
\r
9795 *pr = (void *) cp;
\r
9797 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9798 2000 where engines sometimes don't see the initial command(s)
\r
9799 from WinBoard and hang. I don't understand how that can happen,
\r
9800 but the Sleep is harmless, so I've put it in. Others have also
\r
9801 reported what may be the same problem, so hopefully this will fix
\r
9802 it for them too. */
\r
9810 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9812 ChildProc *cp; int result;
\r
9814 cp = (ChildProc *) pr;
\r
9815 if (cp == NULL) return;
\r
9817 switch (cp->kind) {
\r
9819 /* TerminateProcess is considered harmful, so... */
\r
9820 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9821 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9822 /* The following doesn't work because the chess program
\r
9823 doesn't "have the same console" as WinBoard. Maybe
\r
9824 we could arrange for this even though neither WinBoard
\r
9825 nor the chess program uses a console for stdio? */
\r
9826 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9828 /* [AS] Special termination modes for misbehaving programs... */
\r
9829 if( signal == 9 ) {
\r
9830 result = TerminateProcess( cp->hProcess, 0 );
\r
9832 if ( appData.debugMode) {
\r
9833 fprintf( debugFP, "Terminating process %lu, result=%d\n", cp->pid, result );
\r
9836 else if( signal == 10 ) {
\r
9837 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9839 if( dw != WAIT_OBJECT_0 ) {
\r
9840 result = TerminateProcess( cp->hProcess, 0 );
\r
9842 if ( appData.debugMode) {
\r
9843 fprintf( debugFP, "Process %lu still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9849 CloseHandle(cp->hProcess);
\r
9853 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9857 closesocket(cp->sock);
\r
9862 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9863 closesocket(cp->sock);
\r
9864 closesocket(cp->sock2);
\r
9872 InterruptChildProcess(ProcRef pr)
\r
9876 cp = (ChildProc *) pr;
\r
9877 if (cp == NULL) return;
\r
9878 switch (cp->kind) {
\r
9880 /* The following doesn't work because the chess program
\r
9881 doesn't "have the same console" as WinBoard. Maybe
\r
9882 we could arrange for this even though neither WinBoard
\r
9883 nor the chess program uses a console for stdio */
\r
9884 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9889 /* Can't interrupt */
\r
9893 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9900 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9902 char cmdLine[MSG_SIZ];
\r
9904 if (port[0] == NULLCHAR) {
\r
9905 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9907 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9909 return StartChildProcess(cmdLine, "", pr);
\r
9913 /* Code to open TCP sockets */
\r
9916 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9921 struct sockaddr_in sa, mysa;
\r
9922 struct hostent FAR *hp;
\r
9923 unsigned short uport;
\r
9924 WORD wVersionRequested;
\r
9927 /* Initialize socket DLL */
\r
9928 wVersionRequested = MAKEWORD(1, 1);
\r
9929 err = WSAStartup(wVersionRequested, &wsaData);
\r
9930 if (err != 0) return err;
\r
9933 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9934 err = WSAGetLastError();
\r
9939 /* Bind local address using (mostly) don't-care values.
\r
9941 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9942 mysa.sin_family = AF_INET;
\r
9943 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9944 uport = (unsigned short) 0;
\r
9945 mysa.sin_port = htons(uport);
\r
9946 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9947 == SOCKET_ERROR) {
\r
9948 err = WSAGetLastError();
\r
9953 /* Resolve remote host name */
\r
9954 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9955 if (!(hp = gethostbyname(host))) {
\r
9956 unsigned int b0, b1, b2, b3;
\r
9958 err = WSAGetLastError();
\r
9960 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9961 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9962 hp->h_addrtype = AF_INET;
\r
9964 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9965 hp->h_addr_list[0] = (char *) malloc(4);
\r
9966 hp->h_addr_list[0][0] = (char) b0;
\r
9967 hp->h_addr_list[0][1] = (char) b1;
\r
9968 hp->h_addr_list[0][2] = (char) b2;
\r
9969 hp->h_addr_list[0][3] = (char) b3;
\r
9975 sa.sin_family = hp->h_addrtype;
\r
9976 uport = (unsigned short) atoi(port);
\r
9977 sa.sin_port = htons(uport);
\r
9978 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9980 /* Make connection */
\r
9981 if (connect(s, (struct sockaddr *) &sa,
\r
9982 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9983 err = WSAGetLastError();
\r
9988 /* Prepare return value */
\r
9989 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9990 cp->kind = CPSock;
\r
9992 *pr = (ProcRef *) cp;
\r
9998 OpenCommPort(char *name, ProcRef *pr)
\r
10003 char fullname[MSG_SIZ];
\r
10005 if (*name != '\\')
\r
10006 sprintf(fullname, "\\\\.\\%s", name);
\r
10008 strcpy(fullname, name);
\r
10010 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
10011 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
10012 if (h == (HANDLE) -1) {
\r
10013 return GetLastError();
\r
10017 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
10019 /* Accumulate characters until a 100ms pause, then parse */
\r
10020 ct.ReadIntervalTimeout = 100;
\r
10021 ct.ReadTotalTimeoutMultiplier = 0;
\r
10022 ct.ReadTotalTimeoutConstant = 0;
\r
10023 ct.WriteTotalTimeoutMultiplier = 0;
\r
10024 ct.WriteTotalTimeoutConstant = 0;
\r
10025 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
10027 /* Prepare return value */
\r
10028 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10029 cp->kind = CPComm;
\r
10032 *pr = (ProcRef *) cp;
\r
10038 OpenLoopback(ProcRef *pr)
\r
10040 DisplayFatalError("Not implemented", 0, 1);
\r
10046 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
10050 SOCKET s, s2, s3;
\r
10051 struct sockaddr_in sa, mysa;
\r
10052 struct hostent FAR *hp;
\r
10053 unsigned short uport;
\r
10054 WORD wVersionRequested;
\r
10057 char stderrPortStr[MSG_SIZ];
\r
10059 /* Initialize socket DLL */
\r
10060 wVersionRequested = MAKEWORD(1, 1);
\r
10061 err = WSAStartup(wVersionRequested, &wsaData);
\r
10062 if (err != 0) return err;
\r
10064 /* Resolve remote host name */
\r
10065 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10066 if (!(hp = gethostbyname(host))) {
\r
10067 unsigned int b0, b1, b2, b3;
\r
10069 err = WSAGetLastError();
\r
10071 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10072 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10073 hp->h_addrtype = AF_INET;
\r
10074 hp->h_length = 4;
\r
10075 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10076 hp->h_addr_list[0] = (char *) malloc(4);
\r
10077 hp->h_addr_list[0][0] = (char) b0;
\r
10078 hp->h_addr_list[0][1] = (char) b1;
\r
10079 hp->h_addr_list[0][2] = (char) b2;
\r
10080 hp->h_addr_list[0][3] = (char) b3;
\r
10086 sa.sin_family = hp->h_addrtype;
\r
10087 uport = (unsigned short) 514;
\r
10088 sa.sin_port = htons(uport);
\r
10089 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10091 /* Bind local socket to unused "privileged" port address
\r
10093 s = INVALID_SOCKET;
\r
10094 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10095 mysa.sin_family = AF_INET;
\r
10096 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10097 for (fromPort = 1023;; fromPort--) {
\r
10098 if (fromPort < 0) {
\r
10100 return WSAEADDRINUSE;
\r
10102 if (s == INVALID_SOCKET) {
\r
10103 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10104 err = WSAGetLastError();
\r
10109 uport = (unsigned short) fromPort;
\r
10110 mysa.sin_port = htons(uport);
\r
10111 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10112 == SOCKET_ERROR) {
\r
10113 err = WSAGetLastError();
\r
10114 if (err == WSAEADDRINUSE) continue;
\r
10118 if (connect(s, (struct sockaddr *) &sa,
\r
10119 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10120 err = WSAGetLastError();
\r
10121 if (err == WSAEADDRINUSE) {
\r
10132 /* Bind stderr local socket to unused "privileged" port address
\r
10134 s2 = INVALID_SOCKET;
\r
10135 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10136 mysa.sin_family = AF_INET;
\r
10137 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10138 for (fromPort = 1023;; fromPort--) {
\r
10139 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10140 if (fromPort < 0) {
\r
10141 (void) closesocket(s);
\r
10143 return WSAEADDRINUSE;
\r
10145 if (s2 == INVALID_SOCKET) {
\r
10146 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10147 err = WSAGetLastError();
\r
10153 uport = (unsigned short) fromPort;
\r
10154 mysa.sin_port = htons(uport);
\r
10155 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10156 == SOCKET_ERROR) {
\r
10157 err = WSAGetLastError();
\r
10158 if (err == WSAEADDRINUSE) continue;
\r
10159 (void) closesocket(s);
\r
10163 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10164 err = WSAGetLastError();
\r
10165 if (err == WSAEADDRINUSE) {
\r
10167 s2 = INVALID_SOCKET;
\r
10170 (void) closesocket(s);
\r
10171 (void) closesocket(s2);
\r
10177 prevStderrPort = fromPort; // remember port used
\r
10178 sprintf(stderrPortStr, "%d", fromPort);
\r
10180 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10181 err = WSAGetLastError();
\r
10182 (void) closesocket(s);
\r
10183 (void) closesocket(s2);
\r
10188 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10189 err = WSAGetLastError();
\r
10190 (void) closesocket(s);
\r
10191 (void) closesocket(s2);
\r
10195 if (*user == NULLCHAR) user = UserName();
\r
10196 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10197 err = WSAGetLastError();
\r
10198 (void) closesocket(s);
\r
10199 (void) closesocket(s2);
\r
10203 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10204 err = WSAGetLastError();
\r
10205 (void) closesocket(s);
\r
10206 (void) closesocket(s2);
\r
10211 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10212 err = WSAGetLastError();
\r
10213 (void) closesocket(s);
\r
10214 (void) closesocket(s2);
\r
10218 (void) closesocket(s2); /* Stop listening */
\r
10220 /* Prepare return value */
\r
10221 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10222 cp->kind = CPRcmd;
\r
10225 *pr = (ProcRef *) cp;
\r
10232 AddInputSource(ProcRef pr, int lineByLine,
\r
10233 InputCallback func, VOIDSTAR closure)
\r
10235 InputSource *is, *is2 = NULL;
\r
10236 ChildProc *cp = (ChildProc *) pr;
\r
10238 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10239 is->lineByLine = lineByLine;
\r
10241 is->closure = closure;
\r
10242 is->second = NULL;
\r
10243 is->next = is->buf;
\r
10244 if (pr == NoProc) {
\r
10245 is->kind = CPReal;
\r
10246 consoleInputSource = is;
\r
10248 is->kind = cp->kind;
\r
10250 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10251 we create all threads suspended so that the is->hThread variable can be
\r
10252 safely assigned, then let the threads start with ResumeThread.
\r
10254 switch (cp->kind) {
\r
10256 is->hFile = cp->hFrom;
\r
10257 cp->hFrom = NULL; /* now owned by InputThread */
\r
10259 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10260 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10264 is->hFile = cp->hFrom;
\r
10265 cp->hFrom = NULL; /* now owned by InputThread */
\r
10267 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10268 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10272 is->sock = cp->sock;
\r
10274 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10275 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10279 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10281 is->sock = cp->sock;
\r
10282 is->second = is2;
\r
10283 is2->sock = cp->sock2;
\r
10284 is2->second = is2;
\r
10286 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10287 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10289 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10290 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10294 if( is->hThread != NULL ) {
\r
10295 ResumeThread( is->hThread );
\r
10298 if( is2 != NULL && is2->hThread != NULL ) {
\r
10299 ResumeThread( is2->hThread );
\r
10303 return (InputSourceRef) is;
\r
10307 RemoveInputSource(InputSourceRef isr)
\r
10311 is = (InputSource *) isr;
\r
10312 is->hThread = NULL; /* tell thread to stop */
\r
10313 CloseHandle(is->hThread);
\r
10314 if (is->second != NULL) {
\r
10315 is->second->hThread = NULL;
\r
10316 CloseHandle(is->second->hThread);
\r
10322 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10325 int outCount = SOCKET_ERROR;
\r
10326 ChildProc *cp = (ChildProc *) pr;
\r
10327 static OVERLAPPED ovl;
\r
10329 if (pr == NoProc) {
\r
10330 ConsoleOutput(message, count, FALSE);
\r
10334 if (ovl.hEvent == NULL) {
\r
10335 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10337 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10339 switch (cp->kind) {
\r
10342 outCount = send(cp->sock, message, count, 0);
\r
10343 if (outCount == SOCKET_ERROR) {
\r
10344 *outError = WSAGetLastError();
\r
10346 *outError = NO_ERROR;
\r
10351 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10352 &dOutCount, NULL)) {
\r
10353 *outError = NO_ERROR;
\r
10354 outCount = (int) dOutCount;
\r
10356 *outError = GetLastError();
\r
10361 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10362 &dOutCount, &ovl);
\r
10363 if (*outError == NO_ERROR) {
\r
10364 outCount = (int) dOutCount;
\r
10372 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10375 /* Ignore delay, not implemented for WinBoard */
\r
10376 return OutputToProcess(pr, message, count, outError);
\r
10381 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10382 char *buf, int count, int error)
\r
10384 DisplayFatalError("Not implemented", 0, 1);
\r
10387 /* see wgamelist.c for Game List functions */
\r
10388 /* see wedittags.c for Edit Tags functions */
\r
10395 char buf[MSG_SIZ];
\r
10398 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10399 f = fopen(buf, "r");
\r
10401 ProcessICSInitScript(f);
\r
10409 StartAnalysisClock()
\r
10411 if (analysisTimerEvent) return;
\r
10412 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10413 (UINT) 2000, NULL);
\r
10417 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10419 static HANDLE hwndText;
\r
10421 static int sizeX, sizeY;
\r
10422 int newSizeX, newSizeY, flags;
\r
10425 switch (message) {
\r
10426 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10427 /* Initialize the dialog items */
\r
10428 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10429 SetWindowText(hDlg, analysisTitle);
\r
10430 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10431 /* Size and position the dialog */
\r
10432 if (!analysisDialog) {
\r
10433 analysisDialog = hDlg;
\r
10434 flags = SWP_NOZORDER;
\r
10435 GetClientRect(hDlg, &rect);
\r
10436 sizeX = rect.right;
\r
10437 sizeY = rect.bottom;
\r
10438 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10439 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10440 WINDOWPLACEMENT wp;
\r
10441 EnsureOnScreen(&analysisX, &analysisY);
\r
10442 wp.length = sizeof(WINDOWPLACEMENT);
\r
10444 wp.showCmd = SW_SHOW;
\r
10445 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10446 wp.rcNormalPosition.left = analysisX;
\r
10447 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10448 wp.rcNormalPosition.top = analysisY;
\r
10449 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10450 SetWindowPlacement(hDlg, &wp);
\r
10452 GetClientRect(hDlg, &rect);
\r
10453 newSizeX = rect.right;
\r
10454 newSizeY = rect.bottom;
\r
10455 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10456 newSizeX, newSizeY);
\r
10457 sizeX = newSizeX;
\r
10458 sizeY = newSizeY;
\r
10463 case WM_COMMAND: /* message: received a command */
\r
10464 switch (LOWORD(wParam)) {
\r
10466 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10467 ExitAnalyzeMode();
\r
10479 newSizeX = LOWORD(lParam);
\r
10480 newSizeY = HIWORD(lParam);
\r
10481 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10482 sizeX = newSizeX;
\r
10483 sizeY = newSizeY;
\r
10486 case WM_GETMINMAXINFO:
\r
10487 /* Prevent resizing window too small */
\r
10488 mmi = (MINMAXINFO *) lParam;
\r
10489 mmi->ptMinTrackSize.x = 100;
\r
10490 mmi->ptMinTrackSize.y = 100;
\r
10497 AnalysisPopUp(char* title, char* str)
\r
10503 EngineOutputPopUp();
\r
10506 if (str == NULL) str = "";
\r
10507 p = (char *) malloc(2 * strlen(str) + 2);
\r
10510 if (*str == '\n') *q++ = '\r';
\r
10514 if (analysisText != NULL) free(analysisText);
\r
10515 analysisText = p;
\r
10517 if (analysisDialog) {
\r
10518 SetWindowText(analysisDialog, title);
\r
10519 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10520 ShowWindow(analysisDialog, SW_SHOW);
\r
10522 analysisTitle = title;
\r
10523 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10524 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10525 hwndMain, (DLGPROC)lpProc);
\r
10526 FreeProcInstance(lpProc);
\r
10528 analysisDialogUp = TRUE;
\r
10532 AnalysisPopDown()
\r
10534 if (analysisDialog) {
\r
10535 ShowWindow(analysisDialog, SW_HIDE);
\r
10537 analysisDialogUp = FALSE;
\r
10542 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10544 highlightInfo.sq[0].x = fromX;
\r
10545 highlightInfo.sq[0].y = fromY;
\r
10546 highlightInfo.sq[1].x = toX;
\r
10547 highlightInfo.sq[1].y = toY;
\r
10551 ClearHighlights()
\r
10553 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10554 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10558 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10560 premoveHighlightInfo.sq[0].x = fromX;
\r
10561 premoveHighlightInfo.sq[0].y = fromY;
\r
10562 premoveHighlightInfo.sq[1].x = toX;
\r
10563 premoveHighlightInfo.sq[1].y = toY;
\r
10567 ClearPremoveHighlights()
\r
10569 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10570 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10574 ShutDownFrontEnd()
\r
10576 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10577 DeleteClipboardTempFiles();
\r
10583 if (IsIconic(hwndMain))
\r
10584 ShowWindow(hwndMain, SW_RESTORE);
\r
10586 SetActiveWindow(hwndMain);
\r
10590 * Prototypes for animation support routines
\r
10592 static void ScreenSquare(int column, int row, POINT * pt);
\r
10593 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10594 POINT frames[], int * nFrames);
\r
10598 AnimateAtomicCapture(int toX, int toY, int nFrames)
\r
10599 { // [HGM] atomic: animate blast wave
\r
10601 if(appData.debugMode) fprintf(debugFP, "exploding (%d,%d)\n", toX, toY);
\r
10602 explodeInfo.x = toX;
\r
10603 explodeInfo.y = toY;
\r
10604 for(i=0; i<nFrames; i++) {
\r
10605 explodeInfo.radius = (i*180)/(nFrames-1);
\r
10606 DrawPosition(FALSE, NULL);
\r
10607 Sleep(appData.animSpeed);
\r
10609 explodeInfo.radius = 0;
\r
10610 DrawPosition(TRUE, NULL);
\r
10613 #define kFactor 4
\r
10616 AnimateMove(board, fromX, fromY, toX, toY)
\r
10623 ChessSquare piece;
\r
10624 POINT start, finish, mid;
\r
10625 POINT frames[kFactor * 2 + 1];
\r
10628 if (!appData.animate) return;
\r
10629 if (doingSizing) return;
\r
10630 if (fromY < 0 || fromX < 0) return;
\r
10631 piece = board[fromY][fromX];
\r
10632 if (piece >= EmptySquare) return;
\r
10634 ScreenSquare(fromX, fromY, &start);
\r
10635 ScreenSquare(toX, toY, &finish);
\r
10637 /* All pieces except knights move in straight line */
\r
10638 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10639 mid.x = start.x + (finish.x - start.x) / 2;
\r
10640 mid.y = start.y + (finish.y - start.y) / 2;
\r
10642 /* Knight: make diagonal movement then straight */
\r
10643 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10644 mid.x = start.x + (finish.x - start.x) / 2;
\r
10645 mid.y = finish.y;
\r
10647 mid.x = finish.x;
\r
10648 mid.y = start.y + (finish.y - start.y) / 2;
\r
10652 /* Don't use as many frames for very short moves */
\r
10653 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10654 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10656 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10658 animInfo.from.x = fromX;
\r
10659 animInfo.from.y = fromY;
\r
10660 animInfo.to.x = toX;
\r
10661 animInfo.to.y = toY;
\r
10662 animInfo.lastpos = start;
\r
10663 animInfo.piece = piece;
\r
10664 for (n = 0; n < nFrames; n++) {
\r
10665 animInfo.pos = frames[n];
\r
10666 DrawPosition(FALSE, NULL);
\r
10667 animInfo.lastpos = animInfo.pos;
\r
10668 Sleep(appData.animSpeed);
\r
10670 animInfo.pos = finish;
\r
10671 DrawPosition(FALSE, NULL);
\r
10672 animInfo.piece = EmptySquare;
\r
10673 if(gameInfo.variant == VariantAtomic && board[toY][toX] != EmptySquare)
\r
10674 AnimateAtomicCapture(toX, toY, 2*nFrames);
\r
10677 /* Convert board position to corner of screen rect and color */
\r
10680 ScreenSquare(column, row, pt)
\r
10681 int column; int row; POINT * pt;
\r
10684 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10685 pt->y = lineGap + row * (squareSize + lineGap);
\r
10687 pt->x = lineGap + column * (squareSize + lineGap);
\r
10688 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10692 /* Generate a series of frame coords from start->mid->finish.
\r
10693 The movement rate doubles until the half way point is
\r
10694 reached, then halves back down to the final destination,
\r
10695 which gives a nice slow in/out effect. The algorithmn
\r
10696 may seem to generate too many intermediates for short
\r
10697 moves, but remember that the purpose is to attract the
\r
10698 viewers attention to the piece about to be moved and
\r
10699 then to where it ends up. Too few frames would be less
\r
10703 Tween(start, mid, finish, factor, frames, nFrames)
\r
10704 POINT * start; POINT * mid;
\r
10705 POINT * finish; int factor;
\r
10706 POINT frames[]; int * nFrames;
\r
10708 int n, fraction = 1, count = 0;
\r
10710 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10711 for (n = 0; n < factor; n++)
\r
10713 for (n = 0; n < factor; n++) {
\r
10714 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10715 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10717 fraction = fraction / 2;
\r
10721 frames[count] = *mid;
\r
10724 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10726 for (n = 0; n < factor; n++) {
\r
10727 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10728 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10730 fraction = fraction * 2;
\r
10732 *nFrames = count;
\r
10736 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10741 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10742 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10744 OutputDebugString( buf );
\r
10747 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10749 EvalGraphSet( first, last, current, pvInfoList );
\r
10752 void SetProgramStats( FrontEndProgramStats * stats )
\r
10757 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10758 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10760 OutputDebugString( buf );
\r
10763 EngineOutputUpdate( stats );
\r