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, Massachusetts.
\r
6 * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.
\r
8 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
9 * which was written and is copyrighted by Wayne Christopher.
\r
11 * The following terms apply to Digital Equipment Corporation's copyright
\r
12 * interest in XBoard:
\r
13 * ------------------------------------------------------------------------
\r
14 * All Rights Reserved
\r
16 * Permission to use, copy, modify, and distribute this software and its
\r
17 * documentation for any purpose and without fee is hereby granted,
\r
18 * provided that the above copyright notice appear in all copies and that
\r
19 * both that copyright notice and this permission notice appear in
\r
20 * supporting documentation, and that the name of Digital not be
\r
21 * used in advertising or publicity pertaining to distribution of the
\r
22 * software without specific, written prior permission.
\r
24 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
25 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
26 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
27 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
28 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
29 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
31 * ------------------------------------------------------------------------
\r
33 * The following terms apply to the enhanced version of XBoard distributed
\r
34 * by the Free Software Foundation:
\r
35 * ------------------------------------------------------------------------
\r
36 * This program is free software; you can redistribute it and/or modify
\r
37 * it under the terms of the GNU General Public License as published by
\r
38 * the Free Software Foundation; either version 2 of the License, or
\r
39 * (at your option) any later version.
\r
41 * This program is distributed in the hope that it will be useful,
\r
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
44 * GNU General Public License for more details.
\r
46 * You should have received a copy of the GNU General Public License
\r
47 * along with this program; if not, write to the Free Software
\r
48 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
\r
49 * ------------------------------------------------------------------------
\r
54 #include <windows.h>
\r
55 #include <winuser.h>
\r
56 #include <winsock.h>
\r
62 #include <sys/stat.h>
\r
65 #include <commdlg.h>
\r
67 #include <richedit.h>
\r
68 #include <mmsystem.h>
\r
76 #include "winboard.h"
\r
77 #include "frontend.h"
\r
78 #include "backend.h"
\r
80 #include "wclipbrd.h"
\r
81 #include "wgamelist.h"
\r
82 #include "wedittags.h"
\r
83 #include "woptions.h"
\r
84 #include "wsockerr.h"
\r
85 #include "defaults.h"
\r
89 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
92 void mysrandom(unsigned int seed);
\r
94 extern int whiteFlag, blackFlag;
\r
95 Boolean flipClock = FALSE;
\r
97 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
100 ChessSquare piece;
\r
101 POINT pos; /* window coordinates of current pos */
\r
102 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
103 POINT from; /* board coordinates of the piece's orig pos */
\r
104 POINT to; /* board coordinates of the piece's new pos */
\r
107 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
110 POINT start; /* window coordinates of start pos */
\r
111 POINT pos; /* window coordinates of current pos */
\r
112 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
113 POINT from; /* board coordinates of the piece's orig pos */
\r
116 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
119 POINT sq[2]; /* board coordinates of from, to squares */
\r
122 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
123 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
125 /* Window class names */
\r
126 char szAppName[] = "WinBoard";
\r
127 char szConsoleName[] = "WBConsole";
\r
129 /* Title bar text */
\r
130 char szTitle[] = "WinBoard";
\r
131 char szConsoleTitle[] = "ICS Interaction";
\r
134 char *settingsFileName;
\r
135 BOOLEAN saveSettingsOnExit;
\r
136 char installDir[MSG_SIZ];
\r
138 BoardSize boardSize;
\r
139 BOOLEAN chessProgram;
\r
140 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
141 static int squareSize, lineGap, minorSize;
\r
142 static int winWidth, winHeight;
\r
143 static RECT messageRect, whiteRect, blackRect, leftLogoRect, rightLogoRect; // [HGM] logo
\r
144 static int logoHeight = 0;
\r
145 static char messageText[MESSAGE_TEXT_MAX];
\r
146 static int clockTimerEvent = 0;
\r
147 static int loadGameTimerEvent = 0;
\r
148 static int analysisTimerEvent = 0;
\r
149 static DelayedEventCallback delayedTimerCallback;
\r
150 static int delayedTimerEvent = 0;
\r
151 static int buttonCount = 2;
\r
152 char *icsTextMenuString;
\r
154 char *firstChessProgramNames;
\r
155 char *secondChessProgramNames;
\r
157 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
159 #define PALETTESIZE 256
\r
161 HINSTANCE hInst; /* current instance */
\r
162 HWND hwndMain = NULL; /* root window*/
\r
163 HWND hwndConsole = NULL;
\r
164 BOOLEAN alwaysOnTop = FALSE;
\r
166 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
167 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
169 ColorClass currentColorClass;
\r
171 HWND hCommPort = NULL; /* currently open comm port */
\r
172 static HWND hwndPause; /* pause button */
\r
173 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
174 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
175 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
176 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
177 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
178 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
179 static HPEN gridPen = NULL;
\r
180 static HPEN highlightPen = NULL;
\r
181 static HPEN premovePen = NULL;
\r
182 static NPLOGPALETTE pLogPal;
\r
183 static BOOL paletteChanged = FALSE;
\r
184 static HICON iconWhite, iconBlack, iconCurrent;
\r
185 static int doingSizing = FALSE;
\r
186 static int lastSizing = 0;
\r
187 static int prevStderrPort;
\r
189 /* [AS] Support for background textures */
\r
190 #define BACK_TEXTURE_MODE_DISABLED 0
\r
191 #define BACK_TEXTURE_MODE_PLAIN 1
\r
192 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
194 static HBITMAP liteBackTexture = NULL;
\r
195 static HBITMAP darkBackTexture = NULL;
\r
196 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
197 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
198 static int backTextureSquareSize = 0;
\r
199 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
201 #if __GNUC__ && !defined(_winmajor)
\r
202 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
204 #define oldDialog (_winmajor < 4)
\r
207 char *defaultTextAttribs[] =
\r
209 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
210 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
220 int cliWidth, cliHeight;
\r
223 SizeInfo sizeInfo[] =
\r
225 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
226 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
227 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
228 { "petite", 33, 1, 1, 1, 0, 0 },
\r
229 { "slim", 37, 2, 1, 0, 0, 0 },
\r
230 { "small", 40, 2, 1, 0, 0, 0 },
\r
231 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
232 { "middling", 49, 2, 0, 0, 0, 0 },
\r
233 { "average", 54, 2, 0, 0, 0, 0 },
\r
234 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
235 { "medium", 64, 3, 0, 0, 0, 0 },
\r
236 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
237 { "large", 80, 3, 0, 0, 0, 0 },
\r
238 { "big", 87, 3, 0, 0, 0, 0 },
\r
239 { "huge", 95, 3, 0, 0, 0, 0 },
\r
240 { "giant", 108, 3, 0, 0, 0, 0 },
\r
241 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
242 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
243 { NULL, 0, 0, 0, 0, 0, 0 }
\r
246 #define MF(x) {x, {0, }, {0, }, 0}
\r
247 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
249 { 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
250 { 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
251 { 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
252 { 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
253 { 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
254 { 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
255 { 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
256 { 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
257 { 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
258 { 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
259 { 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
260 { 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
261 { 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
262 { 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
263 { 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
264 { 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
265 { 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
266 { 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
269 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
278 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
279 #define N_BUTTONS 5
\r
281 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
283 {"<<", IDM_ToStart, NULL, NULL},
\r
284 {"<", IDM_Backward, NULL, NULL},
\r
285 {"P", IDM_Pause, NULL, NULL},
\r
286 {">", IDM_Forward, NULL, NULL},
\r
287 {">>", IDM_ToEnd, NULL, NULL},
\r
290 int tinyLayout = 0, smallLayout = 0;
\r
291 #define MENU_BAR_ITEMS 6
\r
292 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
293 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
294 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
298 MySound sounds[(int)NSoundClasses];
\r
299 MyTextAttribs textAttribs[(int)NColorClasses];
\r
301 MyColorizeAttribs colorizeAttribs[] = {
\r
302 { (COLORREF)0, 0, "Shout Text" },
\r
303 { (COLORREF)0, 0, "SShout/CShout" },
\r
304 { (COLORREF)0, 0, "Channel 1 Text" },
\r
305 { (COLORREF)0, 0, "Channel Text" },
\r
306 { (COLORREF)0, 0, "Kibitz Text" },
\r
307 { (COLORREF)0, 0, "Tell Text" },
\r
308 { (COLORREF)0, 0, "Challenge Text" },
\r
309 { (COLORREF)0, 0, "Request Text" },
\r
310 { (COLORREF)0, 0, "Seek Text" },
\r
311 { (COLORREF)0, 0, "Normal Text" },
\r
312 { (COLORREF)0, 0, "None" }
\r
317 static char *commentTitle;
\r
318 static char *commentText;
\r
319 static int commentIndex;
\r
320 static Boolean editComment = FALSE;
\r
321 HWND commentDialog = NULL;
\r
322 BOOLEAN commentDialogUp = FALSE;
\r
323 static int commentX, commentY, commentH, commentW;
\r
325 static char *analysisTitle;
\r
326 static char *analysisText;
\r
327 HWND analysisDialog = NULL;
\r
328 BOOLEAN analysisDialogUp = FALSE;
\r
329 static int analysisX, analysisY, analysisH, analysisW;
\r
331 char errorTitle[MSG_SIZ];
\r
332 char errorMessage[2*MSG_SIZ];
\r
333 HWND errorDialog = NULL;
\r
334 BOOLEAN moveErrorMessageUp = FALSE;
\r
335 BOOLEAN consoleEcho = TRUE;
\r
336 CHARFORMAT consoleCF;
\r
337 COLORREF consoleBackgroundColor;
\r
339 char *programVersion;
\r
345 typedef int CPKind;
\r
354 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
357 #define INPUT_SOURCE_BUF_SIZE 4096
\r
359 typedef struct _InputSource {
\r
366 char buf[INPUT_SOURCE_BUF_SIZE];
\r
370 InputCallback func;
\r
371 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
375 InputSource *consoleInputSource;
\r
380 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
381 VOID ConsoleCreate();
\r
383 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
384 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
385 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
386 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
388 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
389 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
390 void ParseIcsTextMenu(char *icsTextMenuString);
\r
391 VOID PopUpMoveDialog(char firstchar);
\r
392 VOID PopUpNameDialog(char firstchar);
\r
393 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
397 int GameListOptions();
\r
399 HWND moveHistoryDialog = NULL;
\r
400 BOOLEAN moveHistoryDialogUp = FALSE;
\r
402 WindowPlacement wpMoveHistory;
\r
404 HWND evalGraphDialog = NULL;
\r
405 BOOLEAN evalGraphDialogUp = FALSE;
\r
407 WindowPlacement wpEvalGraph;
\r
409 HWND engineOutputDialog = NULL;
\r
410 BOOLEAN engineOutputDialogUp = FALSE;
\r
412 WindowPlacement wpEngineOutput;
\r
414 VOID MoveHistoryPopUp();
\r
415 VOID MoveHistoryPopDown();
\r
416 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
417 BOOL MoveHistoryIsUp();
\r
419 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
420 VOID EvalGraphPopUp();
\r
421 VOID EvalGraphPopDown();
\r
422 BOOL EvalGraphIsUp();
\r
424 VOID EngineOutputPopUp();
\r
425 VOID EngineOutputPopDown();
\r
426 BOOL EngineOutputIsUp();
\r
427 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
429 VOID GothicPopUp(char *title, VariantClass variant);
\r
431 * Setting "frozen" should disable all user input other than deleting
\r
432 * the window. We do this while engines are initializing themselves.
\r
434 static int frozen = 0;
\r
435 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
441 if (frozen) return;
\r
443 hmenu = GetMenu(hwndMain);
\r
444 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
445 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
447 DrawMenuBar(hwndMain);
\r
450 /* Undo a FreezeUI */
\r
456 if (!frozen) return;
\r
458 hmenu = GetMenu(hwndMain);
\r
459 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
460 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
462 DrawMenuBar(hwndMain);
\r
465 /*---------------------------------------------------------------------------*\
\r
469 \*---------------------------------------------------------------------------*/
\r
472 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
473 LPSTR lpCmdLine, int nCmdShow)
\r
476 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
480 LoadLibrary("RICHED32.DLL");
\r
481 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
483 if (!InitApplication(hInstance)) {
\r
486 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
490 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
491 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
492 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
494 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
496 while (GetMessage(&msg, /* message structure */
\r
497 NULL, /* handle of window receiving the message */
\r
498 0, /* lowest message to examine */
\r
499 0)) /* highest message to examine */
\r
501 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
502 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
503 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
504 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
505 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
506 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
507 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
508 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
509 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
510 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
511 TranslateMessage(&msg); /* Translates virtual key codes */
\r
512 DispatchMessage(&msg); /* Dispatches message to window */
\r
517 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
520 /*---------------------------------------------------------------------------*\
\r
522 * Initialization functions
\r
524 \*---------------------------------------------------------------------------*/
\r
527 InitApplication(HINSTANCE hInstance)
\r
531 /* Fill in window class structure with parameters that describe the */
\r
534 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
535 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
536 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
537 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
538 wc.hInstance = hInstance; /* Owner of this class */
\r
539 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
540 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
541 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
542 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
543 wc.lpszClassName = szAppName; /* Name to register as */
\r
545 /* Register the window class and return success/failure code. */
\r
546 if (!RegisterClass(&wc)) return FALSE;
\r
548 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
549 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
551 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
552 wc.hInstance = hInstance;
\r
553 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
554 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
555 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
556 wc.lpszMenuName = NULL;
\r
557 wc.lpszClassName = szConsoleName;
\r
559 if (!RegisterClass(&wc)) return FALSE;
\r
564 /* Set by InitInstance, used by EnsureOnScreen */
\r
565 int screenHeight, screenWidth;
\r
568 EnsureOnScreen(int *x, int *y)
\r
570 int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
571 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
572 if (*x > screenWidth - 32) *x = 0;
\r
573 if (*y > screenHeight - 32) *y = 0;
\r
574 if (*x < 10) *x = 10;
\r
575 if (*y < gap) *y = gap;
\r
579 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
581 HWND hwnd; /* Main window handle. */
\r
583 WINDOWPLACEMENT wp;
\r
586 hInst = hInstance; /* Store instance handle in our global variable */
\r
588 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
589 *filepart = NULLCHAR;
\r
591 GetCurrentDirectory(MSG_SIZ, installDir);
\r
593 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
594 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
595 if (appData.debugMode) {
\r
596 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
597 setbuf(debugFP, NULL);
\r
602 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
603 // InitEngineUCI( installDir, &second );
\r
605 /* Create a main window for this application instance. */
\r
606 hwnd = CreateWindow(szAppName, szTitle,
\r
607 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
608 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
609 NULL, NULL, hInstance, NULL);
\r
612 /* If window could not be created, return "failure" */
\r
617 /* [HGM] logo: Load logos if specified (must be done before InitDrawingSizes) */
\r
618 if( appData.firstLogo && appData.firstLogo[0] != NULLCHAR) {
\r
619 first.programLogo = LoadImage( 0, appData.firstLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
621 if (first.programLogo == NULL && appData.debugMode) {
\r
622 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.firstLogo );
\r
624 } else if(appData.autoLogo) {
\r
625 if(appData.firstDirectory && appData.firstDirectory[0]) {
\r
627 sprintf(buf, "%s/logo.bmp", appData.firstDirectory);
\r
628 first.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
632 if( appData.secondLogo && appData.secondLogo[0] != NULLCHAR) {
\r
633 second.programLogo = LoadImage( 0, appData.secondLogo, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
635 if (second.programLogo == NULL && appData.debugMode) {
\r
636 fprintf( debugFP, "Unable to load logo bitmap '%s'\n", appData.secondLogo );
\r
638 } else if(appData.autoLogo) {
\r
639 if(appData.secondDirectory && appData.secondDirectory[0]) {
\r
641 sprintf(buf, "%s\\logo.bmp", appData.secondDirectory);
\r
642 second.programLogo = LoadImage( 0, buf, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
646 iconWhite = LoadIcon(hInstance, "icon_white");
\r
647 iconBlack = LoadIcon(hInstance, "icon_black");
\r
648 iconCurrent = iconWhite;
\r
649 InitDrawingColors();
\r
650 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
651 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
652 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
653 /* Compute window size for each board size, and use the largest
\r
654 size that fits on this screen as the default. */
\r
655 InitDrawingSizes((BoardSize)ibs, 0);
\r
656 if (boardSize == (BoardSize)-1 &&
\r
657 winHeight <= screenHeight
\r
658 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
659 && winWidth <= screenWidth) {
\r
660 boardSize = (BoardSize)ibs;
\r
664 InitDrawingSizes(boardSize, 0);
\r
666 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
668 /* [AS] Load textures if specified */
\r
669 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
671 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
672 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
673 liteBackTextureMode = appData.liteBackTextureMode;
\r
675 if (liteBackTexture == NULL && appData.debugMode) {
\r
676 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
680 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
681 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
682 darkBackTextureMode = appData.darkBackTextureMode;
\r
684 if (darkBackTexture == NULL && appData.debugMode) {
\r
685 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
689 mysrandom( (unsigned) time(NULL) );
\r
691 /* [AS] Restore layout */
\r
692 if( wpMoveHistory.visible ) {
\r
693 MoveHistoryPopUp();
\r
696 if( wpEvalGraph.visible ) {
\r
700 if( wpEngineOutput.visible ) {
\r
701 EngineOutputPopUp();
\r
706 /* Make the window visible; update its client area; and return "success" */
\r
707 EnsureOnScreen(&boardX, &boardY);
\r
708 wp.length = sizeof(WINDOWPLACEMENT);
\r
710 wp.showCmd = nCmdShow;
\r
711 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
712 wp.rcNormalPosition.left = boardX;
\r
713 wp.rcNormalPosition.right = boardX + winWidth;
\r
714 wp.rcNormalPosition.top = boardY;
\r
715 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
716 SetWindowPlacement(hwndMain, &wp);
\r
718 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
719 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
722 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
723 if( gameInfo.variant != VariantFischeRandom ) {
\r
724 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
729 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
730 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
732 ShowWindow(hwndConsole, nCmdShow);
\r
734 UpdateWindow(hwnd);
\r
742 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
743 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
744 ArgSettingsFilename
\r
752 String *pString; // ArgString
\r
753 int *pInt; // ArgInt
\r
754 float *pFloat; // ArgFloat
\r
755 Boolean *pBoolean; // ArgBoolean
\r
756 COLORREF *pColor; // ArgColor
\r
757 ColorClass cc; // ArgAttribs
\r
758 String *pFilename; // ArgFilename
\r
759 BoardSize *pBoardSize; // ArgBoardSize
\r
760 int whichFont; // ArgFont
\r
761 DCB *pDCB; // ArgCommSettings
\r
762 String *pFilename; // ArgSettingsFilename
\r
770 ArgDescriptor argDescriptors[] = {
\r
771 /* positional arguments */
\r
772 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
773 { "", ArgNone, NULL },
\r
774 /* keyword arguments */
\r
775 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
776 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
777 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
778 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
779 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
780 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
781 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
782 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
783 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
784 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
785 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
786 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
787 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
788 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
789 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
790 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
791 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
792 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
794 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
796 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
798 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
799 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
801 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
802 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
803 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
804 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
805 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
806 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
807 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
808 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
809 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
810 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
811 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
812 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
813 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
814 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
815 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
816 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
817 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
818 /*!!bitmapDirectory?*/
\r
819 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
820 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
821 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
822 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
823 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
824 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
825 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
826 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
827 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
828 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
829 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
830 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
831 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
832 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
833 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
834 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
835 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
836 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
837 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
838 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
839 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
840 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
841 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
842 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
843 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
844 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
845 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
846 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
847 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
848 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
849 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
850 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
851 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
852 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
853 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
854 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
855 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
856 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
857 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
858 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
859 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
860 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
861 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
862 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
863 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
864 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
865 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
866 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
867 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
868 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
869 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
870 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
871 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
872 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
873 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
874 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
875 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
876 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
877 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
878 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
879 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
880 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
881 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
882 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
883 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
884 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
885 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
886 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
887 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
888 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
889 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
890 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
891 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
892 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
893 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
894 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
895 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
896 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
897 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
898 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
899 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
900 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
901 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
902 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
903 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
904 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
905 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
906 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
907 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
908 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
909 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
910 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
911 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
912 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
913 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
914 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
915 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
916 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
917 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
918 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
919 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
920 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
921 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
922 TRUE }, /* must come after all fonts */
\r
923 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
924 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
925 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
926 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
927 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
928 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
929 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
930 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
931 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
932 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
933 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
934 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
935 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
936 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
937 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
938 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
939 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
940 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
941 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
942 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
943 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
944 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
945 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
946 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
947 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
948 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
949 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
950 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
951 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
952 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
953 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
955 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
956 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
958 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
959 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
960 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
961 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
962 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
963 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
964 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
965 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
966 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
967 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
968 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
969 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
970 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
971 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
972 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
973 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
974 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
975 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
976 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
977 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
978 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
979 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
980 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
981 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
982 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
983 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
984 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
985 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
986 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
987 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
988 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
989 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
990 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
991 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
992 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
993 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
994 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
995 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
996 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
997 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
998 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
999 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
1000 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1001 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
1002 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
1003 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
1004 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1005 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
1006 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
1007 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
1008 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
1009 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1010 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
1011 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
1012 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
1013 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1014 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
1015 { "highlightLastMove", ArgBoolean,
\r
1016 (LPVOID) &appData.highlightLastMove, TRUE },
\r
1017 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1018 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1019 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
1020 { "highlightDragging", ArgBoolean,
\r
1021 (LPVOID) &appData.highlightDragging, TRUE },
\r
1022 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
1023 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1024 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
1025 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1026 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1027 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1028 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1029 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1030 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1031 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1032 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1033 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1034 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1035 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1036 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1037 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1038 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1039 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1040 { "soundShout", ArgFilename,
\r
1041 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1042 { "soundSShout", ArgFilename,
\r
1043 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1044 { "soundChannel1", ArgFilename,
\r
1045 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1046 { "soundChannel", ArgFilename,
\r
1047 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1048 { "soundKibitz", ArgFilename,
\r
1049 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1050 { "soundTell", ArgFilename,
\r
1051 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1052 { "soundChallenge", ArgFilename,
\r
1053 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1054 { "soundRequest", ArgFilename,
\r
1055 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1056 { "soundSeek", ArgFilename,
\r
1057 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1058 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1059 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1060 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1061 { "soundIcsLoss", ArgFilename,
\r
1062 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1063 { "soundIcsDraw", ArgFilename,
\r
1064 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1065 { "soundIcsUnfinished", ArgFilename,
\r
1066 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1067 { "soundIcsAlarm", ArgFilename,
\r
1068 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1069 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1070 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1071 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1072 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1073 { "reuseChessPrograms", ArgBoolean,
\r
1074 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1075 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1076 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1077 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1078 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1079 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1080 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1081 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1082 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1083 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1084 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1085 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1086 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1087 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1088 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1089 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1090 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1091 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1092 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1093 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1094 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1095 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1096 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1097 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1098 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1099 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1100 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1101 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1102 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1103 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1104 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1105 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1106 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1107 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1108 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1109 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1110 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1111 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1113 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1115 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1116 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1117 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1118 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1119 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1120 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1121 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1122 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1123 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1124 /* [AS] New features */
\r
1125 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1126 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1127 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1128 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1129 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1130 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1131 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1132 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1133 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1134 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1135 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1136 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1137 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1138 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1139 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1140 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1141 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1142 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1143 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1144 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1145 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1146 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1147 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1148 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1149 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1150 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1151 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1152 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1153 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1154 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1155 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1156 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1157 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1158 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1159 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1160 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1161 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1162 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1163 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1164 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1165 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1166 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1167 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1168 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1169 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1170 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1171 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1172 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1174 /* [AS] Layout stuff */
\r
1175 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1176 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1177 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1178 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1179 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1181 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1182 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1183 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1184 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1185 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1187 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1188 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1189 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1190 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1191 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1193 /* [HGM] board-size, adjudication and misc. options */
\r
1194 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1195 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1196 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1197 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1198 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1199 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1200 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1201 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1202 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1203 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1204 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1205 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1206 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1207 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1208 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1209 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1210 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1211 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1212 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1213 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1214 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1215 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1216 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1217 { "niceEngines", ArgInt, (LPVOID) &appData.niceEngines, TRUE },
\r
1218 { "firstLogo", ArgFilename, (LPVOID) &appData.firstLogo, FALSE },
\r
1219 { "secondLogo", ArgFilename, (LPVOID) &appData.secondLogo, FALSE },
\r
1220 { "autoLogo", ArgBoolean, (LPVOID) &appData.autoLogo, TRUE },
\r
1223 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1224 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1225 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1226 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1227 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1228 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1229 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1230 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1231 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1232 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1233 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1234 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1235 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1237 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1238 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1239 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1240 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1241 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1242 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1243 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1245 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1246 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1247 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1248 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1249 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1250 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1251 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1252 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1253 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1254 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1255 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1256 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1257 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1258 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1259 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1260 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1261 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1262 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1264 /* [HGM] options for broadcasting and time odds */
\r
1265 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1266 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1267 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1268 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1269 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1270 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1271 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1272 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1273 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1274 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1275 { "noGUI", ArgTrue, (LPVOID) &appData.noGUI, FALSE },
\r
1276 { NULL, ArgNone, NULL, FALSE }
\r
1280 /* Kludge for indirection files on command line */
\r
1281 char* lastIndirectionFilename;
\r
1282 ArgDescriptor argDescriptorIndirection =
\r
1283 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1287 ExitArgError(char *msg, char *badArg)
\r
1289 char buf[MSG_SIZ];
\r
1291 sprintf(buf, "%s %s", msg, badArg);
\r
1292 DisplayFatalError(buf, 0, 2);
\r
1296 /* Command line font name parser. NULL name means do nothing.
\r
1297 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1298 For backward compatibility, syntax without the colon is also
\r
1299 accepted, but font names with digits in them won't work in that case.
\r
1302 ParseFontName(char *name, MyFontParams *mfp)
\r
1305 if (name == NULL) return;
\r
1307 q = strchr(p, ':');
\r
1309 if (q - p >= sizeof(mfp->faceName))
\r
1310 ExitArgError("Font name too long:", name);
\r
1311 memcpy(mfp->faceName, p, q - p);
\r
1312 mfp->faceName[q - p] = NULLCHAR;
\r
1315 q = mfp->faceName;
\r
1316 while (*p && !isdigit(*p)) {
\r
1318 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1319 ExitArgError("Font name too long:", name);
\r
1321 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1324 if (!*p) ExitArgError("Font point size missing:", name);
\r
1325 mfp->pointSize = (float) atof(p);
\r
1326 mfp->bold = (strchr(p, 'b') != NULL);
\r
1327 mfp->italic = (strchr(p, 'i') != NULL);
\r
1328 mfp->underline = (strchr(p, 'u') != NULL);
\r
1329 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1332 /* Color name parser.
\r
1333 X version accepts X color names, but this one
\r
1334 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1336 ParseColorName(char *name)
\r
1338 int red, green, blue, count;
\r
1339 char buf[MSG_SIZ];
\r
1341 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1343 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1344 &red, &green, &blue);
\r
1347 sprintf(buf, "Can't parse color name %s", name);
\r
1348 DisplayError(buf, 0);
\r
1349 return RGB(0, 0, 0);
\r
1351 return PALETTERGB(red, green, blue);
\r
1355 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1357 char *e = argValue;
\r
1361 if (*e == 'b') eff |= CFE_BOLD;
\r
1362 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1363 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1364 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1365 else if (*e == '#' || isdigit(*e)) break;
\r
1369 *color = ParseColorName(e);
\r
1374 ParseBoardSize(char *name)
\r
1376 BoardSize bs = SizeTiny;
\r
1377 while (sizeInfo[bs].name != NULL) {
\r
1378 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1381 ExitArgError("Unrecognized board size value", name);
\r
1382 return bs; /* not reached */
\r
1387 StringGet(void *getClosure)
\r
1389 char **p = (char **) getClosure;
\r
1394 FileGet(void *getClosure)
\r
1397 FILE* f = (FILE*) getClosure;
\r
1406 /* Parse settings file named "name". If file found, return the
\r
1407 full name in fullname and return TRUE; else return FALSE */
\r
1409 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1414 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1415 f = fopen(fullname, "r");
\r
1417 ParseArgs(FileGet, f);
\r
1426 ParseArgs(GetFunc get, void *cl)
\r
1428 char argName[ARG_MAX];
\r
1429 char argValue[ARG_MAX];
\r
1430 ArgDescriptor *ad;
\r
1439 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1440 if (ch == NULLCHAR) break;
\r
1442 /* Comment to end of line */
\r
1444 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1446 } else if (ch == '/' || ch == '-') {
\r
1449 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1450 ch != '\n' && ch != '\t') {
\r
1456 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1457 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1459 if (ad->argName == NULL)
\r
1460 ExitArgError("Unrecognized argument", argName);
\r
1462 } else if (ch == '@') {
\r
1463 /* Indirection file */
\r
1464 ad = &argDescriptorIndirection;
\r
1467 /* Positional argument */
\r
1468 ad = &argDescriptors[posarg++];
\r
1469 strcpy(argName, ad->argName);
\r
1472 if (ad->argType == ArgTrue) {
\r
1473 *(Boolean *) ad->argLoc = TRUE;
\r
1476 if (ad->argType == ArgFalse) {
\r
1477 *(Boolean *) ad->argLoc = FALSE;
\r
1481 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1482 if (ch == NULLCHAR || ch == '\n') {
\r
1483 ExitArgError("No value provided for argument", argName);
\r
1487 // Quoting with { }. No characters have to (or can) be escaped.
\r
1488 // Thus the string cannot contain a '}' character.
\r
1508 } else if (ch == '\'' || ch == '"') {
\r
1509 // Quoting with ' ' or " ", with \ as escape character.
\r
1510 // Inconvenient for long strings that may contain Windows filenames.
\r
1527 if (ch == start) {
\r
1536 if (ad->argType == ArgFilename
\r
1537 || ad->argType == ArgSettingsFilename) {
\r
1543 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1567 for (i = 0; i < 3; i++) {
\r
1568 if (ch >= '0' && ch <= '7') {
\r
1569 octval = octval*8 + (ch - '0');
\r
1576 *q++ = (char) octval;
\r
1587 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1594 switch (ad->argType) {
\r
1596 *(int *) ad->argLoc = atoi(argValue);
\r
1600 *(float *) ad->argLoc = (float) atof(argValue);
\r
1605 *(char **) ad->argLoc = strdup(argValue);
\r
1608 case ArgSettingsFilename:
\r
1610 char fullname[MSG_SIZ];
\r
1611 if (ParseSettingsFile(argValue, fullname)) {
\r
1612 if (ad->argLoc != NULL) {
\r
1613 *(char **) ad->argLoc = strdup(fullname);
\r
1616 if (ad->argLoc != NULL) {
\r
1618 ExitArgError("Failed to open indirection file", argValue);
\r
1625 switch (argValue[0]) {
\r
1628 *(Boolean *) ad->argLoc = TRUE;
\r
1632 *(Boolean *) ad->argLoc = FALSE;
\r
1635 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1641 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1644 case ArgAttribs: {
\r
1645 ColorClass cc = (ColorClass)ad->argLoc;
\r
1646 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1650 case ArgBoardSize:
\r
1651 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1655 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1658 case ArgCommSettings:
\r
1659 ParseCommSettings(argValue, &dcb);
\r
1663 ExitArgError("Unrecognized argument", argValue);
\r
1670 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1672 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1673 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1676 lf->lfEscapement = 0;
\r
1677 lf->lfOrientation = 0;
\r
1678 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1679 lf->lfItalic = mfp->italic;
\r
1680 lf->lfUnderline = mfp->underline;
\r
1681 lf->lfStrikeOut = mfp->strikeout;
\r
1682 lf->lfCharSet = DEFAULT_CHARSET;
\r
1683 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1684 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1685 lf->lfQuality = DEFAULT_QUALITY;
\r
1686 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1687 strcpy(lf->lfFaceName, mfp->faceName);
\r
1691 CreateFontInMF(MyFont *mf)
\r
1693 LFfromMFP(&mf->lf, &mf->mfp);
\r
1694 if (mf->hf) DeleteObject(mf->hf);
\r
1695 mf->hf = CreateFontIndirect(&mf->lf);
\r
1699 SetDefaultTextAttribs()
\r
1702 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1703 ParseAttribs(&textAttribs[cc].color,
\r
1704 &textAttribs[cc].effects,
\r
1705 defaultTextAttribs[cc]);
\r
1710 SetDefaultSounds()
\r
1714 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1715 textAttribs[cc].sound.name = strdup("");
\r
1716 textAttribs[cc].sound.data = NULL;
\r
1718 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1719 sounds[sc].name = strdup("");
\r
1720 sounds[sc].data = NULL;
\r
1722 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1730 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1731 MyLoadSound(&textAttribs[cc].sound);
\r
1733 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1734 MyLoadSound(&sounds[sc]);
\r
1739 InitAppData(LPSTR lpCmdLine)
\r
1742 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1745 programName = szAppName;
\r
1747 /* Initialize to defaults */
\r
1748 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1749 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1750 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1751 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1752 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1753 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1754 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1755 SetDefaultTextAttribs();
\r
1756 SetDefaultSounds();
\r
1757 appData.movesPerSession = MOVES_PER_SESSION;
\r
1758 appData.initString = INIT_STRING;
\r
1759 appData.secondInitString = INIT_STRING;
\r
1760 appData.firstComputerString = COMPUTER_STRING;
\r
1761 appData.secondComputerString = COMPUTER_STRING;
\r
1762 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1763 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1764 appData.firstPlaysBlack = FALSE;
\r
1765 appData.noChessProgram = FALSE;
\r
1766 chessProgram = FALSE;
\r
1767 appData.firstHost = FIRST_HOST;
\r
1768 appData.secondHost = SECOND_HOST;
\r
1769 appData.firstDirectory = FIRST_DIRECTORY;
\r
1770 appData.secondDirectory = SECOND_DIRECTORY;
\r
1771 appData.bitmapDirectory = "";
\r
1772 appData.remoteShell = REMOTE_SHELL;
\r
1773 appData.remoteUser = "";
\r
1774 appData.timeDelay = TIME_DELAY;
\r
1775 appData.timeControl = TIME_CONTROL;
\r
1776 appData.timeIncrement = TIME_INCREMENT;
\r
1777 appData.icsActive = FALSE;
\r
1778 appData.icsHost = "";
\r
1779 appData.icsPort = ICS_PORT;
\r
1780 appData.icsCommPort = ICS_COMM_PORT;
\r
1781 appData.icsLogon = ICS_LOGON;
\r
1782 appData.icsHelper = "";
\r
1783 appData.useTelnet = FALSE;
\r
1784 appData.telnetProgram = TELNET_PROGRAM;
\r
1785 appData.gateway = "";
\r
1786 appData.loadGameFile = "";
\r
1787 appData.loadGameIndex = 0;
\r
1788 appData.saveGameFile = "";
\r
1789 appData.autoSaveGames = FALSE;
\r
1790 appData.loadPositionFile = "";
\r
1791 appData.loadPositionIndex = 1;
\r
1792 appData.savePositionFile = "";
\r
1793 appData.matchMode = FALSE;
\r
1794 appData.matchGames = 0;
\r
1795 appData.monoMode = FALSE;
\r
1796 appData.debugMode = FALSE;
\r
1797 appData.clockMode = TRUE;
\r
1798 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1799 appData.Iconic = FALSE; /*unused*/
\r
1800 appData.searchTime = "";
\r
1801 appData.searchDepth = 0;
\r
1802 appData.showCoords = FALSE;
\r
1803 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1804 appData.autoCallFlag = FALSE;
\r
1805 appData.flipView = FALSE;
\r
1806 appData.autoFlipView = TRUE;
\r
1807 appData.cmailGameName = "";
\r
1808 appData.alwaysPromoteToQueen = FALSE;
\r
1809 appData.oldSaveStyle = FALSE;
\r
1810 appData.quietPlay = FALSE;
\r
1811 appData.showThinking = FALSE;
\r
1812 appData.ponderNextMove = TRUE;
\r
1813 appData.periodicUpdates = TRUE;
\r
1814 appData.popupExitMessage = TRUE;
\r
1815 appData.popupMoveErrors = FALSE;
\r
1816 appData.autoObserve = FALSE;
\r
1817 appData.autoComment = FALSE;
\r
1818 appData.animate = TRUE;
\r
1819 appData.animSpeed = 10;
\r
1820 appData.animateDragging = TRUE;
\r
1821 appData.highlightLastMove = TRUE;
\r
1822 appData.getMoveList = TRUE;
\r
1823 appData.testLegality = TRUE;
\r
1824 appData.premove = TRUE;
\r
1825 appData.premoveWhite = FALSE;
\r
1826 appData.premoveWhiteText = "";
\r
1827 appData.premoveBlack = FALSE;
\r
1828 appData.premoveBlackText = "";
\r
1829 appData.icsAlarm = TRUE;
\r
1830 appData.icsAlarmTime = 5000;
\r
1831 appData.autoRaiseBoard = TRUE;
\r
1832 appData.localLineEditing = TRUE;
\r
1833 appData.colorize = TRUE;
\r
1834 appData.reuseFirst = TRUE;
\r
1835 appData.reuseSecond = TRUE;
\r
1836 appData.blindfold = FALSE;
\r
1837 appData.icsEngineAnalyze = FALSE;
\r
1838 dcb.DCBlength = sizeof(DCB);
\r
1839 dcb.BaudRate = 9600;
\r
1840 dcb.fBinary = TRUE;
\r
1841 dcb.fParity = FALSE;
\r
1842 dcb.fOutxCtsFlow = FALSE;
\r
1843 dcb.fOutxDsrFlow = FALSE;
\r
1844 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1845 dcb.fDsrSensitivity = FALSE;
\r
1846 dcb.fTXContinueOnXoff = TRUE;
\r
1847 dcb.fOutX = FALSE;
\r
1849 dcb.fNull = FALSE;
\r
1850 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1851 dcb.fAbortOnError = FALSE;
\r
1852 /* Microsoft SDK >= Feb. 2003 (MS VS >= 2002) */
\r
1853 #if (defined(_MSC_VER) && _MSC_VER <= 1200)
\r
1854 //dcb.wReserved = 0;
\r
1856 dcb.wReserved = 0;
\r
1859 dcb.Parity = SPACEPARITY;
\r
1860 dcb.StopBits = ONESTOPBIT;
\r
1861 settingsFileName = SETTINGS_FILE;
\r
1862 saveSettingsOnExit = TRUE;
\r
1863 boardX = CW_USEDEFAULT;
\r
1864 boardY = CW_USEDEFAULT;
\r
1865 consoleX = CW_USEDEFAULT;
\r
1866 consoleY = CW_USEDEFAULT;
\r
1867 consoleW = CW_USEDEFAULT;
\r
1868 consoleH = CW_USEDEFAULT;
\r
1869 analysisX = CW_USEDEFAULT;
\r
1870 analysisY = CW_USEDEFAULT;
\r
1871 analysisW = CW_USEDEFAULT;
\r
1872 analysisH = CW_USEDEFAULT;
\r
1873 commentX = CW_USEDEFAULT;
\r
1874 commentY = CW_USEDEFAULT;
\r
1875 commentW = CW_USEDEFAULT;
\r
1876 commentH = CW_USEDEFAULT;
\r
1877 editTagsX = CW_USEDEFAULT;
\r
1878 editTagsY = CW_USEDEFAULT;
\r
1879 editTagsW = CW_USEDEFAULT;
\r
1880 editTagsH = CW_USEDEFAULT;
\r
1881 gameListX = CW_USEDEFAULT;
\r
1882 gameListY = CW_USEDEFAULT;
\r
1883 gameListW = CW_USEDEFAULT;
\r
1884 gameListH = CW_USEDEFAULT;
\r
1885 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1886 icsNames = ICS_NAMES;
\r
1887 firstChessProgramNames = FCP_NAMES;
\r
1888 secondChessProgramNames = SCP_NAMES;
\r
1889 appData.initialMode = "";
\r
1890 appData.variant = "normal";
\r
1891 appData.firstProtocolVersion = PROTOVER;
\r
1892 appData.secondProtocolVersion = PROTOVER;
\r
1893 appData.showButtonBar = TRUE;
\r
1895 /* [AS] New properties (see comments in header file) */
\r
1896 appData.firstScoreIsAbsolute = FALSE;
\r
1897 appData.secondScoreIsAbsolute = FALSE;
\r
1898 appData.saveExtendedInfoInPGN = FALSE;
\r
1899 appData.hideThinkingFromHuman = FALSE;
\r
1900 appData.liteBackTextureFile = "";
\r
1901 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1902 appData.darkBackTextureFile = "";
\r
1903 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1904 appData.renderPiecesWithFont = "";
\r
1905 appData.fontToPieceTable = "";
\r
1906 appData.fontBackColorWhite = 0;
\r
1907 appData.fontForeColorWhite = 0;
\r
1908 appData.fontBackColorBlack = 0;
\r
1909 appData.fontForeColorBlack = 0;
\r
1910 appData.fontPieceSize = 80;
\r
1911 appData.overrideLineGap = 1;
\r
1912 appData.adjudicateLossThreshold = 0;
\r
1913 appData.delayBeforeQuit = 0;
\r
1914 appData.delayAfterQuit = 0;
\r
1915 appData.nameOfDebugFile = "winboard.debug";
\r
1916 appData.pgnEventHeader = "Computer Chess Game";
\r
1917 appData.defaultFrcPosition = -1;
\r
1918 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1919 appData.saveOutOfBookInfo = TRUE;
\r
1920 appData.showEvalInMoveHistory = TRUE;
\r
1921 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1922 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1923 appData.highlightMoveWithArrow = FALSE;
\r
1924 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1925 appData.useStickyWindows = TRUE;
\r
1926 appData.adjudicateDrawMoves = 0;
\r
1927 appData.autoDisplayComment = TRUE;
\r
1928 appData.autoDisplayTags = TRUE;
\r
1929 appData.firstIsUCI = FALSE;
\r
1930 appData.secondIsUCI = FALSE;
\r
1931 appData.firstHasOwnBookUCI = TRUE;
\r
1932 appData.secondHasOwnBookUCI = TRUE;
\r
1933 appData.polyglotDir = "";
\r
1934 appData.usePolyglotBook = FALSE;
\r
1935 appData.polyglotBook = "";
\r
1936 appData.defaultHashSize = 64;
\r
1937 appData.defaultCacheSizeEGTB = 4;
\r
1938 appData.defaultPathEGTB = "c:\\egtb";
\r
1940 InitWindowPlacement( &wpMoveHistory );
\r
1941 InitWindowPlacement( &wpEvalGraph );
\r
1942 InitWindowPlacement( &wpEngineOutput );
\r
1944 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1945 appData.NrFiles = -1;
\r
1946 appData.NrRanks = -1;
\r
1947 appData.holdingsSize = -1;
\r
1948 appData.testClaims = FALSE;
\r
1949 appData.checkMates = FALSE;
\r
1950 appData.materialDraws= FALSE;
\r
1951 appData.trivialDraws = FALSE;
\r
1952 appData.ruleMoves = 51;
\r
1953 appData.drawRepeats = 6;
\r
1954 appData.matchPause = 10000;
\r
1955 appData.alphaRank = FALSE;
\r
1956 appData.allWhite = FALSE;
\r
1957 appData.upsideDown = FALSE;
\r
1958 appData.serverPause = 15;
\r
1959 appData.serverMovesName = NULL;
\r
1960 appData.suppressLoadMoves = FALSE;
\r
1961 appData.firstTimeOdds = 1;
\r
1962 appData.secondTimeOdds = 1;
\r
1963 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
1964 appData.secondAccumulateTC = 1;
\r
1965 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
1966 appData.secondNPS = -1;
\r
1967 appData.engineComments = 1;
\r
1968 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
1969 appData.egtFormats = "";
\r
1972 appData.zippyTalk = ZIPPY_TALK;
\r
1973 appData.zippyPlay = ZIPPY_PLAY;
\r
1974 appData.zippyLines = ZIPPY_LINES;
\r
1975 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1976 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1977 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1978 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1979 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1980 appData.zippyUseI = ZIPPY_USE_I;
\r
1981 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1982 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1983 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1984 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1985 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1986 appData.zippyAbort = ZIPPY_ABORT;
\r
1987 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1988 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1989 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1992 /* Point font array elements to structures and
\r
1993 parse default font names */
\r
1994 for (i=0; i<NUM_FONTS; i++) {
\r
1995 for (j=0; j<NUM_SIZES; j++) {
\r
1996 font[j][i] = &fontRec[j][i];
\r
1997 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
2001 /* Parse default settings file if any */
\r
2002 if (ParseSettingsFile(settingsFileName, buf)) {
\r
2003 settingsFileName = strdup(buf);
\r
2006 /* Parse command line */
\r
2007 ParseArgs(StringGet, &lpCmdLine);
\r
2009 /* [HGM] make sure board size is acceptable */
\r
2010 if(appData.NrFiles > BOARD_SIZE ||
\r
2011 appData.NrRanks > BOARD_SIZE )
\r
2012 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
2014 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
2015 * with options from the command line, we now make an even higher priority
\r
2016 * overrule by WB options attached to the engine command line. This so that
\r
2017 * tournament managers can use WB options (such as /timeOdds) that follow
\r
2020 if(appData.firstChessProgram != NULL) {
\r
2021 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
2022 static char *f = "first";
\r
2023 char buf[MSG_SIZ], *q = buf;
\r
2024 if(p != NULL) { // engine command line contains WinBoard options
\r
2025 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
2026 ParseArgs(StringGet, &q);
\r
2027 p[-1] = 0; // cut them offengine command line
\r
2030 // now do same for second chess program
\r
2031 if(appData.secondChessProgram != NULL) {
\r
2032 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
2033 static char *s = "second";
\r
2034 char buf[MSG_SIZ], *q = buf;
\r
2035 if(p != NULL) { // engine command line contains WinBoard options
\r
2036 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2037 ParseArgs(StringGet, &q);
\r
2038 p[-1] = 0; // cut them offengine command line
\r
2043 /* Propagate options that affect others */
\r
2044 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2045 if (appData.icsActive || appData.noChessProgram) {
\r
2046 chessProgram = FALSE; /* not local chess program mode */
\r
2049 /* Open startup dialog if needed */
\r
2050 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2051 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2052 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2053 *appData.secondChessProgram == NULLCHAR))) {
\r
2056 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2057 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2058 FreeProcInstance(lpProc);
\r
2061 /* Make sure save files land in the right (?) directory */
\r
2062 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2063 appData.saveGameFile = strdup(buf);
\r
2065 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2066 appData.savePositionFile = strdup(buf);
\r
2069 /* Finish initialization for fonts and sounds */
\r
2070 for (i=0; i<NUM_FONTS; i++) {
\r
2071 for (j=0; j<NUM_SIZES; j++) {
\r
2072 CreateFontInMF(font[j][i]);
\r
2075 /* xboard, and older WinBoards, controlled the move sound with the
\r
2076 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2077 always turn the option on (so that the backend will call us),
\r
2078 then let the user turn the sound off by setting it to silence if
\r
2079 desired. To accommodate old winboard.ini files saved by old
\r
2080 versions of WinBoard, we also turn off the sound if the option
\r
2081 was initially set to false. */
\r
2082 if (!appData.ringBellAfterMoves) {
\r
2083 sounds[(int)SoundMove].name = strdup("");
\r
2084 appData.ringBellAfterMoves = TRUE;
\r
2086 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2087 SetCurrentDirectory(installDir);
\r
2089 SetCurrentDirectory(currDir);
\r
2091 p = icsTextMenuString;
\r
2092 if (p[0] == '@') {
\r
2093 FILE* f = fopen(p + 1, "r");
\r
2095 DisplayFatalError(p + 1, errno, 2);
\r
2098 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2100 buf[i] = NULLCHAR;
\r
2103 ParseIcsTextMenu(strdup(p));
\r
2110 HMENU hmenu = GetMenu(hwndMain);
\r
2112 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2113 MF_BYCOMMAND|((appData.icsActive &&
\r
2114 *appData.icsCommPort != NULLCHAR) ?
\r
2115 MF_ENABLED : MF_GRAYED));
\r
2116 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2117 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2118 MF_CHECKED : MF_UNCHECKED));
\r
2123 SaveSettings(char* name)
\r
2126 ArgDescriptor *ad;
\r
2127 WINDOWPLACEMENT wp;
\r
2128 char dir[MSG_SIZ];
\r
2130 if (!hwndMain) return;
\r
2132 GetCurrentDirectory(MSG_SIZ, dir);
\r
2133 SetCurrentDirectory(installDir);
\r
2134 f = fopen(name, "w");
\r
2135 SetCurrentDirectory(dir);
\r
2137 DisplayError(name, errno);
\r
2140 fprintf(f, ";\n");
\r
2141 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2142 fprintf(f, ";\n");
\r
2143 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2144 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2145 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2146 fprintf(f, ";\n");
\r
2148 wp.length = sizeof(WINDOWPLACEMENT);
\r
2149 GetWindowPlacement(hwndMain, &wp);
\r
2150 boardX = wp.rcNormalPosition.left;
\r
2151 boardY = wp.rcNormalPosition.top;
\r
2153 if (hwndConsole) {
\r
2154 GetWindowPlacement(hwndConsole, &wp);
\r
2155 consoleX = wp.rcNormalPosition.left;
\r
2156 consoleY = wp.rcNormalPosition.top;
\r
2157 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2158 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2161 if (analysisDialog) {
\r
2162 GetWindowPlacement(analysisDialog, &wp);
\r
2163 analysisX = wp.rcNormalPosition.left;
\r
2164 analysisY = wp.rcNormalPosition.top;
\r
2165 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2166 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2169 if (commentDialog) {
\r
2170 GetWindowPlacement(commentDialog, &wp);
\r
2171 commentX = wp.rcNormalPosition.left;
\r
2172 commentY = wp.rcNormalPosition.top;
\r
2173 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2174 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2177 if (editTagsDialog) {
\r
2178 GetWindowPlacement(editTagsDialog, &wp);
\r
2179 editTagsX = wp.rcNormalPosition.left;
\r
2180 editTagsY = wp.rcNormalPosition.top;
\r
2181 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2182 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2185 if (gameListDialog) {
\r
2186 GetWindowPlacement(gameListDialog, &wp);
\r
2187 gameListX = wp.rcNormalPosition.left;
\r
2188 gameListY = wp.rcNormalPosition.top;
\r
2189 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2190 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2193 /* [AS] Move history */
\r
2194 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2196 if( moveHistoryDialog ) {
\r
2197 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2198 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2199 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2200 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2201 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2204 /* [AS] Eval graph */
\r
2205 wpEvalGraph.visible = EvalGraphIsUp();
\r
2207 if( evalGraphDialog ) {
\r
2208 GetWindowPlacement(evalGraphDialog, &wp);
\r
2209 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2210 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2211 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2212 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2215 /* [AS] Engine output */
\r
2216 wpEngineOutput.visible = EngineOutputIsUp();
\r
2218 if( engineOutputDialog ) {
\r
2219 GetWindowPlacement(engineOutputDialog, &wp);
\r
2220 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2221 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2222 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2223 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2226 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2227 if (!ad->save) continue;
\r
2228 switch (ad->argType) {
\r
2231 char *p = *(char **)ad->argLoc;
\r
2232 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2233 /* Quote multiline values or \-containing values
\r
2234 with { } if possible */
\r
2235 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2237 /* Else quote with " " */
\r
2238 fprintf(f, "/%s=\"", ad->argName);
\r
2240 if (*p == '\n') fprintf(f, "\n");
\r
2241 else if (*p == '\r') fprintf(f, "\\r");
\r
2242 else if (*p == '\t') fprintf(f, "\\t");
\r
2243 else if (*p == '\b') fprintf(f, "\\b");
\r
2244 else if (*p == '\f') fprintf(f, "\\f");
\r
2245 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2246 else if (*p == '\"') fprintf(f, "\\\"");
\r
2247 else if (*p == '\\') fprintf(f, "\\\\");
\r
2251 fprintf(f, "\"\n");
\r
2256 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2259 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2262 fprintf(f, "/%s=%s\n", ad->argName,
\r
2263 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2266 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2269 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2273 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2274 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2275 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2280 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2281 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2282 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2283 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2284 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2285 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2286 (ta->effects) ? " " : "",
\r
2287 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2291 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2292 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2294 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2297 case ArgBoardSize:
\r
2298 fprintf(f, "/%s=%s\n", ad->argName,
\r
2299 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2304 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2305 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2306 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2307 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2308 ad->argName, mfp->faceName, mfp->pointSize,
\r
2309 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2310 mfp->bold ? "b" : "",
\r
2311 mfp->italic ? "i" : "",
\r
2312 mfp->underline ? "u" : "",
\r
2313 mfp->strikeout ? "s" : "");
\r
2317 case ArgCommSettings:
\r
2318 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2326 /*---------------------------------------------------------------------------*\
\r
2328 * GDI board drawing routines
\r
2330 \*---------------------------------------------------------------------------*/
\r
2332 /* [AS] Draw square using background texture */
\r
2333 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2338 return; /* Should never happen! */
\r
2341 SetGraphicsMode( dst, GM_ADVANCED );
\r
2348 /* X reflection */
\r
2353 x.eDx = (FLOAT) dw + dx - 1;
\r
2356 SetWorldTransform( dst, &x );
\r
2359 /* Y reflection */
\r
2365 x.eDy = (FLOAT) dh + dy - 1;
\r
2367 SetWorldTransform( dst, &x );
\r
2375 x.eDx = (FLOAT) dx;
\r
2376 x.eDy = (FLOAT) dy;
\r
2379 SetWorldTransform( dst, &x );
\r
2383 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2391 SetWorldTransform( dst, &x );
\r
2393 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2396 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2398 PM_WP = (int) WhitePawn,
\r
2399 PM_WN = (int) WhiteKnight,
\r
2400 PM_WB = (int) WhiteBishop,
\r
2401 PM_WR = (int) WhiteRook,
\r
2402 PM_WQ = (int) WhiteQueen,
\r
2403 PM_WF = (int) WhiteFerz,
\r
2404 PM_WW = (int) WhiteWazir,
\r
2405 PM_WE = (int) WhiteAlfil,
\r
2406 PM_WM = (int) WhiteMan,
\r
2407 PM_WO = (int) WhiteCannon,
\r
2408 PM_WU = (int) WhiteUnicorn,
\r
2409 PM_WH = (int) WhiteNightrider,
\r
2410 PM_WA = (int) WhiteAngel,
\r
2411 PM_WC = (int) WhiteMarshall,
\r
2412 PM_WAB = (int) WhiteCardinal,
\r
2413 PM_WD = (int) WhiteDragon,
\r
2414 PM_WL = (int) WhiteLance,
\r
2415 PM_WS = (int) WhiteCobra,
\r
2416 PM_WV = (int) WhiteFalcon,
\r
2417 PM_WSG = (int) WhiteSilver,
\r
2418 PM_WG = (int) WhiteGrasshopper,
\r
2419 PM_WK = (int) WhiteKing,
\r
2420 PM_BP = (int) BlackPawn,
\r
2421 PM_BN = (int) BlackKnight,
\r
2422 PM_BB = (int) BlackBishop,
\r
2423 PM_BR = (int) BlackRook,
\r
2424 PM_BQ = (int) BlackQueen,
\r
2425 PM_BF = (int) BlackFerz,
\r
2426 PM_BW = (int) BlackWazir,
\r
2427 PM_BE = (int) BlackAlfil,
\r
2428 PM_BM = (int) BlackMan,
\r
2429 PM_BO = (int) BlackCannon,
\r
2430 PM_BU = (int) BlackUnicorn,
\r
2431 PM_BH = (int) BlackNightrider,
\r
2432 PM_BA = (int) BlackAngel,
\r
2433 PM_BC = (int) BlackMarshall,
\r
2434 PM_BG = (int) BlackGrasshopper,
\r
2435 PM_BAB = (int) BlackCardinal,
\r
2436 PM_BD = (int) BlackDragon,
\r
2437 PM_BL = (int) BlackLance,
\r
2438 PM_BS = (int) BlackCobra,
\r
2439 PM_BV = (int) BlackFalcon,
\r
2440 PM_BSG = (int) BlackSilver,
\r
2441 PM_BK = (int) BlackKing
\r
2444 static HFONT hPieceFont = NULL;
\r
2445 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2446 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2447 static int fontBitmapSquareSize = 0;
\r
2448 static char pieceToFontChar[(int) EmptySquare] =
\r
2449 { 'p', 'n', 'b', 'r', 'q',
\r
2450 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2451 'k', 'o', 'm', 'v', 't', 'w',
\r
2452 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2455 extern BOOL SetCharTable( char *table, const char * map );
\r
2456 /* [HGM] moved to backend.c */
\r
2458 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2461 BYTE r1 = GetRValue( color );
\r
2462 BYTE g1 = GetGValue( color );
\r
2463 BYTE b1 = GetBValue( color );
\r
2469 /* Create a uniform background first */
\r
2470 hbrush = CreateSolidBrush( color );
\r
2471 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2472 FillRect( hdc, &rc, hbrush );
\r
2473 DeleteObject( hbrush );
\r
2476 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2477 int steps = squareSize / 2;
\r
2480 for( i=0; i<steps; i++ ) {
\r
2481 BYTE r = r1 - (r1-r2) * i / steps;
\r
2482 BYTE g = g1 - (g1-g2) * i / steps;
\r
2483 BYTE b = b1 - (b1-b2) * i / steps;
\r
2485 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2486 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2487 FillRect( hdc, &rc, hbrush );
\r
2488 DeleteObject(hbrush);
\r
2491 else if( mode == 2 ) {
\r
2492 /* Diagonal gradient, good more or less for every piece */
\r
2493 POINT triangle[3];
\r
2494 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2495 HBRUSH hbrush_old;
\r
2496 int steps = squareSize;
\r
2499 triangle[0].x = squareSize - steps;
\r
2500 triangle[0].y = squareSize;
\r
2501 triangle[1].x = squareSize;
\r
2502 triangle[1].y = squareSize;
\r
2503 triangle[2].x = squareSize;
\r
2504 triangle[2].y = squareSize - steps;
\r
2506 for( i=0; i<steps; i++ ) {
\r
2507 BYTE r = r1 - (r1-r2) * i / steps;
\r
2508 BYTE g = g1 - (g1-g2) * i / steps;
\r
2509 BYTE b = b1 - (b1-b2) * i / steps;
\r
2511 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2512 hbrush_old = SelectObject( hdc, hbrush );
\r
2513 Polygon( hdc, triangle, 3 );
\r
2514 SelectObject( hdc, hbrush_old );
\r
2515 DeleteObject(hbrush);
\r
2520 SelectObject( hdc, hpen );
\r
2525 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2526 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2527 piece: follow the steps as explained below.
\r
2529 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2533 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2537 int backColor = whitePieceColor;
\r
2538 int foreColor = blackPieceColor;
\r
2540 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2541 backColor = appData.fontBackColorWhite;
\r
2542 foreColor = appData.fontForeColorWhite;
\r
2544 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2545 backColor = appData.fontBackColorBlack;
\r
2546 foreColor = appData.fontForeColorBlack;
\r
2550 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2552 hbm_old = SelectObject( hdc, hbm );
\r
2556 rc.right = squareSize;
\r
2557 rc.bottom = squareSize;
\r
2559 /* Step 1: background is now black */
\r
2560 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2562 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2564 pt.x = (squareSize - sz.cx) / 2;
\r
2565 pt.y = (squareSize - sz.cy) / 2;
\r
2567 SetBkMode( hdc, TRANSPARENT );
\r
2568 SetTextColor( hdc, chroma );
\r
2569 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2570 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2572 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2573 /* Step 3: the area outside the piece is filled with white */
\r
2574 // FloodFill( hdc, 0, 0, chroma );
\r
2575 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2576 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2577 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2578 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2579 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2581 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2582 but if the start point is not inside the piece we're lost!
\r
2583 There should be a better way to do this... if we could create a region or path
\r
2584 from the fill operation we would be fine for example.
\r
2586 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2587 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2589 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2590 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2591 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2593 SelectObject( dc2, bm2 );
\r
2594 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2595 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2596 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2597 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2598 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2601 DeleteObject( bm2 );
\r
2604 SetTextColor( hdc, 0 );
\r
2606 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2607 draw the piece again in black for safety.
\r
2609 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2611 SelectObject( hdc, hbm_old );
\r
2613 if( hPieceMask[index] != NULL ) {
\r
2614 DeleteObject( hPieceMask[index] );
\r
2617 hPieceMask[index] = hbm;
\r
2620 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2622 SelectObject( hdc, hbm );
\r
2625 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2626 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2627 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2629 SelectObject( dc1, hPieceMask[index] );
\r
2630 SelectObject( dc2, bm2 );
\r
2631 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2632 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2635 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2636 the piece background and deletes (makes transparent) the rest.
\r
2637 Thanks to that mask, we are free to paint the background with the greates
\r
2638 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2639 We use this, to make gradients and give the pieces a "roundish" look.
\r
2641 SetPieceBackground( hdc, backColor, 2 );
\r
2642 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2646 DeleteObject( bm2 );
\r
2649 SetTextColor( hdc, foreColor );
\r
2650 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[appData.allWhite && index >= (int)BlackPawn ? index - (int)BlackPawn : index], 1 );
\r
2652 SelectObject( hdc, hbm_old );
\r
2654 if( hPieceFace[index] != NULL ) {
\r
2655 DeleteObject( hPieceFace[index] );
\r
2658 hPieceFace[index] = hbm;
\r
2661 static int TranslatePieceToFontPiece( int piece )
\r
2691 case BlackMarshall:
\r
2695 case BlackNightrider:
\r
2701 case BlackUnicorn:
\r
2705 case BlackGrasshopper:
\r
2717 case BlackCardinal:
\r
2724 case WhiteMarshall:
\r
2728 case WhiteNightrider:
\r
2734 case WhiteUnicorn:
\r
2738 case WhiteGrasshopper:
\r
2750 case WhiteCardinal:
\r
2759 void CreatePiecesFromFont()
\r
2762 HDC hdc_window = NULL;
\r
2768 if( fontBitmapSquareSize < 0 ) {
\r
2769 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2773 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2774 fontBitmapSquareSize = -1;
\r
2778 if( fontBitmapSquareSize != squareSize ) {
\r
2779 hdc_window = GetDC( hwndMain );
\r
2780 hdc = CreateCompatibleDC( hdc_window );
\r
2782 if( hPieceFont != NULL ) {
\r
2783 DeleteObject( hPieceFont );
\r
2786 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2787 hPieceMask[i] = NULL;
\r
2788 hPieceFace[i] = NULL;
\r
2794 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2795 fontHeight = appData.fontPieceSize;
\r
2798 fontHeight = (fontHeight * squareSize) / 100;
\r
2800 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2802 lf.lfEscapement = 0;
\r
2803 lf.lfOrientation = 0;
\r
2804 lf.lfWeight = FW_NORMAL;
\r
2806 lf.lfUnderline = 0;
\r
2807 lf.lfStrikeOut = 0;
\r
2808 lf.lfCharSet = DEFAULT_CHARSET;
\r
2809 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2810 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2811 lf.lfQuality = PROOF_QUALITY;
\r
2812 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2813 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2814 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2816 hPieceFont = CreateFontIndirect( &lf );
\r
2818 if( hPieceFont == NULL ) {
\r
2819 fontBitmapSquareSize = -2;
\r
2822 /* Setup font-to-piece character table */
\r
2823 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2824 /* No (or wrong) global settings, try to detect the font */
\r
2825 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2827 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2829 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2830 /* DiagramTT* family */
\r
2831 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2833 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2834 /* Fairy symbols */
\r
2835 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2837 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2838 /* Good Companion (Some characters get warped as literal :-( */
\r
2839 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2840 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2841 SetCharTable(pieceToFontChar, s);
\r
2844 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2845 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2849 /* Create bitmaps */
\r
2850 hfont_old = SelectObject( hdc, hPieceFont );
\r
2852 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2853 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2854 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2855 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2856 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2857 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2858 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2859 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2860 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2861 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2862 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2863 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2865 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2866 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2867 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2868 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2869 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2870 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2871 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2872 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2873 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2874 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2875 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
2876 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
2877 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
2878 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
2879 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
2880 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
2881 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2882 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2883 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2884 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2885 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2886 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2887 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2888 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2889 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2890 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2891 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
2892 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
2893 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
2894 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
2895 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
2896 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
2898 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2899 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2900 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2902 SelectObject( hdc, hfont_old );
\r
2904 fontBitmapSquareSize = squareSize;
\r
2908 if( hdc != NULL ) {
\r
2912 if( hdc_window != NULL ) {
\r
2913 ReleaseDC( hwndMain, hdc_window );
\r
2918 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2922 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2923 if (gameInfo.event &&
\r
2924 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2925 strcmp(name, "k80s") == 0) {
\r
2926 strcpy(name, "tim");
\r
2928 return LoadBitmap(hinst, name);
\r
2932 /* Insert a color into the program's logical palette
\r
2933 structure. This code assumes the given color is
\r
2934 the result of the RGB or PALETTERGB macro, and it
\r
2935 knows how those macros work (which is documented).
\r
2938 InsertInPalette(COLORREF color)
\r
2940 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2942 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2943 DisplayFatalError("Too many colors", 0, 1);
\r
2944 pLogPal->palNumEntries--;
\r
2948 pe->peFlags = (char) 0;
\r
2949 pe->peRed = (char) (0xFF & color);
\r
2950 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2951 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2957 InitDrawingColors()
\r
2959 if (pLogPal == NULL) {
\r
2960 /* Allocate enough memory for a logical palette with
\r
2961 * PALETTESIZE entries and set the size and version fields
\r
2962 * of the logical palette structure.
\r
2964 pLogPal = (NPLOGPALETTE)
\r
2965 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2966 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2967 pLogPal->palVersion = 0x300;
\r
2969 pLogPal->palNumEntries = 0;
\r
2971 InsertInPalette(lightSquareColor);
\r
2972 InsertInPalette(darkSquareColor);
\r
2973 InsertInPalette(whitePieceColor);
\r
2974 InsertInPalette(blackPieceColor);
\r
2975 InsertInPalette(highlightSquareColor);
\r
2976 InsertInPalette(premoveHighlightColor);
\r
2978 /* create a logical color palette according the information
\r
2979 * in the LOGPALETTE structure.
\r
2981 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2983 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2984 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2985 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2986 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2987 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2988 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2990 /* [AS] Force rendering of the font-based pieces */
\r
2991 if( fontBitmapSquareSize > 0 ) {
\r
2992 fontBitmapSquareSize = 0;
\r
2998 BoardWidth(int boardSize, int n)
\r
2999 { /* [HGM] argument n added to allow different width and height */
\r
3000 int lineGap = sizeInfo[boardSize].lineGap;
\r
3002 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3003 lineGap = appData.overrideLineGap;
\r
3006 return (n + 1) * lineGap +
\r
3007 n * sizeInfo[boardSize].squareSize;
\r
3010 /* Respond to board resize by dragging edge */
\r
3012 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
3014 BoardSize newSize = NUM_SIZES - 1;
\r
3015 static int recurse = 0;
\r
3016 if (IsIconic(hwndMain)) return;
\r
3017 if (recurse > 0) return;
\r
3019 while (newSize > 0) {
\r
3020 InitDrawingSizes(newSize, 0);
\r
3021 if(newSizeX >= sizeInfo[newSize].cliWidth ||
\r
3022 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
3025 boardSize = newSize;
\r
3026 InitDrawingSizes(boardSize, flags);
\r
3033 InitDrawingSizes(BoardSize boardSize, int flags)
\r
3035 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
3036 ChessSquare piece;
\r
3037 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3039 SIZE clockSize, messageSize;
\r
3041 char buf[MSG_SIZ];
\r
3043 HMENU hmenu = GetMenu(hwndMain);
\r
3044 RECT crect, wrect;
\r
3046 LOGBRUSH logbrush;
\r
3048 /* [HGM] call with -1 uses old size (for if nr of files, ranks changes) */
\r
3049 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3051 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3052 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3053 squareSize = sizeInfo[boardSize].squareSize;
\r
3054 lineGap = sizeInfo[boardSize].lineGap;
\r
3055 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3057 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3058 lineGap = appData.overrideLineGap;
\r
3061 if (tinyLayout != oldTinyLayout) {
\r
3062 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3064 style &= ~WS_SYSMENU;
\r
3065 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3066 "&Minimize\tCtrl+F4");
\r
3068 style |= WS_SYSMENU;
\r
3069 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3071 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3073 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3074 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3075 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3077 DrawMenuBar(hwndMain);
\r
3080 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3081 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3083 /* Get text area sizes */
\r
3084 hdc = GetDC(hwndMain);
\r
3085 if (appData.clockMode) {
\r
3086 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3088 sprintf(buf, "White");
\r
3090 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3091 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3092 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3093 str = "We only care about the height here";
\r
3094 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3095 SelectObject(hdc, oldFont);
\r
3096 ReleaseDC(hwndMain, hdc);
\r
3098 /* Compute where everything goes */
\r
3099 if(first.programLogo || second.programLogo) {
\r
3100 /* [HGM] logo: if either logo is on, reserve space for it */
\r
3101 logoHeight = 2*clockSize.cy;
\r
3102 leftLogoRect.left = OUTER_MARGIN;
\r
3103 leftLogoRect.right = leftLogoRect.left + 4*clockSize.cy;
\r
3104 leftLogoRect.top = OUTER_MARGIN;
\r
3105 leftLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3107 rightLogoRect.right = OUTER_MARGIN + boardWidth;
\r
3108 rightLogoRect.left = rightLogoRect.right - 4*clockSize.cy;
\r
3109 rightLogoRect.top = OUTER_MARGIN;
\r
3110 rightLogoRect.bottom = OUTER_MARGIN + logoHeight;
\r
3113 blackRect.left = leftLogoRect.right;
\r
3114 blackRect.right = rightLogoRect.left;
\r
3115 blackRect.top = OUTER_MARGIN;
\r
3116 blackRect.bottom = blackRect.top + clockSize.cy;
\r
3118 whiteRect.left = blackRect.left ;
\r
3119 whiteRect.right = blackRect.right;
\r
3120 whiteRect.top = blackRect.bottom;
\r
3121 whiteRect.bottom = leftLogoRect.bottom;
\r
3123 whiteRect.left = OUTER_MARGIN;
\r
3124 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3125 whiteRect.top = OUTER_MARGIN + logoHeight;
\r
3126 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3128 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3129 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3130 blackRect.top = whiteRect.top;
\r
3131 blackRect.bottom = whiteRect.bottom;
\r
3134 messageRect.left = OUTER_MARGIN + MESSAGE_LINE_LEFTMARGIN;
\r
3135 if (appData.showButtonBar) {
\r
3136 messageRect.right = OUTER_MARGIN + boardWidth // [HGM] logo: expressed independent of clock placement
\r
3137 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3139 messageRect.right = OUTER_MARGIN + boardWidth;
\r
3141 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3142 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3144 boardRect.left = OUTER_MARGIN;
\r
3145 boardRect.right = boardRect.left + boardWidth;
\r
3146 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3147 boardRect.bottom = boardRect.top + boardHeight;
\r
3149 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3150 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3151 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3152 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3153 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3154 GetWindowRect(hwndMain, &wrect);
\r
3155 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3156 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3157 /* compensate if menu bar wrapped */
\r
3158 GetClientRect(hwndMain, &crect);
\r
3159 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3160 winHeight += offby;
\r
3162 case WMSZ_TOPLEFT:
\r
3163 SetWindowPos(hwndMain, NULL,
\r
3164 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3165 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3168 case WMSZ_TOPRIGHT:
\r
3170 SetWindowPos(hwndMain, NULL,
\r
3171 wrect.left, wrect.bottom - winHeight,
\r
3172 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3175 case WMSZ_BOTTOMLEFT:
\r
3177 SetWindowPos(hwndMain, NULL,
\r
3178 wrect.right - winWidth, wrect.top,
\r
3179 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3182 case WMSZ_BOTTOMRIGHT:
\r
3186 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3187 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3192 for (i = 0; i < N_BUTTONS; i++) {
\r
3193 if (buttonDesc[i].hwnd != NULL) {
\r
3194 DestroyWindow(buttonDesc[i].hwnd);
\r
3195 buttonDesc[i].hwnd = NULL;
\r
3197 if (appData.showButtonBar) {
\r
3198 buttonDesc[i].hwnd =
\r
3199 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3200 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3201 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3202 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3203 (HMENU) buttonDesc[i].id,
\r
3204 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3206 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3207 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3208 MAKELPARAM(FALSE, 0));
\r
3210 if (buttonDesc[i].id == IDM_Pause)
\r
3211 hwndPause = buttonDesc[i].hwnd;
\r
3212 buttonDesc[i].wndproc = (WNDPROC)
\r
3213 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3216 if (gridPen != NULL) DeleteObject(gridPen);
\r
3217 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3218 if (premovePen != NULL) DeleteObject(premovePen);
\r
3219 if (lineGap != 0) {
\r
3220 logbrush.lbStyle = BS_SOLID;
\r
3221 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3223 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3224 lineGap, &logbrush, 0, NULL);
\r
3225 logbrush.lbColor = highlightSquareColor;
\r
3227 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3228 lineGap, &logbrush, 0, NULL);
\r
3230 logbrush.lbColor = premoveHighlightColor;
\r
3232 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3233 lineGap, &logbrush, 0, NULL);
\r
3235 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3236 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3237 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3238 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3239 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3240 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3241 BOARD_WIDTH * (squareSize + lineGap);
\r
3242 lineGap / 2 + (i * (squareSize + lineGap));
\r
3243 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3245 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3246 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3247 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3248 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3249 lineGap / 2 + (i * (squareSize + lineGap));
\r
3250 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3251 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3252 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3256 /* [HGM] Licensing requirement */
\r
3258 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3261 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3263 GothicPopUp( "", VariantNormal);
\r
3266 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3267 oldBoardSize = boardSize;
\r
3268 oldTinyLayout = tinyLayout;
\r
3270 /* Load piece bitmaps for this board size */
\r
3271 for (i=0; i<=2; i++) {
\r
3272 for (piece = WhitePawn;
\r
3273 (int) piece < (int) BlackPawn;
\r
3274 piece = (ChessSquare) ((int) piece + 1)) {
\r
3275 if (pieceBitmap[i][piece] != NULL)
\r
3276 DeleteObject(pieceBitmap[i][piece]);
\r
3280 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3281 // Orthodox Chess pieces
\r
3282 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3283 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3284 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3285 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3286 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3287 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3288 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3289 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3290 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3291 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3292 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3293 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3294 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3295 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3296 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3297 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3298 // in Shogi, Hijack the unused Queen for Lance
\r
3299 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3300 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3301 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3303 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3304 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3305 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3308 if(squareSize <= 72 && squareSize >= 33) {
\r
3309 /* A & C are available in most sizes now */
\r
3310 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3311 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3312 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3313 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3314 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3315 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3316 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3317 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3318 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3319 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3320 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3321 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3322 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3323 } else { // Smirf-like
\r
3324 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3325 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3326 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3328 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3329 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3330 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3331 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3332 } else { // WinBoard standard
\r
3333 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3334 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3335 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3340 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3341 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3342 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3343 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3344 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3345 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3346 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3347 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3348 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3349 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3350 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3351 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3352 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3353 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3354 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3355 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3356 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3357 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3358 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3359 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3360 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3361 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3362 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3363 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3364 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3365 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3366 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3367 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3368 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3369 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3370 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3372 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3373 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3374 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3375 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3376 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3377 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3378 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3379 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3380 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3381 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3382 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3383 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3384 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3386 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3387 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3388 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3389 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3390 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3391 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3392 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3393 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3394 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3395 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3396 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3397 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3400 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3401 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3402 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3403 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3404 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3405 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3406 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3407 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3408 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3409 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3410 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3411 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3412 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3413 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3414 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3418 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3419 /* special Shogi support in this size */
\r
3420 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3421 for (piece = WhitePawn;
\r
3422 (int) piece < (int) BlackPawn;
\r
3423 piece = (ChessSquare) ((int) piece + 1)) {
\r
3424 if (pieceBitmap[i][piece] != NULL)
\r
3425 DeleteObject(pieceBitmap[i][piece]);
\r
3428 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3429 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3430 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3431 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3432 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3433 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3434 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3435 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3436 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3437 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3438 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3439 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3440 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3441 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3442 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3443 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3444 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3445 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3446 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3447 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3448 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3449 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3450 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3451 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3452 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3453 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3454 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3455 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3456 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3457 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3458 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3459 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3460 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3461 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3462 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3463 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3464 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3465 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3466 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3467 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3468 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3469 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3475 PieceBitmap(ChessSquare p, int kind)
\r
3477 if ((int) p >= (int) BlackPawn)
\r
3478 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3480 return pieceBitmap[kind][(int) p];
\r
3483 /***************************************************************/
\r
3485 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3486 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3488 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3489 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3493 SquareToPos(int row, int column, int * x, int * y)
\r
3496 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3497 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3499 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3500 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3505 DrawCoordsOnDC(HDC hdc)
\r
3507 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
3508 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
3509 char str[2] = { NULLCHAR, NULLCHAR };
\r
3510 int oldMode, oldAlign, x, y, start, i;
\r
3514 if (!appData.showCoords)
\r
3517 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3519 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3520 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3521 oldAlign = GetTextAlign(hdc);
\r
3522 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3524 y = boardRect.top + lineGap;
\r
3525 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3527 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3528 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3529 str[0] = files[start + i];
\r
3530 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3531 y += squareSize + lineGap;
\r
3534 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3536 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3537 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3538 str[0] = ranks[start + i];
\r
3539 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3540 x += squareSize + lineGap;
\r
3543 SelectObject(hdc, oldBrush);
\r
3544 SetBkMode(hdc, oldMode);
\r
3545 SetTextAlign(hdc, oldAlign);
\r
3546 SelectObject(hdc, oldFont);
\r
3550 DrawGridOnDC(HDC hdc)
\r
3554 if (lineGap != 0) {
\r
3555 oldPen = SelectObject(hdc, gridPen);
\r
3556 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3557 SelectObject(hdc, oldPen);
\r
3561 #define HIGHLIGHT_PEN 0
\r
3562 #define PREMOVE_PEN 1
\r
3565 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3568 HPEN oldPen, hPen;
\r
3569 if (lineGap == 0) return;
\r
3571 x1 = boardRect.left +
\r
3572 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3573 y1 = boardRect.top +
\r
3574 lineGap/2 + y * (squareSize + lineGap);
\r
3576 x1 = boardRect.left +
\r
3577 lineGap/2 + x * (squareSize + lineGap);
\r
3578 y1 = boardRect.top +
\r
3579 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3581 hPen = pen ? premovePen : highlightPen;
\r
3582 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3583 MoveToEx(hdc, x1, y1, NULL);
\r
3584 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3585 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3586 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3587 LineTo(hdc, x1, y1);
\r
3588 SelectObject(hdc, oldPen);
\r
3592 DrawHighlightsOnDC(HDC hdc)
\r
3595 for (i=0; i<2; i++) {
\r
3596 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3597 DrawHighlightOnDC(hdc, TRUE,
\r
3598 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3601 for (i=0; i<2; i++) {
\r
3602 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3603 premoveHighlightInfo.sq[i].y >= 0) {
\r
3604 DrawHighlightOnDC(hdc, TRUE,
\r
3605 premoveHighlightInfo.sq[i].x,
\r
3606 premoveHighlightInfo.sq[i].y,
\r
3612 /* Note: sqcolor is used only in monoMode */
\r
3613 /* Note that this code is largely duplicated in woptions.c,
\r
3614 function DrawSampleSquare, so that needs to be updated too */
\r
3616 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3618 HBITMAP oldBitmap;
\r
3622 if (appData.blindfold) return;
\r
3624 /* [AS] Use font-based pieces if needed */
\r
3625 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3626 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3627 CreatePiecesFromFont();
\r
3629 if( fontBitmapSquareSize == squareSize ) {
\r
3630 int index = TranslatePieceToFontPiece(piece);
\r
3632 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3636 squareSize, squareSize,
\r
3641 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3645 squareSize, squareSize,
\r
3654 if (appData.monoMode) {
\r
3655 SelectObject(tmphdc, PieceBitmap(piece,
\r
3656 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3657 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3658 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3660 tmpSize = squareSize;
\r
3662 (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||
\r
3663 piece >= (int)BlackNightrider && piece <= BlackGrasshopper) ) {
\r
3664 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3665 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3666 x += (squareSize - minorSize)>>1;
\r
3667 y += squareSize - minorSize - 2;
\r
3668 tmpSize = minorSize;
\r
3670 if (color || appData.allWhite ) {
\r
3671 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3673 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3674 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3675 if(appData.upsideDown && color==flipView)
\r
3676 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3678 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3680 /* Use black piece color for outline of white pieces */
\r
3681 /* Not sure this looks really good (though xboard does it).
\r
3682 Maybe better to have another selectable color, default black */
\r
3683 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3684 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3685 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3687 /* Use black for outline of white pieces */
\r
3688 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3689 if(appData.upsideDown && color==flipView)
\r
3690 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3692 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3696 /* Use white piece color for details of black pieces */
\r
3697 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3698 WHITE_PIECE ones aren't always the right shape. */
\r
3699 /* Not sure this looks really good (though xboard does it).
\r
3700 Maybe better to have another selectable color, default medium gray? */
\r
3701 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3702 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3703 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3704 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3705 SelectObject(hdc, blackPieceBrush);
\r
3706 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3708 /* Use square color for details of black pieces */
\r
3709 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3710 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3711 if(appData.upsideDown && !flipView)
\r
3712 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3714 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3717 SelectObject(hdc, oldBrush);
\r
3718 SelectObject(tmphdc, oldBitmap);
\r
3722 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3723 int GetBackTextureMode( int algo )
\r
3725 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3729 case BACK_TEXTURE_MODE_PLAIN:
\r
3730 result = 1; /* Always use identity map */
\r
3732 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3733 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3741 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3742 to handle redraws cleanly (as random numbers would always be different).
\r
3744 VOID RebuildTextureSquareInfo()
\r
3754 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3756 if( liteBackTexture != NULL ) {
\r
3757 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3758 lite_w = bi.bmWidth;
\r
3759 lite_h = bi.bmHeight;
\r
3763 if( darkBackTexture != NULL ) {
\r
3764 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3765 dark_w = bi.bmWidth;
\r
3766 dark_h = bi.bmHeight;
\r
3770 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3771 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3772 if( (col + row) & 1 ) {
\r
3774 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3775 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / (BOARD_WIDTH-1); /* [HGM] divide by size-1 in stead of size! */
\r
3776 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (lite_h - squareSize) / (BOARD_HEIGHT-1);
\r
3777 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3782 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3783 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / (BOARD_WIDTH-1);
\r
3784 backTextureSquareInfo[row][col].y = (BOARD_HEIGHT-1-row) * (dark_h - squareSize) / (BOARD_HEIGHT-1);
\r
3785 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3792 /* [AS] Arrow highlighting support */
\r
3794 static int A_WIDTH = 5; /* Width of arrow body */
\r
3796 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3797 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3799 static double Sqr( double x )
\r
3804 static int Round( double x )
\r
3806 return (int) (x + 0.5);
\r
3809 /* Draw an arrow between two points using current settings */
\r
3810 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3813 double dx, dy, j, k, x, y;
\r
3815 if( d_x == s_x ) {
\r
3816 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3818 arrow[0].x = s_x + A_WIDTH;
\r
3821 arrow[1].x = s_x + A_WIDTH;
\r
3822 arrow[1].y = d_y - h;
\r
3824 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3825 arrow[2].y = d_y - h;
\r
3830 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3831 arrow[4].y = d_y - h;
\r
3833 arrow[5].x = s_x - A_WIDTH;
\r
3834 arrow[5].y = d_y - h;
\r
3836 arrow[6].x = s_x - A_WIDTH;
\r
3839 else if( d_y == s_y ) {
\r
3840 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3843 arrow[0].y = s_y + A_WIDTH;
\r
3845 arrow[1].x = d_x - w;
\r
3846 arrow[1].y = s_y + A_WIDTH;
\r
3848 arrow[2].x = d_x - w;
\r
3849 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3854 arrow[4].x = d_x - w;
\r
3855 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3857 arrow[5].x = d_x - w;
\r
3858 arrow[5].y = s_y - A_WIDTH;
\r
3861 arrow[6].y = s_y - A_WIDTH;
\r
3864 /* [AS] Needed a lot of paper for this! :-) */
\r
3865 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3866 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3868 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3870 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3875 arrow[0].x = Round(x - j);
\r
3876 arrow[0].y = Round(y + j*dx);
\r
3878 arrow[1].x = Round(x + j);
\r
3879 arrow[1].y = Round(y - j*dx);
\r
3882 x = (double) d_x - k;
\r
3883 y = (double) d_y - k*dy;
\r
3886 x = (double) d_x + k;
\r
3887 y = (double) d_y + k*dy;
\r
3890 arrow[2].x = Round(x + j);
\r
3891 arrow[2].y = Round(y - j*dx);
\r
3893 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3894 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3899 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3900 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3902 arrow[6].x = Round(x - j);
\r
3903 arrow[6].y = Round(y + j*dx);
\r
3906 Polygon( hdc, arrow, 7 );
\r
3909 /* [AS] Draw an arrow between two squares */
\r
3910 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3912 int s_x, s_y, d_x, d_y;
\r
3919 if( s_col == d_col && s_row == d_row ) {
\r
3923 /* Get source and destination points */
\r
3924 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3925 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3928 d_y += squareSize / 4;
\r
3930 else if( d_y < s_y ) {
\r
3931 d_y += 3 * squareSize / 4;
\r
3934 d_y += squareSize / 2;
\r
3938 d_x += squareSize / 4;
\r
3940 else if( d_x < s_x ) {
\r
3941 d_x += 3 * squareSize / 4;
\r
3944 d_x += squareSize / 2;
\r
3947 s_x += squareSize / 2;
\r
3948 s_y += squareSize / 2;
\r
3950 /* Adjust width */
\r
3951 A_WIDTH = squareSize / 14;
\r
3954 stLB.lbStyle = BS_SOLID;
\r
3955 stLB.lbColor = appData.highlightArrowColor;
\r
3958 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3959 holdpen = SelectObject( hdc, hpen );
\r
3960 hbrush = CreateBrushIndirect( &stLB );
\r
3961 holdbrush = SelectObject( hdc, hbrush );
\r
3963 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3965 SelectObject( hdc, holdpen );
\r
3966 SelectObject( hdc, holdbrush );
\r
3967 DeleteObject( hpen );
\r
3968 DeleteObject( hbrush );
\r
3971 BOOL HasHighlightInfo()
\r
3973 BOOL result = FALSE;
\r
3975 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3976 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3984 BOOL IsDrawArrowEnabled()
\r
3986 BOOL result = FALSE;
\r
3988 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3995 VOID DrawArrowHighlight( HDC hdc )
\r
3997 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3998 DrawArrowBetweenSquares( hdc,
\r
3999 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
4000 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
4004 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
4006 HRGN result = NULL;
\r
4008 if( HasHighlightInfo() ) {
\r
4009 int x1, y1, x2, y2;
\r
4010 int sx, sy, dx, dy;
\r
4012 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
4013 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
4015 sx = MIN( x1, x2 );
\r
4016 sy = MIN( y1, y2 );
\r
4017 dx = MAX( x1, x2 ) + squareSize;
\r
4018 dy = MAX( y1, y2 ) + squareSize;
\r
4020 result = CreateRectRgn( sx, sy, dx, dy );
\r
4027 Warning: this function modifies the behavior of several other functions.
\r
4029 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
4030 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
4031 repaint is scattered all over the place, which is not good for features such as
\r
4032 "arrow highlighting" that require a full repaint of the board.
\r
4034 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
4035 user interaction, when speed is not so important) but especially to avoid errors
\r
4036 in the displayed graphics.
\r
4038 In such patched places, I always try refer to this function so there is a single
\r
4039 place to maintain knowledge.
\r
4041 To restore the original behavior, just return FALSE unconditionally.
\r
4043 BOOL IsFullRepaintPreferrable()
\r
4045 BOOL result = FALSE;
\r
4047 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
4048 /* Arrow may appear on the board */
\r
4056 This function is called by DrawPosition to know whether a full repaint must
\r
4059 Only DrawPosition may directly call this function, which makes use of
\r
4060 some state information. Other function should call DrawPosition specifying
\r
4061 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4063 BOOL DrawPositionNeedsFullRepaint()
\r
4065 BOOL result = FALSE;
\r
4068 Probably a slightly better policy would be to trigger a full repaint
\r
4069 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4070 but animation is fast enough that it's difficult to notice.
\r
4072 if( animInfo.piece == EmptySquare ) {
\r
4073 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4082 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4084 int row, column, x, y, square_color, piece_color;
\r
4085 ChessSquare piece;
\r
4087 HDC texture_hdc = NULL;
\r
4089 /* [AS] Initialize background textures if needed */
\r
4090 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4091 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4092 if( backTextureSquareSize != squareSize
\r
4093 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4094 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4095 backTextureSquareSize = squareSize;
\r
4096 RebuildTextureSquareInfo();
\r
4099 texture_hdc = CreateCompatibleDC( hdc );
\r
4102 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4103 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4105 SquareToPos(row, column, &x, &y);
\r
4107 piece = board[row][column];
\r
4109 square_color = ((column + row) % 2) == 1;
\r
4110 if( gameInfo.variant == VariantXiangqi ) {
\r
4111 square_color = !InPalace(row, column);
\r
4112 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4113 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4115 piece_color = (int) piece < (int) BlackPawn;
\r
4118 /* [HGM] holdings file: light square or black */
\r
4119 if(column == BOARD_LEFT-2) {
\r
4120 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4123 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4127 if(column == BOARD_RGHT + 1 ) {
\r
4128 if( row < gameInfo.holdingsSize )
\r
4131 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4135 if(column == BOARD_LEFT-1 ) /* left align */
\r
4136 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4137 else if( column == BOARD_RGHT) /* right align */
\r
4138 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4140 if (appData.monoMode) {
\r
4141 if (piece == EmptySquare) {
\r
4142 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4143 square_color ? WHITENESS : BLACKNESS);
\r
4145 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4148 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4149 /* [AS] Draw the square using a texture bitmap */
\r
4150 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4151 int r = row, c = column; // [HGM] do not flip board in flipView
\r
4152 if(flipView) { r = BOARD_HEIGHT-1 - r; c = BOARD_WIDTH-1 - c; }
\r
4155 squareSize, squareSize,
\r
4158 backTextureSquareInfo[r][c].mode,
\r
4159 backTextureSquareInfo[r][c].x,
\r
4160 backTextureSquareInfo[r][c].y );
\r
4162 SelectObject( texture_hdc, hbm );
\r
4164 if (piece != EmptySquare) {
\r
4165 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4169 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4171 oldBrush = SelectObject(hdc, brush );
\r
4172 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4173 SelectObject(hdc, oldBrush);
\r
4174 if (piece != EmptySquare)
\r
4175 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4180 if( texture_hdc != NULL ) {
\r
4181 DeleteDC( texture_hdc );
\r
4185 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4186 void fputDW(FILE *f, int x)
\r
4188 fputc(x & 255, f);
\r
4189 fputc(x>>8 & 255, f);
\r
4190 fputc(x>>16 & 255, f);
\r
4191 fputc(x>>24 & 255, f);
\r
4194 #define MAX_CLIPS 200 /* more than enough */
\r
4197 DrawLogoOnDC(HDC hdc, RECT logoRect, ChessProgramState *cps)
\r
4199 HBITMAP bufferBitmap;
\r
4204 int w = 100, h = 50;
\r
4206 if(cps->programLogo == NULL) return;
\r
4207 // GetClientRect(hwndMain, &Rect);
\r
4208 // bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4209 // Rect.bottom-Rect.top+1);
\r
4210 tmphdc = CreateCompatibleDC(hdc);
\r
4211 hbm = SelectObject(tmphdc, (HBITMAP) cps->programLogo);
\r
4212 if( GetObject( cps->programLogo, sizeof(bi), &bi ) > 0 ) {
\r
4216 StretchBlt(hdc, logoRect.left, logoRect.top, logoRect.right - logoRect.left,
\r
4217 logoRect.bottom - logoRect.top, tmphdc, 0, 0, w, h, SRCCOPY);
\r
4218 SelectObject(tmphdc, hbm);
\r
4223 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4225 static Board lastReq, lastDrawn;
\r
4226 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4227 static int lastDrawnFlipView = 0;
\r
4228 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4229 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4232 HBITMAP bufferBitmap;
\r
4233 HBITMAP oldBitmap;
\r
4235 HRGN clips[MAX_CLIPS];
\r
4236 ChessSquare dragged_piece = EmptySquare;
\r
4238 /* I'm undecided on this - this function figures out whether a full
\r
4239 * repaint is necessary on its own, so there's no real reason to have the
\r
4240 * caller tell it that. I think this can safely be set to FALSE - but
\r
4241 * if we trust the callers not to request full repaints unnessesarily, then
\r
4242 * we could skip some clipping work. In other words, only request a full
\r
4243 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4244 * gamestart and similar) --Hawk
\r
4246 Boolean fullrepaint = repaint;
\r
4248 if( DrawPositionNeedsFullRepaint() ) {
\r
4249 fullrepaint = TRUE;
\r
4253 if( fullrepaint ) {
\r
4254 static int repaint_count = 0;
\r
4258 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4259 OutputDebugString( buf );
\r
4263 if (board == NULL) {
\r
4264 if (!lastReqValid) {
\r
4269 CopyBoard(lastReq, board);
\r
4273 if (doingSizing) {
\r
4277 if (IsIconic(hwndMain)) {
\r
4281 if (hdc == NULL) {
\r
4282 hdc = GetDC(hwndMain);
\r
4283 if (!appData.monoMode) {
\r
4284 SelectPalette(hdc, hPal, FALSE);
\r
4285 RealizePalette(hdc);
\r
4289 releaseDC = FALSE;
\r
4293 fprintf(debugFP, "*******************************\n"
\r
4295 "dragInfo.from (%d,%d)\n"
\r
4296 "dragInfo.start (%d,%d)\n"
\r
4297 "dragInfo.pos (%d,%d)\n"
\r
4298 "dragInfo.lastpos (%d,%d)\n",
\r
4299 repaint ? "TRUE" : "FALSE",
\r
4300 dragInfo.from.x, dragInfo.from.y,
\r
4301 dragInfo.start.x, dragInfo.start.y,
\r
4302 dragInfo.pos.x, dragInfo.pos.y,
\r
4303 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4304 fprintf(debugFP, "prev: ");
\r
4305 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4306 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4307 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4310 fprintf(debugFP, "\n");
\r
4311 fprintf(debugFP, "board: ");
\r
4312 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4313 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4314 fprintf(debugFP, "%d ", board[row][column]);
\r
4317 fprintf(debugFP, "\n");
\r
4321 /* Create some work-DCs */
\r
4322 hdcmem = CreateCompatibleDC(hdc);
\r
4323 tmphdc = CreateCompatibleDC(hdc);
\r
4325 /* If dragging is in progress, we temporarely remove the piece */
\r
4326 /* [HGM] or temporarily decrease count if stacked */
\r
4327 /* !! Moved to before board compare !! */
\r
4328 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4329 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4330 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4331 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4332 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4334 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4335 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4336 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4338 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4341 /* Figure out which squares need updating by comparing the
\r
4342 * newest board with the last drawn board and checking if
\r
4343 * flipping has changed.
\r
4345 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4346 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4347 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4348 if (lastDrawn[row][column] != board[row][column]) {
\r
4349 SquareToPos(row, column, &x, &y);
\r
4350 clips[num_clips++] =
\r
4351 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4355 for (i=0; i<2; i++) {
\r
4356 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4357 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4358 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4359 lastDrawnHighlight.sq[i].y >= 0) {
\r
4360 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4361 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4362 clips[num_clips++] =
\r
4363 CreateRectRgn(x - lineGap, y - lineGap,
\r
4364 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4366 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4367 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4368 clips[num_clips++] =
\r
4369 CreateRectRgn(x - lineGap, y - lineGap,
\r
4370 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4374 for (i=0; i<2; i++) {
\r
4375 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4376 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4377 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4378 lastDrawnPremove.sq[i].y >= 0) {
\r
4379 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4380 lastDrawnPremove.sq[i].x, &x, &y);
\r
4381 clips[num_clips++] =
\r
4382 CreateRectRgn(x - lineGap, y - lineGap,
\r
4383 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4385 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4386 premoveHighlightInfo.sq[i].y >= 0) {
\r
4387 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4388 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4389 clips[num_clips++] =
\r
4390 CreateRectRgn(x - lineGap, y - lineGap,
\r
4391 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4396 fullrepaint = TRUE;
\r
4399 /* Create a buffer bitmap - this is the actual bitmap
\r
4400 * being written to. When all the work is done, we can
\r
4401 * copy it to the real DC (the screen). This avoids
\r
4402 * the problems with flickering.
\r
4404 GetClientRect(hwndMain, &Rect);
\r
4405 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4406 Rect.bottom-Rect.top+1);
\r
4407 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4408 if (!appData.monoMode) {
\r
4409 SelectPalette(hdcmem, hPal, FALSE);
\r
4412 /* Create clips for dragging */
\r
4413 if (!fullrepaint) {
\r
4414 if (dragInfo.from.x >= 0) {
\r
4415 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4416 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4418 if (dragInfo.start.x >= 0) {
\r
4419 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4420 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4422 if (dragInfo.pos.x >= 0) {
\r
4423 x = dragInfo.pos.x - squareSize / 2;
\r
4424 y = dragInfo.pos.y - squareSize / 2;
\r
4425 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4427 if (dragInfo.lastpos.x >= 0) {
\r
4428 x = dragInfo.lastpos.x - squareSize / 2;
\r
4429 y = dragInfo.lastpos.y - squareSize / 2;
\r
4430 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4434 /* Are we animating a move?
\r
4436 * - remove the piece from the board (temporarely)
\r
4437 * - calculate the clipping region
\r
4439 if (!fullrepaint) {
\r
4440 if (animInfo.piece != EmptySquare) {
\r
4441 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4442 x = boardRect.left + animInfo.lastpos.x;
\r
4443 y = boardRect.top + animInfo.lastpos.y;
\r
4444 x2 = boardRect.left + animInfo.pos.x;
\r
4445 y2 = boardRect.top + animInfo.pos.y;
\r
4446 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4447 /* Slight kludge. The real problem is that after AnimateMove is
\r
4448 done, the position on the screen does not match lastDrawn.
\r
4449 This currently causes trouble only on e.p. captures in
\r
4450 atomic, where the piece moves to an empty square and then
\r
4451 explodes. The old and new positions both had an empty square
\r
4452 at the destination, but animation has drawn a piece there and
\r
4453 we have to remember to erase it. */
\r
4454 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4458 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4459 if (num_clips == 0)
\r
4460 fullrepaint = TRUE;
\r
4462 /* Set clipping on the memory DC */
\r
4463 if (!fullrepaint) {
\r
4464 SelectClipRgn(hdcmem, clips[0]);
\r
4465 for (x = 1; x < num_clips; x++) {
\r
4466 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4467 abort(); // this should never ever happen!
\r
4471 /* Do all the drawing to the memory DC */
\r
4472 DrawGridOnDC(hdcmem);
\r
4473 DrawHighlightsOnDC(hdcmem);
\r
4474 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4477 DrawLogoOnDC(hdc, leftLogoRect, flipClock ? &second : &first);
\r
4478 DrawLogoOnDC(hdc, rightLogoRect, flipClock ? &first : &second);
\r
4481 if( appData.highlightMoveWithArrow ) {
\r
4482 DrawArrowHighlight(hdcmem);
\r
4485 DrawCoordsOnDC(hdcmem);
\r
4487 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4488 /* to make sure lastDrawn contains what is actually drawn */
\r
4490 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4491 if (dragged_piece != EmptySquare) {
\r
4492 /* [HGM] or restack */
\r
4493 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4494 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4496 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4497 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4498 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4499 x = dragInfo.pos.x - squareSize / 2;
\r
4500 y = dragInfo.pos.y - squareSize / 2;
\r
4501 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4502 ((int) dragged_piece < (int) BlackPawn),
\r
4503 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4506 /* Put the animated piece back into place and draw it */
\r
4507 if (animInfo.piece != EmptySquare) {
\r
4508 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4509 x = boardRect.left + animInfo.pos.x;
\r
4510 y = boardRect.top + animInfo.pos.y;
\r
4511 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4512 ((int) animInfo.piece < (int) BlackPawn),
\r
4513 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4516 /* Release the bufferBitmap by selecting in the old bitmap
\r
4517 * and delete the memory DC
\r
4519 SelectObject(hdcmem, oldBitmap);
\r
4522 /* Set clipping on the target DC */
\r
4523 if (!fullrepaint) {
\r
4524 SelectClipRgn(hdc, clips[0]);
\r
4525 for (x = 1; x < num_clips; x++) {
\r
4526 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4527 abort(); // this should never ever happen!
\r
4531 /* Copy the new bitmap onto the screen in one go.
\r
4532 * This way we avoid any flickering
\r
4534 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4535 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4536 boardRect.right - boardRect.left,
\r
4537 boardRect.bottom - boardRect.top,
\r
4538 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4539 if(saveDiagFlag) {
\r
4540 BITMAP b; int i, j, m, w, wb, fac=0; char pData[1000000];
\r
4541 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4543 GetObject(bufferBitmap, sizeof(b), &b);
\r
4544 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4545 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4546 bih.biWidth = b.bmWidth;
\r
4547 bih.biHeight = b.bmHeight;
\r
4549 bih.biBitCount = b.bmBitsPixel;
\r
4550 bih.biCompression = 0;
\r
4551 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4552 bih.biXPelsPerMeter = 0;
\r
4553 bih.biYPelsPerMeter = 0;
\r
4554 bih.biClrUsed = 0;
\r
4555 bih.biClrImportant = 0;
\r
4556 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4557 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4558 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4559 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4562 wb = b.bmWidthBytes;
\r
4564 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4565 int k = ((int*) pData)[i];
\r
4566 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4567 if(j >= 16) break;
\r
4569 if(j >= nrColors) nrColors = j+1;
\r
4571 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4573 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4574 for(w=0; w<(wb>>2); w+=2) {
\r
4575 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4576 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4577 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4578 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4579 pData[p++] = m | j<<4;
\r
4581 while(p&3) pData[p++] = 0;
\r
4584 wb = (wb+31>>5)<<2;
\r
4586 // write BITMAPFILEHEADER
\r
4587 fprintf(diagFile, "BM");
\r
4588 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4589 fputDW(diagFile, 0);
\r
4590 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4591 // write BITMAPINFOHEADER
\r
4592 fputDW(diagFile, 40);
\r
4593 fputDW(diagFile, b.bmWidth);
\r
4594 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4595 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4596 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4597 fputDW(diagFile, 0);
\r
4598 fputDW(diagFile, 0);
\r
4599 fputDW(diagFile, 0);
\r
4600 fputDW(diagFile, 0);
\r
4601 fputDW(diagFile, 0);
\r
4602 fputDW(diagFile, 0);
\r
4603 // write color table
\r
4605 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4606 // write bitmap data
\r
4607 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4608 fputc(pData[i], diagFile);
\r
4613 SelectObject(tmphdc, oldBitmap);
\r
4615 /* Massive cleanup */
\r
4616 for (x = 0; x < num_clips; x++)
\r
4617 DeleteObject(clips[x]);
\r
4620 DeleteObject(bufferBitmap);
\r
4623 ReleaseDC(hwndMain, hdc);
\r
4625 if (lastDrawnFlipView != flipView) {
\r
4627 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4629 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4632 /* CopyBoard(lastDrawn, board);*/
\r
4633 lastDrawnHighlight = highlightInfo;
\r
4634 lastDrawnPremove = premoveHighlightInfo;
\r
4635 lastDrawnFlipView = flipView;
\r
4636 lastDrawnValid = 1;
\r
4639 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4647 saveDiagFlag = 1; diagFile = f;
\r
4648 HDCDrawPosition(NULL, TRUE, NULL);
\r
4652 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4659 /*---------------------------------------------------------------------------*\
\r
4660 | CLIENT PAINT PROCEDURE
\r
4661 | This is the main event-handler for the WM_PAINT message.
\r
4663 \*---------------------------------------------------------------------------*/
\r
4665 PaintProc(HWND hwnd)
\r
4671 if(hdc = BeginPaint(hwnd, &ps)) {
\r
4672 if (IsIconic(hwnd)) {
\r
4673 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4675 if (!appData.monoMode) {
\r
4676 SelectPalette(hdc, hPal, FALSE);
\r
4677 RealizePalette(hdc);
\r
4679 HDCDrawPosition(hdc, 1, NULL);
\r
4681 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4682 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4683 ETO_CLIPPED|ETO_OPAQUE,
\r
4684 &messageRect, messageText, strlen(messageText), NULL);
\r
4685 SelectObject(hdc, oldFont);
\r
4686 DisplayBothClocks();
\r
4688 EndPaint(hwnd,&ps);
\r
4696 * If the user selects on a border boundary, return -1; if off the board,
\r
4697 * return -2. Otherwise map the event coordinate to the square.
\r
4698 * The offset boardRect.left or boardRect.top must already have been
\r
4699 * subtracted from x.
\r
4702 EventToSquare(int x)
\r
4709 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4711 x /= (squareSize + lineGap);
\r
4712 if (x >= BOARD_SIZE)
\r
4723 DropEnable dropEnables[] = {
\r
4724 { 'P', DP_Pawn, "Pawn" },
\r
4725 { 'N', DP_Knight, "Knight" },
\r
4726 { 'B', DP_Bishop, "Bishop" },
\r
4727 { 'R', DP_Rook, "Rook" },
\r
4728 { 'Q', DP_Queen, "Queen" },
\r
4732 SetupDropMenu(HMENU hmenu)
\r
4734 int i, count, enable;
\r
4736 extern char white_holding[], black_holding[];
\r
4737 char item[MSG_SIZ];
\r
4739 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4740 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4741 dropEnables[i].piece);
\r
4743 while (p && *p++ == dropEnables[i].piece) count++;
\r
4744 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4745 enable = count > 0 || !appData.testLegality
\r
4746 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4747 && !appData.icsActive);
\r
4748 ModifyMenu(hmenu, dropEnables[i].command,
\r
4749 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4750 dropEnables[i].command, item);
\r
4754 static int fromX = -1, fromY = -1, toX, toY;
\r
4756 /* Event handler for mouse messages */
\r
4758 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4762 static int recursive = 0;
\r
4764 BOOLEAN needsRedraw = FALSE;
\r
4765 BOOLEAN saveAnimate;
\r
4766 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4767 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4768 ChessMove moveType;
\r
4771 if (message == WM_MBUTTONUP) {
\r
4772 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4773 to the middle button: we simulate pressing the left button too!
\r
4775 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4776 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4782 pt.x = LOWORD(lParam);
\r
4783 pt.y = HIWORD(lParam);
\r
4784 x = EventToSquare(pt.x - boardRect.left);
\r
4785 y = EventToSquare(pt.y - boardRect.top);
\r
4786 if (!flipView && y >= 0) {
\r
4787 y = BOARD_HEIGHT - 1 - y;
\r
4789 if (flipView && x >= 0) {
\r
4790 x = BOARD_WIDTH - 1 - x;
\r
4793 switch (message) {
\r
4794 case WM_LBUTTONDOWN:
\r
4795 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4796 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4797 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4798 if(gameInfo.holdingsWidth &&
\r
4799 (WhiteOnMove(currentMove)
\r
4800 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4801 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4802 // click in right holdings, for determining promotion piece
\r
4803 ChessSquare p = boards[currentMove][y][x];
\r
4804 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4805 if(p != EmptySquare) {
\r
4806 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4807 fromX = fromY = -1;
\r
4811 DrawPosition(FALSE, boards[currentMove]);
\r
4815 sameAgain = FALSE;
\r
4817 /* Downclick vertically off board; check if on clock */
\r
4818 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4819 if (gameMode == EditPosition) {
\r
4820 SetWhiteToPlayEvent();
\r
4821 } else if (gameMode == IcsPlayingBlack ||
\r
4822 gameMode == MachinePlaysWhite) {
\r
4824 } else if (gameMode == EditGame) {
\r
4825 AdjustClock((logoHeight > 0 ? flipView: flipClock), -1);
\r
4827 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4828 if (gameMode == EditPosition) {
\r
4829 SetBlackToPlayEvent();
\r
4830 } else if (gameMode == IcsPlayingWhite ||
\r
4831 gameMode == MachinePlaysBlack) {
\r
4833 } else if (gameMode == EditGame) {
\r
4834 AdjustClock(!(logoHeight > 0 ? flipView: flipClock), -1);
\r
4837 if (!appData.highlightLastMove) {
\r
4838 ClearHighlights();
\r
4839 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4841 fromX = fromY = -1;
\r
4842 dragInfo.start.x = dragInfo.start.y = -1;
\r
4843 dragInfo.from = dragInfo.start;
\r
4845 } else if (x < 0 || y < 0
\r
4846 /* [HGM] block clicks between board and holdings */
\r
4847 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4848 || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
\r
4849 || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize
\r
4850 /* EditPosition, empty square, or different color piece;
\r
4851 click-click move is possible */
\r
4854 } else if (fromX == x && fromY == y) {
\r
4855 /* Downclick on same square again */
\r
4856 ClearHighlights();
\r
4857 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4858 sameAgain = TRUE;
\r
4859 } else if (fromX != -1 &&
\r
4860 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4862 /* Downclick on different square. */
\r
4863 /* [HGM] if on holdings file, should count as new first click ! */
\r
4864 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4867 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4868 to make sure move is legal before showing promotion popup */
\r
4869 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4870 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4871 fromX = fromY = -1;
\r
4872 ClearHighlights();
\r
4873 DrawPosition(FALSE, boards[currentMove]);
\r
4876 if(moveType != ImpossibleMove) {
\r
4877 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4878 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4879 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4880 appData.alwaysPromoteToQueen) {
\r
4881 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4882 if (!appData.highlightLastMove) {
\r
4883 ClearHighlights();
\r
4884 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4887 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4888 SetHighlights(fromX, fromY, toX, toY);
\r
4889 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4890 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4891 If promotion to Q is legal, all are legal! */
\r
4892 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4893 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4894 // kludge to temporarily execute move on display, wthout promotng yet
\r
4895 promotionChoice = TRUE;
\r
4896 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4897 boards[currentMove][toY][toX] = p;
\r
4898 DrawPosition(FALSE, boards[currentMove]);
\r
4899 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4900 boards[currentMove][toY][toX] = q;
\r
4902 PromotionPopup(hwnd);
\r
4903 } else { /* not a promotion */
\r
4904 if (appData.animate || appData.highlightLastMove) {
\r
4905 SetHighlights(fromX, fromY, toX, toY);
\r
4907 ClearHighlights();
\r
4909 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4910 fromX = fromY = -1;
\r
4911 if (appData.animate && !appData.highlightLastMove) {
\r
4912 ClearHighlights();
\r
4913 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4919 /* [HGM] it seemed that braces were missing here */
\r
4920 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4921 fromX = fromY = -1;
\r
4925 ClearHighlights();
\r
4926 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4928 /* First downclick, or restart on a square with same color piece */
\r
4929 if (!frozen && OKToStartUserMove(x, y)) {
\r
4932 dragInfo.lastpos = pt;
\r
4933 dragInfo.from.x = fromX;
\r
4934 dragInfo.from.y = fromY;
\r
4935 dragInfo.start = dragInfo.from;
\r
4936 SetCapture(hwndMain);
\r
4938 fromX = fromY = -1;
\r
4939 dragInfo.start.x = dragInfo.start.y = -1;
\r
4940 dragInfo.from = dragInfo.start;
\r
4941 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4945 case WM_LBUTTONUP:
\r
4947 if (fromX == -1) break;
\r
4948 if (x == fromX && y == fromY) {
\r
4949 dragInfo.from.x = dragInfo.from.y = -1;
\r
4950 /* Upclick on same square */
\r
4952 /* Clicked same square twice: abort click-click move */
\r
4953 fromX = fromY = -1;
\r
4955 ClearPremoveHighlights();
\r
4957 /* First square clicked: start click-click move */
\r
4958 SetHighlights(fromX, fromY, -1, -1);
\r
4960 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4961 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4962 /* Errant click; ignore */
\r
4965 /* Finish drag move. */
\r
4966 if (appData.debugMode) {
\r
4967 fprintf(debugFP, "release\n");
\r
4969 dragInfo.from.x = dragInfo.from.y = -1;
\r
4972 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4973 appData.animate = appData.animate && !appData.animateDragging;
\r
4974 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4975 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4976 fromX = fromY = -1;
\r
4977 ClearHighlights();
\r
4978 DrawPosition(FALSE, boards[currentMove]);
\r
4981 if(moveType != ImpossibleMove) {
\r
4982 /* [HGM] use move type to determine if move is promotion.
\r
4983 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
4984 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4985 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4986 appData.alwaysPromoteToQueen)
\r
4987 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4989 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4990 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4991 if(gameInfo.variant == VariantSuper || gameInfo.variant == VariantGreat)
\r
4992 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4993 // kludge to temporarily execute move on display, wthout promotng yet
\r
4994 promotionChoice = TRUE;
\r
4995 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4996 boards[currentMove][toY][toX] = p;
\r
4997 DrawPosition(FALSE, boards[currentMove]);
\r
4998 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4999 boards[currentMove][toY][toX] = q;
\r
5002 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
5003 } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
5005 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
5006 appData.animate = saveAnimate;
\r
5007 fromX = fromY = -1;
\r
5008 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
5009 ClearHighlights();
\r
5011 if (appData.animate || appData.animateDragging ||
\r
5012 appData.highlightDragging || gotPremove) {
\r
5013 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
5016 dragInfo.start.x = dragInfo.start.y = -1;
\r
5017 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
5020 case WM_MOUSEMOVE:
\r
5021 if ((appData.animateDragging || appData.highlightDragging)
\r
5022 && (wParam & MK_LBUTTON)
\r
5023 && dragInfo.from.x >= 0)
\r
5025 BOOL full_repaint = FALSE;
\r
5027 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
5028 if (appData.animateDragging) {
\r
5029 dragInfo.pos = pt;
\r
5031 if (appData.highlightDragging) {
\r
5032 SetHighlights(fromX, fromY, x, y);
\r
5033 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
5034 full_repaint = TRUE;
\r
5038 DrawPosition( full_repaint, NULL);
\r
5040 dragInfo.lastpos = dragInfo.pos;
\r
5044 case WM_MOUSEWHEEL: // [DM]
\r
5045 /* Mouse Wheel is being rolled forward
\r
5046 * Play moves forward
\r
5048 if((short)HIWORD(wParam) > 0 && currentMove < forwardMostMove) ForwardEvent();
\r
5049 /* Mouse Wheel is being rolled backward
\r
5050 * Play moves backward
\r
5052 if((short)HIWORD(wParam) < 0 && currentMove > backwardMostMove) BackwardEvent();
\r
5055 case WM_MBUTTONDOWN:
\r
5056 case WM_RBUTTONDOWN:
\r
5059 fromX = fromY = -1;
\r
5060 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
5061 dragInfo.start.x = dragInfo.start.y = -1;
\r
5062 dragInfo.from = dragInfo.start;
\r
5063 dragInfo.lastpos = dragInfo.pos;
\r
5064 if (appData.highlightDragging) {
\r
5065 ClearHighlights();
\r
5068 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
5069 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
5070 if (gameMode == EditGame) AdjustClock((logoHeight > 0 ? flipView: flipClock), 1);
\r
5071 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
5072 if (gameMode == EditGame) AdjustClock(!(logoHeight > 0 ? flipView: flipClock), 1);
\r
5075 DrawPosition(TRUE, NULL);
\r
5077 switch (gameMode) {
\r
5078 case EditPosition:
\r
5079 case IcsExamining:
\r
5080 if (x < 0 || y < 0) break;
\r
5083 if (message == WM_MBUTTONDOWN) {
\r
5084 buttonCount = 3; /* even if system didn't think so */
\r
5085 if (wParam & MK_SHIFT)
\r
5086 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5088 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5089 } else { /* message == WM_RBUTTONDOWN */
\r
5091 if (buttonCount == 3) {
\r
5092 if (wParam & MK_SHIFT)
\r
5093 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
5095 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
5097 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5100 /* Just have one menu, on the right button. Windows users don't
\r
5101 think to try the middle one, and sometimes other software steals
\r
5102 it, or it doesn't really exist. */
\r
5103 if(gameInfo.variant != VariantShogi)
\r
5104 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5106 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5110 case IcsPlayingWhite:
\r
5111 case IcsPlayingBlack:
\r
5113 case MachinePlaysWhite:
\r
5114 case MachinePlaysBlack:
\r
5115 if (appData.testLegality &&
\r
5116 gameInfo.variant != VariantBughouse &&
\r
5117 gameInfo.variant != VariantCrazyhouse) break;
\r
5118 if (x < 0 || y < 0) break;
\r
5121 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5122 SetupDropMenu(hmenu);
\r
5123 MenuPopup(hwnd, pt, hmenu, -1);
\r
5134 /* Preprocess messages for buttons in main window */
\r
5136 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5138 int id = GetWindowLong(hwnd, GWL_ID);
\r
5141 for (i=0; i<N_BUTTONS; i++) {
\r
5142 if (buttonDesc[i].id == id) break;
\r
5144 if (i == N_BUTTONS) return 0;
\r
5145 switch (message) {
\r
5150 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5151 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5158 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5161 if (appData.icsActive) {
\r
5162 if (GetKeyState(VK_SHIFT) < 0) {
\r
5164 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5165 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5169 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5170 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5177 if (appData.icsActive) {
\r
5178 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5179 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5181 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5183 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5184 PopUpMoveDialog((char)wParam);
\r
5190 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5193 /* Process messages for Promotion dialog box */
\r
5195 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5199 switch (message) {
\r
5200 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5201 /* Center the dialog over the application window */
\r
5202 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5203 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5204 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5205 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5206 SW_SHOW : SW_HIDE);
\r
5207 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5208 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5209 (PieceToChar(WhiteAngel) >= 'A' &&
\r
5210 PieceToChar(WhiteAngel) != '~' ||
\r
5211 PieceToChar(BlackAngel) >= 'A' &&
\r
5212 PieceToChar(BlackAngel) != '~' ) ?
\r
5213 SW_SHOW : SW_HIDE);
\r
5214 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5215 (PieceToChar(WhiteMarshall) >= 'A' &&
\r
5216 PieceToChar(WhiteMarshall) != '~' ||
\r
5217 PieceToChar(BlackMarshall) >= 'A' &&
\r
5218 PieceToChar(BlackMarshall) != '~' ) ?
\r
5219 SW_SHOW : SW_HIDE);
\r
5220 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5221 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5222 gameInfo.variant != VariantShogi ?
\r
5223 SW_SHOW : SW_HIDE);
\r
5224 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5225 gameInfo.variant != VariantShogi ?
\r
5226 SW_SHOW : SW_HIDE);
\r
5227 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5228 gameInfo.variant == VariantShogi ?
\r
5229 SW_SHOW : SW_HIDE);
\r
5230 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5231 gameInfo.variant == VariantShogi ?
\r
5232 SW_SHOW : SW_HIDE);
\r
5233 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5234 gameInfo.variant == VariantSuper ?
\r
5235 SW_SHOW : SW_HIDE);
\r
5238 case WM_COMMAND: /* message: received a command */
\r
5239 switch (LOWORD(wParam)) {
\r
5241 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5242 ClearHighlights();
\r
5243 DrawPosition(FALSE, NULL);
\r
5246 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5249 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5252 promoChar = PieceToChar(BlackRook);
\r
5255 promoChar = PieceToChar(BlackBishop);
\r
5257 case PB_Chancellor:
\r
5258 promoChar = PieceToChar(BlackMarshall);
\r
5260 case PB_Archbishop:
\r
5261 promoChar = PieceToChar(BlackAngel);
\r
5264 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5269 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5270 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5271 only show the popup when we are already sure the move is valid or
\r
5272 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5273 will figure out it is a promotion from the promoChar. */
\r
5274 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5275 if (!appData.highlightLastMove) {
\r
5276 ClearHighlights();
\r
5277 DrawPosition(FALSE, NULL);
\r
5284 /* Pop up promotion dialog */
\r
5286 PromotionPopup(HWND hwnd)
\r
5290 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5291 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5292 hwnd, (DLGPROC)lpProc);
\r
5293 FreeProcInstance(lpProc);
\r
5296 /* Toggle ShowThinking */
\r
5298 ToggleShowThinking()
\r
5300 appData.showThinking = !appData.showThinking;
\r
5301 ShowThinkingEvent();
\r
5305 LoadGameDialog(HWND hwnd, char* title)
\r
5309 char fileTitle[MSG_SIZ];
\r
5310 f = OpenFileDialog(hwnd, "rb", "",
\r
5311 appData.oldSaveStyle ? "gam" : "pgn",
\r
5313 title, &number, fileTitle, NULL);
\r
5315 cmailMsgLoaded = FALSE;
\r
5316 if (number == 0) {
\r
5317 int error = GameListBuild(f);
\r
5319 DisplayError("Cannot build game list", error);
\r
5320 } else if (!ListEmpty(&gameList) &&
\r
5321 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5322 GameListPopUp(f, fileTitle);
\r
5325 GameListDestroy();
\r
5328 LoadGame(f, number, fileTitle, FALSE);
\r
5333 ChangedConsoleFont()
\r
5336 CHARRANGE tmpsel, sel;
\r
5337 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5338 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5339 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5342 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5343 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5344 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5345 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5346 * size. This was undocumented in the version of MSVC++ that I had
\r
5347 * when I wrote the code, but is apparently documented now.
\r
5349 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5350 cfmt.bCharSet = f->lf.lfCharSet;
\r
5351 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5352 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5353 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5354 /* Why are the following seemingly needed too? */
\r
5355 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5356 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5357 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5359 tmpsel.cpMax = -1; /*999999?*/
\r
5360 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5361 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5362 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5363 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5365 paraf.cbSize = sizeof(paraf);
\r
5366 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5367 paraf.dxStartIndent = 0;
\r
5368 paraf.dxOffset = WRAP_INDENT;
\r
5369 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5370 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5373 /*---------------------------------------------------------------------------*\
\r
5375 * Window Proc for main window
\r
5377 \*---------------------------------------------------------------------------*/
\r
5379 /* Process messages for main window, etc. */
\r
5381 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5384 int wmId, wmEvent;
\r
5388 char fileTitle[MSG_SIZ];
\r
5389 char buf[MSG_SIZ];
\r
5390 static SnapData sd;
\r
5392 switch (message) {
\r
5394 case WM_PAINT: /* message: repaint portion of window */
\r
5398 case WM_ERASEBKGND:
\r
5399 if (IsIconic(hwnd)) {
\r
5400 /* Cheat; change the message */
\r
5401 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5403 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5407 case WM_LBUTTONDOWN:
\r
5408 case WM_MBUTTONDOWN:
\r
5409 case WM_RBUTTONDOWN:
\r
5410 case WM_LBUTTONUP:
\r
5411 case WM_MBUTTONUP:
\r
5412 case WM_RBUTTONUP:
\r
5413 case WM_MOUSEMOVE:
\r
5414 case WM_MOUSEWHEEL:
\r
5415 MouseEvent(hwnd, message, wParam, lParam);
\r
5420 if (appData.icsActive) {
\r
5421 if (wParam == '\t') {
\r
5422 if (GetKeyState(VK_SHIFT) < 0) {
\r
5424 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5425 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5429 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5430 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5434 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5435 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5437 SendMessage(h, message, wParam, lParam);
\r
5439 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5440 PopUpMoveDialog((char)wParam);
\r
5444 case WM_PALETTECHANGED:
\r
5445 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5447 HDC hdc = GetDC(hwndMain);
\r
5448 SelectPalette(hdc, hPal, TRUE);
\r
5449 nnew = RealizePalette(hdc);
\r
5451 paletteChanged = TRUE;
\r
5453 UpdateColors(hdc);
\r
5455 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5458 ReleaseDC(hwnd, hdc);
\r
5462 case WM_QUERYNEWPALETTE:
\r
5463 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5465 HDC hdc = GetDC(hwndMain);
\r
5466 paletteChanged = FALSE;
\r
5467 SelectPalette(hdc, hPal, FALSE);
\r
5468 nnew = RealizePalette(hdc);
\r
5470 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5472 ReleaseDC(hwnd, hdc);
\r
5477 case WM_COMMAND: /* message: command from application menu */
\r
5478 wmId = LOWORD(wParam);
\r
5479 wmEvent = HIWORD(wParam);
\r
5484 AnalysisPopDown();
\r
5487 case IDM_NewGameFRC:
\r
5488 if( NewGameFRC() == 0 ) {
\r
5490 AnalysisPopDown();
\r
5494 case IDM_NewVariant:
\r
5495 NewVariantPopup(hwnd);
\r
5498 case IDM_LoadGame:
\r
5499 LoadGameDialog(hwnd, "Load Game from File");
\r
5502 case IDM_LoadNextGame:
\r
5506 case IDM_LoadPrevGame:
\r
5510 case IDM_ReloadGame:
\r
5514 case IDM_LoadPosition:
\r
5515 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5516 Reset(FALSE, TRUE);
\r
5519 f = OpenFileDialog(hwnd, "rb", "",
\r
5520 appData.oldSaveStyle ? "pos" : "fen",
\r
5522 "Load Position from File", &number, fileTitle, NULL);
\r
5524 LoadPosition(f, number, fileTitle);
\r
5528 case IDM_LoadNextPosition:
\r
5529 ReloadPosition(1);
\r
5532 case IDM_LoadPrevPosition:
\r
5533 ReloadPosition(-1);
\r
5536 case IDM_ReloadPosition:
\r
5537 ReloadPosition(0);
\r
5540 case IDM_SaveGame:
\r
5541 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5542 f = OpenFileDialog(hwnd, "a", defName,
\r
5543 appData.oldSaveStyle ? "gam" : "pgn",
\r
5545 "Save Game to File", NULL, fileTitle, NULL);
\r
5547 SaveGame(f, 0, "");
\r
5551 case IDM_SavePosition:
\r
5552 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5553 f = OpenFileDialog(hwnd, "a", defName,
\r
5554 appData.oldSaveStyle ? "pos" : "fen",
\r
5556 "Save Position to File", NULL, fileTitle, NULL);
\r
5558 SavePosition(f, 0, "");
\r
5562 case IDM_SaveDiagram:
\r
5563 defName = "diagram";
\r
5564 f = OpenFileDialog(hwnd, "wb", defName,
\r
5567 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5573 case IDM_CopyGame:
\r
5574 CopyGameToClipboard();
\r
5577 case IDM_PasteGame:
\r
5578 PasteGameFromClipboard();
\r
5581 case IDM_CopyGameListToClipboard:
\r
5582 CopyGameListToClipboard();
\r
5585 /* [AS] Autodetect FEN or PGN data */
\r
5586 case IDM_PasteAny:
\r
5587 PasteGameOrFENFromClipboard();
\r
5590 /* [AS] Move history */
\r
5591 case IDM_ShowMoveHistory:
\r
5592 if( MoveHistoryIsUp() ) {
\r
5593 MoveHistoryPopDown();
\r
5596 MoveHistoryPopUp();
\r
5600 /* [AS] Eval graph */
\r
5601 case IDM_ShowEvalGraph:
\r
5602 if( EvalGraphIsUp() ) {
\r
5603 EvalGraphPopDown();
\r
5610 /* [AS] Engine output */
\r
5611 case IDM_ShowEngineOutput:
\r
5612 if( EngineOutputIsUp() ) {
\r
5613 EngineOutputPopDown();
\r
5616 EngineOutputPopUp();
\r
5620 /* [AS] User adjudication */
\r
5621 case IDM_UserAdjudication_White:
\r
5622 UserAdjudicationEvent( +1 );
\r
5625 case IDM_UserAdjudication_Black:
\r
5626 UserAdjudicationEvent( -1 );
\r
5629 case IDM_UserAdjudication_Draw:
\r
5630 UserAdjudicationEvent( 0 );
\r
5633 /* [AS] Game list options dialog */
\r
5634 case IDM_GameListOptions:
\r
5635 GameListOptions();
\r
5638 case IDM_CopyPosition:
\r
5639 CopyFENToClipboard();
\r
5642 case IDM_PastePosition:
\r
5643 PasteFENFromClipboard();
\r
5646 case IDM_MailMove:
\r
5650 case IDM_ReloadCMailMsg:
\r
5651 Reset(TRUE, TRUE);
\r
5652 ReloadCmailMsgEvent(FALSE);
\r
5655 case IDM_Minimize:
\r
5656 ShowWindow(hwnd, SW_MINIMIZE);
\r
5663 case IDM_MachineWhite:
\r
5664 MachineWhiteEvent();
\r
5666 * refresh the tags dialog only if it's visible
\r
5668 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5670 tags = PGNTags(&gameInfo);
\r
5671 TagsPopUp(tags, CmailMsg());
\r
5676 case IDM_MachineBlack:
\r
5677 MachineBlackEvent();
\r
5679 * refresh the tags dialog only if it's visible
\r
5681 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5683 tags = PGNTags(&gameInfo);
\r
5684 TagsPopUp(tags, CmailMsg());
\r
5689 case IDM_TwoMachines:
\r
5690 TwoMachinesEvent();
\r
5692 * refresh the tags dialog only if it's visible
\r
5694 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5696 tags = PGNTags(&gameInfo);
\r
5697 TagsPopUp(tags, CmailMsg());
\r
5702 case IDM_AnalysisMode:
\r
5703 if (!first.analysisSupport) {
\r
5704 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5705 DisplayError(buf, 0);
\r
5707 /* [DM] icsEngineAnlyze [HGM] Why is this front-end??? */
\r
5708 if (appData.icsActive) {
\r
5709 if (gameMode != IcsObserving) {
\r
5710 sprintf(buf, "You are not observing a game");
\r
5711 DisplayError(buf, 0);
\r
5712 /* secure check */
\r
5713 if (appData.icsEngineAnalyze) {
\r
5714 if (appData.debugMode)
\r
5715 fprintf(debugFP, "Found unexpected active ICS engine analyze \n");
\r
5716 ExitAnalyzeMode();
\r
5722 /* if enable, user want disable icsEngineAnalyze */
\r
5723 if (appData.icsEngineAnalyze) {
\r
5724 ExitAnalyzeMode();
\r
5728 appData.icsEngineAnalyze = TRUE;
\r
5729 if (appData.debugMode) fprintf(debugFP, "ICS engine analyze starting...\n");
\r
5732 if (!appData.showThinking) ToggleShowThinking();
\r
5733 AnalyzeModeEvent();
\r
5737 case IDM_AnalyzeFile:
\r
5738 if (!first.analysisSupport) {
\r
5739 char buf[MSG_SIZ];
\r
5740 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5741 DisplayError(buf, 0);
\r
5743 if (!appData.showThinking) ToggleShowThinking();
\r
5744 AnalyzeFileEvent();
\r
5745 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5746 AnalysisPeriodicEvent(1);
\r
5750 case IDM_IcsClient:
\r
5754 case IDM_EditGame:
\r
5758 case IDM_EditPosition:
\r
5759 EditPositionEvent();
\r
5762 case IDM_Training:
\r
5766 case IDM_ShowGameList:
\r
5767 ShowGameListProc();
\r
5770 case IDM_EditTags:
\r
5774 case IDM_EditComment:
\r
5775 if (commentDialogUp && editComment) {
\r
5778 EditCommentEvent();
\r
5798 case IDM_CallFlag:
\r
5818 case IDM_StopObserving:
\r
5819 StopObservingEvent();
\r
5822 case IDM_StopExamining:
\r
5823 StopExaminingEvent();
\r
5826 case IDM_TypeInMove:
\r
5827 PopUpMoveDialog('\000');
\r
5830 case IDM_TypeInName:
\r
5831 PopUpNameDialog('\000');
\r
5834 case IDM_Backward:
\r
5836 SetFocus(hwndMain);
\r
5841 SetFocus(hwndMain);
\r
5846 SetFocus(hwndMain);
\r
5851 SetFocus(hwndMain);
\r
5858 case IDM_TruncateGame:
\r
5859 TruncateGameEvent();
\r
5866 case IDM_RetractMove:
\r
5867 RetractMoveEvent();
\r
5870 case IDM_FlipView:
\r
5871 flipView = !flipView;
\r
5872 DrawPosition(FALSE, NULL);
\r
5875 case IDM_FlipClock:
\r
5876 flipClock = !flipClock;
\r
5877 DisplayBothClocks();
\r
5880 case IDM_GeneralOptions:
\r
5881 GeneralOptionsPopup(hwnd);
\r
5882 DrawPosition(TRUE, NULL);
\r
5885 case IDM_BoardOptions:
\r
5886 BoardOptionsPopup(hwnd);
\r
5889 case IDM_EnginePlayOptions:
\r
5890 EnginePlayOptionsPopup(hwnd);
\r
5893 case IDM_OptionsUCI:
\r
5894 UciOptionsPopup(hwnd);
\r
5897 case IDM_IcsOptions:
\r
5898 IcsOptionsPopup(hwnd);
\r
5902 FontsOptionsPopup(hwnd);
\r
5906 SoundOptionsPopup(hwnd);
\r
5909 case IDM_CommPort:
\r
5910 CommPortOptionsPopup(hwnd);
\r
5913 case IDM_LoadOptions:
\r
5914 LoadOptionsPopup(hwnd);
\r
5917 case IDM_SaveOptions:
\r
5918 SaveOptionsPopup(hwnd);
\r
5921 case IDM_TimeControl:
\r
5922 TimeControlOptionsPopup(hwnd);
\r
5925 case IDM_SaveSettings:
\r
5926 SaveSettings(settingsFileName);
\r
5929 case IDM_SaveSettingsOnExit:
\r
5930 saveSettingsOnExit = !saveSettingsOnExit;
\r
5931 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5932 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5933 MF_CHECKED : MF_UNCHECKED));
\r
5944 case IDM_AboutGame:
\r
5949 appData.debugMode = !appData.debugMode;
\r
5950 if (appData.debugMode) {
\r
5951 char dir[MSG_SIZ];
\r
5952 GetCurrentDirectory(MSG_SIZ, dir);
\r
5953 SetCurrentDirectory(installDir);
\r
5954 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5955 SetCurrentDirectory(dir);
\r
5956 setbuf(debugFP, NULL);
\r
5963 case IDM_HELPCONTENTS:
\r
5964 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5965 MessageBox (GetFocus(),
\r
5966 "Unable to activate help",
\r
5967 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5971 case IDM_HELPSEARCH:
\r
5972 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5973 MessageBox (GetFocus(),
\r
5974 "Unable to activate help",
\r
5975 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5979 case IDM_HELPHELP:
\r
5980 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5981 MessageBox (GetFocus(),
\r
5982 "Unable to activate help",
\r
5983 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5988 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5990 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5991 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5992 FreeProcInstance(lpProc);
\r
5995 case IDM_DirectCommand1:
\r
5996 AskQuestionEvent("Direct Command",
\r
5997 "Send to chess program:", "", "1");
\r
5999 case IDM_DirectCommand2:
\r
6000 AskQuestionEvent("Direct Command",
\r
6001 "Send to second chess program:", "", "2");
\r
6004 case EP_WhitePawn:
\r
6005 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
6006 fromX = fromY = -1;
\r
6009 case EP_WhiteKnight:
\r
6010 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
6011 fromX = fromY = -1;
\r
6014 case EP_WhiteBishop:
\r
6015 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
6016 fromX = fromY = -1;
\r
6019 case EP_WhiteRook:
\r
6020 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
6021 fromX = fromY = -1;
\r
6024 case EP_WhiteQueen:
\r
6025 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
6026 fromX = fromY = -1;
\r
6029 case EP_WhiteFerz:
\r
6030 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
6031 fromX = fromY = -1;
\r
6034 case EP_WhiteWazir:
\r
6035 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
6036 fromX = fromY = -1;
\r
6039 case EP_WhiteAlfil:
\r
6040 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
6041 fromX = fromY = -1;
\r
6044 case EP_WhiteCannon:
\r
6045 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
6046 fromX = fromY = -1;
\r
6049 case EP_WhiteCardinal:
\r
6050 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
6051 fromX = fromY = -1;
\r
6054 case EP_WhiteMarshall:
\r
6055 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
6056 fromX = fromY = -1;
\r
6059 case EP_WhiteKing:
\r
6060 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
6061 fromX = fromY = -1;
\r
6064 case EP_BlackPawn:
\r
6065 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
6066 fromX = fromY = -1;
\r
6069 case EP_BlackKnight:
\r
6070 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
6071 fromX = fromY = -1;
\r
6074 case EP_BlackBishop:
\r
6075 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
6076 fromX = fromY = -1;
\r
6079 case EP_BlackRook:
\r
6080 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
6081 fromX = fromY = -1;
\r
6084 case EP_BlackQueen:
\r
6085 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
6086 fromX = fromY = -1;
\r
6089 case EP_BlackFerz:
\r
6090 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
6091 fromX = fromY = -1;
\r
6094 case EP_BlackWazir:
\r
6095 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
6096 fromX = fromY = -1;
\r
6099 case EP_BlackAlfil:
\r
6100 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
6101 fromX = fromY = -1;
\r
6104 case EP_BlackCannon:
\r
6105 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
6106 fromX = fromY = -1;
\r
6109 case EP_BlackCardinal:
\r
6110 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
6111 fromX = fromY = -1;
\r
6114 case EP_BlackMarshall:
\r
6115 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
6116 fromX = fromY = -1;
\r
6119 case EP_BlackKing:
\r
6120 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
6121 fromX = fromY = -1;
\r
6124 case EP_EmptySquare:
\r
6125 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
6126 fromX = fromY = -1;
\r
6129 case EP_ClearBoard:
\r
6130 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
6131 fromX = fromY = -1;
\r
6135 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6136 fromX = fromY = -1;
\r
6140 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6141 fromX = fromY = -1;
\r
6145 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6146 fromX = fromY = -1;
\r
6150 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6151 fromX = fromY = -1;
\r
6155 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6156 fromX = fromY = -1;
\r
6160 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6161 fromX = fromY = -1;
\r
6165 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6166 fromX = fromY = -1;
\r
6170 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6171 fromX = fromY = -1;
\r
6175 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6176 fromX = fromY = -1;
\r
6180 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6186 case CLOCK_TIMER_ID:
\r
6187 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6188 clockTimerEvent = 0;
\r
6189 DecrementClocks(); /* call into back end */
\r
6191 case LOAD_GAME_TIMER_ID:
\r
6192 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6193 loadGameTimerEvent = 0;
\r
6194 AutoPlayGameLoop(); /* call into back end */
\r
6196 case ANALYSIS_TIMER_ID:
\r
6197 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile
\r
6198 || appData.icsEngineAnalyze) && appData.periodicUpdates) {
\r
6199 AnalysisPeriodicEvent(0);
\r
6201 KillTimer(hwnd, analysisTimerEvent);
\r
6202 analysisTimerEvent = 0;
\r
6205 case DELAYED_TIMER_ID:
\r
6206 KillTimer(hwnd, delayedTimerEvent);
\r
6207 delayedTimerEvent = 0;
\r
6208 delayedTimerCallback();
\r
6213 case WM_USER_Input:
\r
6214 InputEvent(hwnd, message, wParam, lParam);
\r
6217 /* [AS] Also move "attached" child windows */
\r
6218 case WM_WINDOWPOSCHANGING:
\r
6219 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6220 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6222 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6223 /* Window is moving */
\r
6226 GetWindowRect( hwnd, &rcMain );
\r
6228 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6229 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6230 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6235 /* [AS] Snapping */
\r
6236 case WM_ENTERSIZEMOVE:
\r
6237 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6238 if (hwnd == hwndMain) {
\r
6239 doingSizing = TRUE;
\r
6242 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6246 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6247 if (hwnd == hwndMain) {
\r
6248 lastSizing = wParam;
\r
6253 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6254 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6256 case WM_EXITSIZEMOVE:
\r
6257 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6258 if (hwnd == hwndMain) {
\r
6260 doingSizing = FALSE;
\r
6261 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6262 GetClientRect(hwnd, &client);
\r
6263 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6265 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6267 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6270 case WM_DESTROY: /* message: window being destroyed */
\r
6271 PostQuitMessage(0);
\r
6275 if (hwnd == hwndMain) {
\r
6280 default: /* Passes it on if unprocessed */
\r
6281 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6286 /*---------------------------------------------------------------------------*\
\r
6288 * Misc utility routines
\r
6290 \*---------------------------------------------------------------------------*/
\r
6293 * Decent random number generator, at least not as bad as Windows
\r
6294 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6296 unsigned int randstate;
\r
6301 randstate = randstate * 1664525 + 1013904223;
\r
6302 return (int) randstate & 0x7fffffff;
\r
6306 mysrandom(unsigned int seed)
\r
6313 * returns TRUE if user selects a different color, FALSE otherwise
\r
6317 ChangeColor(HWND hwnd, COLORREF *which)
\r
6319 static BOOL firstTime = TRUE;
\r
6320 static DWORD customColors[16];
\r
6322 COLORREF newcolor;
\r
6327 /* Make initial colors in use available as custom colors */
\r
6328 /* Should we put the compiled-in defaults here instead? */
\r
6330 customColors[i++] = lightSquareColor & 0xffffff;
\r
6331 customColors[i++] = darkSquareColor & 0xffffff;
\r
6332 customColors[i++] = whitePieceColor & 0xffffff;
\r
6333 customColors[i++] = blackPieceColor & 0xffffff;
\r
6334 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6335 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6337 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6338 customColors[i++] = textAttribs[ccl].color;
\r
6340 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6341 firstTime = FALSE;
\r
6344 cc.lStructSize = sizeof(cc);
\r
6345 cc.hwndOwner = hwnd;
\r
6346 cc.hInstance = NULL;
\r
6347 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6348 cc.lpCustColors = (LPDWORD) customColors;
\r
6349 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6351 if (!ChooseColor(&cc)) return FALSE;
\r
6353 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6354 if (newcolor == *which) return FALSE;
\r
6355 *which = newcolor;
\r
6359 InitDrawingColors();
\r
6360 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6365 MyLoadSound(MySound *ms)
\r
6371 if (ms->data) free(ms->data);
\r
6374 switch (ms->name[0]) {
\r
6380 /* System sound from Control Panel. Don't preload here. */
\r
6384 if (ms->name[1] == NULLCHAR) {
\r
6385 /* "!" alone = silence */
\r
6388 /* Builtin wave resource. Error if not found. */
\r
6389 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6390 if (h == NULL) break;
\r
6391 ms->data = (void *)LoadResource(hInst, h);
\r
6392 if (h == NULL) break;
\r
6397 /* .wav file. Error if not found. */
\r
6398 f = fopen(ms->name, "rb");
\r
6399 if (f == NULL) break;
\r
6400 if (fstat(fileno(f), &st) < 0) break;
\r
6401 ms->data = malloc(st.st_size);
\r
6402 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6408 char buf[MSG_SIZ];
\r
6409 sprintf(buf, "Error loading sound %s", ms->name);
\r
6410 DisplayError(buf, GetLastError());
\r
6416 MyPlaySound(MySound *ms)
\r
6418 BOOLEAN ok = FALSE;
\r
6419 switch (ms->name[0]) {
\r
6425 /* System sound from Control Panel (deprecated feature).
\r
6426 "$" alone or an unset sound name gets default beep (still in use). */
\r
6427 if (ms->name[1]) {
\r
6428 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6430 if (!ok) ok = MessageBeep(MB_OK);
\r
6433 /* Builtin wave resource, or "!" alone for silence */
\r
6434 if (ms->name[1]) {
\r
6435 if (ms->data == NULL) return FALSE;
\r
6436 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6442 /* .wav file. Error if not found. */
\r
6443 if (ms->data == NULL) return FALSE;
\r
6444 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6447 /* Don't print an error: this can happen innocently if the sound driver
\r
6448 is busy; for instance, if another instance of WinBoard is playing
\r
6449 a sound at about the same time. */
\r
6452 char buf[MSG_SIZ];
\r
6453 sprintf(buf, "Error playing sound %s", ms->name);
\r
6454 DisplayError(buf, GetLastError());
\r
6462 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6465 OPENFILENAME *ofn;
\r
6466 static UINT *number; /* gross that this is static */
\r
6468 switch (message) {
\r
6469 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6470 /* Center the dialog over the application window */
\r
6471 ofn = (OPENFILENAME *) lParam;
\r
6472 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6473 number = (UINT *) ofn->lCustData;
\r
6474 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6478 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6479 return FALSE; /* Allow for further processing */
\r
6482 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6483 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6485 return FALSE; /* Allow for further processing */
\r
6491 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6493 static UINT *number;
\r
6494 OPENFILENAME *ofname;
\r
6497 case WM_INITDIALOG:
\r
6498 ofname = (OPENFILENAME *)lParam;
\r
6499 number = (UINT *)(ofname->lCustData);
\r
6502 ofnot = (OFNOTIFY *)lParam;
\r
6503 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6504 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6513 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6514 char *nameFilt, char *dlgTitle, UINT *number,
\r
6515 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6517 OPENFILENAME openFileName;
\r
6518 char buf1[MSG_SIZ];
\r
6521 if (fileName == NULL) fileName = buf1;
\r
6522 if (defName == NULL) {
\r
6523 strcpy(fileName, "*.");
\r
6524 strcat(fileName, defExt);
\r
6526 strcpy(fileName, defName);
\r
6528 if (fileTitle) strcpy(fileTitle, "");
\r
6529 if (number) *number = 0;
\r
6531 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6532 openFileName.hwndOwner = hwnd;
\r
6533 openFileName.hInstance = (HANDLE) hInst;
\r
6534 openFileName.lpstrFilter = nameFilt;
\r
6535 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6536 openFileName.nMaxCustFilter = 0L;
\r
6537 openFileName.nFilterIndex = 1L;
\r
6538 openFileName.lpstrFile = fileName;
\r
6539 openFileName.nMaxFile = MSG_SIZ;
\r
6540 openFileName.lpstrFileTitle = fileTitle;
\r
6541 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6542 openFileName.lpstrInitialDir = NULL;
\r
6543 openFileName.lpstrTitle = dlgTitle;
\r
6544 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6545 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6546 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6547 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6548 openFileName.nFileOffset = 0;
\r
6549 openFileName.nFileExtension = 0;
\r
6550 openFileName.lpstrDefExt = defExt;
\r
6551 openFileName.lCustData = (LONG) number;
\r
6552 openFileName.lpfnHook = oldDialog ?
\r
6553 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6554 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6556 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6557 GetOpenFileName(&openFileName)) {
\r
6558 /* open the file */
\r
6559 f = fopen(openFileName.lpstrFile, write);
\r
6561 MessageBox(hwnd, "File open failed", NULL,
\r
6562 MB_OK|MB_ICONEXCLAMATION);
\r
6566 int err = CommDlgExtendedError();
\r
6567 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6576 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6578 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6581 * Get the first pop-up menu in the menu template. This is the
\r
6582 * menu that TrackPopupMenu displays.
\r
6584 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6586 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6589 * TrackPopup uses screen coordinates, so convert the
\r
6590 * coordinates of the mouse click to screen coordinates.
\r
6592 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6594 /* Draw and track the floating pop-up menu. */
\r
6595 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6596 pt.x, pt.y, 0, hwnd, NULL);
\r
6598 /* Destroy the menu.*/
\r
6599 DestroyMenu(hmenu);
\r
6604 int sizeX, sizeY, newSizeX, newSizeY;
\r
6606 } ResizeEditPlusButtonsClosure;
\r
6609 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6611 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6615 if (hChild == cl->hText) return TRUE;
\r
6616 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6617 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6618 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6619 ScreenToClient(cl->hDlg, &pt);
\r
6620 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6621 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6625 /* Resize a dialog that has a (rich) edit field filling most of
\r
6626 the top, with a row of buttons below */
\r
6628 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6631 int newTextHeight, newTextWidth;
\r
6632 ResizeEditPlusButtonsClosure cl;
\r
6634 /*if (IsIconic(hDlg)) return;*/
\r
6635 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6637 cl.hdwp = BeginDeferWindowPos(8);
\r
6639 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6640 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6641 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6642 if (newTextHeight < 0) {
\r
6643 newSizeY += -newTextHeight;
\r
6644 newTextHeight = 0;
\r
6646 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6647 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6653 cl.newSizeX = newSizeX;
\r
6654 cl.newSizeY = newSizeY;
\r
6655 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6657 EndDeferWindowPos(cl.hdwp);
\r
6660 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6662 RECT rChild, rParent;
\r
6663 int wChild, hChild, wParent, hParent;
\r
6664 int wScreen, hScreen, xNew, yNew;
\r
6667 /* Get the Height and Width of the child window */
\r
6668 GetWindowRect (hwndChild, &rChild);
\r
6669 wChild = rChild.right - rChild.left;
\r
6670 hChild = rChild.bottom - rChild.top;
\r
6672 /* Get the Height and Width of the parent window */
\r
6673 GetWindowRect (hwndParent, &rParent);
\r
6674 wParent = rParent.right - rParent.left;
\r
6675 hParent = rParent.bottom - rParent.top;
\r
6677 /* Get the display limits */
\r
6678 hdc = GetDC (hwndChild);
\r
6679 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6680 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6681 ReleaseDC(hwndChild, hdc);
\r
6683 /* Calculate new X position, then adjust for screen */
\r
6684 xNew = rParent.left + ((wParent - wChild) /2);
\r
6687 } else if ((xNew+wChild) > wScreen) {
\r
6688 xNew = wScreen - wChild;
\r
6691 /* Calculate new Y position, then adjust for screen */
\r
6693 yNew = rParent.top + ((hParent - hChild) /2);
\r
6696 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6701 } else if ((yNew+hChild) > hScreen) {
\r
6702 yNew = hScreen - hChild;
\r
6705 /* Set it, and return */
\r
6706 return SetWindowPos (hwndChild, NULL,
\r
6707 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6710 /* Center one window over another */
\r
6711 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6713 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6716 /*---------------------------------------------------------------------------*\
\r
6718 * Startup Dialog functions
\r
6720 \*---------------------------------------------------------------------------*/
\r
6722 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6724 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6726 while (*cd != NULL) {
\r
6727 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6733 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6735 char buf1[ARG_MAX];
\r
6738 if (str[0] == '@') {
\r
6739 FILE* f = fopen(str + 1, "r");
\r
6741 DisplayFatalError(str + 1, errno, 2);
\r
6744 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6746 buf1[len] = NULLCHAR;
\r
6750 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6753 char buf[MSG_SIZ];
\r
6754 char *end = strchr(str, '\n');
\r
6755 if (end == NULL) return;
\r
6756 memcpy(buf, str, end - str);
\r
6757 buf[end - str] = NULLCHAR;
\r
6758 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6764 SetStartupDialogEnables(HWND hDlg)
\r
6766 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6767 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6768 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6769 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6770 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6771 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6772 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6773 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6774 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6775 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6776 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6777 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6778 IsDlgButtonChecked(hDlg, OPT_View));
\r
6782 QuoteForFilename(char *filename)
\r
6784 int dquote, space;
\r
6785 dquote = strchr(filename, '"') != NULL;
\r
6786 space = strchr(filename, ' ') != NULL;
\r
6787 if (dquote || space) {
\r
6799 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6801 char buf[MSG_SIZ];
\r
6804 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6805 q = QuoteForFilename(nthcp);
\r
6806 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6807 if (*nthdir != NULLCHAR) {
\r
6808 q = QuoteForFilename(nthdir);
\r
6809 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6811 if (*nthcp == NULLCHAR) {
\r
6812 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6813 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6814 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6815 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6820 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6822 char buf[MSG_SIZ];
\r
6826 switch (message) {
\r
6827 case WM_INITDIALOG:
\r
6828 /* Center the dialog */
\r
6829 CenterWindow (hDlg, GetDesktopWindow());
\r
6830 /* Initialize the dialog items */
\r
6831 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6832 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6833 firstChessProgramNames);
\r
6834 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6835 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6836 secondChessProgramNames);
\r
6837 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6838 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6839 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6840 if (*appData.icsHelper != NULLCHAR) {
\r
6841 char *q = QuoteForFilename(appData.icsHelper);
\r
6842 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6844 if (*appData.icsHost == NULLCHAR) {
\r
6845 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6846 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6847 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6848 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6849 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6852 if (appData.icsActive) {
\r
6853 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6855 else if (appData.noChessProgram) {
\r
6856 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6859 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6862 SetStartupDialogEnables(hDlg);
\r
6866 switch (LOWORD(wParam)) {
\r
6868 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6869 strcpy(buf, "/fcp=");
\r
6870 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6872 ParseArgs(StringGet, &p);
\r
6873 strcpy(buf, "/scp=");
\r
6874 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6876 ParseArgs(StringGet, &p);
\r
6877 appData.noChessProgram = FALSE;
\r
6878 appData.icsActive = FALSE;
\r
6879 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6880 strcpy(buf, "/ics /icshost=");
\r
6881 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6883 ParseArgs(StringGet, &p);
\r
6884 if (appData.zippyPlay) {
\r
6885 strcpy(buf, "/fcp=");
\r
6886 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6888 ParseArgs(StringGet, &p);
\r
6890 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6891 appData.noChessProgram = TRUE;
\r
6892 appData.icsActive = FALSE;
\r
6894 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6895 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6898 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6899 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6901 ParseArgs(StringGet, &p);
\r
6903 EndDialog(hDlg, TRUE);
\r
6910 case IDM_HELPCONTENTS:
\r
6911 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6912 MessageBox (GetFocus(),
\r
6913 "Unable to activate help",
\r
6914 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6919 SetStartupDialogEnables(hDlg);
\r
6927 /*---------------------------------------------------------------------------*\
\r
6929 * About box dialog functions
\r
6931 \*---------------------------------------------------------------------------*/
\r
6933 /* Process messages for "About" dialog box */
\r
6935 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6937 switch (message) {
\r
6938 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6939 /* Center the dialog over the application window */
\r
6940 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6941 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6944 case WM_COMMAND: /* message: received a command */
\r
6945 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6946 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6947 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6955 /*---------------------------------------------------------------------------*\
\r
6957 * Comment Dialog functions
\r
6959 \*---------------------------------------------------------------------------*/
\r
6962 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6964 static HANDLE hwndText = NULL;
\r
6965 int len, newSizeX, newSizeY, flags;
\r
6966 static int sizeX, sizeY;
\r
6971 switch (message) {
\r
6972 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6973 /* Initialize the dialog items */
\r
6974 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6975 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6976 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6977 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6978 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6979 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6980 SetWindowText(hDlg, commentTitle);
\r
6981 if (editComment) {
\r
6982 SetFocus(hwndText);
\r
6984 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6986 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6987 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6988 MAKELPARAM(FALSE, 0));
\r
6989 /* Size and position the dialog */
\r
6990 if (!commentDialog) {
\r
6991 commentDialog = hDlg;
\r
6992 flags = SWP_NOZORDER;
\r
6993 GetClientRect(hDlg, &rect);
\r
6994 sizeX = rect.right;
\r
6995 sizeY = rect.bottom;
\r
6996 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
6997 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
6998 WINDOWPLACEMENT wp;
\r
6999 EnsureOnScreen(&commentX, &commentY);
\r
7000 wp.length = sizeof(WINDOWPLACEMENT);
\r
7002 wp.showCmd = SW_SHOW;
\r
7003 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7004 wp.rcNormalPosition.left = commentX;
\r
7005 wp.rcNormalPosition.right = commentX + commentW;
\r
7006 wp.rcNormalPosition.top = commentY;
\r
7007 wp.rcNormalPosition.bottom = commentY + commentH;
\r
7008 SetWindowPlacement(hDlg, &wp);
\r
7010 GetClientRect(hDlg, &rect);
\r
7011 newSizeX = rect.right;
\r
7012 newSizeY = rect.bottom;
\r
7013 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
7014 newSizeX, newSizeY);
\r
7021 case WM_COMMAND: /* message: received a command */
\r
7022 switch (LOWORD(wParam)) {
\r
7024 if (editComment) {
\r
7026 /* Read changed options from the dialog box */
\r
7027 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
7028 len = GetWindowTextLength(hwndText);
\r
7029 str = (char *) malloc(len + 1);
\r
7030 GetWindowText(hwndText, str, len + 1);
\r
7039 ReplaceComment(commentIndex, str);
\r
7046 case OPT_CancelComment:
\r
7050 case OPT_ClearComment:
\r
7051 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
7054 case OPT_EditComment:
\r
7055 EditCommentEvent();
\r
7064 newSizeX = LOWORD(lParam);
\r
7065 newSizeY = HIWORD(lParam);
\r
7066 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
7071 case WM_GETMINMAXINFO:
\r
7072 /* Prevent resizing window too small */
\r
7073 mmi = (MINMAXINFO *) lParam;
\r
7074 mmi->ptMinTrackSize.x = 100;
\r
7075 mmi->ptMinTrackSize.y = 100;
\r
7082 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
7087 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
7089 if (str == NULL) str = "";
\r
7090 p = (char *) malloc(2 * strlen(str) + 2);
\r
7093 if (*str == '\n') *q++ = '\r';
\r
7097 if (commentText != NULL) free(commentText);
\r
7099 commentIndex = index;
\r
7100 commentTitle = title;
\r
7102 editComment = edit;
\r
7104 if (commentDialog) {
\r
7105 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
7106 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
7108 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
7109 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
7110 hwndMain, (DLGPROC)lpProc);
\r
7111 FreeProcInstance(lpProc);
\r
7113 commentDialogUp = TRUE;
\r
7117 /*---------------------------------------------------------------------------*\
\r
7119 * Type-in move dialog functions
\r
7121 \*---------------------------------------------------------------------------*/
\r
7124 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7126 char move[MSG_SIZ];
\r
7128 ChessMove moveType;
\r
7129 int fromX, fromY, toX, toY;
\r
7132 switch (message) {
\r
7133 case WM_INITDIALOG:
\r
7134 move[0] = (char) lParam;
\r
7135 move[1] = NULLCHAR;
\r
7136 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7137 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7138 SetWindowText(hInput, move);
\r
7140 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7144 switch (LOWORD(wParam)) {
\r
7146 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7147 gameMode != Training) {
\r
7148 DisplayMoveError("Displayed move is not current");
\r
7150 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7151 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7152 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7153 if (gameMode != Training)
\r
7154 forwardMostMove = currentMove;
\r
7155 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7157 DisplayMoveError("Could not parse move");
\r
7160 EndDialog(hDlg, TRUE);
\r
7163 EndDialog(hDlg, FALSE);
\r
7174 PopUpMoveDialog(char firstchar)
\r
7178 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7179 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7180 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7181 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7182 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7183 gameMode == Training) {
\r
7184 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7185 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7186 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7187 FreeProcInstance(lpProc);
\r
7191 /*---------------------------------------------------------------------------*\
\r
7193 * Type-in name dialog functions
\r
7195 \*---------------------------------------------------------------------------*/
\r
7198 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7200 char move[MSG_SIZ];
\r
7203 switch (message) {
\r
7204 case WM_INITDIALOG:
\r
7205 move[0] = (char) lParam;
\r
7206 move[1] = NULLCHAR;
\r
7207 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7208 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7209 SetWindowText(hInput, move);
\r
7211 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7215 switch (LOWORD(wParam)) {
\r
7217 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7218 appData.userName = strdup(move);
\r
7220 EndDialog(hDlg, TRUE);
\r
7223 EndDialog(hDlg, FALSE);
\r
7234 PopUpNameDialog(char firstchar)
\r
7238 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7239 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7240 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7241 FreeProcInstance(lpProc);
\r
7244 /*---------------------------------------------------------------------------*\
\r
7248 \*---------------------------------------------------------------------------*/
\r
7250 /* Nonmodal error box */
\r
7251 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7252 WPARAM wParam, LPARAM lParam);
\r
7255 ErrorPopUp(char *title, char *content)
\r
7259 BOOLEAN modal = hwndMain == NULL;
\r
7277 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7278 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7281 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7283 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7284 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7285 hwndMain, (DLGPROC)lpProc);
\r
7286 FreeProcInstance(lpProc);
\r
7293 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7294 if (errorDialog == NULL) return;
\r
7295 DestroyWindow(errorDialog);
\r
7296 errorDialog = NULL;
\r
7300 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7305 switch (message) {
\r
7306 case WM_INITDIALOG:
\r
7307 GetWindowRect(hDlg, &rChild);
\r
7310 SetWindowPos(hDlg, NULL, rChild.left,
\r
7311 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7312 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7316 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7317 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7318 and it doesn't work when you resize the dialog.
\r
7319 For now, just give it a default position.
\r
7321 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7323 errorDialog = hDlg;
\r
7324 SetWindowText(hDlg, errorTitle);
\r
7325 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7326 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7330 switch (LOWORD(wParam)) {
\r
7333 if (errorDialog == hDlg) errorDialog = NULL;
\r
7334 DestroyWindow(hDlg);
\r
7346 HWND gothicDialog = NULL;
\r
7349 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7353 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7355 switch (message) {
\r
7356 case WM_INITDIALOG:
\r
7357 GetWindowRect(hDlg, &rChild);
\r
7359 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7363 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7364 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7365 and it doesn't work when you resize the dialog.
\r
7366 For now, just give it a default position.
\r
7368 gothicDialog = hDlg;
\r
7369 SetWindowText(hDlg, errorTitle);
\r
7370 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7371 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7375 switch (LOWORD(wParam)) {
\r
7378 if (errorDialog == hDlg) errorDialog = NULL;
\r
7379 DestroyWindow(hDlg);
\r
7391 GothicPopUp(char *title, VariantClass variant)
\r
7395 BOOLEAN modal = hwndMain == NULL;
\r
7396 static char *lastTitle;
\r
7398 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7399 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7401 if(lastTitle != title && gothicDialog != NULL) {
\r
7402 DestroyWindow(gothicDialog);
\r
7403 gothicDialog = NULL;
\r
7405 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7406 title = lastTitle;
\r
7407 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7408 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7409 hwndMain, (DLGPROC)lpProc);
\r
7410 FreeProcInstance(lpProc);
\r
7415 /*---------------------------------------------------------------------------*\
\r
7417 * Ics Interaction console functions
\r
7419 \*---------------------------------------------------------------------------*/
\r
7421 #define HISTORY_SIZE 64
\r
7422 static char *history[HISTORY_SIZE];
\r
7423 int histIn = 0, histP = 0;
\r
7426 SaveInHistory(char *cmd)
\r
7428 if (history[histIn] != NULL) {
\r
7429 free(history[histIn]);
\r
7430 history[histIn] = NULL;
\r
7432 if (*cmd == NULLCHAR) return;
\r
7433 history[histIn] = StrSave(cmd);
\r
7434 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7435 if (history[histIn] != NULL) {
\r
7436 free(history[histIn]);
\r
7437 history[histIn] = NULL;
\r
7443 PrevInHistory(char *cmd)
\r
7446 if (histP == histIn) {
\r
7447 if (history[histIn] != NULL) free(history[histIn]);
\r
7448 history[histIn] = StrSave(cmd);
\r
7450 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7451 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7453 return history[histP];
\r
7459 if (histP == histIn) return NULL;
\r
7460 histP = (histP + 1) % HISTORY_SIZE;
\r
7461 return history[histP];
\r
7468 BOOLEAN immediate;
\r
7469 } IcsTextMenuEntry;
\r
7470 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7471 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7474 ParseIcsTextMenu(char *icsTextMenuString)
\r
7477 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7478 char *p = icsTextMenuString;
\r
7479 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7482 if (e->command != NULL) {
\r
7484 e->command = NULL;
\r
7488 e = icsTextMenuEntry;
\r
7489 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7490 if (*p == ';' || *p == '\n') {
\r
7491 e->item = strdup("-");
\r
7492 e->command = NULL;
\r
7494 } else if (*p == '-') {
\r
7495 e->item = strdup("-");
\r
7496 e->command = NULL;
\r
7500 char *q, *r, *s, *t;
\r
7502 q = strchr(p, ',');
\r
7503 if (q == NULL) break;
\r
7505 r = strchr(q + 1, ',');
\r
7506 if (r == NULL) break;
\r
7508 s = strchr(r + 1, ',');
\r
7509 if (s == NULL) break;
\r
7512 t = strchr(s + 1, c);
\r
7515 t = strchr(s + 1, c);
\r
7517 if (t != NULL) *t = NULLCHAR;
\r
7518 e->item = strdup(p);
\r
7519 e->command = strdup(q + 1);
\r
7520 e->getname = *(r + 1) != '0';
\r
7521 e->immediate = *(s + 1) != '0';
\r
7525 if (t == NULL) break;
\r
7534 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7538 hmenu = LoadMenu(hInst, "TextMenu");
\r
7539 h = GetSubMenu(hmenu, 0);
\r
7541 if (strcmp(e->item, "-") == 0) {
\r
7542 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7544 if (e->item[0] == '|') {
\r
7545 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7546 IDM_CommandX + i, &e->item[1]);
\r
7548 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7557 WNDPROC consoleTextWindowProc;
\r
7560 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7562 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7563 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7567 SetWindowText(hInput, command);
\r
7569 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7571 sel.cpMin = 999999;
\r
7572 sel.cpMax = 999999;
\r
7573 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7578 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7579 if (sel.cpMin == sel.cpMax) {
\r
7580 /* Expand to surrounding word */
\r
7583 tr.chrg.cpMax = sel.cpMin;
\r
7584 tr.chrg.cpMin = --sel.cpMin;
\r
7585 if (sel.cpMin < 0) break;
\r
7586 tr.lpstrText = name;
\r
7587 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7588 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7592 tr.chrg.cpMin = sel.cpMax;
\r
7593 tr.chrg.cpMax = ++sel.cpMax;
\r
7594 tr.lpstrText = name;
\r
7595 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7596 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7599 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7600 MessageBeep(MB_ICONEXCLAMATION);
\r
7604 tr.lpstrText = name;
\r
7605 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7607 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7608 MessageBeep(MB_ICONEXCLAMATION);
\r
7611 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7614 sprintf(buf, "%s %s", command, name);
\r
7615 SetWindowText(hInput, buf);
\r
7616 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7618 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7619 SetWindowText(hInput, buf);
\r
7620 sel.cpMin = 999999;
\r
7621 sel.cpMax = 999999;
\r
7622 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7628 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7633 switch (message) {
\r
7635 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7638 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7641 sel.cpMin = 999999;
\r
7642 sel.cpMax = 999999;
\r
7643 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7644 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7649 if (wParam == '\t') {
\r
7650 if (GetKeyState(VK_SHIFT) < 0) {
\r
7652 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7653 if (buttonDesc[0].hwnd) {
\r
7654 SetFocus(buttonDesc[0].hwnd);
\r
7656 SetFocus(hwndMain);
\r
7660 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7663 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7665 SendMessage(hInput, message, wParam, lParam);
\r
7669 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7671 return SendMessage(hInput, message, wParam, lParam);
\r
7672 case WM_MBUTTONDOWN:
\r
7673 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7674 case WM_RBUTTONDOWN:
\r
7675 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7676 /* Move selection here if it was empty */
\r
7678 pt.x = LOWORD(lParam);
\r
7679 pt.y = HIWORD(lParam);
\r
7680 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7681 if (sel.cpMin == sel.cpMax) {
\r
7682 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7683 sel.cpMax = sel.cpMin;
\r
7684 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7686 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7689 case WM_RBUTTONUP:
\r
7690 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7691 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7692 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7695 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7696 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7697 if (sel.cpMin == sel.cpMax) {
\r
7698 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7699 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7701 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7702 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7704 pt.x = LOWORD(lParam);
\r
7705 pt.y = HIWORD(lParam);
\r
7706 MenuPopup(hwnd, pt, hmenu, -1);
\r
7710 switch (LOWORD(wParam)) {
\r
7711 case IDM_QuickPaste:
\r
7713 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7714 if (sel.cpMin == sel.cpMax) {
\r
7715 MessageBeep(MB_ICONEXCLAMATION);
\r
7718 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7719 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7720 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7725 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7728 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7731 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7735 int i = LOWORD(wParam) - IDM_CommandX;
\r
7736 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7737 icsTextMenuEntry[i].command != NULL) {
\r
7738 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7739 icsTextMenuEntry[i].getname,
\r
7740 icsTextMenuEntry[i].immediate);
\r
7748 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7751 WNDPROC consoleInputWindowProc;
\r
7754 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7756 char buf[MSG_SIZ];
\r
7758 static BOOL sendNextChar = FALSE;
\r
7759 static BOOL quoteNextChar = FALSE;
\r
7760 InputSource *is = consoleInputSource;
\r
7764 switch (message) {
\r
7766 if (!appData.localLineEditing || sendNextChar) {
\r
7767 is->buf[0] = (CHAR) wParam;
\r
7769 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7770 sendNextChar = FALSE;
\r
7773 if (quoteNextChar) {
\r
7774 buf[0] = (char) wParam;
\r
7775 buf[1] = NULLCHAR;
\r
7776 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7777 quoteNextChar = FALSE;
\r
7781 case '\r': /* Enter key */
\r
7782 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7783 if (consoleEcho) SaveInHistory(is->buf);
\r
7784 is->buf[is->count++] = '\n';
\r
7785 is->buf[is->count] = NULLCHAR;
\r
7786 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7787 if (consoleEcho) {
\r
7788 ConsoleOutput(is->buf, is->count, TRUE);
\r
7789 } else if (appData.localLineEditing) {
\r
7790 ConsoleOutput("\n", 1, TRUE);
\r
7793 case '\033': /* Escape key */
\r
7794 SetWindowText(hwnd, "");
\r
7795 cf.cbSize = sizeof(CHARFORMAT);
\r
7796 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7797 if (consoleEcho) {
\r
7798 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7800 cf.crTextColor = COLOR_ECHOOFF;
\r
7802 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7803 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7805 case '\t': /* Tab key */
\r
7806 if (GetKeyState(VK_SHIFT) < 0) {
\r
7808 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7811 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7812 if (buttonDesc[0].hwnd) {
\r
7813 SetFocus(buttonDesc[0].hwnd);
\r
7815 SetFocus(hwndMain);
\r
7819 case '\023': /* Ctrl+S */
\r
7820 sendNextChar = TRUE;
\r
7822 case '\021': /* Ctrl+Q */
\r
7823 quoteNextChar = TRUE;
\r
7832 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7833 p = PrevInHistory(buf);
\r
7835 SetWindowText(hwnd, p);
\r
7836 sel.cpMin = 999999;
\r
7837 sel.cpMax = 999999;
\r
7838 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7843 p = NextInHistory();
\r
7845 SetWindowText(hwnd, p);
\r
7846 sel.cpMin = 999999;
\r
7847 sel.cpMax = 999999;
\r
7848 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7854 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7858 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7862 case WM_MBUTTONDOWN:
\r
7863 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7864 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7866 case WM_RBUTTONUP:
\r
7867 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7868 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7869 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7873 hmenu = LoadMenu(hInst, "InputMenu");
\r
7874 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7875 if (sel.cpMin == sel.cpMax) {
\r
7876 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7877 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7879 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7880 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7882 pt.x = LOWORD(lParam);
\r
7883 pt.y = HIWORD(lParam);
\r
7884 MenuPopup(hwnd, pt, hmenu, -1);
\r
7888 switch (LOWORD(wParam)) {
\r
7890 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7892 case IDM_SelectAll:
\r
7894 sel.cpMax = -1; /*999999?*/
\r
7895 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7898 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7901 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7904 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7909 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7912 #define CO_MAX 100000
\r
7913 #define CO_TRIM 1000
\r
7916 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7918 static SnapData sd;
\r
7919 static HWND hText, hInput, hFocus;
\r
7920 InputSource *is = consoleInputSource;
\r
7922 static int sizeX, sizeY;
\r
7923 int newSizeX, newSizeY;
\r
7926 switch (message) {
\r
7927 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7928 hwndConsole = hDlg;
\r
7929 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7930 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7932 consoleTextWindowProc = (WNDPROC)
\r
7933 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7934 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7935 consoleInputWindowProc = (WNDPROC)
\r
7936 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7937 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7938 Colorize(ColorNormal, TRUE);
\r
7939 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7940 ChangedConsoleFont();
\r
7941 GetClientRect(hDlg, &rect);
\r
7942 sizeX = rect.right;
\r
7943 sizeY = rect.bottom;
\r
7944 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7945 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7946 WINDOWPLACEMENT wp;
\r
7947 EnsureOnScreen(&consoleX, &consoleY);
\r
7948 wp.length = sizeof(WINDOWPLACEMENT);
\r
7950 wp.showCmd = SW_SHOW;
\r
7951 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7952 wp.rcNormalPosition.left = consoleX;
\r
7953 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7954 wp.rcNormalPosition.top = consoleY;
\r
7955 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7956 SetWindowPlacement(hDlg, &wp);
\r
7959 // [HGM] Chessknight's change 2004-07-13
\r
7960 else { /* Determine Defaults */
\r
7961 WINDOWPLACEMENT wp;
\r
7962 consoleX = winWidth + 1;
\r
7963 consoleY = boardY;
\r
7964 consoleW = screenWidth - winWidth;
\r
7965 consoleH = winHeight;
\r
7966 EnsureOnScreen(&consoleX, &consoleY);
\r
7967 wp.length = sizeof(WINDOWPLACEMENT);
\r
7969 wp.showCmd = SW_SHOW;
\r
7970 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7971 wp.rcNormalPosition.left = consoleX;
\r
7972 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7973 wp.rcNormalPosition.top = consoleY;
\r
7974 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7975 SetWindowPlacement(hDlg, &wp);
\r
7990 if (IsIconic(hDlg)) break;
\r
7991 newSizeX = LOWORD(lParam);
\r
7992 newSizeY = HIWORD(lParam);
\r
7993 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7994 RECT rectText, rectInput;
\r
7996 int newTextHeight, newTextWidth;
\r
7997 GetWindowRect(hText, &rectText);
\r
7998 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7999 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
8000 if (newTextHeight < 0) {
\r
8001 newSizeY += -newTextHeight;
\r
8002 newTextHeight = 0;
\r
8004 SetWindowPos(hText, NULL, 0, 0,
\r
8005 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
8006 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
8007 pt.x = rectInput.left;
\r
8008 pt.y = rectInput.top + newSizeY - sizeY;
\r
8009 ScreenToClient(hDlg, &pt);
\r
8010 SetWindowPos(hInput, NULL,
\r
8011 pt.x, pt.y, /* needs client coords */
\r
8012 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
8013 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
8019 case WM_GETMINMAXINFO:
\r
8020 /* Prevent resizing window too small */
\r
8021 mmi = (MINMAXINFO *) lParam;
\r
8022 mmi->ptMinTrackSize.x = 100;
\r
8023 mmi->ptMinTrackSize.y = 100;
\r
8026 /* [AS] Snapping */
\r
8027 case WM_ENTERSIZEMOVE:
\r
8028 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
8031 return OnSizing( &sd, hDlg, wParam, lParam );
\r
8034 return OnMoving( &sd, hDlg, wParam, lParam );
\r
8036 case WM_EXITSIZEMOVE:
\r
8037 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
8040 return DefWindowProc(hDlg, message, wParam, lParam);
\r
8048 if (hwndConsole) return;
\r
8049 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
8050 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
8055 ConsoleOutput(char* data, int length, int forceVisible)
\r
8060 char buf[CO_MAX+1];
\r
8063 static int delayLF = 0;
\r
8064 CHARRANGE savesel, sel;
\r
8066 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
8074 while (length--) {
\r
8082 } else if (*p == '\007') {
\r
8083 MyPlaySound(&sounds[(int)SoundBell]);
\r
8090 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
8091 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8092 /* Save current selection */
\r
8093 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
8094 exlen = GetWindowTextLength(hText);
\r
8095 /* Find out whether current end of text is visible */
\r
8096 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
8097 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
8098 /* Trim existing text if it's too long */
\r
8099 if (exlen + (q - buf) > CO_MAX) {
\r
8100 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
8103 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8104 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
8106 savesel.cpMin -= trim;
\r
8107 savesel.cpMax -= trim;
\r
8108 if (exlen < 0) exlen = 0;
\r
8109 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
8110 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
8112 /* Append the new text */
\r
8113 sel.cpMin = exlen;
\r
8114 sel.cpMax = exlen;
\r
8115 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8116 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
8117 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
8118 if (forceVisible || exlen == 0 ||
\r
8119 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
8120 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
8121 /* Scroll to make new end of text visible if old end of text
\r
8122 was visible or new text is an echo of user typein */
\r
8123 sel.cpMin = 9999999;
\r
8124 sel.cpMax = 9999999;
\r
8125 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8126 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8127 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
8128 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
8130 if (savesel.cpMax == exlen || forceVisible) {
\r
8131 /* Move insert point to new end of text if it was at the old
\r
8132 end of text or if the new text is an echo of user typein */
\r
8133 sel.cpMin = 9999999;
\r
8134 sel.cpMax = 9999999;
\r
8135 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
8137 /* Restore previous selection */
\r
8138 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
8140 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
8147 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
8151 COLORREF oldFg, oldBg;
\r
8155 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8157 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8158 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8159 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8162 rect.right = x + squareSize;
\r
8164 rect.bottom = y + squareSize;
\r
8167 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8168 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8169 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8170 &rect, str, strlen(str), NULL);
\r
8172 (void) SetTextColor(hdc, oldFg);
\r
8173 (void) SetBkColor(hdc, oldBg);
\r
8174 (void) SelectObject(hdc, oldFont);
\r
8178 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8179 RECT *rect, char *color, char *flagFell)
\r
8183 COLORREF oldFg, oldBg;
\r
8186 if (appData.clockMode) {
\r
8188 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8190 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
8197 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8198 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8200 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8201 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8203 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8205 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8206 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8207 rect, str, strlen(str), NULL);
\r
8209 (void) SetTextColor(hdc, oldFg);
\r
8210 (void) SetBkColor(hdc, oldBg);
\r
8211 (void) SelectObject(hdc, oldFont);
\r
8216 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8222 if( count <= 0 ) {
\r
8223 if (appData.debugMode) {
\r
8224 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8227 return ERROR_INVALID_USER_BUFFER;
\r
8230 ResetEvent(ovl->hEvent);
\r
8231 ovl->Offset = ovl->OffsetHigh = 0;
\r
8232 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8236 err = GetLastError();
\r
8237 if (err == ERROR_IO_PENDING) {
\r
8238 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8242 err = GetLastError();
\r
8249 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8254 ResetEvent(ovl->hEvent);
\r
8255 ovl->Offset = ovl->OffsetHigh = 0;
\r
8256 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8260 err = GetLastError();
\r
8261 if (err == ERROR_IO_PENDING) {
\r
8262 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8266 err = GetLastError();
\r
8272 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8273 void CheckForInputBufferFull( InputSource * is )
\r
8275 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8276 /* Look for end of line */
\r
8277 char * p = is->buf;
\r
8279 while( p < is->next && *p != '\n' ) {
\r
8283 if( p >= is->next ) {
\r
8284 if (appData.debugMode) {
\r
8285 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
\r
8288 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8289 is->count = (DWORD) -1;
\r
8290 is->next = is->buf;
\r
8296 InputThread(LPVOID arg)
\r
8301 is = (InputSource *) arg;
\r
8302 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8303 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8304 while (is->hThread != NULL) {
\r
8305 is->error = DoReadFile(is->hFile, is->next,
\r
8306 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8307 &is->count, &ovl);
\r
8308 if (is->error == NO_ERROR) {
\r
8309 is->next += is->count;
\r
8311 if (is->error == ERROR_BROKEN_PIPE) {
\r
8312 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8315 is->count = (DWORD) -1;
\r
8316 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8321 CheckForInputBufferFull( is );
\r
8323 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8325 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8327 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8330 CloseHandle(ovl.hEvent);
\r
8331 CloseHandle(is->hFile);
\r
8333 if (appData.debugMode) {
\r
8334 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
\r
8341 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8343 NonOvlInputThread(LPVOID arg)
\r
8350 is = (InputSource *) arg;
\r
8351 while (is->hThread != NULL) {
\r
8352 is->error = ReadFile(is->hFile, is->next,
\r
8353 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8354 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8355 if (is->error == NO_ERROR) {
\r
8356 /* Change CRLF to LF */
\r
8357 if (is->next > is->buf) {
\r
8359 i = is->count + 1;
\r
8367 if (prev == '\r' && *p == '\n') {
\r
8379 if (is->error == ERROR_BROKEN_PIPE) {
\r
8380 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8383 is->count = (DWORD) -1;
\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 error */
\r
8395 CloseHandle(is->hFile);
\r
8400 SocketInputThread(LPVOID arg)
\r
8404 is = (InputSource *) arg;
\r
8405 while (is->hThread != NULL) {
\r
8406 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8407 if ((int)is->count == SOCKET_ERROR) {
\r
8408 is->count = (DWORD) -1;
\r
8409 is->error = WSAGetLastError();
\r
8411 is->error = NO_ERROR;
\r
8412 is->next += is->count;
\r
8413 if (is->count == 0 && is->second == is) {
\r
8414 /* End of file on stderr; quit with no message */
\r
8418 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8420 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8422 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8428 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8432 is = (InputSource *) lParam;
\r
8433 if (is->lineByLine) {
\r
8434 /* Feed in lines one by one */
\r
8435 char *p = is->buf;
\r
8437 while (q < is->next) {
\r
8438 if (*q++ == '\n') {
\r
8439 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8444 /* Move any partial line to the start of the buffer */
\r
8446 while (p < is->next) {
\r
8451 if (is->error != NO_ERROR || is->count == 0) {
\r
8452 /* Notify backend of the error. Note: If there was a partial
\r
8453 line at the end, it is not flushed through. */
\r
8454 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8457 /* Feed in the whole chunk of input at once */
\r
8458 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8459 is->next = is->buf;
\r
8463 /*---------------------------------------------------------------------------*\
\r
8465 * Menu enables. Used when setting various modes.
\r
8467 \*---------------------------------------------------------------------------*/
\r
8475 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8477 while (enab->item > 0) {
\r
8478 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8483 Enables gnuEnables[] = {
\r
8484 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8485 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8486 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8487 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8488 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8489 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8490 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8491 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8492 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8493 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8497 Enables icsEnables[] = {
\r
8498 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8499 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8500 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8501 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8502 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8503 { IDM_AnalysisMode, MF_BYCOMMAND|MF_ENABLED },
\r
8504 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8505 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8506 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8507 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8508 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8509 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8514 Enables zippyEnables[] = {
\r
8515 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8516 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8517 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8522 Enables ncpEnables[] = {
\r
8523 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8524 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8525 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8526 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8527 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8528 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8529 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8530 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8531 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8532 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8533 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8534 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8535 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8536 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8537 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8541 Enables trainingOnEnables[] = {
\r
8542 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8543 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8544 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8545 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8546 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8547 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8548 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8549 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8553 Enables trainingOffEnables[] = {
\r
8554 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8555 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8556 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8557 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8558 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8559 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8560 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8561 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8565 /* These modify either ncpEnables or gnuEnables */
\r
8566 Enables cmailEnables[] = {
\r
8567 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8568 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8569 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8570 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8571 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8572 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8573 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8577 Enables machineThinkingEnables[] = {
\r
8578 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8579 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8580 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8581 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8582 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8583 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8584 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8585 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8586 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8587 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8588 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8589 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8590 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8591 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8592 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8596 Enables userThinkingEnables[] = {
\r
8597 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8598 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8599 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8600 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8601 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8602 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8603 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8604 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8605 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8606 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8607 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8608 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8609 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8610 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8611 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8615 /*---------------------------------------------------------------------------*\
\r
8617 * Front-end interface functions exported by XBoard.
\r
8618 * Functions appear in same order as prototypes in frontend.h.
\r
8620 \*---------------------------------------------------------------------------*/
\r
8624 static UINT prevChecked = 0;
\r
8625 static int prevPausing = 0;
\r
8628 if (pausing != prevPausing) {
\r
8629 prevPausing = pausing;
\r
8630 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8631 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8632 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8635 switch (gameMode) {
\r
8636 case BeginningOfGame:
\r
8637 if (appData.icsActive)
\r
8638 nowChecked = IDM_IcsClient;
\r
8639 else if (appData.noChessProgram)
\r
8640 nowChecked = IDM_EditGame;
\r
8642 nowChecked = IDM_MachineBlack;
\r
8644 case MachinePlaysBlack:
\r
8645 nowChecked = IDM_MachineBlack;
\r
8647 case MachinePlaysWhite:
\r
8648 nowChecked = IDM_MachineWhite;
\r
8650 case TwoMachinesPlay:
\r
8651 nowChecked = IDM_TwoMachines;
\r
8654 nowChecked = IDM_AnalysisMode;
\r
8657 nowChecked = IDM_AnalyzeFile;
\r
8660 nowChecked = IDM_EditGame;
\r
8662 case PlayFromGameFile:
\r
8663 nowChecked = IDM_LoadGame;
\r
8665 case EditPosition:
\r
8666 nowChecked = IDM_EditPosition;
\r
8669 nowChecked = IDM_Training;
\r
8671 case IcsPlayingWhite:
\r
8672 case IcsPlayingBlack:
\r
8673 case IcsObserving:
\r
8675 nowChecked = IDM_IcsClient;
\r
8682 if (prevChecked != 0)
\r
8683 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8684 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8685 if (nowChecked != 0)
\r
8686 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8687 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8689 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8690 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8691 MF_BYCOMMAND|MF_ENABLED);
\r
8693 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8694 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8697 prevChecked = nowChecked;
\r
8699 /* [DM] icsEngineAnalyze - Do a sceure check too */
\r
8700 if (appData.icsActive) {
\r
8701 if (appData.icsEngineAnalyze) {
\r
8702 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8703 MF_BYCOMMAND|MF_CHECKED);
\r
8705 (void) CheckMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8706 MF_BYCOMMAND|MF_UNCHECKED);
\r
8714 HMENU hmenu = GetMenu(hwndMain);
\r
8715 SetMenuEnables(hmenu, icsEnables);
\r
8716 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8717 MF_BYPOSITION|MF_ENABLED);
\r
8719 if (appData.zippyPlay) {
\r
8720 SetMenuEnables(hmenu, zippyEnables);
\r
8721 if (!appData.noChessProgram) /* [DM] icsEngineAnalyze */
\r
8722 (void) EnableMenuItem(GetMenu(hwndMain), IDM_AnalysisMode,
\r
8723 MF_BYCOMMAND|MF_ENABLED);
\r
8731 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8737 HMENU hmenu = GetMenu(hwndMain);
\r
8738 SetMenuEnables(hmenu, ncpEnables);
\r
8739 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8740 MF_BYPOSITION|MF_GRAYED);
\r
8741 DrawMenuBar(hwndMain);
\r
8747 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8751 SetTrainingModeOn()
\r
8754 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8755 for (i = 0; i < N_BUTTONS; i++) {
\r
8756 if (buttonDesc[i].hwnd != NULL)
\r
8757 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8762 VOID SetTrainingModeOff()
\r
8765 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8766 for (i = 0; i < N_BUTTONS; i++) {
\r
8767 if (buttonDesc[i].hwnd != NULL)
\r
8768 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8774 SetUserThinkingEnables()
\r
8776 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8780 SetMachineThinkingEnables()
\r
8782 HMENU hMenu = GetMenu(hwndMain);
\r
8783 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8785 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8787 if (gameMode == MachinePlaysBlack) {
\r
8788 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8789 } else if (gameMode == MachinePlaysWhite) {
\r
8790 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8791 } else if (gameMode == TwoMachinesPlay) {
\r
8792 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8798 DisplayTitle(char *str)
\r
8800 char title[MSG_SIZ], *host;
\r
8801 if (str[0] != NULLCHAR) {
\r
8802 strcpy(title, str);
\r
8803 } else if (appData.icsActive) {
\r
8804 if (appData.icsCommPort[0] != NULLCHAR)
\r
8807 host = appData.icsHost;
\r
8808 sprintf(title, "%s: %s", szTitle, host);
\r
8809 } else if (appData.noChessProgram) {
\r
8810 strcpy(title, szTitle);
\r
8812 strcpy(title, szTitle);
\r
8813 strcat(title, ": ");
\r
8814 strcat(title, first.tidy);
\r
8816 SetWindowText(hwndMain, title);
\r
8821 DisplayMessage(char *str1, char *str2)
\r
8825 int remain = MESSAGE_TEXT_MAX - 1;
\r
8828 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8829 messageText[0] = NULLCHAR;
\r
8831 len = strlen(str1);
\r
8832 if (len > remain) len = remain;
\r
8833 strncpy(messageText, str1, len);
\r
8834 messageText[len] = NULLCHAR;
\r
8837 if (*str2 && remain >= 2) {
\r
8839 strcat(messageText, " ");
\r
8842 len = strlen(str2);
\r
8843 if (len > remain) len = remain;
\r
8844 strncat(messageText, str2, len);
\r
8846 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8848 if (IsIconic(hwndMain)) return;
\r
8849 hdc = GetDC(hwndMain);
\r
8850 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8851 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8852 &messageRect, messageText, strlen(messageText), NULL);
\r
8853 (void) SelectObject(hdc, oldFont);
\r
8854 (void) ReleaseDC(hwndMain, hdc);
\r
8858 DisplayError(char *str, int error)
\r
8860 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8866 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8867 NULL, error, LANG_NEUTRAL,
\r
8868 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8870 sprintf(buf, "%s:\n%s", str, buf2);
\r
8872 ErrorMap *em = errmap;
\r
8873 while (em->err != 0 && em->err != error) em++;
\r
8874 if (em->err != 0) {
\r
8875 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8877 sprintf(buf, "%s:\nError code %d", str, error);
\r
8882 ErrorPopUp("Error", buf);
\r
8887 DisplayMoveError(char *str)
\r
8889 fromX = fromY = -1;
\r
8890 ClearHighlights();
\r
8891 DrawPosition(FALSE, NULL);
\r
8892 if (appData.popupMoveErrors) {
\r
8893 ErrorPopUp("Error", str);
\r
8895 DisplayMessage(str, "");
\r
8896 moveErrorMessageUp = TRUE;
\r
8901 DisplayFatalError(char *str, int error, int exitStatus)
\r
8903 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8905 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8908 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8909 NULL, error, LANG_NEUTRAL,
\r
8910 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8912 sprintf(buf, "%s:\n%s", str, buf2);
\r
8914 ErrorMap *em = errmap;
\r
8915 while (em->err != 0 && em->err != error) em++;
\r
8916 if (em->err != 0) {
\r
8917 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8919 sprintf(buf, "%s:\nError code %d", str, error);
\r
8924 if (appData.debugMode) {
\r
8925 fprintf(debugFP, "%s: %s\n", label, str);
\r
8927 if (appData.popupExitMessage) {
\r
8928 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8929 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8931 ExitEvent(exitStatus);
\r
8936 DisplayInformation(char *str)
\r
8938 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8943 DisplayNote(char *str)
\r
8945 ErrorPopUp("Note", str);
\r
8950 char *title, *question, *replyPrefix;
\r
8955 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8957 static QuestionParams *qp;
\r
8958 char reply[MSG_SIZ];
\r
8961 switch (message) {
\r
8962 case WM_INITDIALOG:
\r
8963 qp = (QuestionParams *) lParam;
\r
8964 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8965 SetWindowText(hDlg, qp->title);
\r
8966 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8967 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8971 switch (LOWORD(wParam)) {
\r
8973 strcpy(reply, qp->replyPrefix);
\r
8974 if (*reply) strcat(reply, " ");
\r
8975 len = strlen(reply);
\r
8976 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8977 strcat(reply, "\n");
\r
8978 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8979 EndDialog(hDlg, TRUE);
\r
8980 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
8983 EndDialog(hDlg, FALSE);
\r
8994 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8996 QuestionParams qp;
\r
9000 qp.question = question;
\r
9001 qp.replyPrefix = replyPrefix;
\r
9003 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
9004 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
9005 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
9006 FreeProcInstance(lpProc);
\r
9009 /* [AS] Pick FRC position */
\r
9010 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9012 static int * lpIndexFRC;
\r
9018 case WM_INITDIALOG:
\r
9019 lpIndexFRC = (int *) lParam;
\r
9021 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9023 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
9024 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
9025 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
9026 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
9031 switch( LOWORD(wParam) ) {
\r
9033 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9034 EndDialog( hDlg, 0 );
\r
9035 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
9038 EndDialog( hDlg, 1 );
\r
9040 case IDC_NFG_Edit:
\r
9041 if( HIWORD(wParam) == EN_CHANGE ) {
\r
9042 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
9044 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
9047 case IDC_NFG_Random:
\r
9048 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
9049 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
9062 int index = appData.defaultFrcPosition;
\r
9063 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
9065 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
9067 if( result == 0 ) {
\r
9068 appData.defaultFrcPosition = index;
\r
9074 /* [AS] Game list options */
\r
9080 static GLT_Item GLT_ItemInfo[] = {
\r
9081 { GLT_EVENT, "Event" },
\r
9082 { GLT_SITE, "Site" },
\r
9083 { GLT_DATE, "Date" },
\r
9084 { GLT_ROUND, "Round" },
\r
9085 { GLT_PLAYERS, "Players" },
\r
9086 { GLT_RESULT, "Result" },
\r
9087 { GLT_WHITE_ELO, "White Rating" },
\r
9088 { GLT_BLACK_ELO, "Black Rating" },
\r
9089 { GLT_TIME_CONTROL,"Time Control" },
\r
9090 { GLT_VARIANT, "Variant" },
\r
9091 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
9095 const char * GLT_FindItem( char id )
\r
9097 const char * result = 0;
\r
9099 GLT_Item * list = GLT_ItemInfo;
\r
9101 while( list->id != 0 ) {
\r
9102 if( list->id == id ) {
\r
9103 result = list->name;
\r
9113 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
9115 const char * name = GLT_FindItem( id );
\r
9118 if( index >= 0 ) {
\r
9119 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
9122 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
9127 void GLT_TagsToList( HWND hDlg, char * tags )
\r
9131 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
9134 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9138 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
9140 pc = GLT_ALL_TAGS;
\r
9143 if( strchr( tags, *pc ) == 0 ) {
\r
9144 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
9149 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
9152 char GLT_ListItemToTag( HWND hDlg, int index )
\r
9154 char result = '\0';
\r
9157 GLT_Item * list = GLT_ItemInfo;
\r
9159 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
9160 while( list->id != 0 ) {
\r
9161 if( strcmp( list->name, name ) == 0 ) {
\r
9162 result = list->id;
\r
9173 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9175 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9176 int idx2 = idx1 + delta;
\r
9177 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9179 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9182 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9183 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9184 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9185 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9189 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9191 static char glt[64];
\r
9192 static char * lpUserGLT;
\r
9196 case WM_INITDIALOG:
\r
9197 lpUserGLT = (char *) lParam;
\r
9199 strcpy( glt, lpUserGLT );
\r
9201 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9203 /* Initialize list */
\r
9204 GLT_TagsToList( hDlg, glt );
\r
9206 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9211 switch( LOWORD(wParam) ) {
\r
9214 char * pc = lpUserGLT;
\r
9216 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9220 id = GLT_ListItemToTag( hDlg, idx );
\r
9224 } while( id != '\0' );
\r
9226 EndDialog( hDlg, 0 );
\r
9229 EndDialog( hDlg, 1 );
\r
9232 case IDC_GLT_Default:
\r
9233 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9234 GLT_TagsToList( hDlg, glt );
\r
9237 case IDC_GLT_Restore:
\r
9238 strcpy( glt, lpUserGLT );
\r
9239 GLT_TagsToList( hDlg, glt );
\r
9243 GLT_MoveSelection( hDlg, -1 );
\r
9246 case IDC_GLT_Down:
\r
9247 GLT_MoveSelection( hDlg, +1 );
\r
9257 int GameListOptions()
\r
9261 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9263 strcpy( glt, appData.gameListTags );
\r
9265 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9267 if( result == 0 ) {
\r
9268 /* [AS] Memory leak here! */
\r
9269 appData.gameListTags = strdup( glt );
\r
9277 DisplayIcsInteractionTitle(char *str)
\r
9279 char consoleTitle[MSG_SIZ];
\r
9281 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9282 SetWindowText(hwndConsole, consoleTitle);
\r
9286 DrawPosition(int fullRedraw, Board board)
\r
9288 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9295 fromX = fromY = -1;
\r
9296 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9297 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9298 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9299 dragInfo.lastpos = dragInfo.pos;
\r
9300 dragInfo.start.x = dragInfo.start.y = -1;
\r
9301 dragInfo.from = dragInfo.start;
\r
9303 DrawPosition(TRUE, NULL);
\r
9309 CommentPopUp(char *title, char *str)
\r
9311 HWND hwnd = GetActiveWindow();
\r
9312 EitherCommentPopUp(0, title, str, FALSE);
\r
9313 SetActiveWindow(hwnd);
\r
9317 CommentPopDown(void)
\r
9319 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9320 if (commentDialog) {
\r
9321 ShowWindow(commentDialog, SW_HIDE);
\r
9323 commentDialogUp = FALSE;
\r
9327 EditCommentPopUp(int index, char *title, char *str)
\r
9329 EitherCommentPopUp(index, title, str, TRUE);
\r
9336 MyPlaySound(&sounds[(int)SoundMove]);
\r
9339 VOID PlayIcsWinSound()
\r
9341 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9344 VOID PlayIcsLossSound()
\r
9346 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9349 VOID PlayIcsDrawSound()
\r
9351 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9354 VOID PlayIcsUnfinishedSound()
\r
9356 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9362 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9370 consoleEcho = TRUE;
\r
9371 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9372 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9373 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9382 consoleEcho = FALSE;
\r
9383 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9384 /* This works OK: set text and background both to the same color */
\r
9386 cf.crTextColor = COLOR_ECHOOFF;
\r
9387 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9388 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9391 /* No Raw()...? */
\r
9393 void Colorize(ColorClass cc, int continuation)
\r
9395 currentColorClass = cc;
\r
9396 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9397 consoleCF.crTextColor = textAttribs[cc].color;
\r
9398 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9399 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9405 static char buf[MSG_SIZ];
\r
9406 DWORD bufsiz = MSG_SIZ;
\r
9408 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9409 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9411 if (!GetUserName(buf, &bufsiz)) {
\r
9412 /*DisplayError("Error getting user name", GetLastError());*/
\r
9413 strcpy(buf, "User");
\r
9421 static char buf[MSG_SIZ];
\r
9422 DWORD bufsiz = MSG_SIZ;
\r
9424 if (!GetComputerName(buf, &bufsiz)) {
\r
9425 /*DisplayError("Error getting host name", GetLastError());*/
\r
9426 strcpy(buf, "Unknown");
\r
9433 ClockTimerRunning()
\r
9435 return clockTimerEvent != 0;
\r
9441 if (clockTimerEvent == 0) return FALSE;
\r
9442 KillTimer(hwndMain, clockTimerEvent);
\r
9443 clockTimerEvent = 0;
\r
9448 StartClockTimer(long millisec)
\r
9450 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9451 (UINT) millisec, NULL);
\r
9455 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9458 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9460 if(appData.noGUI) return;
\r
9461 hdc = GetDC(hwndMain);
\r
9462 if (!IsIconic(hwndMain)) {
\r
9463 DisplayAClock(hdc, timeRemaining, highlight,
\r
9464 (logoHeight > 0 ? flipView: flipClock) ? &blackRect : &whiteRect, "White", flag);
\r
9466 if (highlight && iconCurrent == iconBlack) {
\r
9467 iconCurrent = iconWhite;
\r
9468 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9469 if (IsIconic(hwndMain)) {
\r
9470 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9473 (void) ReleaseDC(hwndMain, hdc);
\r
9475 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9479 DisplayBlackClock(long timeRemaining, int highlight)
\r
9482 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9484 if(appData.noGUI) return;
\r
9485 hdc = GetDC(hwndMain);
\r
9486 if (!IsIconic(hwndMain)) {
\r
9487 DisplayAClock(hdc, timeRemaining, highlight,
\r
9488 (logoHeight > 0 ? flipView: flipClock) ? &whiteRect : &blackRect, "Black", flag);
\r
9490 if (highlight && iconCurrent == iconWhite) {
\r
9491 iconCurrent = iconBlack;
\r
9492 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9493 if (IsIconic(hwndMain)) {
\r
9494 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9497 (void) ReleaseDC(hwndMain, hdc);
\r
9499 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9504 LoadGameTimerRunning()
\r
9506 return loadGameTimerEvent != 0;
\r
9510 StopLoadGameTimer()
\r
9512 if (loadGameTimerEvent == 0) return FALSE;
\r
9513 KillTimer(hwndMain, loadGameTimerEvent);
\r
9514 loadGameTimerEvent = 0;
\r
9519 StartLoadGameTimer(long millisec)
\r
9521 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9522 (UINT) millisec, NULL);
\r
9530 char fileTitle[MSG_SIZ];
\r
9532 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9533 f = OpenFileDialog(hwndMain, "a", defName,
\r
9534 appData.oldSaveStyle ? "gam" : "pgn",
\r
9536 "Save Game to File", NULL, fileTitle, NULL);
\r
9538 SaveGame(f, 0, "");
\r
9545 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9547 if (delayedTimerEvent != 0) {
\r
9548 if (appData.debugMode) {
\r
9549 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9551 KillTimer(hwndMain, delayedTimerEvent);
\r
9552 delayedTimerEvent = 0;
\r
9553 delayedTimerCallback();
\r
9555 delayedTimerCallback = cb;
\r
9556 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9557 (UINT) millisec, NULL);
\r
9560 DelayedEventCallback
\r
9563 if (delayedTimerEvent) {
\r
9564 return delayedTimerCallback;
\r
9571 CancelDelayedEvent()
\r
9573 if (delayedTimerEvent) {
\r
9574 KillTimer(hwndMain, delayedTimerEvent);
\r
9575 delayedTimerEvent = 0;
\r
9579 DWORD GetWin32Priority(int nice)
\r
9580 { // [HGM] nice: translate Unix nice() value to indows priority class. (Code stolen from Polyglot 1.4w11)
\r
9582 REALTIME_PRIORITY_CLASS 0x00000100
\r
9583 HIGH_PRIORITY_CLASS 0x00000080
\r
9584 ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
\r
9585 NORMAL_PRIORITY_CLASS 0x00000020
\r
9586 BELOW_NORMAL_PRIORITY_CLASS 0x00004000
\r
9587 IDLE_PRIORITY_CLASS 0x00000040
\r
9589 if (nice < -15) return 0x00000080;
\r
9590 if (nice < 0) return 0x00008000;
\r
9591 if (nice == 0) return 0x00000020;
\r
9592 if (nice < 15) return 0x00004000;
\r
9593 return 0x00000040;
\r
9596 /* Start a child process running the given program.
\r
9597 The process's standard output can be read from "from", and its
\r
9598 standard input can be written to "to".
\r
9599 Exit with fatal error if anything goes wrong.
\r
9600 Returns an opaque pointer that can be used to destroy the process
\r
9604 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9606 #define BUFSIZE 4096
\r
9608 HANDLE hChildStdinRd, hChildStdinWr,
\r
9609 hChildStdoutRd, hChildStdoutWr;
\r
9610 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9611 SECURITY_ATTRIBUTES saAttr;
\r
9613 PROCESS_INFORMATION piProcInfo;
\r
9614 STARTUPINFO siStartInfo;
\r
9616 char buf[MSG_SIZ];
\r
9619 if (appData.debugMode) {
\r
9620 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9625 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9626 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9627 saAttr.bInheritHandle = TRUE;
\r
9628 saAttr.lpSecurityDescriptor = NULL;
\r
9631 * The steps for redirecting child's STDOUT:
\r
9632 * 1. Create anonymous pipe to be STDOUT for child.
\r
9633 * 2. Create a noninheritable duplicate of read handle,
\r
9634 * and close the inheritable read handle.
\r
9637 /* Create a pipe for the child's STDOUT. */
\r
9638 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9639 return GetLastError();
\r
9642 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9643 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9644 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9645 FALSE, /* not inherited */
\r
9646 DUPLICATE_SAME_ACCESS);
\r
9648 return GetLastError();
\r
9650 CloseHandle(hChildStdoutRd);
\r
9653 * The steps for redirecting child's STDIN:
\r
9654 * 1. Create anonymous pipe to be STDIN for child.
\r
9655 * 2. Create a noninheritable duplicate of write handle,
\r
9656 * and close the inheritable write handle.
\r
9659 /* Create a pipe for the child's STDIN. */
\r
9660 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9661 return GetLastError();
\r
9664 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9665 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9666 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9667 FALSE, /* not inherited */
\r
9668 DUPLICATE_SAME_ACCESS);
\r
9670 return GetLastError();
\r
9672 CloseHandle(hChildStdinWr);
\r
9674 /* Arrange to (1) look in dir for the child .exe file, and
\r
9675 * (2) have dir be the child's working directory. Interpret
\r
9676 * dir relative to the directory WinBoard loaded from. */
\r
9677 GetCurrentDirectory(MSG_SIZ, buf);
\r
9678 SetCurrentDirectory(installDir);
\r
9679 SetCurrentDirectory(dir);
\r
9681 /* Now create the child process. */
\r
9683 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9684 siStartInfo.lpReserved = NULL;
\r
9685 siStartInfo.lpDesktop = NULL;
\r
9686 siStartInfo.lpTitle = NULL;
\r
9687 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9688 siStartInfo.cbReserved2 = 0;
\r
9689 siStartInfo.lpReserved2 = NULL;
\r
9690 siStartInfo.hStdInput = hChildStdinRd;
\r
9691 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9692 siStartInfo.hStdError = hChildStdoutWr;
\r
9694 fSuccess = CreateProcess(NULL,
\r
9695 cmdLine, /* command line */
\r
9696 NULL, /* process security attributes */
\r
9697 NULL, /* primary thread security attrs */
\r
9698 TRUE, /* handles are inherited */
\r
9699 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9700 NULL, /* use parent's environment */
\r
9702 &siStartInfo, /* STARTUPINFO pointer */
\r
9703 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9705 err = GetLastError();
\r
9706 SetCurrentDirectory(buf); /* return to prev directory */
\r
9711 if (appData.niceEngines){ // [HGM] nice: adjust engine proc priority
\r
9712 if(appData.debugMode) fprintf(debugFP, "nice engine proc to %d\n", appData.niceEngines);
\r
9713 SetPriorityClass(piProcInfo.hProcess, GetWin32Priority(appData.niceEngines));
\r
9716 /* Close the handles we don't need in the parent */
\r
9717 CloseHandle(piProcInfo.hThread);
\r
9718 CloseHandle(hChildStdinRd);
\r
9719 CloseHandle(hChildStdoutWr);
\r
9721 /* Prepare return value */
\r
9722 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9723 cp->kind = CPReal;
\r
9724 cp->hProcess = piProcInfo.hProcess;
\r
9725 cp->pid = piProcInfo.dwProcessId;
\r
9726 cp->hFrom = hChildStdoutRdDup;
\r
9727 cp->hTo = hChildStdinWrDup;
\r
9729 *pr = (void *) cp;
\r
9731 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9732 2000 where engines sometimes don't see the initial command(s)
\r
9733 from WinBoard and hang. I don't understand how that can happen,
\r
9734 but the Sleep is harmless, so I've put it in. Others have also
\r
9735 reported what may be the same problem, so hopefully this will fix
\r
9736 it for them too. */
\r
9744 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9746 ChildProc *cp; int result;
\r
9748 cp = (ChildProc *) pr;
\r
9749 if (cp == NULL) return;
\r
9751 switch (cp->kind) {
\r
9753 /* TerminateProcess is considered harmful, so... */
\r
9754 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9755 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9756 /* The following doesn't work because the chess program
\r
9757 doesn't "have the same console" as WinBoard. Maybe
\r
9758 we could arrange for this even though neither WinBoard
\r
9759 nor the chess program uses a console for stdio? */
\r
9760 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9762 /* [AS] Special termination modes for misbehaving programs... */
\r
9763 if( signal == 9 ) {
\r
9764 result = TerminateProcess( cp->hProcess, 0 );
\r
9766 if ( appData.debugMode) {
\r
9767 fprintf( debugFP, "Terminating process %u, result=%d\n", cp->pid, result );
\r
9770 else if( signal == 10 ) {
\r
9771 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9773 if( dw != WAIT_OBJECT_0 ) {
\r
9774 result = TerminateProcess( cp->hProcess, 0 );
\r
9776 if ( appData.debugMode) {
\r
9777 fprintf( debugFP, "Process %u still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9783 CloseHandle(cp->hProcess);
\r
9787 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9791 closesocket(cp->sock);
\r
9796 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9797 closesocket(cp->sock);
\r
9798 closesocket(cp->sock2);
\r
9806 InterruptChildProcess(ProcRef pr)
\r
9810 cp = (ChildProc *) pr;
\r
9811 if (cp == NULL) return;
\r
9812 switch (cp->kind) {
\r
9814 /* The following doesn't work because the chess program
\r
9815 doesn't "have the same console" as WinBoard. Maybe
\r
9816 we could arrange for this even though neither WinBoard
\r
9817 nor the chess program uses a console for stdio */
\r
9818 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9823 /* Can't interrupt */
\r
9827 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9834 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9836 char cmdLine[MSG_SIZ];
\r
9838 if (port[0] == NULLCHAR) {
\r
9839 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9841 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9843 return StartChildProcess(cmdLine, "", pr);
\r
9847 /* Code to open TCP sockets */
\r
9850 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9855 struct sockaddr_in sa, mysa;
\r
9856 struct hostent FAR *hp;
\r
9857 unsigned short uport;
\r
9858 WORD wVersionRequested;
\r
9861 /* Initialize socket DLL */
\r
9862 wVersionRequested = MAKEWORD(1, 1);
\r
9863 err = WSAStartup(wVersionRequested, &wsaData);
\r
9864 if (err != 0) return err;
\r
9867 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9868 err = WSAGetLastError();
\r
9873 /* Bind local address using (mostly) don't-care values.
\r
9875 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9876 mysa.sin_family = AF_INET;
\r
9877 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9878 uport = (unsigned short) 0;
\r
9879 mysa.sin_port = htons(uport);
\r
9880 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9881 == SOCKET_ERROR) {
\r
9882 err = WSAGetLastError();
\r
9887 /* Resolve remote host name */
\r
9888 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9889 if (!(hp = gethostbyname(host))) {
\r
9890 unsigned int b0, b1, b2, b3;
\r
9892 err = WSAGetLastError();
\r
9894 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9895 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9896 hp->h_addrtype = AF_INET;
\r
9898 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9899 hp->h_addr_list[0] = (char *) malloc(4);
\r
9900 hp->h_addr_list[0][0] = (char) b0;
\r
9901 hp->h_addr_list[0][1] = (char) b1;
\r
9902 hp->h_addr_list[0][2] = (char) b2;
\r
9903 hp->h_addr_list[0][3] = (char) b3;
\r
9909 sa.sin_family = hp->h_addrtype;
\r
9910 uport = (unsigned short) atoi(port);
\r
9911 sa.sin_port = htons(uport);
\r
9912 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9914 /* Make connection */
\r
9915 if (connect(s, (struct sockaddr *) &sa,
\r
9916 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9917 err = WSAGetLastError();
\r
9922 /* Prepare return value */
\r
9923 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9924 cp->kind = CPSock;
\r
9926 *pr = (ProcRef *) cp;
\r
9932 OpenCommPort(char *name, ProcRef *pr)
\r
9937 char fullname[MSG_SIZ];
\r
9939 if (*name != '\\')
\r
9940 sprintf(fullname, "\\\\.\\%s", name);
\r
9942 strcpy(fullname, name);
\r
9944 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9945 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9946 if (h == (HANDLE) -1) {
\r
9947 return GetLastError();
\r
9951 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9953 /* Accumulate characters until a 100ms pause, then parse */
\r
9954 ct.ReadIntervalTimeout = 100;
\r
9955 ct.ReadTotalTimeoutMultiplier = 0;
\r
9956 ct.ReadTotalTimeoutConstant = 0;
\r
9957 ct.WriteTotalTimeoutMultiplier = 0;
\r
9958 ct.WriteTotalTimeoutConstant = 0;
\r
9959 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9961 /* Prepare return value */
\r
9962 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9963 cp->kind = CPComm;
\r
9966 *pr = (ProcRef *) cp;
\r
9972 OpenLoopback(ProcRef *pr)
\r
9974 DisplayFatalError("Not implemented", 0, 1);
\r
9980 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9985 struct sockaddr_in sa, mysa;
\r
9986 struct hostent FAR *hp;
\r
9987 unsigned short uport;
\r
9988 WORD wVersionRequested;
\r
9991 char stderrPortStr[MSG_SIZ];
\r
9993 /* Initialize socket DLL */
\r
9994 wVersionRequested = MAKEWORD(1, 1);
\r
9995 err = WSAStartup(wVersionRequested, &wsaData);
\r
9996 if (err != 0) return err;
\r
9998 /* Resolve remote host name */
\r
9999 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
10000 if (!(hp = gethostbyname(host))) {
\r
10001 unsigned int b0, b1, b2, b3;
\r
10003 err = WSAGetLastError();
\r
10005 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
10006 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
10007 hp->h_addrtype = AF_INET;
\r
10008 hp->h_length = 4;
\r
10009 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
10010 hp->h_addr_list[0] = (char *) malloc(4);
\r
10011 hp->h_addr_list[0][0] = (char) b0;
\r
10012 hp->h_addr_list[0][1] = (char) b1;
\r
10013 hp->h_addr_list[0][2] = (char) b2;
\r
10014 hp->h_addr_list[0][3] = (char) b3;
\r
10020 sa.sin_family = hp->h_addrtype;
\r
10021 uport = (unsigned short) 514;
\r
10022 sa.sin_port = htons(uport);
\r
10023 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
10025 /* Bind local socket to unused "privileged" port address
\r
10027 s = INVALID_SOCKET;
\r
10028 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10029 mysa.sin_family = AF_INET;
\r
10030 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10031 for (fromPort = 1023;; fromPort--) {
\r
10032 if (fromPort < 0) {
\r
10034 return WSAEADDRINUSE;
\r
10036 if (s == INVALID_SOCKET) {
\r
10037 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10038 err = WSAGetLastError();
\r
10043 uport = (unsigned short) fromPort;
\r
10044 mysa.sin_port = htons(uport);
\r
10045 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10046 == SOCKET_ERROR) {
\r
10047 err = WSAGetLastError();
\r
10048 if (err == WSAEADDRINUSE) continue;
\r
10052 if (connect(s, (struct sockaddr *) &sa,
\r
10053 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
10054 err = WSAGetLastError();
\r
10055 if (err == WSAEADDRINUSE) {
\r
10066 /* Bind stderr local socket to unused "privileged" port address
\r
10068 s2 = INVALID_SOCKET;
\r
10069 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
10070 mysa.sin_family = AF_INET;
\r
10071 mysa.sin_addr.s_addr = INADDR_ANY;
\r
10072 for (fromPort = 1023;; fromPort--) {
\r
10073 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
10074 if (fromPort < 0) {
\r
10075 (void) closesocket(s);
\r
10077 return WSAEADDRINUSE;
\r
10079 if (s2 == INVALID_SOCKET) {
\r
10080 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
10081 err = WSAGetLastError();
\r
10087 uport = (unsigned short) fromPort;
\r
10088 mysa.sin_port = htons(uport);
\r
10089 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
10090 == SOCKET_ERROR) {
\r
10091 err = WSAGetLastError();
\r
10092 if (err == WSAEADDRINUSE) continue;
\r
10093 (void) closesocket(s);
\r
10097 if (listen(s2, 1) == SOCKET_ERROR) {
\r
10098 err = WSAGetLastError();
\r
10099 if (err == WSAEADDRINUSE) {
\r
10101 s2 = INVALID_SOCKET;
\r
10104 (void) closesocket(s);
\r
10105 (void) closesocket(s2);
\r
10111 prevStderrPort = fromPort; // remember port used
\r
10112 sprintf(stderrPortStr, "%d", fromPort);
\r
10114 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
10115 err = WSAGetLastError();
\r
10116 (void) closesocket(s);
\r
10117 (void) closesocket(s2);
\r
10122 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
10123 err = WSAGetLastError();
\r
10124 (void) closesocket(s);
\r
10125 (void) closesocket(s2);
\r
10129 if (*user == NULLCHAR) user = UserName();
\r
10130 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
10131 err = WSAGetLastError();
\r
10132 (void) closesocket(s);
\r
10133 (void) closesocket(s2);
\r
10137 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
10138 err = WSAGetLastError();
\r
10139 (void) closesocket(s);
\r
10140 (void) closesocket(s2);
\r
10145 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
10146 err = WSAGetLastError();
\r
10147 (void) closesocket(s);
\r
10148 (void) closesocket(s2);
\r
10152 (void) closesocket(s2); /* Stop listening */
\r
10154 /* Prepare return value */
\r
10155 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
10156 cp->kind = CPRcmd;
\r
10159 *pr = (ProcRef *) cp;
\r
10166 AddInputSource(ProcRef pr, int lineByLine,
\r
10167 InputCallback func, VOIDSTAR closure)
\r
10169 InputSource *is, *is2 = NULL;
\r
10170 ChildProc *cp = (ChildProc *) pr;
\r
10172 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
10173 is->lineByLine = lineByLine;
\r
10175 is->closure = closure;
\r
10176 is->second = NULL;
\r
10177 is->next = is->buf;
\r
10178 if (pr == NoProc) {
\r
10179 is->kind = CPReal;
\r
10180 consoleInputSource = is;
\r
10182 is->kind = cp->kind;
\r
10184 [AS] Try to avoid a race condition if the thread is given control too early:
\r
10185 we create all threads suspended so that the is->hThread variable can be
\r
10186 safely assigned, then let the threads start with ResumeThread.
\r
10188 switch (cp->kind) {
\r
10190 is->hFile = cp->hFrom;
\r
10191 cp->hFrom = NULL; /* now owned by InputThread */
\r
10193 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10194 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10198 is->hFile = cp->hFrom;
\r
10199 cp->hFrom = NULL; /* now owned by InputThread */
\r
10201 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10202 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10206 is->sock = cp->sock;
\r
10208 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10209 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10213 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10215 is->sock = cp->sock;
\r
10216 is->second = is2;
\r
10217 is2->sock = cp->sock2;
\r
10218 is2->second = is2;
\r
10220 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10221 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10223 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10224 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10228 if( is->hThread != NULL ) {
\r
10229 ResumeThread( is->hThread );
\r
10232 if( is2 != NULL && is2->hThread != NULL ) {
\r
10233 ResumeThread( is2->hThread );
\r
10237 return (InputSourceRef) is;
\r
10241 RemoveInputSource(InputSourceRef isr)
\r
10245 is = (InputSource *) isr;
\r
10246 is->hThread = NULL; /* tell thread to stop */
\r
10247 CloseHandle(is->hThread);
\r
10248 if (is->second != NULL) {
\r
10249 is->second->hThread = NULL;
\r
10250 CloseHandle(is->second->hThread);
\r
10256 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10259 int outCount = SOCKET_ERROR;
\r
10260 ChildProc *cp = (ChildProc *) pr;
\r
10261 static OVERLAPPED ovl;
\r
10263 if (pr == NoProc) {
\r
10264 ConsoleOutput(message, count, FALSE);
\r
10268 if (ovl.hEvent == NULL) {
\r
10269 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10271 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10273 switch (cp->kind) {
\r
10276 outCount = send(cp->sock, message, count, 0);
\r
10277 if (outCount == SOCKET_ERROR) {
\r
10278 *outError = WSAGetLastError();
\r
10280 *outError = NO_ERROR;
\r
10285 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10286 &dOutCount, NULL)) {
\r
10287 *outError = NO_ERROR;
\r
10288 outCount = (int) dOutCount;
\r
10290 *outError = GetLastError();
\r
10295 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10296 &dOutCount, &ovl);
\r
10297 if (*outError == NO_ERROR) {
\r
10298 outCount = (int) dOutCount;
\r
10306 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10309 /* Ignore delay, not implemented for WinBoard */
\r
10310 return OutputToProcess(pr, message, count, outError);
\r
10315 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10316 char *buf, int count, int error)
\r
10318 DisplayFatalError("Not implemented", 0, 1);
\r
10321 /* see wgamelist.c for Game List functions */
\r
10322 /* see wedittags.c for Edit Tags functions */
\r
10329 char buf[MSG_SIZ];
\r
10332 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10333 f = fopen(buf, "r");
\r
10335 ProcessICSInitScript(f);
\r
10343 StartAnalysisClock()
\r
10345 if (analysisTimerEvent) return;
\r
10346 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10347 (UINT) 2000, NULL);
\r
10351 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10353 static HANDLE hwndText;
\r
10355 static int sizeX, sizeY;
\r
10356 int newSizeX, newSizeY, flags;
\r
10359 switch (message) {
\r
10360 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10361 /* Initialize the dialog items */
\r
10362 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10363 SetWindowText(hDlg, analysisTitle);
\r
10364 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10365 /* Size and position the dialog */
\r
10366 if (!analysisDialog) {
\r
10367 analysisDialog = hDlg;
\r
10368 flags = SWP_NOZORDER;
\r
10369 GetClientRect(hDlg, &rect);
\r
10370 sizeX = rect.right;
\r
10371 sizeY = rect.bottom;
\r
10372 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10373 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10374 WINDOWPLACEMENT wp;
\r
10375 EnsureOnScreen(&analysisX, &analysisY);
\r
10376 wp.length = sizeof(WINDOWPLACEMENT);
\r
10378 wp.showCmd = SW_SHOW;
\r
10379 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10380 wp.rcNormalPosition.left = analysisX;
\r
10381 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10382 wp.rcNormalPosition.top = analysisY;
\r
10383 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10384 SetWindowPlacement(hDlg, &wp);
\r
10386 GetClientRect(hDlg, &rect);
\r
10387 newSizeX = rect.right;
\r
10388 newSizeY = rect.bottom;
\r
10389 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10390 newSizeX, newSizeY);
\r
10391 sizeX = newSizeX;
\r
10392 sizeY = newSizeY;
\r
10397 case WM_COMMAND: /* message: received a command */
\r
10398 switch (LOWORD(wParam)) {
\r
10400 if (appData.icsActive && appData.icsEngineAnalyze) { /* [DM] icsEngineAnalyze */
\r
10401 ExitAnalyzeMode();
\r
10413 newSizeX = LOWORD(lParam);
\r
10414 newSizeY = HIWORD(lParam);
\r
10415 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10416 sizeX = newSizeX;
\r
10417 sizeY = newSizeY;
\r
10420 case WM_GETMINMAXINFO:
\r
10421 /* Prevent resizing window too small */
\r
10422 mmi = (MINMAXINFO *) lParam;
\r
10423 mmi->ptMinTrackSize.x = 100;
\r
10424 mmi->ptMinTrackSize.y = 100;
\r
10431 AnalysisPopUp(char* title, char* str)
\r
10437 EngineOutputPopUp();
\r
10440 if (str == NULL) str = "";
\r
10441 p = (char *) malloc(2 * strlen(str) + 2);
\r
10444 if (*str == '\n') *q++ = '\r';
\r
10448 if (analysisText != NULL) free(analysisText);
\r
10449 analysisText = p;
\r
10451 if (analysisDialog) {
\r
10452 SetWindowText(analysisDialog, title);
\r
10453 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10454 ShowWindow(analysisDialog, SW_SHOW);
\r
10456 analysisTitle = title;
\r
10457 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10458 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10459 hwndMain, (DLGPROC)lpProc);
\r
10460 FreeProcInstance(lpProc);
\r
10462 analysisDialogUp = TRUE;
\r
10466 AnalysisPopDown()
\r
10468 if (analysisDialog) {
\r
10469 ShowWindow(analysisDialog, SW_HIDE);
\r
10471 analysisDialogUp = FALSE;
\r
10476 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10478 highlightInfo.sq[0].x = fromX;
\r
10479 highlightInfo.sq[0].y = fromY;
\r
10480 highlightInfo.sq[1].x = toX;
\r
10481 highlightInfo.sq[1].y = toY;
\r
10485 ClearHighlights()
\r
10487 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10488 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10492 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10494 premoveHighlightInfo.sq[0].x = fromX;
\r
10495 premoveHighlightInfo.sq[0].y = fromY;
\r
10496 premoveHighlightInfo.sq[1].x = toX;
\r
10497 premoveHighlightInfo.sq[1].y = toY;
\r
10501 ClearPremoveHighlights()
\r
10503 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10504 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10508 ShutDownFrontEnd()
\r
10510 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10511 DeleteClipboardTempFiles();
\r
10517 if (IsIconic(hwndMain))
\r
10518 ShowWindow(hwndMain, SW_RESTORE);
\r
10520 SetActiveWindow(hwndMain);
\r
10524 * Prototypes for animation support routines
\r
10526 static void ScreenSquare(int column, int row, POINT * pt);
\r
10527 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10528 POINT frames[], int * nFrames);
\r
10531 #define kFactor 4
\r
10534 AnimateMove(board, fromX, fromY, toX, toY)
\r
10541 ChessSquare piece;
\r
10542 POINT start, finish, mid;
\r
10543 POINT frames[kFactor * 2 + 1];
\r
10546 if (!appData.animate) return;
\r
10547 if (doingSizing) return;
\r
10548 if (fromY < 0 || fromX < 0) return;
\r
10549 piece = board[fromY][fromX];
\r
10550 if (piece >= EmptySquare) return;
\r
10552 ScreenSquare(fromX, fromY, &start);
\r
10553 ScreenSquare(toX, toY, &finish);
\r
10555 /* All pieces except knights move in straight line */
\r
10556 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10557 mid.x = start.x + (finish.x - start.x) / 2;
\r
10558 mid.y = start.y + (finish.y - start.y) / 2;
\r
10560 /* Knight: make diagonal movement then straight */
\r
10561 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10562 mid.x = start.x + (finish.x - start.x) / 2;
\r
10563 mid.y = finish.y;
\r
10565 mid.x = finish.x;
\r
10566 mid.y = start.y + (finish.y - start.y) / 2;
\r
10570 /* Don't use as many frames for very short moves */
\r
10571 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10572 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10574 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10576 animInfo.from.x = fromX;
\r
10577 animInfo.from.y = fromY;
\r
10578 animInfo.to.x = toX;
\r
10579 animInfo.to.y = toY;
\r
10580 animInfo.lastpos = start;
\r
10581 animInfo.piece = piece;
\r
10582 for (n = 0; n < nFrames; n++) {
\r
10583 animInfo.pos = frames[n];
\r
10584 DrawPosition(FALSE, NULL);
\r
10585 animInfo.lastpos = animInfo.pos;
\r
10586 Sleep(appData.animSpeed);
\r
10588 animInfo.pos = finish;
\r
10589 DrawPosition(FALSE, NULL);
\r
10590 animInfo.piece = EmptySquare;
\r
10593 /* Convert board position to corner of screen rect and color */
\r
10596 ScreenSquare(column, row, pt)
\r
10597 int column; int row; POINT * pt;
\r
10600 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10601 pt->y = lineGap + row * (squareSize + lineGap);
\r
10603 pt->x = lineGap + column * (squareSize + lineGap);
\r
10604 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10608 /* Generate a series of frame coords from start->mid->finish.
\r
10609 The movement rate doubles until the half way point is
\r
10610 reached, then halves back down to the final destination,
\r
10611 which gives a nice slow in/out effect. The algorithmn
\r
10612 may seem to generate too many intermediates for short
\r
10613 moves, but remember that the purpose is to attract the
\r
10614 viewers attention to the piece about to be moved and
\r
10615 then to where it ends up. Too few frames would be less
\r
10619 Tween(start, mid, finish, factor, frames, nFrames)
\r
10620 POINT * start; POINT * mid;
\r
10621 POINT * finish; int factor;
\r
10622 POINT frames[]; int * nFrames;
\r
10624 int n, fraction = 1, count = 0;
\r
10626 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10627 for (n = 0; n < factor; n++)
\r
10629 for (n = 0; n < factor; n++) {
\r
10630 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10631 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10633 fraction = fraction / 2;
\r
10637 frames[count] = *mid;
\r
10640 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10642 for (n = 0; n < factor; n++) {
\r
10643 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10644 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10646 fraction = fraction * 2;
\r
10648 *nFrames = count;
\r
10652 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10657 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10658 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10660 OutputDebugString( buf );
\r
10663 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10665 EvalGraphSet( first, last, current, pvInfoList );
\r
10668 void SetProgramStats( FrontEndProgramStats * stats )
\r
10673 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10674 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10676 OutputDebugString( buf );
\r
10679 EngineOutputUpdate( stats );
\r