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;
\r
144 static char messageText[MESSAGE_TEXT_MAX];
\r
145 static int clockTimerEvent = 0;
\r
146 static int loadGameTimerEvent = 0;
\r
147 static int analysisTimerEvent = 0;
\r
148 static DelayedEventCallback delayedTimerCallback;
\r
149 static int delayedTimerEvent = 0;
\r
150 static int buttonCount = 2;
\r
151 char *icsTextMenuString;
\r
153 char *firstChessProgramNames;
\r
154 char *secondChessProgramNames;
\r
156 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
158 #define PALETTESIZE 256
\r
160 HINSTANCE hInst; /* current instance */
\r
161 HWND hwndMain = NULL; /* root window*/
\r
162 HWND hwndConsole = NULL;
\r
163 BOOLEAN alwaysOnTop = FALSE;
\r
165 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
166 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
168 ColorClass currentColorClass;
\r
170 HWND hCommPort = NULL; /* currently open comm port */
\r
171 static HWND hwndPause; /* pause button */
\r
172 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
173 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
174 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
175 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
176 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
177 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
178 static HPEN gridPen = NULL;
\r
179 static HPEN highlightPen = NULL;
\r
180 static HPEN premovePen = NULL;
\r
181 static NPLOGPALETTE pLogPal;
\r
182 static BOOL paletteChanged = FALSE;
\r
183 static HICON iconWhite, iconBlack, iconCurrent;
\r
184 static int doingSizing = FALSE;
\r
185 static int lastSizing = 0;
\r
186 static int prevStderrPort;
\r
188 /* [AS] Support for background textures */
\r
189 #define BACK_TEXTURE_MODE_DISABLED 0
\r
190 #define BACK_TEXTURE_MODE_PLAIN 1
\r
191 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
193 static HBITMAP liteBackTexture = NULL;
\r
194 static HBITMAP darkBackTexture = NULL;
\r
195 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
196 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
197 static int backTextureSquareSize = 0;
\r
198 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
200 #if __GNUC__ && !defined(_winmajor)
\r
201 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
203 #define oldDialog (_winmajor < 4)
\r
206 char *defaultTextAttribs[] =
\r
208 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
209 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
219 int cliWidth, cliHeight;
\r
222 SizeInfo sizeInfo[] =
\r
224 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
225 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
226 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
227 { "petite", 33, 1, 1, 1, 0, 0 },
\r
228 { "slim", 37, 2, 1, 0, 0, 0 },
\r
229 { "small", 40, 2, 1, 0, 0, 0 },
\r
230 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
231 { "middling", 49, 2, 0, 0, 0, 0 },
\r
232 { "average", 54, 2, 0, 0, 0, 0 },
\r
233 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
234 { "medium", 64, 3, 0, 0, 0, 0 },
\r
235 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
236 { "large", 80, 3, 0, 0, 0, 0 },
\r
237 { "big", 87, 3, 0, 0, 0, 0 },
\r
238 { "huge", 95, 3, 0, 0, 0, 0 },
\r
239 { "giant", 108, 3, 0, 0, 0, 0 },
\r
240 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
241 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
242 { NULL, 0, 0, 0, 0, 0, 0 }
\r
245 #define MF(x) {x, {0, }, {0, }, 0}
\r
246 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
248 { 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
249 { 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
250 { 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
251 { 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
252 { 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
253 { 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
254 { 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
255 { 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
256 { 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
257 { 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
258 { 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
259 { 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
260 { 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
261 { 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
262 { 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
263 { 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
264 { 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
265 { 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
268 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
277 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
278 #define N_BUTTONS 5
\r
280 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
282 {"<<", IDM_ToStart, NULL, NULL},
\r
283 {"<", IDM_Backward, NULL, NULL},
\r
284 {"P", IDM_Pause, NULL, NULL},
\r
285 {">", IDM_Forward, NULL, NULL},
\r
286 {">>", IDM_ToEnd, NULL, NULL},
\r
289 int tinyLayout = 0, smallLayout = 0;
\r
290 #define MENU_BAR_ITEMS 6
\r
291 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
292 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
293 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
297 MySound sounds[(int)NSoundClasses];
\r
298 MyTextAttribs textAttribs[(int)NColorClasses];
\r
300 MyColorizeAttribs colorizeAttribs[] = {
\r
301 { (COLORREF)0, 0, "Shout Text" },
\r
302 { (COLORREF)0, 0, "SShout/CShout" },
\r
303 { (COLORREF)0, 0, "Channel 1 Text" },
\r
304 { (COLORREF)0, 0, "Channel Text" },
\r
305 { (COLORREF)0, 0, "Kibitz Text" },
\r
306 { (COLORREF)0, 0, "Tell Text" },
\r
307 { (COLORREF)0, 0, "Challenge Text" },
\r
308 { (COLORREF)0, 0, "Request Text" },
\r
309 { (COLORREF)0, 0, "Seek Text" },
\r
310 { (COLORREF)0, 0, "Normal Text" },
\r
311 { (COLORREF)0, 0, "None" }
\r
316 static char *commentTitle;
\r
317 static char *commentText;
\r
318 static int commentIndex;
\r
319 static Boolean editComment = FALSE;
\r
320 HWND commentDialog = NULL;
\r
321 BOOLEAN commentDialogUp = FALSE;
\r
322 static int commentX, commentY, commentH, commentW;
\r
324 static char *analysisTitle;
\r
325 static char *analysisText;
\r
326 HWND analysisDialog = NULL;
\r
327 BOOLEAN analysisDialogUp = FALSE;
\r
328 static int analysisX, analysisY, analysisH, analysisW;
\r
330 char errorTitle[MSG_SIZ];
\r
331 char errorMessage[2*MSG_SIZ];
\r
332 HWND errorDialog = NULL;
\r
333 BOOLEAN moveErrorMessageUp = FALSE;
\r
334 BOOLEAN consoleEcho = TRUE;
\r
335 CHARFORMAT consoleCF;
\r
336 COLORREF consoleBackgroundColor;
\r
338 char *programVersion;
\r
344 typedef int CPKind;
\r
353 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
356 #define INPUT_SOURCE_BUF_SIZE 4096
\r
358 typedef struct _InputSource {
\r
365 char buf[INPUT_SOURCE_BUF_SIZE];
\r
369 InputCallback func;
\r
370 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
374 InputSource *consoleInputSource;
\r
379 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
380 VOID ConsoleCreate();
\r
382 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
383 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
384 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
385 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
387 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
388 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
389 void ParseIcsTextMenu(char *icsTextMenuString);
\r
390 VOID PopUpMoveDialog(char firstchar);
\r
391 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
395 int GameListOptions();
\r
397 HWND moveHistoryDialog = NULL;
\r
398 BOOLEAN moveHistoryDialogUp = FALSE;
\r
400 WindowPlacement wpMoveHistory;
\r
402 HWND evalGraphDialog = NULL;
\r
403 BOOLEAN evalGraphDialogUp = FALSE;
\r
405 WindowPlacement wpEvalGraph;
\r
407 HWND engineOutputDialog = NULL;
\r
408 BOOLEAN engineOutputDialogUp = FALSE;
\r
410 WindowPlacement wpEngineOutput;
\r
412 VOID MoveHistoryPopUp();
\r
413 VOID MoveHistoryPopDown();
\r
414 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
415 BOOL MoveHistoryIsUp();
\r
417 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
418 VOID EvalGraphPopUp();
\r
419 VOID EvalGraphPopDown();
\r
420 BOOL EvalGraphIsUp();
\r
422 VOID EngineOutputPopUp();
\r
423 VOID EngineOutputPopDown();
\r
424 BOOL EngineOutputIsUp();
\r
425 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
427 VOID GothicPopUp(char *title, VariantClass variant);
\r
429 * Setting "frozen" should disable all user input other than deleting
\r
430 * the window. We do this while engines are initializing themselves.
\r
432 static int frozen = 0;
\r
433 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
439 if (frozen) return;
\r
441 hmenu = GetMenu(hwndMain);
\r
442 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
443 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
445 DrawMenuBar(hwndMain);
\r
448 /* Undo a FreezeUI */
\r
454 if (!frozen) return;
\r
456 hmenu = GetMenu(hwndMain);
\r
457 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
458 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
460 DrawMenuBar(hwndMain);
\r
463 /*---------------------------------------------------------------------------*\
\r
467 \*---------------------------------------------------------------------------*/
\r
470 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
471 LPSTR lpCmdLine, int nCmdShow)
\r
474 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
478 LoadLibrary("RICHED32.DLL");
\r
479 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
481 if (!InitApplication(hInstance)) {
\r
484 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
488 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
489 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
490 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
492 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
494 while (GetMessage(&msg, /* message structure */
\r
495 NULL, /* handle of window receiving the message */
\r
496 0, /* lowest message to examine */
\r
497 0)) /* highest message to examine */
\r
499 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
500 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
501 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
502 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
503 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
504 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
505 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
506 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
507 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
508 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
509 TranslateMessage(&msg); /* Translates virtual key codes */
\r
510 DispatchMessage(&msg); /* Dispatches message to window */
\r
515 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
518 /*---------------------------------------------------------------------------*\
\r
520 * Initialization functions
\r
522 \*---------------------------------------------------------------------------*/
\r
525 InitApplication(HINSTANCE hInstance)
\r
529 /* Fill in window class structure with parameters that describe the */
\r
532 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
533 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
534 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
535 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
536 wc.hInstance = hInstance; /* Owner of this class */
\r
537 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
538 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
539 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
540 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
541 wc.lpszClassName = szAppName; /* Name to register as */
\r
543 /* Register the window class and return success/failure code. */
\r
544 if (!RegisterClass(&wc)) return FALSE;
\r
546 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
547 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
549 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
550 wc.hInstance = hInstance;
\r
551 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
552 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
553 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
554 wc.lpszMenuName = NULL;
\r
555 wc.lpszClassName = szConsoleName;
\r
557 if (!RegisterClass(&wc)) return FALSE;
\r
562 /* Set by InitInstance, used by EnsureOnScreen */
\r
563 int screenHeight, screenWidth;
\r
566 EnsureOnScreen(int *x, int *y)
\r
568 int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
569 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
570 if (*x > screenWidth - 32) *x = 0;
\r
571 if (*y > screenHeight - 32) *y = 0;
\r
572 if (*x < 10) *x = 10;
\r
573 if (*y < gap) *y = gap;
\r
577 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
579 HWND hwnd; /* Main window handle. */
\r
581 WINDOWPLACEMENT wp;
\r
584 hInst = hInstance; /* Store instance handle in our global variable */
\r
586 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
587 *filepart = NULLCHAR;
\r
589 GetCurrentDirectory(MSG_SIZ, installDir);
\r
591 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
592 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
593 if (appData.debugMode) {
\r
594 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
595 setbuf(debugFP, NULL);
\r
600 InitEngineUCI( installDir, &first );
\r
601 InitEngineUCI( installDir, &second );
\r
603 /* Create a main window for this application instance. */
\r
604 hwnd = CreateWindow(szAppName, szTitle,
\r
605 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
606 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
607 NULL, NULL, hInstance, NULL);
\r
610 /* If window could not be created, return "failure" */
\r
615 iconWhite = LoadIcon(hInstance, "icon_white");
\r
616 iconBlack = LoadIcon(hInstance, "icon_black");
\r
617 iconCurrent = iconWhite;
\r
618 InitDrawingColors();
\r
619 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
620 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
621 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
622 /* Compute window size for each board size, and use the largest
\r
623 size that fits on this screen as the default. */
\r
624 InitDrawingSizes((BoardSize)ibs, 0);
\r
625 if (boardSize == (BoardSize)-1 &&
\r
626 winHeight <= screenHeight
\r
627 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
628 && winWidth <= screenWidth) {
\r
629 boardSize = (BoardSize)ibs;
\r
632 InitDrawingSizes(boardSize, 0);
\r
634 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
636 /* [AS] Load textures if specified */
\r
637 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
639 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
640 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
641 liteBackTextureMode = appData.liteBackTextureMode;
\r
643 if (liteBackTexture == NULL && appData.debugMode) {
\r
644 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
648 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
649 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
650 darkBackTextureMode = appData.darkBackTextureMode;
\r
652 if (darkBackTexture == NULL && appData.debugMode) {
\r
653 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
657 mysrandom( (unsigned) time(NULL) );
\r
659 /* Make a console window if needed */
\r
660 if (appData.icsActive) {
\r
664 /* [AS] Restore layout */
\r
665 if( wpMoveHistory.visible ) {
\r
666 MoveHistoryPopUp();
\r
669 if( wpEvalGraph.visible ) {
\r
673 if( wpEngineOutput.visible ) {
\r
674 EngineOutputPopUp();
\r
679 /* Make the window visible; update its client area; and return "success" */
\r
680 EnsureOnScreen(&boardX, &boardY);
\r
681 wp.length = sizeof(WINDOWPLACEMENT);
\r
683 wp.showCmd = nCmdShow;
\r
684 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
685 wp.rcNormalPosition.left = boardX;
\r
686 wp.rcNormalPosition.right = boardX + winWidth;
\r
687 wp.rcNormalPosition.top = boardY;
\r
688 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
689 SetWindowPlacement(hwndMain, &wp);
\r
691 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
692 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
695 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
696 if( gameInfo.variant != VariantFischeRandom ) {
\r
697 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
702 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
703 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
705 ShowWindow(hwndConsole, nCmdShow);
\r
707 UpdateWindow(hwnd);
\r
715 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
716 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
717 ArgSettingsFilename
\r
725 String *pString; // ArgString
\r
726 int *pInt; // ArgInt
\r
727 float *pFloat; // ArgFloat
\r
728 Boolean *pBoolean; // ArgBoolean
\r
729 COLORREF *pColor; // ArgColor
\r
730 ColorClass cc; // ArgAttribs
\r
731 String *pFilename; // ArgFilename
\r
732 BoardSize *pBoardSize; // ArgBoardSize
\r
733 int whichFont; // ArgFont
\r
734 DCB *pDCB; // ArgCommSettings
\r
735 String *pFilename; // ArgSettingsFilename
\r
743 ArgDescriptor argDescriptors[] = {
\r
744 /* positional arguments */
\r
745 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
746 { "", ArgNone, NULL },
\r
747 /* keyword arguments */
\r
748 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
749 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
750 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
751 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
752 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
753 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
754 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
755 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
756 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
757 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
758 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
759 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
760 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
761 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
762 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
763 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
764 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
765 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
767 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
769 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
771 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
772 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
774 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
775 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
776 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
777 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
778 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
779 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
780 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
781 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
782 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
783 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
784 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
785 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
786 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
787 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
788 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
789 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
790 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
791 /*!!bitmapDirectory?*/
\r
792 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
793 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
794 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
795 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
796 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
797 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
798 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
799 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
800 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
801 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
802 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
803 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
804 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
805 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
806 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
807 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
808 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
809 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
810 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
811 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
812 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
813 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
814 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
815 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
816 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
817 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
818 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
819 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
820 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
821 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
822 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
823 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
824 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
825 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
826 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
827 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
828 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
829 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
830 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
831 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
832 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
833 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
834 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
835 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
836 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
837 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
838 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
839 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
840 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
841 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
842 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
843 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
844 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
845 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
846 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
847 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
848 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
849 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
850 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
851 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
852 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
853 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
854 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
855 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
856 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
857 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
858 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
859 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
860 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
861 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
862 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
863 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
864 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
865 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
866 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
867 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
868 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
869 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
870 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
871 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
872 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
873 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
874 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
875 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
876 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
877 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
878 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
879 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
880 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
881 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
882 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
883 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
884 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
885 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
886 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
887 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
888 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
889 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
890 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
891 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
892 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
893 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
894 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
895 TRUE }, /* must come after all fonts */
\r
896 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
897 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
898 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
899 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
900 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
901 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
902 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
903 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
904 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
905 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
906 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
907 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
908 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
909 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
910 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
911 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
912 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
913 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
914 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
915 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
916 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
917 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
918 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
919 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
920 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
921 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
922 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
923 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
924 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
925 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
926 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
928 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
929 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
931 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
932 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
933 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
934 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
935 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
936 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
937 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
938 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
939 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
940 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
941 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
942 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
943 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
944 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
945 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
946 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
947 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
948 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
949 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
950 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
951 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
952 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
953 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
954 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
955 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
956 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
957 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
958 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
959 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
960 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
961 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
962 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
963 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
964 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
965 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
966 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
967 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
968 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
969 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
970 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
971 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
972 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
973 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
974 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
975 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
976 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
977 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
978 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
979 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
980 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
981 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
982 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
983 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
984 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
985 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
986 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
987 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
988 { "highlightLastMove", ArgBoolean,
\r
989 (LPVOID) &appData.highlightLastMove, TRUE },
\r
990 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
991 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
992 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
993 { "highlightDragging", ArgBoolean,
\r
994 (LPVOID) &appData.highlightDragging, TRUE },
\r
995 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
996 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
997 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
998 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
999 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1000 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1001 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1002 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1003 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1004 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1005 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1006 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1007 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1008 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1009 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1010 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1011 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1012 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1013 { "soundShout", ArgFilename,
\r
1014 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1015 { "soundSShout", ArgFilename,
\r
1016 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1017 { "soundChannel1", ArgFilename,
\r
1018 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1019 { "soundChannel", ArgFilename,
\r
1020 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1021 { "soundKibitz", ArgFilename,
\r
1022 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1023 { "soundTell", ArgFilename,
\r
1024 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1025 { "soundChallenge", ArgFilename,
\r
1026 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1027 { "soundRequest", ArgFilename,
\r
1028 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1029 { "soundSeek", ArgFilename,
\r
1030 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1031 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1032 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1033 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1034 { "soundIcsLoss", ArgFilename,
\r
1035 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1036 { "soundIcsDraw", ArgFilename,
\r
1037 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1038 { "soundIcsUnfinished", ArgFilename,
\r
1039 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1040 { "soundIcsAlarm", ArgFilename,
\r
1041 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1042 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1043 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1044 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1045 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1046 { "reuseChessPrograms", ArgBoolean,
\r
1047 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1048 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1049 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1050 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1051 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1052 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1053 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1054 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1055 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1056 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1057 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1058 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1059 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1060 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1061 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1062 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1063 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1064 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1065 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1066 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1067 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1068 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1069 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1070 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1071 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1072 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1073 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1074 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1075 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1076 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1077 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1078 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1079 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1080 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1081 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1082 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1083 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1084 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1086 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1088 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1089 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1090 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1091 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1092 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1093 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1094 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1095 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1096 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1097 /* [AS] New features */
\r
1098 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1099 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1100 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1101 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1102 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1103 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1104 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1105 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1106 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1107 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1108 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1109 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1110 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1111 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1112 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1113 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1114 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1115 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1116 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1117 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1118 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1119 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1120 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1121 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1122 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1123 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1124 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1125 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1126 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1127 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1128 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1129 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1130 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1131 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1132 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1133 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1134 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1135 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1136 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1137 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1138 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1139 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1140 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1141 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1142 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1143 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1144 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1145 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1147 /* [AS] Layout stuff */
\r
1148 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1149 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1150 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1151 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1152 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1154 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1155 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1156 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1157 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1158 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1160 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1161 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1162 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1163 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1164 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1166 /* [HGM] board-size, adjudication and misc. options */
\r
1167 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1168 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1169 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1170 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1171 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1172 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1173 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1174 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1175 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1176 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1177 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1178 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1179 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1180 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1183 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1184 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1185 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1186 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1187 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1188 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1189 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1190 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1191 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1192 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1193 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1194 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1195 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1197 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1198 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1199 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1200 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1201 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1202 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1203 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1205 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1206 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1207 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1208 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1209 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1210 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1211 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1212 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1213 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1214 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1215 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1216 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1217 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1218 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1219 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1220 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1221 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1222 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1224 /* [HGM] options for broadcasting and time odds */
\r
1225 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1226 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1227 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1228 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1229 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1230 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1231 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1232 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1233 { NULL, ArgNone, NULL, FALSE }
\r
1237 /* Kludge for indirection files on command line */
\r
1238 char* lastIndirectionFilename;
\r
1239 ArgDescriptor argDescriptorIndirection =
\r
1240 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1244 ExitArgError(char *msg, char *badArg)
\r
1246 char buf[MSG_SIZ];
\r
1248 sprintf(buf, "%s %s", msg, badArg);
\r
1249 DisplayFatalError(buf, 0, 2);
\r
1253 /* Command line font name parser. NULL name means do nothing.
\r
1254 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1255 For backward compatibility, syntax without the colon is also
\r
1256 accepted, but font names with digits in them won't work in that case.
\r
1259 ParseFontName(char *name, MyFontParams *mfp)
\r
1262 if (name == NULL) return;
\r
1264 q = strchr(p, ':');
\r
1266 if (q - p >= sizeof(mfp->faceName))
\r
1267 ExitArgError("Font name too long:", name);
\r
1268 memcpy(mfp->faceName, p, q - p);
\r
1269 mfp->faceName[q - p] = NULLCHAR;
\r
1272 q = mfp->faceName;
\r
1273 while (*p && !isdigit(*p)) {
\r
1275 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1276 ExitArgError("Font name too long:", name);
\r
1278 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1281 if (!*p) ExitArgError("Font point size missing:", name);
\r
1282 mfp->pointSize = (float) atof(p);
\r
1283 mfp->bold = (strchr(p, 'b') != NULL);
\r
1284 mfp->italic = (strchr(p, 'i') != NULL);
\r
1285 mfp->underline = (strchr(p, 'u') != NULL);
\r
1286 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1289 /* Color name parser.
\r
1290 X version accepts X color names, but this one
\r
1291 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1293 ParseColorName(char *name)
\r
1295 int red, green, blue, count;
\r
1296 char buf[MSG_SIZ];
\r
1298 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1300 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1301 &red, &green, &blue);
\r
1304 sprintf(buf, "Can't parse color name %s", name);
\r
1305 DisplayError(buf, 0);
\r
1306 return RGB(0, 0, 0);
\r
1308 return PALETTERGB(red, green, blue);
\r
1312 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1314 char *e = argValue;
\r
1318 if (*e == 'b') eff |= CFE_BOLD;
\r
1319 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1320 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1321 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1322 else if (*e == '#' || isdigit(*e)) break;
\r
1326 *color = ParseColorName(e);
\r
1331 ParseBoardSize(char *name)
\r
1333 BoardSize bs = SizeTiny;
\r
1334 while (sizeInfo[bs].name != NULL) {
\r
1335 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1338 ExitArgError("Unrecognized board size value", name);
\r
1339 return bs; /* not reached */
\r
1344 StringGet(void *getClosure)
\r
1346 char **p = (char **) getClosure;
\r
1351 FileGet(void *getClosure)
\r
1354 FILE* f = (FILE*) getClosure;
\r
1363 /* Parse settings file named "name". If file found, return the
\r
1364 full name in fullname and return TRUE; else return FALSE */
\r
1366 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1371 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1372 f = fopen(fullname, "r");
\r
1374 ParseArgs(FileGet, f);
\r
1383 ParseArgs(GetFunc get, void *cl)
\r
1385 char argName[ARG_MAX];
\r
1386 char argValue[ARG_MAX];
\r
1387 ArgDescriptor *ad;
\r
1396 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1397 if (ch == NULLCHAR) break;
\r
1399 /* Comment to end of line */
\r
1401 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1403 } else if (ch == '/' || ch == '-') {
\r
1406 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1407 ch != '\n' && ch != '\t') {
\r
1413 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1414 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1416 if (ad->argName == NULL)
\r
1417 ExitArgError("Unrecognized argument", argName);
\r
1419 } else if (ch == '@') {
\r
1420 /* Indirection file */
\r
1421 ad = &argDescriptorIndirection;
\r
1424 /* Positional argument */
\r
1425 ad = &argDescriptors[posarg++];
\r
1426 strcpy(argName, ad->argName);
\r
1429 if (ad->argType == ArgTrue) {
\r
1430 *(Boolean *) ad->argLoc = TRUE;
\r
1433 if (ad->argType == ArgFalse) {
\r
1434 *(Boolean *) ad->argLoc = FALSE;
\r
1438 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1439 if (ch == NULLCHAR || ch == '\n') {
\r
1440 ExitArgError("No value provided for argument", argName);
\r
1444 // Quoting with { }. No characters have to (or can) be escaped.
\r
1445 // Thus the string cannot contain a '}' character.
\r
1465 } else if (ch == '\'' || ch == '"') {
\r
1466 // Quoting with ' ' or " ", with \ as escape character.
\r
1467 // Inconvenient for long strings that may contain Windows filenames.
\r
1484 if (ch == start) {
\r
1493 if (ad->argType == ArgFilename
\r
1494 || ad->argType == ArgSettingsFilename) {
\r
1500 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1524 for (i = 0; i < 3; i++) {
\r
1525 if (ch >= '0' && ch <= '7') {
\r
1526 octval = octval*8 + (ch - '0');
\r
1533 *q++ = (char) octval;
\r
1544 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1551 switch (ad->argType) {
\r
1553 *(int *) ad->argLoc = atoi(argValue);
\r
1557 *(float *) ad->argLoc = (float) atof(argValue);
\r
1562 *(char **) ad->argLoc = strdup(argValue);
\r
1565 case ArgSettingsFilename:
\r
1567 char fullname[MSG_SIZ];
\r
1568 if (ParseSettingsFile(argValue, fullname)) {
\r
1569 if (ad->argLoc != NULL) {
\r
1570 *(char **) ad->argLoc = strdup(fullname);
\r
1573 if (ad->argLoc != NULL) {
\r
1575 ExitArgError("Failed to open indirection file", argValue);
\r
1582 switch (argValue[0]) {
\r
1585 *(Boolean *) ad->argLoc = TRUE;
\r
1589 *(Boolean *) ad->argLoc = FALSE;
\r
1592 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1598 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1601 case ArgAttribs: {
\r
1602 ColorClass cc = (ColorClass)ad->argLoc;
\r
1603 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1607 case ArgBoardSize:
\r
1608 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1612 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1615 case ArgCommSettings:
\r
1616 ParseCommSettings(argValue, &dcb);
\r
1620 ExitArgError("Unrecognized argument", argValue);
\r
1627 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1629 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1630 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1633 lf->lfEscapement = 0;
\r
1634 lf->lfOrientation = 0;
\r
1635 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1636 lf->lfItalic = mfp->italic;
\r
1637 lf->lfUnderline = mfp->underline;
\r
1638 lf->lfStrikeOut = mfp->strikeout;
\r
1639 lf->lfCharSet = DEFAULT_CHARSET;
\r
1640 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1641 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1642 lf->lfQuality = DEFAULT_QUALITY;
\r
1643 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1644 strcpy(lf->lfFaceName, mfp->faceName);
\r
1648 CreateFontInMF(MyFont *mf)
\r
1650 LFfromMFP(&mf->lf, &mf->mfp);
\r
1651 if (mf->hf) DeleteObject(mf->hf);
\r
1652 mf->hf = CreateFontIndirect(&mf->lf);
\r
1656 SetDefaultTextAttribs()
\r
1659 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1660 ParseAttribs(&textAttribs[cc].color,
\r
1661 &textAttribs[cc].effects,
\r
1662 defaultTextAttribs[cc]);
\r
1667 SetDefaultSounds()
\r
1671 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1672 textAttribs[cc].sound.name = strdup("");
\r
1673 textAttribs[cc].sound.data = NULL;
\r
1675 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1676 sounds[sc].name = strdup("");
\r
1677 sounds[sc].data = NULL;
\r
1679 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1687 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1688 MyLoadSound(&textAttribs[cc].sound);
\r
1690 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1691 MyLoadSound(&sounds[sc]);
\r
1696 InitAppData(LPSTR lpCmdLine)
\r
1699 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1702 programName = szAppName;
\r
1704 /* Initialize to defaults */
\r
1705 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1706 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1707 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1708 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1709 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1710 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1711 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1712 SetDefaultTextAttribs();
\r
1713 SetDefaultSounds();
\r
1714 appData.movesPerSession = MOVES_PER_SESSION;
\r
1715 appData.initString = INIT_STRING;
\r
1716 appData.secondInitString = INIT_STRING;
\r
1717 appData.firstComputerString = COMPUTER_STRING;
\r
1718 appData.secondComputerString = COMPUTER_STRING;
\r
1719 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1720 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1721 appData.firstPlaysBlack = FALSE;
\r
1722 appData.noChessProgram = FALSE;
\r
1723 chessProgram = FALSE;
\r
1724 appData.firstHost = FIRST_HOST;
\r
1725 appData.secondHost = SECOND_HOST;
\r
1726 appData.firstDirectory = FIRST_DIRECTORY;
\r
1727 appData.secondDirectory = SECOND_DIRECTORY;
\r
1728 appData.bitmapDirectory = "";
\r
1729 appData.remoteShell = REMOTE_SHELL;
\r
1730 appData.remoteUser = "";
\r
1731 appData.timeDelay = TIME_DELAY;
\r
1732 appData.timeControl = TIME_CONTROL;
\r
1733 appData.timeIncrement = TIME_INCREMENT;
\r
1734 appData.icsActive = FALSE;
\r
1735 appData.icsHost = "";
\r
1736 appData.icsPort = ICS_PORT;
\r
1737 appData.icsCommPort = ICS_COMM_PORT;
\r
1738 appData.icsLogon = ICS_LOGON;
\r
1739 appData.icsHelper = "";
\r
1740 appData.useTelnet = FALSE;
\r
1741 appData.telnetProgram = TELNET_PROGRAM;
\r
1742 appData.gateway = "";
\r
1743 appData.loadGameFile = "";
\r
1744 appData.loadGameIndex = 0;
\r
1745 appData.saveGameFile = "";
\r
1746 appData.autoSaveGames = FALSE;
\r
1747 appData.loadPositionFile = "";
\r
1748 appData.loadPositionIndex = 1;
\r
1749 appData.savePositionFile = "";
\r
1750 appData.matchMode = FALSE;
\r
1751 appData.matchGames = 0;
\r
1752 appData.monoMode = FALSE;
\r
1753 appData.debugMode = FALSE;
\r
1754 appData.clockMode = TRUE;
\r
1755 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1756 appData.Iconic = FALSE; /*unused*/
\r
1757 appData.searchTime = "";
\r
1758 appData.searchDepth = 0;
\r
1759 appData.showCoords = FALSE;
\r
1760 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1761 appData.autoCallFlag = FALSE;
\r
1762 appData.flipView = FALSE;
\r
1763 appData.autoFlipView = TRUE;
\r
1764 appData.cmailGameName = "";
\r
1765 appData.alwaysPromoteToQueen = FALSE;
\r
1766 appData.oldSaveStyle = FALSE;
\r
1767 appData.quietPlay = FALSE;
\r
1768 appData.showThinking = FALSE;
\r
1769 appData.ponderNextMove = TRUE;
\r
1770 appData.periodicUpdates = TRUE;
\r
1771 appData.popupExitMessage = TRUE;
\r
1772 appData.popupMoveErrors = FALSE;
\r
1773 appData.autoObserve = FALSE;
\r
1774 appData.autoComment = FALSE;
\r
1775 appData.animate = TRUE;
\r
1776 appData.animSpeed = 10;
\r
1777 appData.animateDragging = TRUE;
\r
1778 appData.highlightLastMove = TRUE;
\r
1779 appData.getMoveList = TRUE;
\r
1780 appData.testLegality = TRUE;
\r
1781 appData.premove = TRUE;
\r
1782 appData.premoveWhite = FALSE;
\r
1783 appData.premoveWhiteText = "";
\r
1784 appData.premoveBlack = FALSE;
\r
1785 appData.premoveBlackText = "";
\r
1786 appData.icsAlarm = TRUE;
\r
1787 appData.icsAlarmTime = 5000;
\r
1788 appData.autoRaiseBoard = TRUE;
\r
1789 appData.localLineEditing = TRUE;
\r
1790 appData.colorize = TRUE;
\r
1791 appData.reuseFirst = TRUE;
\r
1792 appData.reuseSecond = TRUE;
\r
1793 appData.blindfold = FALSE;
\r
1794 dcb.DCBlength = sizeof(DCB);
\r
1795 dcb.BaudRate = 9600;
\r
1796 dcb.fBinary = TRUE;
\r
1797 dcb.fParity = FALSE;
\r
1798 dcb.fOutxCtsFlow = FALSE;
\r
1799 dcb.fOutxDsrFlow = FALSE;
\r
1800 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1801 dcb.fDsrSensitivity = FALSE;
\r
1802 dcb.fTXContinueOnXoff = TRUE;
\r
1803 dcb.fOutX = FALSE;
\r
1805 dcb.fNull = FALSE;
\r
1806 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1807 dcb.fAbortOnError = FALSE;
\r
1808 dcb.wReserved = 0;
\r
1810 dcb.Parity = SPACEPARITY;
\r
1811 dcb.StopBits = ONESTOPBIT;
\r
1812 settingsFileName = SETTINGS_FILE;
\r
1813 saveSettingsOnExit = TRUE;
\r
1814 boardX = CW_USEDEFAULT;
\r
1815 boardY = CW_USEDEFAULT;
\r
1816 consoleX = CW_USEDEFAULT;
\r
1817 consoleY = CW_USEDEFAULT;
\r
1818 consoleW = CW_USEDEFAULT;
\r
1819 consoleH = CW_USEDEFAULT;
\r
1820 analysisX = CW_USEDEFAULT;
\r
1821 analysisY = CW_USEDEFAULT;
\r
1822 analysisW = CW_USEDEFAULT;
\r
1823 analysisH = CW_USEDEFAULT;
\r
1824 commentX = CW_USEDEFAULT;
\r
1825 commentY = CW_USEDEFAULT;
\r
1826 commentW = CW_USEDEFAULT;
\r
1827 commentH = CW_USEDEFAULT;
\r
1828 editTagsX = CW_USEDEFAULT;
\r
1829 editTagsY = CW_USEDEFAULT;
\r
1830 editTagsW = CW_USEDEFAULT;
\r
1831 editTagsH = CW_USEDEFAULT;
\r
1832 gameListX = CW_USEDEFAULT;
\r
1833 gameListY = CW_USEDEFAULT;
\r
1834 gameListW = CW_USEDEFAULT;
\r
1835 gameListH = CW_USEDEFAULT;
\r
1836 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1837 icsNames = ICS_NAMES;
\r
1838 firstChessProgramNames = FCP_NAMES;
\r
1839 secondChessProgramNames = SCP_NAMES;
\r
1840 appData.initialMode = "";
\r
1841 appData.variant = "normal";
\r
1842 appData.firstProtocolVersion = PROTOVER;
\r
1843 appData.secondProtocolVersion = PROTOVER;
\r
1844 appData.showButtonBar = TRUE;
\r
1846 /* [AS] New properties (see comments in header file) */
\r
1847 appData.firstScoreIsAbsolute = FALSE;
\r
1848 appData.secondScoreIsAbsolute = FALSE;
\r
1849 appData.saveExtendedInfoInPGN = FALSE;
\r
1850 appData.hideThinkingFromHuman = FALSE;
\r
1851 appData.liteBackTextureFile = "";
\r
1852 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1853 appData.darkBackTextureFile = "";
\r
1854 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1855 appData.renderPiecesWithFont = "";
\r
1856 appData.fontToPieceTable = "";
\r
1857 appData.fontBackColorWhite = 0;
\r
1858 appData.fontForeColorWhite = 0;
\r
1859 appData.fontBackColorBlack = 0;
\r
1860 appData.fontForeColorBlack = 0;
\r
1861 appData.fontPieceSize = 80;
\r
1862 appData.overrideLineGap = 1;
\r
1863 appData.adjudicateLossThreshold = 0;
\r
1864 appData.delayBeforeQuit = 0;
\r
1865 appData.delayAfterQuit = 0;
\r
1866 appData.nameOfDebugFile = "winboard.debug";
\r
1867 appData.pgnEventHeader = "Computer Chess Game";
\r
1868 appData.defaultFrcPosition = -1;
\r
1869 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1870 appData.saveOutOfBookInfo = TRUE;
\r
1871 appData.showEvalInMoveHistory = TRUE;
\r
1872 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1873 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1874 appData.highlightMoveWithArrow = FALSE;
\r
1875 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1876 appData.useStickyWindows = TRUE;
\r
1877 appData.adjudicateDrawMoves = 0;
\r
1878 appData.autoDisplayComment = TRUE;
\r
1879 appData.autoDisplayTags = TRUE;
\r
1880 appData.firstIsUCI = FALSE;
\r
1881 appData.secondIsUCI = FALSE;
\r
1882 appData.firstHasOwnBookUCI = TRUE;
\r
1883 appData.secondHasOwnBookUCI = TRUE;
\r
1884 appData.polyglotDir = "";
\r
1885 appData.usePolyglotBook = FALSE;
\r
1886 appData.polyglotBook = "";
\r
1887 appData.defaultHashSize = 64;
\r
1888 appData.defaultCacheSizeEGTB = 4;
\r
1889 appData.defaultPathEGTB = "c:\\egtb";
\r
1891 InitWindowPlacement( &wpMoveHistory );
\r
1892 InitWindowPlacement( &wpEvalGraph );
\r
1893 InitWindowPlacement( &wpEngineOutput );
\r
1895 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1896 appData.NrFiles = -1;
\r
1897 appData.NrRanks = -1;
\r
1898 appData.holdingsSize = -1;
\r
1899 appData.testClaims = FALSE;
\r
1900 appData.checkMates = FALSE;
\r
1901 appData.materialDraws= FALSE;
\r
1902 appData.trivialDraws = FALSE;
\r
1903 appData.ruleMoves = 51;
\r
1904 appData.drawRepeats = 6;
\r
1905 appData.matchPause = 10000;
\r
1906 appData.alphaRank = FALSE;
\r
1907 appData.allWhite = FALSE;
\r
1908 appData.upsideDown = FALSE;
\r
1909 appData.serverPause = 15;
\r
1910 appData.serverMovesName = NULL;
\r
1911 appData.suppressLoadMoves = FALSE;
\r
1912 appData.firstTimeOdds = 1;
\r
1913 appData.secondTimeOdds = 1;
\r
1914 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
1915 appData.secondAccumulateTC = 1;
\r
1918 appData.zippyTalk = ZIPPY_TALK;
\r
1919 appData.zippyPlay = ZIPPY_PLAY;
\r
1920 appData.zippyLines = ZIPPY_LINES;
\r
1921 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1922 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1923 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1924 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1925 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1926 appData.zippyUseI = ZIPPY_USE_I;
\r
1927 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1928 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1929 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1930 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1931 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1932 appData.zippyAbort = ZIPPY_ABORT;
\r
1933 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1934 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1935 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1938 /* Point font array elements to structures and
\r
1939 parse default font names */
\r
1940 for (i=0; i<NUM_FONTS; i++) {
\r
1941 for (j=0; j<NUM_SIZES; j++) {
\r
1942 font[j][i] = &fontRec[j][i];
\r
1943 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1947 /* Parse default settings file if any */
\r
1948 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1949 settingsFileName = strdup(buf);
\r
1952 /* Parse command line */
\r
1953 ParseArgs(StringGet, &lpCmdLine);
\r
1955 /* [HGM] make sure board size is acceptable */
\r
1956 if(appData.NrFiles > BOARD_SIZE ||
\r
1957 appData.NrRanks > BOARD_SIZE )
\r
1958 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
1960 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
1961 * with options from the command line, we now make an even higher priority
\r
1962 * overrule by WB options attached to the engine command line. This so that
\r
1963 * tournament managers can use WB options (such as /timeOdds) that follow
\r
1966 if(appData.firstChessProgram != NULL) {
\r
1967 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
1968 static char *f = "first";
\r
1969 char buf[MSG_SIZ], *q = buf;
\r
1970 if(p != NULL) { // engine command line contains WinBoard options
\r
1971 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
1972 ParseArgs(StringGet, &q);
\r
1973 p[-1] = 0; // cut them offengine command line
\r
1976 // now do same for second chess program
\r
1977 if(appData.secondChessProgram != NULL) {
\r
1978 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
1979 static char *s = "second";
\r
1980 char buf[MSG_SIZ], *q = buf;
\r
1981 if(p != NULL) { // engine command line contains WinBoard options
\r
1982 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
1983 ParseArgs(StringGet, &q);
\r
1984 p[-1] = 0; // cut them offengine command line
\r
1989 /* Propagate options that affect others */
\r
1990 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1991 if (appData.icsActive || appData.noChessProgram) {
\r
1992 chessProgram = FALSE; /* not local chess program mode */
\r
1995 /* Open startup dialog if needed */
\r
1996 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1997 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1998 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1999 *appData.secondChessProgram == NULLCHAR))) {
\r
2002 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2003 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2004 FreeProcInstance(lpProc);
\r
2007 /* Make sure save files land in the right (?) directory */
\r
2008 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2009 appData.saveGameFile = strdup(buf);
\r
2011 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2012 appData.savePositionFile = strdup(buf);
\r
2015 /* Finish initialization for fonts and sounds */
\r
2016 for (i=0; i<NUM_FONTS; i++) {
\r
2017 for (j=0; j<NUM_SIZES; j++) {
\r
2018 CreateFontInMF(font[j][i]);
\r
2021 /* xboard, and older WinBoards, controlled the move sound with the
\r
2022 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2023 always turn the option on (so that the backend will call us),
\r
2024 then let the user turn the sound off by setting it to silence if
\r
2025 desired. To accommodate old winboard.ini files saved by old
\r
2026 versions of WinBoard, we also turn off the sound if the option
\r
2027 was initially set to false. */
\r
2028 if (!appData.ringBellAfterMoves) {
\r
2029 sounds[(int)SoundMove].name = strdup("");
\r
2030 appData.ringBellAfterMoves = TRUE;
\r
2032 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2033 SetCurrentDirectory(installDir);
\r
2035 SetCurrentDirectory(currDir);
\r
2037 p = icsTextMenuString;
\r
2038 if (p[0] == '@') {
\r
2039 FILE* f = fopen(p + 1, "r");
\r
2041 DisplayFatalError(p + 1, errno, 2);
\r
2044 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2046 buf[i] = NULLCHAR;
\r
2049 ParseIcsTextMenu(strdup(p));
\r
2056 HMENU hmenu = GetMenu(hwndMain);
\r
2058 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2059 MF_BYCOMMAND|((appData.icsActive &&
\r
2060 *appData.icsCommPort != NULLCHAR) ?
\r
2061 MF_ENABLED : MF_GRAYED));
\r
2062 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2063 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2064 MF_CHECKED : MF_UNCHECKED));
\r
2069 SaveSettings(char* name)
\r
2072 ArgDescriptor *ad;
\r
2073 WINDOWPLACEMENT wp;
\r
2074 char dir[MSG_SIZ];
\r
2076 if (!hwndMain) return;
\r
2078 GetCurrentDirectory(MSG_SIZ, dir);
\r
2079 SetCurrentDirectory(installDir);
\r
2080 f = fopen(name, "w");
\r
2081 SetCurrentDirectory(dir);
\r
2083 DisplayError(name, errno);
\r
2086 fprintf(f, ";\n");
\r
2087 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2088 fprintf(f, ";\n");
\r
2089 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2090 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2091 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2092 fprintf(f, ";\n");
\r
2094 wp.length = sizeof(WINDOWPLACEMENT);
\r
2095 GetWindowPlacement(hwndMain, &wp);
\r
2096 boardX = wp.rcNormalPosition.left;
\r
2097 boardY = wp.rcNormalPosition.top;
\r
2099 if (hwndConsole) {
\r
2100 GetWindowPlacement(hwndConsole, &wp);
\r
2101 consoleX = wp.rcNormalPosition.left;
\r
2102 consoleY = wp.rcNormalPosition.top;
\r
2103 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2104 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2107 if (analysisDialog) {
\r
2108 GetWindowPlacement(analysisDialog, &wp);
\r
2109 analysisX = wp.rcNormalPosition.left;
\r
2110 analysisY = wp.rcNormalPosition.top;
\r
2111 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2112 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2115 if (commentDialog) {
\r
2116 GetWindowPlacement(commentDialog, &wp);
\r
2117 commentX = wp.rcNormalPosition.left;
\r
2118 commentY = wp.rcNormalPosition.top;
\r
2119 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2120 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2123 if (editTagsDialog) {
\r
2124 GetWindowPlacement(editTagsDialog, &wp);
\r
2125 editTagsX = wp.rcNormalPosition.left;
\r
2126 editTagsY = wp.rcNormalPosition.top;
\r
2127 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2128 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2131 if (gameListDialog) {
\r
2132 GetWindowPlacement(gameListDialog, &wp);
\r
2133 gameListX = wp.rcNormalPosition.left;
\r
2134 gameListY = wp.rcNormalPosition.top;
\r
2135 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2136 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2139 /* [AS] Move history */
\r
2140 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2142 if( moveHistoryDialog ) {
\r
2143 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2144 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2145 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2146 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2147 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2150 /* [AS] Eval graph */
\r
2151 wpEvalGraph.visible = EvalGraphIsUp();
\r
2153 if( evalGraphDialog ) {
\r
2154 GetWindowPlacement(evalGraphDialog, &wp);
\r
2155 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2156 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2157 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2158 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2161 /* [AS] Engine output */
\r
2162 wpEngineOutput.visible = EngineOutputIsUp();
\r
2164 if( engineOutputDialog ) {
\r
2165 GetWindowPlacement(engineOutputDialog, &wp);
\r
2166 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2167 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2168 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2169 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2172 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2173 if (!ad->save) continue;
\r
2174 switch (ad->argType) {
\r
2177 char *p = *(char **)ad->argLoc;
\r
2178 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2179 /* Quote multiline values or \-containing values
\r
2180 with { } if possible */
\r
2181 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2183 /* Else quote with " " */
\r
2184 fprintf(f, "/%s=\"", ad->argName);
\r
2186 if (*p == '\n') fprintf(f, "\n");
\r
2187 else if (*p == '\r') fprintf(f, "\\r");
\r
2188 else if (*p == '\t') fprintf(f, "\\t");
\r
2189 else if (*p == '\b') fprintf(f, "\\b");
\r
2190 else if (*p == '\f') fprintf(f, "\\f");
\r
2191 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2192 else if (*p == '\"') fprintf(f, "\\\"");
\r
2193 else if (*p == '\\') fprintf(f, "\\\\");
\r
2197 fprintf(f, "\"\n");
\r
2202 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2205 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2208 fprintf(f, "/%s=%s\n", ad->argName,
\r
2209 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2212 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2215 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2219 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2220 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2221 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2226 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2227 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2228 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2229 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2230 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2231 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2232 (ta->effects) ? " " : "",
\r
2233 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2237 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2238 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2240 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2243 case ArgBoardSize:
\r
2244 fprintf(f, "/%s=%s\n", ad->argName,
\r
2245 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2250 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2251 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2252 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2253 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2254 ad->argName, mfp->faceName, mfp->pointSize,
\r
2255 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2256 mfp->bold ? "b" : "",
\r
2257 mfp->italic ? "i" : "",
\r
2258 mfp->underline ? "u" : "",
\r
2259 mfp->strikeout ? "s" : "");
\r
2263 case ArgCommSettings:
\r
2264 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2272 /*---------------------------------------------------------------------------*\
\r
2274 * GDI board drawing routines
\r
2276 \*---------------------------------------------------------------------------*/
\r
2278 /* [AS] Draw square using background texture */
\r
2279 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2284 return; /* Should never happen! */
\r
2287 SetGraphicsMode( dst, GM_ADVANCED );
\r
2294 /* X reflection */
\r
2299 x.eDx = (FLOAT) dw + dx - 1;
\r
2302 SetWorldTransform( dst, &x );
\r
2305 /* Y reflection */
\r
2311 x.eDy = (FLOAT) dh + dy - 1;
\r
2313 SetWorldTransform( dst, &x );
\r
2321 x.eDx = (FLOAT) dx;
\r
2322 x.eDy = (FLOAT) dy;
\r
2325 SetWorldTransform( dst, &x );
\r
2329 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2337 SetWorldTransform( dst, &x );
\r
2339 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2342 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2344 PM_WP = (int) WhitePawn,
\r
2345 PM_WN = (int) WhiteKnight,
\r
2346 PM_WB = (int) WhiteBishop,
\r
2347 PM_WR = (int) WhiteRook,
\r
2348 PM_WQ = (int) WhiteQueen,
\r
2349 PM_WF = (int) WhiteFerz,
\r
2350 PM_WW = (int) WhiteWazir,
\r
2351 PM_WE = (int) WhiteAlfil,
\r
2352 PM_WM = (int) WhiteMan,
\r
2353 PM_WO = (int) WhiteCannon,
\r
2354 PM_WU = (int) WhiteUnicorn,
\r
2355 PM_WH = (int) WhiteNightrider,
\r
2356 PM_WA = (int) WhiteAngel,
\r
2357 PM_WC = (int) WhiteMarshall,
\r
2358 PM_WG = (int) WhiteGrasshopper,
\r
2359 PM_WK = (int) WhiteKing,
\r
2360 PM_BP = (int) BlackPawn,
\r
2361 PM_BN = (int) BlackKnight,
\r
2362 PM_BB = (int) BlackBishop,
\r
2363 PM_BR = (int) BlackRook,
\r
2364 PM_BQ = (int) BlackQueen,
\r
2365 PM_BF = (int) BlackFerz,
\r
2366 PM_BW = (int) BlackWazir,
\r
2367 PM_BE = (int) BlackAlfil,
\r
2368 PM_BM = (int) BlackMan,
\r
2369 PM_BO = (int) BlackCannon,
\r
2370 PM_BU = (int) BlackUnicorn,
\r
2371 PM_BH = (int) BlackNightrider,
\r
2372 PM_BA = (int) BlackAngel,
\r
2373 PM_BC = (int) BlackMarshall,
\r
2374 PM_BG = (int) BlackGrasshopper,
\r
2375 PM_BK = (int) BlackKing
\r
2378 static HFONT hPieceFont = NULL;
\r
2379 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2380 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2381 static int fontBitmapSquareSize = 0;
\r
2382 static char pieceToFontChar[(int) EmptySquare] =
\r
2383 { 'p', 'n', 'b', 'r', 'q',
\r
2384 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2385 'k', 'o', 'm', 'v', 't', 'w',
\r
2386 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2389 extern BOOL SetCharTable( char *table, const char * map );
\r
2390 /* [HGM] moved to backend.c */
\r
2392 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2395 BYTE r1 = GetRValue( color );
\r
2396 BYTE g1 = GetGValue( color );
\r
2397 BYTE b1 = GetBValue( color );
\r
2403 /* Create a uniform background first */
\r
2404 hbrush = CreateSolidBrush( color );
\r
2405 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2406 FillRect( hdc, &rc, hbrush );
\r
2407 DeleteObject( hbrush );
\r
2410 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2411 int steps = squareSize / 2;
\r
2414 for( i=0; i<steps; i++ ) {
\r
2415 BYTE r = r1 - (r1-r2) * i / steps;
\r
2416 BYTE g = g1 - (g1-g2) * i / steps;
\r
2417 BYTE b = b1 - (b1-b2) * i / steps;
\r
2419 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2420 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2421 FillRect( hdc, &rc, hbrush );
\r
2422 DeleteObject(hbrush);
\r
2425 else if( mode == 2 ) {
\r
2426 /* Diagonal gradient, good more or less for every piece */
\r
2427 POINT triangle[3];
\r
2428 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2429 HBRUSH hbrush_old;
\r
2430 int steps = squareSize;
\r
2433 triangle[0].x = squareSize - steps;
\r
2434 triangle[0].y = squareSize;
\r
2435 triangle[1].x = squareSize;
\r
2436 triangle[1].y = squareSize;
\r
2437 triangle[2].x = squareSize;
\r
2438 triangle[2].y = squareSize - steps;
\r
2440 for( i=0; i<steps; i++ ) {
\r
2441 BYTE r = r1 - (r1-r2) * i / steps;
\r
2442 BYTE g = g1 - (g1-g2) * i / steps;
\r
2443 BYTE b = b1 - (b1-b2) * i / steps;
\r
2445 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2446 hbrush_old = SelectObject( hdc, hbrush );
\r
2447 Polygon( hdc, triangle, 3 );
\r
2448 SelectObject( hdc, hbrush_old );
\r
2449 DeleteObject(hbrush);
\r
2454 SelectObject( hdc, hpen );
\r
2459 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2460 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2461 piece: follow the steps as explained below.
\r
2463 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2467 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2471 int backColor = whitePieceColor;
\r
2472 int foreColor = blackPieceColor;
\r
2473 int shapeIndex = index < 6 ? index+6 : index;
\r
2475 if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2476 backColor = appData.fontBackColorWhite;
\r
2477 foreColor = appData.fontForeColorWhite;
\r
2479 else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2480 backColor = appData.fontBackColorBlack;
\r
2481 foreColor = appData.fontForeColorBlack;
\r
2485 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2487 hbm_old = SelectObject( hdc, hbm );
\r
2491 rc.right = squareSize;
\r
2492 rc.bottom = squareSize;
\r
2494 /* Step 1: background is now black */
\r
2495 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2497 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2499 pt.x = (squareSize - sz.cx) / 2;
\r
2500 pt.y = (squareSize - sz.cy) / 2;
\r
2502 SetBkMode( hdc, TRANSPARENT );
\r
2503 SetTextColor( hdc, chroma );
\r
2504 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2505 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2507 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2508 /* Step 3: the area outside the piece is filled with white */
\r
2509 FloodFill( hdc, 0, 0, chroma );
\r
2510 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2512 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2513 but if the start point is not inside the piece we're lost!
\r
2514 There should be a better way to do this... if we could create a region or path
\r
2515 from the fill operation we would be fine for example.
\r
2517 FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2519 SetTextColor( hdc, 0 );
\r
2521 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2522 draw the piece again in black for safety.
\r
2524 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2526 SelectObject( hdc, hbm_old );
\r
2528 if( hPieceMask[index] != NULL ) {
\r
2529 DeleteObject( hPieceMask[index] );
\r
2532 hPieceMask[index] = hbm;
\r
2535 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2537 SelectObject( hdc, hbm );
\r
2540 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2541 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2542 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2544 SelectObject( dc1, hPieceMask[index] );
\r
2545 SelectObject( dc2, bm2 );
\r
2546 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2547 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2550 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2551 the piece background and deletes (makes transparent) the rest.
\r
2552 Thanks to that mask, we are free to paint the background with the greates
\r
2553 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2554 We use this, to make gradients and give the pieces a "roundish" look.
\r
2556 SetPieceBackground( hdc, backColor, 2 );
\r
2557 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2561 DeleteObject( bm2 );
\r
2564 SetTextColor( hdc, foreColor );
\r
2565 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2567 SelectObject( hdc, hbm_old );
\r
2569 if( hPieceFace[index] != NULL ) {
\r
2570 DeleteObject( hPieceFace[index] );
\r
2573 hPieceFace[index] = hbm;
\r
2576 static int TranslatePieceToFontPiece( int piece )
\r
2605 case BlackMarshall:
\r
2609 case BlackNightrider:
\r
2615 case BlackUnicorn:
\r
2619 case BlackGrasshopper:
\r
2625 case WhiteMarshall:
\r
2629 case WhiteNightrider:
\r
2635 case WhiteUnicorn:
\r
2639 case WhiteGrasshopper:
\r
2648 void CreatePiecesFromFont()
\r
2651 HDC hdc_window = NULL;
\r
2657 if( fontBitmapSquareSize < 0 ) {
\r
2658 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2662 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2663 fontBitmapSquareSize = -1;
\r
2667 if( fontBitmapSquareSize != squareSize ) {
\r
2668 hdc_window = GetDC( hwndMain );
\r
2669 hdc = CreateCompatibleDC( hdc_window );
\r
2671 if( hPieceFont != NULL ) {
\r
2672 DeleteObject( hPieceFont );
\r
2675 for( i=0; i<12; i++ ) {
\r
2676 hPieceMask[i] = NULL;
\r
2677 hPieceFace[i] = NULL;
\r
2683 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2684 fontHeight = appData.fontPieceSize;
\r
2687 fontHeight = (fontHeight * squareSize) / 100;
\r
2689 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2691 lf.lfEscapement = 0;
\r
2692 lf.lfOrientation = 0;
\r
2693 lf.lfWeight = FW_NORMAL;
\r
2695 lf.lfUnderline = 0;
\r
2696 lf.lfStrikeOut = 0;
\r
2697 lf.lfCharSet = DEFAULT_CHARSET;
\r
2698 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2699 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2700 lf.lfQuality = PROOF_QUALITY;
\r
2701 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2702 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2703 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2705 hPieceFont = CreateFontIndirect( &lf );
\r
2707 if( hPieceFont == NULL ) {
\r
2708 fontBitmapSquareSize = -2;
\r
2711 /* Setup font-to-piece character table */
\r
2712 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2713 /* No (or wrong) global settings, try to detect the font */
\r
2714 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2716 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2718 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2719 /* DiagramTT* family */
\r
2720 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2722 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2723 /* Fairy symbols */
\r
2724 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2726 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2727 /* Good Companion (Some characters get warped as literal :-( */
\r
2728 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2729 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2730 SetCharTable(pieceToFontChar, s);
\r
2733 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2734 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2738 /* Create bitmaps */
\r
2739 hfont_old = SelectObject( hdc, hPieceFont );
\r
2741 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2742 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2743 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2744 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2745 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2746 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2747 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2748 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2749 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2750 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2751 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2752 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2754 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2755 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2756 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2757 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2758 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2759 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2760 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2761 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2762 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2763 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2764 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2765 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2766 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2767 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2768 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2769 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2770 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2771 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2772 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2773 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2776 SelectObject( hdc, hfont_old );
\r
2778 fontBitmapSquareSize = squareSize;
\r
2782 if( hdc != NULL ) {
\r
2786 if( hdc_window != NULL ) {
\r
2787 ReleaseDC( hwndMain, hdc_window );
\r
2792 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2796 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2797 if (gameInfo.event &&
\r
2798 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2799 strcmp(name, "k80s") == 0) {
\r
2800 strcpy(name, "tim");
\r
2802 return LoadBitmap(hinst, name);
\r
2806 /* Insert a color into the program's logical palette
\r
2807 structure. This code assumes the given color is
\r
2808 the result of the RGB or PALETTERGB macro, and it
\r
2809 knows how those macros work (which is documented).
\r
2812 InsertInPalette(COLORREF color)
\r
2814 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2816 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2817 DisplayFatalError("Too many colors", 0, 1);
\r
2818 pLogPal->palNumEntries--;
\r
2822 pe->peFlags = (char) 0;
\r
2823 pe->peRed = (char) (0xFF & color);
\r
2824 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2825 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2831 InitDrawingColors()
\r
2833 if (pLogPal == NULL) {
\r
2834 /* Allocate enough memory for a logical palette with
\r
2835 * PALETTESIZE entries and set the size and version fields
\r
2836 * of the logical palette structure.
\r
2838 pLogPal = (NPLOGPALETTE)
\r
2839 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2840 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2841 pLogPal->palVersion = 0x300;
\r
2843 pLogPal->palNumEntries = 0;
\r
2845 InsertInPalette(lightSquareColor);
\r
2846 InsertInPalette(darkSquareColor);
\r
2847 InsertInPalette(whitePieceColor);
\r
2848 InsertInPalette(blackPieceColor);
\r
2849 InsertInPalette(highlightSquareColor);
\r
2850 InsertInPalette(premoveHighlightColor);
\r
2852 /* create a logical color palette according the information
\r
2853 * in the LOGPALETTE structure.
\r
2855 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2857 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2858 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2859 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2860 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2861 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2862 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2864 /* [AS] Force rendering of the font-based pieces */
\r
2865 if( fontBitmapSquareSize > 0 ) {
\r
2866 fontBitmapSquareSize = 0;
\r
2872 BoardWidth(int boardSize, int n)
\r
2873 { /* [HGM] argument n added to allow different width and height */
\r
2874 int lineGap = sizeInfo[boardSize].lineGap;
\r
2876 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2877 lineGap = appData.overrideLineGap;
\r
2880 return (n + 1) * lineGap +
\r
2881 n * sizeInfo[boardSize].squareSize;
\r
2884 /* Respond to board resize by dragging edge */
\r
2886 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2888 BoardSize newSize = NUM_SIZES - 1;
\r
2889 static int recurse = 0;
\r
2890 if (IsIconic(hwndMain)) return;
\r
2891 if (recurse > 0) return;
\r
2893 while (newSize > 0 &&
\r
2894 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2895 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2898 boardSize = newSize;
\r
2899 InitDrawingSizes(boardSize, flags);
\r
2906 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2908 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2909 ChessSquare piece;
\r
2910 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2912 SIZE clockSize, messageSize;
\r
2914 char buf[MSG_SIZ];
\r
2916 HMENU hmenu = GetMenu(hwndMain);
\r
2917 RECT crect, wrect;
\r
2919 LOGBRUSH logbrush;
\r
2921 /* [HGM] call with -1 uses old size (for if nr of files, ranks changes) */
\r
2922 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2924 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2925 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2926 squareSize = sizeInfo[boardSize].squareSize;
\r
2927 lineGap = sizeInfo[boardSize].lineGap;
\r
2928 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2930 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2931 lineGap = appData.overrideLineGap;
\r
2934 if (tinyLayout != oldTinyLayout) {
\r
2935 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2937 style &= ~WS_SYSMENU;
\r
2938 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2939 "&Minimize\tCtrl+F4");
\r
2941 style |= WS_SYSMENU;
\r
2942 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2944 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2946 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2947 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2948 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2950 DrawMenuBar(hwndMain);
\r
2953 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
2954 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
2956 /* Get text area sizes */
\r
2957 hdc = GetDC(hwndMain);
\r
2958 if (appData.clockMode) {
\r
2959 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2961 sprintf(buf, "White");
\r
2963 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2964 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2965 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2966 str = "We only care about the height here";
\r
2967 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2968 SelectObject(hdc, oldFont);
\r
2969 ReleaseDC(hwndMain, hdc);
\r
2971 /* Compute where everything goes */
\r
2972 whiteRect.left = OUTER_MARGIN;
\r
2973 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2974 whiteRect.top = OUTER_MARGIN;
\r
2975 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2977 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2978 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2979 blackRect.top = whiteRect.top;
\r
2980 blackRect.bottom = whiteRect.bottom;
\r
2982 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2983 if (appData.showButtonBar) {
\r
2984 messageRect.right = blackRect.right
\r
2985 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2987 messageRect.right = blackRect.right;
\r
2989 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2990 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2992 boardRect.left = whiteRect.left;
\r
2993 boardRect.right = boardRect.left + boardWidth;
\r
2994 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2995 boardRect.bottom = boardRect.top + boardHeight;
\r
2997 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2998 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2999 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3000 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3001 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3002 GetWindowRect(hwndMain, &wrect);
\r
3003 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3004 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3005 /* compensate if menu bar wrapped */
\r
3006 GetClientRect(hwndMain, &crect);
\r
3007 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3008 winHeight += offby;
\r
3010 case WMSZ_TOPLEFT:
\r
3011 SetWindowPos(hwndMain, NULL,
\r
3012 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3013 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3016 case WMSZ_TOPRIGHT:
\r
3018 SetWindowPos(hwndMain, NULL,
\r
3019 wrect.left, wrect.bottom - winHeight,
\r
3020 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3023 case WMSZ_BOTTOMLEFT:
\r
3025 SetWindowPos(hwndMain, NULL,
\r
3026 wrect.right - winWidth, wrect.top,
\r
3027 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3030 case WMSZ_BOTTOMRIGHT:
\r
3034 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3035 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3040 for (i = 0; i < N_BUTTONS; i++) {
\r
3041 if (buttonDesc[i].hwnd != NULL) {
\r
3042 DestroyWindow(buttonDesc[i].hwnd);
\r
3043 buttonDesc[i].hwnd = NULL;
\r
3045 if (appData.showButtonBar) {
\r
3046 buttonDesc[i].hwnd =
\r
3047 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3048 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3049 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3050 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3051 (HMENU) buttonDesc[i].id,
\r
3052 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3054 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3055 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3056 MAKELPARAM(FALSE, 0));
\r
3058 if (buttonDesc[i].id == IDM_Pause)
\r
3059 hwndPause = buttonDesc[i].hwnd;
\r
3060 buttonDesc[i].wndproc = (WNDPROC)
\r
3061 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3064 if (gridPen != NULL) DeleteObject(gridPen);
\r
3065 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3066 if (premovePen != NULL) DeleteObject(premovePen);
\r
3067 if (lineGap != 0) {
\r
3068 logbrush.lbStyle = BS_SOLID;
\r
3069 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3071 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3072 lineGap, &logbrush, 0, NULL);
\r
3073 logbrush.lbColor = highlightSquareColor;
\r
3075 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3076 lineGap, &logbrush, 0, NULL);
\r
3078 logbrush.lbColor = premoveHighlightColor;
\r
3080 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3081 lineGap, &logbrush, 0, NULL);
\r
3083 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3084 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3085 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3086 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3087 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3088 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3089 BOARD_WIDTH * (squareSize + lineGap);
\r
3090 lineGap / 2 + (i * (squareSize + lineGap));
\r
3091 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3093 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3094 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3095 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3096 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3097 lineGap / 2 + (i * (squareSize + lineGap));
\r
3098 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3099 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3100 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3104 /* [HGM] Licensing requirement */
\r
3106 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3109 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3111 GothicPopUp( "", VariantNormal);
\r
3114 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3115 oldBoardSize = boardSize;
\r
3116 oldTinyLayout = tinyLayout;
\r
3118 /* Load piece bitmaps for this board size */
\r
3119 for (i=0; i<=2; i++) {
\r
3120 for (piece = WhitePawn;
\r
3121 (int) piece < (int) BlackPawn;
\r
3122 piece = (ChessSquare) ((int) piece + 1)) {
\r
3123 if (pieceBitmap[i][piece] != NULL)
\r
3124 DeleteObject(pieceBitmap[i][piece]);
\r
3128 // Orthodox Chess pieces
\r
3129 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3130 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3131 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3132 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3133 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3134 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3135 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3136 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3137 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3138 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3139 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3140 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3141 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3142 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3143 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3144 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3145 // in Shogi, Hijack the unused Queen for Lance
\r
3146 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3147 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3148 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3150 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3151 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3152 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3155 if(squareSize <= 72 && squareSize >= 33) {
\r
3156 /* A & C are available in most sizes now */
\r
3157 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3158 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3159 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3160 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3161 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3162 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3163 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3164 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3165 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3166 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3167 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3168 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3169 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3170 } else { // Smirf-like
\r
3171 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3172 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3173 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3175 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3176 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3177 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3178 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3179 } else { // WinBoard standard
\r
3180 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3181 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3182 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3187 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3188 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3189 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3190 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3191 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3192 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3193 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3194 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3195 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3196 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3197 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3198 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3199 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3200 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3201 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3202 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3203 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3204 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3205 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3206 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3207 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3208 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3209 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3210 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3211 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3212 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3213 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3214 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3215 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3216 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3217 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3219 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3220 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3221 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3222 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3223 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3224 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3225 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3226 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3227 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3228 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3229 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3230 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3231 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3233 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3234 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3235 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3236 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3237 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3238 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3239 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3240 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3241 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3242 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3243 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3244 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3247 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3248 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3249 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3250 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3251 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3252 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3253 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3254 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3255 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3256 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3257 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3258 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3259 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3260 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3261 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3265 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3266 /* special Shogi support in this size */
\r
3267 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3268 for (piece = WhitePawn;
\r
3269 (int) piece < (int) BlackPawn;
\r
3270 piece = (ChessSquare) ((int) piece + 1)) {
\r
3271 if (pieceBitmap[i][piece] != NULL)
\r
3272 DeleteObject(pieceBitmap[i][piece]);
\r
3275 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3276 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3277 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3278 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3279 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3280 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3281 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3282 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3283 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3284 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3285 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3286 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3287 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3288 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3289 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3290 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3291 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3292 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3293 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3294 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3295 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3296 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3297 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3298 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3299 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3300 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3301 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3302 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3303 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3304 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3305 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3306 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3307 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3308 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3309 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3310 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3311 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3312 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3313 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3314 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3315 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3316 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3322 PieceBitmap(ChessSquare p, int kind)
\r
3324 if ((int) p >= (int) BlackPawn)
\r
3325 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3327 return pieceBitmap[kind][(int) p];
\r
3330 /***************************************************************/
\r
3332 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3333 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3335 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3336 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3340 SquareToPos(int row, int column, int * x, int * y)
\r
3343 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3344 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3346 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3347 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3352 DrawCoordsOnDC(HDC hdc)
\r
3354 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
3355 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
3356 char str[2] = { NULLCHAR, NULLCHAR };
\r
3357 int oldMode, oldAlign, x, y, start, i;
\r
3361 if (!appData.showCoords)
\r
3364 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3366 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3367 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3368 oldAlign = GetTextAlign(hdc);
\r
3369 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3371 y = boardRect.top + lineGap;
\r
3372 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3374 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3375 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3376 str[0] = files[start + i];
\r
3377 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3378 y += squareSize + lineGap;
\r
3381 start = flipView ? 12-BOARD_WIDTH : 12;
\r
3383 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3384 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3385 str[0] = ranks[start + i];
\r
3386 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3387 x += squareSize + lineGap;
\r
3390 SelectObject(hdc, oldBrush);
\r
3391 SetBkMode(hdc, oldMode);
\r
3392 SetTextAlign(hdc, oldAlign);
\r
3393 SelectObject(hdc, oldFont);
\r
3397 DrawGridOnDC(HDC hdc)
\r
3401 if (lineGap != 0) {
\r
3402 oldPen = SelectObject(hdc, gridPen);
\r
3403 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3404 SelectObject(hdc, oldPen);
\r
3408 #define HIGHLIGHT_PEN 0
\r
3409 #define PREMOVE_PEN 1
\r
3412 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3415 HPEN oldPen, hPen;
\r
3416 if (lineGap == 0) return;
\r
3418 x1 = boardRect.left +
\r
3419 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3420 y1 = boardRect.top +
\r
3421 lineGap/2 + y * (squareSize + lineGap);
\r
3423 x1 = boardRect.left +
\r
3424 lineGap/2 + x * (squareSize + lineGap);
\r
3425 y1 = boardRect.top +
\r
3426 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3428 hPen = pen ? premovePen : highlightPen;
\r
3429 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3430 MoveToEx(hdc, x1, y1, NULL);
\r
3431 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3432 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3433 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3434 LineTo(hdc, x1, y1);
\r
3435 SelectObject(hdc, oldPen);
\r
3439 DrawHighlightsOnDC(HDC hdc)
\r
3442 for (i=0; i<2; i++) {
\r
3443 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3444 DrawHighlightOnDC(hdc, TRUE,
\r
3445 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3448 for (i=0; i<2; i++) {
\r
3449 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3450 premoveHighlightInfo.sq[i].y >= 0) {
\r
3451 DrawHighlightOnDC(hdc, TRUE,
\r
3452 premoveHighlightInfo.sq[i].x,
\r
3453 premoveHighlightInfo.sq[i].y,
\r
3459 /* Note: sqcolor is used only in monoMode */
\r
3460 /* Note that this code is largely duplicated in woptions.c,
\r
3461 function DrawSampleSquare, so that needs to be updated too */
\r
3463 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3465 HBITMAP oldBitmap;
\r
3469 if (appData.blindfold) return;
\r
3471 /* [AS] Use font-based pieces if needed */
\r
3472 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3473 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3474 CreatePiecesFromFont();
\r
3476 if( fontBitmapSquareSize == squareSize ) {
\r
3477 int index = TranslatePieceToFontPiece( piece );
\r
3479 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3483 squareSize, squareSize,
\r
3488 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3492 squareSize, squareSize,
\r
3501 if (appData.monoMode) {
\r
3502 SelectObject(tmphdc, PieceBitmap(piece,
\r
3503 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3504 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3505 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3507 tmpSize = squareSize;
\r
3509 (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||
\r
3510 piece >= (int)BlackNightrider && piece <= BlackGrasshopper) ) {
\r
3511 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3512 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3513 x += (squareSize - minorSize)>>1;
\r
3514 y += squareSize - minorSize - 2;
\r
3515 tmpSize = minorSize;
\r
3517 if (color || appData.allWhite ) {
\r
3518 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3520 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3521 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3522 if(appData.upsideDown && color==flipView)
\r
3523 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3525 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3527 /* Use black piece color for outline of white pieces */
\r
3528 /* Not sure this looks really good (though xboard does it).
\r
3529 Maybe better to have another selectable color, default black */
\r
3530 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3531 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3532 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3534 /* Use black for outline of white pieces */
\r
3535 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3536 if(appData.upsideDown && color==flipView)
\r
3537 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3539 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3543 /* Use white piece color for details of black pieces */
\r
3544 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3545 WHITE_PIECE ones aren't always the right shape. */
\r
3546 /* Not sure this looks really good (though xboard does it).
\r
3547 Maybe better to have another selectable color, default medium gray? */
\r
3548 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3549 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3550 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3551 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3552 SelectObject(hdc, blackPieceBrush);
\r
3553 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3555 /* Use square color for details of black pieces */
\r
3556 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3557 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3558 if(appData.upsideDown && !flipView)
\r
3559 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3561 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3564 SelectObject(hdc, oldBrush);
\r
3565 SelectObject(tmphdc, oldBitmap);
\r
3569 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3570 int GetBackTextureMode( int algo )
\r
3572 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3576 case BACK_TEXTURE_MODE_PLAIN:
\r
3577 result = 1; /* Always use identity map */
\r
3579 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3580 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3588 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3589 to handle redraws cleanly (as random numbers would always be different).
\r
3591 VOID RebuildTextureSquareInfo()
\r
3601 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3603 if( liteBackTexture != NULL ) {
\r
3604 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3605 lite_w = bi.bmWidth;
\r
3606 lite_h = bi.bmHeight;
\r
3610 if( darkBackTexture != NULL ) {
\r
3611 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3612 dark_w = bi.bmWidth;
\r
3613 dark_h = bi.bmHeight;
\r
3617 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3618 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3619 if( (col + row) & 1 ) {
\r
3621 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3622 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_WIDTH;
\r
3623 backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_HEIGHT;
\r
3624 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3629 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3630 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_WIDTH;
\r
3631 backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_HEIGHT;
\r
3632 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3639 /* [AS] Arrow highlighting support */
\r
3641 static int A_WIDTH = 5; /* Width of arrow body */
\r
3643 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3644 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3646 static double Sqr( double x )
\r
3651 static int Round( double x )
\r
3653 return (int) (x + 0.5);
\r
3656 /* Draw an arrow between two points using current settings */
\r
3657 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3660 double dx, dy, j, k, x, y;
\r
3662 if( d_x == s_x ) {
\r
3663 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3665 arrow[0].x = s_x + A_WIDTH;
\r
3668 arrow[1].x = s_x + A_WIDTH;
\r
3669 arrow[1].y = d_y - h;
\r
3671 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3672 arrow[2].y = d_y - h;
\r
3677 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3678 arrow[4].y = d_y - h;
\r
3680 arrow[5].x = s_x - A_WIDTH;
\r
3681 arrow[5].y = d_y - h;
\r
3683 arrow[6].x = s_x - A_WIDTH;
\r
3686 else if( d_y == s_y ) {
\r
3687 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3690 arrow[0].y = s_y + A_WIDTH;
\r
3692 arrow[1].x = d_x - w;
\r
3693 arrow[1].y = s_y + A_WIDTH;
\r
3695 arrow[2].x = d_x - w;
\r
3696 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3701 arrow[4].x = d_x - w;
\r
3702 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3704 arrow[5].x = d_x - w;
\r
3705 arrow[5].y = s_y - A_WIDTH;
\r
3708 arrow[6].y = s_y - A_WIDTH;
\r
3711 /* [AS] Needed a lot of paper for this! :-) */
\r
3712 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3713 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3715 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3717 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3722 arrow[0].x = Round(x - j);
\r
3723 arrow[0].y = Round(y + j*dx);
\r
3725 arrow[1].x = Round(x + j);
\r
3726 arrow[1].y = Round(y - j*dx);
\r
3729 x = (double) d_x - k;
\r
3730 y = (double) d_y - k*dy;
\r
3733 x = (double) d_x + k;
\r
3734 y = (double) d_y + k*dy;
\r
3737 arrow[2].x = Round(x + j);
\r
3738 arrow[2].y = Round(y - j*dx);
\r
3740 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3741 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3746 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3747 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3749 arrow[6].x = Round(x - j);
\r
3750 arrow[6].y = Round(y + j*dx);
\r
3753 Polygon( hdc, arrow, 7 );
\r
3756 /* [AS] Draw an arrow between two squares */
\r
3757 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3759 int s_x, s_y, d_x, d_y;
\r
3766 if( s_col == d_col && s_row == d_row ) {
\r
3770 /* Get source and destination points */
\r
3771 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3772 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3775 d_y += squareSize / 4;
\r
3777 else if( d_y < s_y ) {
\r
3778 d_y += 3 * squareSize / 4;
\r
3781 d_y += squareSize / 2;
\r
3785 d_x += squareSize / 4;
\r
3787 else if( d_x < s_x ) {
\r
3788 d_x += 3 * squareSize / 4;
\r
3791 d_x += squareSize / 2;
\r
3794 s_x += squareSize / 2;
\r
3795 s_y += squareSize / 2;
\r
3797 /* Adjust width */
\r
3798 A_WIDTH = squareSize / 14;
\r
3801 stLB.lbStyle = BS_SOLID;
\r
3802 stLB.lbColor = appData.highlightArrowColor;
\r
3805 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3806 holdpen = SelectObject( hdc, hpen );
\r
3807 hbrush = CreateBrushIndirect( &stLB );
\r
3808 holdbrush = SelectObject( hdc, hbrush );
\r
3810 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3812 SelectObject( hdc, holdpen );
\r
3813 SelectObject( hdc, holdbrush );
\r
3814 DeleteObject( hpen );
\r
3815 DeleteObject( hbrush );
\r
3818 BOOL HasHighlightInfo()
\r
3820 BOOL result = FALSE;
\r
3822 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3823 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3831 BOOL IsDrawArrowEnabled()
\r
3833 BOOL result = FALSE;
\r
3835 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3842 VOID DrawArrowHighlight( HDC hdc )
\r
3844 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3845 DrawArrowBetweenSquares( hdc,
\r
3846 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3847 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3851 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3853 HRGN result = NULL;
\r
3855 if( HasHighlightInfo() ) {
\r
3856 int x1, y1, x2, y2;
\r
3857 int sx, sy, dx, dy;
\r
3859 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3860 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3862 sx = MIN( x1, x2 );
\r
3863 sy = MIN( y1, y2 );
\r
3864 dx = MAX( x1, x2 ) + squareSize;
\r
3865 dy = MAX( y1, y2 ) + squareSize;
\r
3867 result = CreateRectRgn( sx, sy, dx, dy );
\r
3874 Warning: this function modifies the behavior of several other functions.
\r
3876 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3877 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3878 repaint is scattered all over the place, which is not good for features such as
\r
3879 "arrow highlighting" that require a full repaint of the board.
\r
3881 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3882 user interaction, when speed is not so important) but especially to avoid errors
\r
3883 in the displayed graphics.
\r
3885 In such patched places, I always try refer to this function so there is a single
\r
3886 place to maintain knowledge.
\r
3888 To restore the original behavior, just return FALSE unconditionally.
\r
3890 BOOL IsFullRepaintPreferrable()
\r
3892 BOOL result = FALSE;
\r
3894 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3895 /* Arrow may appear on the board */
\r
3903 This function is called by DrawPosition to know whether a full repaint must
\r
3906 Only DrawPosition may directly call this function, which makes use of
\r
3907 some state information. Other function should call DrawPosition specifying
\r
3908 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3910 BOOL DrawPositionNeedsFullRepaint()
\r
3912 BOOL result = FALSE;
\r
3915 Probably a slightly better policy would be to trigger a full repaint
\r
3916 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3917 but animation is fast enough that it's difficult to notice.
\r
3919 if( animInfo.piece == EmptySquare ) {
\r
3920 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3929 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3931 int row, column, x, y, square_color, piece_color;
\r
3932 ChessSquare piece;
\r
3934 HDC texture_hdc = NULL;
\r
3936 /* [AS] Initialize background textures if needed */
\r
3937 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3938 if( backTextureSquareSize != squareSize ) {
\r
3939 backTextureSquareSize = squareSize;
\r
3940 RebuildTextureSquareInfo();
\r
3943 texture_hdc = CreateCompatibleDC( hdc );
\r
3946 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3947 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3949 SquareToPos(row, column, &x, &y);
\r
3951 piece = board[row][column];
\r
3953 square_color = ((column + row) % 2) == 1;
\r
3954 if(!strcmp(appData.variant, "xiangqi") ) {
\r
3955 square_color = !InPalace(row, column);
\r
3956 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3957 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3959 piece_color = (int) piece < (int) BlackPawn;
\r
3963 /* [HGM] holdings file: light square or black */
\r
3964 if(column == BOARD_LEFT-2) {
\r
3965 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3968 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3972 if(column == BOARD_RGHT + 1 ) {
\r
3973 if( row < gameInfo.holdingsSize )
\r
3976 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3980 if(column == BOARD_LEFT-1 ) /* left align */
\r
3981 DisplayHoldingsCount(hdc, x, y, 0, (int) board[row][column]);
\r
3982 else if( column == BOARD_RGHT) /* right align */
\r
3983 DisplayHoldingsCount(hdc, x, y, 1, (int) board[row][column]);
\r
3986 if (appData.monoMode) {
\r
3987 if (piece == EmptySquare) {
\r
3988 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3989 square_color ? WHITENESS : BLACKNESS);
\r
3991 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3994 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
3995 /* [AS] Draw the square using a texture bitmap */
\r
3996 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3999 squareSize, squareSize,
\r
4002 backTextureSquareInfo[row][column].mode,
\r
4003 backTextureSquareInfo[row][column].x,
\r
4004 backTextureSquareInfo[row][column].y );
\r
4006 SelectObject( texture_hdc, hbm );
\r
4008 if (piece != EmptySquare) {
\r
4009 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4013 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4015 oldBrush = SelectObject(hdc, brush );
\r
4016 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4017 SelectObject(hdc, oldBrush);
\r
4018 if (piece != EmptySquare)
\r
4019 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4024 if( texture_hdc != NULL ) {
\r
4025 DeleteDC( texture_hdc );
\r
4029 #define MAX_CLIPS 200 /* more than enough */
\r
4032 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4034 static Board lastReq, lastDrawn;
\r
4035 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4036 static int lastDrawnFlipView = 0;
\r
4037 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4038 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4041 HBITMAP bufferBitmap;
\r
4042 HBITMAP oldBitmap;
\r
4044 HRGN clips[MAX_CLIPS];
\r
4045 ChessSquare dragged_piece = EmptySquare;
\r
4047 /* I'm undecided on this - this function figures out whether a full
\r
4048 * repaint is necessary on its own, so there's no real reason to have the
\r
4049 * caller tell it that. I think this can safely be set to FALSE - but
\r
4050 * if we trust the callers not to request full repaints unnessesarily, then
\r
4051 * we could skip some clipping work. In other words, only request a full
\r
4052 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4053 * gamestart and similar) --Hawk
\r
4055 Boolean fullrepaint = repaint;
\r
4057 if( DrawPositionNeedsFullRepaint() ) {
\r
4058 fullrepaint = TRUE;
\r
4062 if( fullrepaint ) {
\r
4063 static int repaint_count = 0;
\r
4067 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4068 OutputDebugString( buf );
\r
4072 if (board == NULL) {
\r
4073 if (!lastReqValid) {
\r
4078 CopyBoard(lastReq, board);
\r
4082 if (doingSizing) {
\r
4086 if (IsIconic(hwndMain)) {
\r
4090 if (hdc == NULL) {
\r
4091 hdc = GetDC(hwndMain);
\r
4092 if (!appData.monoMode) {
\r
4093 SelectPalette(hdc, hPal, FALSE);
\r
4094 RealizePalette(hdc);
\r
4098 releaseDC = FALSE;
\r
4102 fprintf(debugFP, "*******************************\n"
\r
4104 "dragInfo.from (%d,%d)\n"
\r
4105 "dragInfo.start (%d,%d)\n"
\r
4106 "dragInfo.pos (%d,%d)\n"
\r
4107 "dragInfo.lastpos (%d,%d)\n",
\r
4108 repaint ? "TRUE" : "FALSE",
\r
4109 dragInfo.from.x, dragInfo.from.y,
\r
4110 dragInfo.start.x, dragInfo.start.y,
\r
4111 dragInfo.pos.x, dragInfo.pos.y,
\r
4112 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4113 fprintf(debugFP, "prev: ");
\r
4114 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4115 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4116 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4119 fprintf(debugFP, "\n");
\r
4120 fprintf(debugFP, "board: ");
\r
4121 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4122 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4123 fprintf(debugFP, "%d ", board[row][column]);
\r
4126 fprintf(debugFP, "\n");
\r
4130 /* Create some work-DCs */
\r
4131 hdcmem = CreateCompatibleDC(hdc);
\r
4132 tmphdc = CreateCompatibleDC(hdc);
\r
4134 /* If dragging is in progress, we temporarely remove the piece */
\r
4135 /* [HGM] or temporarily decrease count if stacked */
\r
4136 /* !! Moved to before board compare !! */
\r
4137 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4138 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4139 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4140 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4141 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4143 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4144 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4145 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4147 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4150 /* Figure out which squares need updating by comparing the
\r
4151 * newest board with the last drawn board and checking if
\r
4152 * flipping has changed.
\r
4154 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4155 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4156 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4157 if (lastDrawn[row][column] != board[row][column]) {
\r
4158 SquareToPos(row, column, &x, &y);
\r
4159 clips[num_clips++] =
\r
4160 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4164 for (i=0; i<2; i++) {
\r
4165 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4166 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4167 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4168 lastDrawnHighlight.sq[i].y >= 0) {
\r
4169 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4170 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4171 clips[num_clips++] =
\r
4172 CreateRectRgn(x - lineGap, y - lineGap,
\r
4173 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4175 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4176 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4177 clips[num_clips++] =
\r
4178 CreateRectRgn(x - lineGap, y - lineGap,
\r
4179 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4183 for (i=0; i<2; i++) {
\r
4184 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4185 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4186 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4187 lastDrawnPremove.sq[i].y >= 0) {
\r
4188 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4189 lastDrawnPremove.sq[i].x, &x, &y);
\r
4190 clips[num_clips++] =
\r
4191 CreateRectRgn(x - lineGap, y - lineGap,
\r
4192 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4194 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4195 premoveHighlightInfo.sq[i].y >= 0) {
\r
4196 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4197 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4198 clips[num_clips++] =
\r
4199 CreateRectRgn(x - lineGap, y - lineGap,
\r
4200 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4205 fullrepaint = TRUE;
\r
4208 /* Create a buffer bitmap - this is the actual bitmap
\r
4209 * being written to. When all the work is done, we can
\r
4210 * copy it to the real DC (the screen). This avoids
\r
4211 * the problems with flickering.
\r
4213 GetClientRect(hwndMain, &Rect);
\r
4214 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4215 Rect.bottom-Rect.top+1);
\r
4216 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4217 if (!appData.monoMode) {
\r
4218 SelectPalette(hdcmem, hPal, FALSE);
\r
4221 /* Create clips for dragging */
\r
4222 if (!fullrepaint) {
\r
4223 if (dragInfo.from.x >= 0) {
\r
4224 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4225 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4227 if (dragInfo.start.x >= 0) {
\r
4228 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4229 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4231 if (dragInfo.pos.x >= 0) {
\r
4232 x = dragInfo.pos.x - squareSize / 2;
\r
4233 y = dragInfo.pos.y - squareSize / 2;
\r
4234 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4236 if (dragInfo.lastpos.x >= 0) {
\r
4237 x = dragInfo.lastpos.x - squareSize / 2;
\r
4238 y = dragInfo.lastpos.y - squareSize / 2;
\r
4239 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4243 /* Are we animating a move?
\r
4245 * - remove the piece from the board (temporarely)
\r
4246 * - calculate the clipping region
\r
4248 if (!fullrepaint) {
\r
4249 if (animInfo.piece != EmptySquare) {
\r
4250 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4251 x = boardRect.left + animInfo.lastpos.x;
\r
4252 y = boardRect.top + animInfo.lastpos.y;
\r
4253 x2 = boardRect.left + animInfo.pos.x;
\r
4254 y2 = boardRect.top + animInfo.pos.y;
\r
4255 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4256 /* Slight kludge. The real problem is that after AnimateMove is
\r
4257 done, the position on the screen does not match lastDrawn.
\r
4258 This currently causes trouble only on e.p. captures in
\r
4259 atomic, where the piece moves to an empty square and then
\r
4260 explodes. The old and new positions both had an empty square
\r
4261 at the destination, but animation has drawn a piece there and
\r
4262 we have to remember to erase it. */
\r
4263 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4267 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4268 if (num_clips == 0)
\r
4269 fullrepaint = TRUE;
\r
4271 /* Set clipping on the memory DC */
\r
4272 if (!fullrepaint) {
\r
4273 SelectClipRgn(hdcmem, clips[0]);
\r
4274 for (x = 1; x < num_clips; x++) {
\r
4275 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4276 abort(); // this should never ever happen!
\r
4280 /* Do all the drawing to the memory DC */
\r
4281 DrawGridOnDC(hdcmem);
\r
4282 DrawHighlightsOnDC(hdcmem);
\r
4283 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4285 if( appData.highlightMoveWithArrow ) {
\r
4286 DrawArrowHighlight(hdcmem);
\r
4289 DrawCoordsOnDC(hdcmem);
\r
4291 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4292 /* to make sure lastDrawn contains what is actually drawn */
\r
4294 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4295 if (dragged_piece != EmptySquare) {
\r
4296 /* [HGM] or restack */
\r
4297 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4298 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4300 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4301 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4302 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4303 x = dragInfo.pos.x - squareSize / 2;
\r
4304 y = dragInfo.pos.y - squareSize / 2;
\r
4305 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4306 ((int) dragged_piece < (int) BlackPawn),
\r
4307 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4310 /* Put the animated piece back into place and draw it */
\r
4311 if (animInfo.piece != EmptySquare) {
\r
4312 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4313 x = boardRect.left + animInfo.pos.x;
\r
4314 y = boardRect.top + animInfo.pos.y;
\r
4315 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4316 ((int) animInfo.piece < (int) BlackPawn),
\r
4317 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4320 /* Release the bufferBitmap by selecting in the old bitmap
\r
4321 * and delete the memory DC
\r
4323 SelectObject(hdcmem, oldBitmap);
\r
4326 /* Set clipping on the target DC */
\r
4327 if (!fullrepaint) {
\r
4328 SelectClipRgn(hdc, clips[0]);
\r
4329 for (x = 1; x < num_clips; x++) {
\r
4330 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4331 abort(); // this should never ever happen!
\r
4335 /* Copy the new bitmap onto the screen in one go.
\r
4336 * This way we avoid any flickering
\r
4338 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4339 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4340 boardRect.right - boardRect.left,
\r
4341 boardRect.bottom - boardRect.top,
\r
4342 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4343 SelectObject(tmphdc, oldBitmap);
\r
4345 /* Massive cleanup */
\r
4346 for (x = 0; x < num_clips; x++)
\r
4347 DeleteObject(clips[x]);
\r
4350 DeleteObject(bufferBitmap);
\r
4353 ReleaseDC(hwndMain, hdc);
\r
4355 if (lastDrawnFlipView != flipView) {
\r
4357 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4359 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4362 /* CopyBoard(lastDrawn, board);*/
\r
4363 lastDrawnHighlight = highlightInfo;
\r
4364 lastDrawnPremove = premoveHighlightInfo;
\r
4365 lastDrawnFlipView = flipView;
\r
4366 lastDrawnValid = 1;
\r
4370 /*---------------------------------------------------------------------------*\
\r
4371 | CLIENT PAINT PROCEDURE
\r
4372 | This is the main event-handler for the WM_PAINT message.
\r
4374 \*---------------------------------------------------------------------------*/
\r
4376 PaintProc(HWND hwnd)
\r
4382 if(hdc = BeginPaint(hwnd, &ps)) {
\r
4383 if (IsIconic(hwnd)) {
\r
4384 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4386 if (!appData.monoMode) {
\r
4387 SelectPalette(hdc, hPal, FALSE);
\r
4388 RealizePalette(hdc);
\r
4390 HDCDrawPosition(hdc, 1, NULL);
\r
4392 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4393 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4394 ETO_CLIPPED|ETO_OPAQUE,
\r
4395 &messageRect, messageText, strlen(messageText), NULL);
\r
4396 SelectObject(hdc, oldFont);
\r
4397 DisplayBothClocks();
\r
4399 EndPaint(hwnd,&ps);
\r
4407 * If the user selects on a border boundary, return -1; if off the board,
\r
4408 * return -2. Otherwise map the event coordinate to the square.
\r
4409 * The offset boardRect.left or boardRect.top must already have been
\r
4410 * subtracted from x.
\r
4413 EventToSquare(int x)
\r
4420 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4422 x /= (squareSize + lineGap);
\r
4423 if (x >= BOARD_SIZE)
\r
4434 DropEnable dropEnables[] = {
\r
4435 { 'P', DP_Pawn, "Pawn" },
\r
4436 { 'N', DP_Knight, "Knight" },
\r
4437 { 'B', DP_Bishop, "Bishop" },
\r
4438 { 'R', DP_Rook, "Rook" },
\r
4439 { 'Q', DP_Queen, "Queen" },
\r
4443 SetupDropMenu(HMENU hmenu)
\r
4445 int i, count, enable;
\r
4447 extern char white_holding[], black_holding[];
\r
4448 char item[MSG_SIZ];
\r
4450 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4451 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4452 dropEnables[i].piece);
\r
4454 while (p && *p++ == dropEnables[i].piece) count++;
\r
4455 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4456 enable = count > 0 || !appData.testLegality
\r
4457 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4458 && !appData.icsActive);
\r
4459 ModifyMenu(hmenu, dropEnables[i].command,
\r
4460 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4461 dropEnables[i].command, item);
\r
4465 static int fromX = -1, fromY = -1, toX, toY;
\r
4467 /* Event handler for mouse messages */
\r
4469 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4473 static int recursive = 0;
\r
4475 BOOLEAN needsRedraw = FALSE;
\r
4476 BOOLEAN saveAnimate;
\r
4477 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4478 static BOOLEAN sameAgain = FALSE;
\r
4479 ChessMove moveType;
\r
4482 if (message == WM_MBUTTONUP) {
\r
4483 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4484 to the middle button: we simulate pressing the left button too!
\r
4486 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4487 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4493 pt.x = LOWORD(lParam);
\r
4494 pt.y = HIWORD(lParam);
\r
4495 x = EventToSquare(pt.x - boardRect.left);
\r
4496 y = EventToSquare(pt.y - boardRect.top);
\r
4497 if (!flipView && y >= 0) {
\r
4498 y = BOARD_HEIGHT - 1 - y;
\r
4500 if (flipView && x >= 0) {
\r
4501 x = BOARD_WIDTH - 1 - x;
\r
4504 switch (message) {
\r
4505 case WM_LBUTTONDOWN:
\r
4507 sameAgain = FALSE;
\r
4509 /* Downclick vertically off board; check if on clock */
\r
4510 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4511 if (gameMode == EditPosition) {
\r
4512 SetWhiteToPlayEvent();
\r
4513 } else if (gameMode == IcsPlayingBlack ||
\r
4514 gameMode == MachinePlaysWhite) {
\r
4516 } else if (gameMode == EditGame) {
\r
4517 AdjustClock(flipClock, -1);
\r
4519 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4520 if (gameMode == EditPosition) {
\r
4521 SetBlackToPlayEvent();
\r
4522 } else if (gameMode == IcsPlayingWhite ||
\r
4523 gameMode == MachinePlaysBlack) {
\r
4525 } else if (gameMode == EditGame) {
\r
4526 AdjustClock(!flipClock, -1);
\r
4529 if (!appData.highlightLastMove) {
\r
4530 ClearHighlights();
\r
4531 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4533 fromX = fromY = -1;
\r
4534 dragInfo.start.x = dragInfo.start.y = -1;
\r
4535 dragInfo.from = dragInfo.start;
\r
4537 } else if (x < 0 || y < 0
\r
4538 /* [HGM] block clicks between board and holdings */
\r
4539 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4540 || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
\r
4541 || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize
\r
4542 /* EditPosition, empty square, or different color piece;
\r
4543 click-click move is possible */
\r
4546 } else if (fromX == x && fromY == y) {
\r
4547 /* Downclick on same square again */
\r
4548 ClearHighlights();
\r
4549 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4550 sameAgain = TRUE;
\r
4551 } else if (fromX != -1 &&
\r
4552 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4554 /* Downclick on different square. */
\r
4555 /* [HGM] if on holdings file, should count as new first click ! */
\r
4556 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4559 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4560 to make sure move is legal before showing promotion popup */
\r
4561 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4562 if(moveType != ImpossibleMove) {
\r
4563 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4564 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4565 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4566 appData.alwaysPromoteToQueen) {
\r
4567 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4568 if (!appData.highlightLastMove) {
\r
4569 ClearHighlights();
\r
4570 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4573 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4574 SetHighlights(fromX, fromY, toX, toY);
\r
4575 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4576 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4577 If promotion to Q is legal, all are legal! */
\r
4578 PromotionPopup(hwnd);
\r
4579 } else { /* not a promotion */
\r
4580 if (appData.animate || appData.highlightLastMove) {
\r
4581 SetHighlights(fromX, fromY, toX, toY);
\r
4583 ClearHighlights();
\r
4585 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4586 if (appData.animate && !appData.highlightLastMove) {
\r
4587 ClearHighlights();
\r
4588 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4594 /* [HGM] it seemed that braces were missing here */
\r
4595 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4596 fromX = fromY = -1;
\r
4600 ClearHighlights();
\r
4601 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4603 /* First downclick, or restart on a square with same color piece */
\r
4604 if (!frozen && OKToStartUserMove(x, y)) {
\r
4607 dragInfo.lastpos = pt;
\r
4608 dragInfo.from.x = fromX;
\r
4609 dragInfo.from.y = fromY;
\r
4610 dragInfo.start = dragInfo.from;
\r
4611 SetCapture(hwndMain);
\r
4613 fromX = fromY = -1;
\r
4614 dragInfo.start.x = dragInfo.start.y = -1;
\r
4615 dragInfo.from = dragInfo.start;
\r
4616 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4620 case WM_LBUTTONUP:
\r
4622 if (fromX == -1) break;
\r
4623 if (x == fromX && y == fromY) {
\r
4624 dragInfo.from.x = dragInfo.from.y = -1;
\r
4625 /* Upclick on same square */
\r
4627 /* Clicked same square twice: abort click-click move */
\r
4628 fromX = fromY = -1;
\r
4630 ClearPremoveHighlights();
\r
4632 /* First square clicked: start click-click move */
\r
4633 SetHighlights(fromX, fromY, -1, -1);
\r
4635 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4636 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4637 /* Errant click; ignore */
\r
4640 /* Finish drag move. */
\r
4641 if (appData.debugMode) {
\r
4642 fprintf(debugFP, "release\n");
\r
4644 dragInfo.from.x = dragInfo.from.y = -1;
\r
4647 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4648 appData.animate = appData.animate && !appData.animateDragging;
\r
4649 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4650 if(moveType != ImpossibleMove) {
\r
4651 /* [HGM] use move type to determine if move is promotion.
\r
4652 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
4653 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4654 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4655 appData.alwaysPromoteToQueen)
\r
4656 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4658 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4659 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4660 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
4661 } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4663 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4664 appData.animate = saveAnimate;
\r
4665 fromX = fromY = -1;
\r
4666 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
4667 ClearHighlights();
\r
4669 if (appData.animate || appData.animateDragging ||
\r
4670 appData.highlightDragging || gotPremove) {
\r
4671 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4674 dragInfo.start.x = dragInfo.start.y = -1;
\r
4675 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4678 case WM_MOUSEMOVE:
\r
4679 if ((appData.animateDragging || appData.highlightDragging)
\r
4680 && (wParam & MK_LBUTTON)
\r
4681 && dragInfo.from.x >= 0)
\r
4683 BOOL full_repaint = FALSE;
\r
4685 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
4686 if (appData.animateDragging) {
\r
4687 dragInfo.pos = pt;
\r
4689 if (appData.highlightDragging) {
\r
4690 SetHighlights(fromX, fromY, x, y);
\r
4691 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4692 full_repaint = TRUE;
\r
4696 DrawPosition( full_repaint, NULL);
\r
4698 dragInfo.lastpos = dragInfo.pos;
\r
4702 case WM_MBUTTONDOWN:
\r
4703 case WM_RBUTTONDOWN:
\r
4706 fromX = fromY = -1;
\r
4707 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4708 dragInfo.start.x = dragInfo.start.y = -1;
\r
4709 dragInfo.from = dragInfo.start;
\r
4710 dragInfo.lastpos = dragInfo.pos;
\r
4711 if (appData.highlightDragging) {
\r
4712 ClearHighlights();
\r
4715 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4716 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4717 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
4718 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4719 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
4722 DrawPosition(TRUE, NULL);
\r
4724 switch (gameMode) {
\r
4725 case EditPosition:
\r
4726 case IcsExamining:
\r
4727 if (x < 0 || y < 0) break;
\r
4730 if (message == WM_MBUTTONDOWN) {
\r
4731 buttonCount = 3; /* even if system didn't think so */
\r
4732 if (wParam & MK_SHIFT)
\r
4733 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4735 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4736 } else { /* message == WM_RBUTTONDOWN */
\r
4738 if (buttonCount == 3) {
\r
4739 if (wParam & MK_SHIFT)
\r
4740 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4742 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4744 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4747 /* Just have one menu, on the right button. Windows users don't
\r
4748 think to try the middle one, and sometimes other software steals
\r
4749 it, or it doesn't really exist. */
\r
4750 if(gameInfo.variant != VariantShogi)
\r
4751 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4753 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4757 case IcsPlayingWhite:
\r
4758 case IcsPlayingBlack:
\r
4760 case MachinePlaysWhite:
\r
4761 case MachinePlaysBlack:
\r
4762 if (appData.testLegality &&
\r
4763 gameInfo.variant != VariantBughouse &&
\r
4764 gameInfo.variant != VariantCrazyhouse) break;
\r
4765 if (x < 0 || y < 0) break;
\r
4768 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4769 SetupDropMenu(hmenu);
\r
4770 MenuPopup(hwnd, pt, hmenu, -1);
\r
4781 /* Preprocess messages for buttons in main window */
\r
4783 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4785 int id = GetWindowLong(hwnd, GWL_ID);
\r
4788 for (i=0; i<N_BUTTONS; i++) {
\r
4789 if (buttonDesc[i].id == id) break;
\r
4791 if (i == N_BUTTONS) return 0;
\r
4792 switch (message) {
\r
4797 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4798 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4805 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4808 if (appData.icsActive) {
\r
4809 if (GetKeyState(VK_SHIFT) < 0) {
\r
4811 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4812 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4816 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4817 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4824 if (appData.icsActive) {
\r
4825 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4826 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4828 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4830 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4831 PopUpMoveDialog((char)wParam);
\r
4837 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4840 /* Process messages for Promotion dialog box */
\r
4842 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4846 switch (message) {
\r
4847 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4848 /* Center the dialog over the application window */
\r
4849 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4850 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4851 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4852 gameInfo.variant == VariantGiveaway) ?
\r
4853 SW_SHOW : SW_HIDE);
\r
4854 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4855 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4856 (PieceToChar(WhiteCardinal) >= 'A' &&
\r
4857 PieceToChar(WhiteCardinal) != '~' ||
\r
4858 PieceToChar(BlackCardinal) >= 'A' &&
\r
4859 PieceToChar(BlackCardinal) != '~' ) ?
\r
4860 SW_SHOW : SW_HIDE);
\r
4861 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4862 (PieceToChar(WhiteMarshall) >= 'A' &&
\r
4863 PieceToChar(WhiteMarshall) != '~' ||
\r
4864 PieceToChar(BlackMarshall) >= 'A' &&
\r
4865 PieceToChar(BlackMarshall) != '~' ) ?
\r
4866 SW_SHOW : SW_HIDE);
\r
4867 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4868 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
4869 gameInfo.variant != VariantShogi ?
\r
4870 SW_SHOW : SW_HIDE);
\r
4871 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
4872 gameInfo.variant != VariantShogi ?
\r
4873 SW_SHOW : SW_HIDE);
\r
4874 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
4875 gameInfo.variant == VariantShogi ?
\r
4876 SW_SHOW : SW_HIDE);
\r
4877 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
4878 gameInfo.variant == VariantShogi ?
\r
4879 SW_SHOW : SW_HIDE);
\r
4882 case WM_COMMAND: /* message: received a command */
\r
4883 switch (LOWORD(wParam)) {
\r
4885 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4886 ClearHighlights();
\r
4887 DrawPosition(FALSE, NULL);
\r
4890 promoChar = PieceToChar(BlackKing);
\r
4893 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
4896 promoChar = PieceToChar(BlackRook);
\r
4899 promoChar = PieceToChar(BlackBishop);
\r
4901 case PB_Chancellor:
\r
4902 promoChar = PieceToChar(BlackMarshall);
\r
4904 case PB_Archbishop:
\r
4905 promoChar = PieceToChar(BlackCardinal);
\r
4908 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
4913 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4914 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
4915 only show the popup when we are already sure the move is valid or
\r
4916 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
4917 will figure out it is a promotion from the promoChar. */
\r
4918 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
4919 if (!appData.highlightLastMove) {
\r
4920 ClearHighlights();
\r
4921 DrawPosition(FALSE, NULL);
\r
4928 /* Pop up promotion dialog */
\r
4930 PromotionPopup(HWND hwnd)
\r
4934 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4935 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4936 hwnd, (DLGPROC)lpProc);
\r
4937 FreeProcInstance(lpProc);
\r
4940 /* Toggle ShowThinking */
\r
4942 ToggleShowThinking()
\r
4944 ShowThinkingEvent(!appData.showThinking);
\r
4948 LoadGameDialog(HWND hwnd, char* title)
\r
4952 char fileTitle[MSG_SIZ];
\r
4953 f = OpenFileDialog(hwnd, FALSE, "",
\r
4954 appData.oldSaveStyle ? "gam" : "pgn",
\r
4956 title, &number, fileTitle, NULL);
\r
4958 cmailMsgLoaded = FALSE;
\r
4959 if (number == 0) {
\r
4960 int error = GameListBuild(f);
\r
4962 DisplayError("Cannot build game list", error);
\r
4963 } else if (!ListEmpty(&gameList) &&
\r
4964 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4965 GameListPopUp(f, fileTitle);
\r
4968 GameListDestroy();
\r
4971 LoadGame(f, number, fileTitle, FALSE);
\r
4976 ChangedConsoleFont()
\r
4979 CHARRANGE tmpsel, sel;
\r
4980 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4981 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4982 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4985 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4986 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4987 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4988 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4989 * size. This was undocumented in the version of MSVC++ that I had
\r
4990 * when I wrote the code, but is apparently documented now.
\r
4992 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4993 cfmt.bCharSet = f->lf.lfCharSet;
\r
4994 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4995 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4996 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4997 /* Why are the following seemingly needed too? */
\r
4998 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4999 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5000 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5002 tmpsel.cpMax = -1; /*999999?*/
\r
5003 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5004 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5005 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5006 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5008 paraf.cbSize = sizeof(paraf);
\r
5009 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5010 paraf.dxStartIndent = 0;
\r
5011 paraf.dxOffset = WRAP_INDENT;
\r
5012 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5013 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5016 /*---------------------------------------------------------------------------*\
\r
5018 * Window Proc for main window
\r
5020 \*---------------------------------------------------------------------------*/
\r
5022 /* Process messages for main window, etc. */
\r
5024 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5027 int wmId, wmEvent;
\r
5031 char fileTitle[MSG_SIZ];
\r
5032 static SnapData sd;
\r
5034 switch (message) {
\r
5036 case WM_PAINT: /* message: repaint portion of window */
\r
5040 case WM_ERASEBKGND:
\r
5041 if (IsIconic(hwnd)) {
\r
5042 /* Cheat; change the message */
\r
5043 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5045 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5049 case WM_LBUTTONDOWN:
\r
5050 case WM_MBUTTONDOWN:
\r
5051 case WM_RBUTTONDOWN:
\r
5052 case WM_LBUTTONUP:
\r
5053 case WM_MBUTTONUP:
\r
5054 case WM_RBUTTONUP:
\r
5055 case WM_MOUSEMOVE:
\r
5056 MouseEvent(hwnd, message, wParam, lParam);
\r
5061 if (appData.icsActive) {
\r
5062 if (wParam == '\t') {
\r
5063 if (GetKeyState(VK_SHIFT) < 0) {
\r
5065 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5066 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5070 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5071 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5075 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5076 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5078 SendMessage(h, message, wParam, lParam);
\r
5080 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5081 PopUpMoveDialog((char)wParam);
\r
5085 case WM_PALETTECHANGED:
\r
5086 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5088 HDC hdc = GetDC(hwndMain);
\r
5089 SelectPalette(hdc, hPal, TRUE);
\r
5090 nnew = RealizePalette(hdc);
\r
5092 paletteChanged = TRUE;
\r
5094 UpdateColors(hdc);
\r
5096 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5099 ReleaseDC(hwnd, hdc);
\r
5103 case WM_QUERYNEWPALETTE:
\r
5104 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5106 HDC hdc = GetDC(hwndMain);
\r
5107 paletteChanged = FALSE;
\r
5108 SelectPalette(hdc, hPal, FALSE);
\r
5109 nnew = RealizePalette(hdc);
\r
5111 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5113 ReleaseDC(hwnd, hdc);
\r
5118 case WM_COMMAND: /* message: command from application menu */
\r
5119 wmId = LOWORD(wParam);
\r
5120 wmEvent = HIWORD(wParam);
\r
5125 AnalysisPopDown();
\r
5128 case IDM_NewGameFRC:
\r
5129 if( NewGameFRC() == 0 ) {
\r
5131 AnalysisPopDown();
\r
5135 case IDM_NewVariant:
\r
5136 NewVariantPopup(hwnd);
\r
5139 case IDM_LoadGame:
\r
5140 LoadGameDialog(hwnd, "Load Game from File");
\r
5143 case IDM_LoadNextGame:
\r
5147 case IDM_LoadPrevGame:
\r
5151 case IDM_ReloadGame:
\r
5155 case IDM_LoadPosition:
\r
5156 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5157 Reset(FALSE, TRUE);
\r
5160 f = OpenFileDialog(hwnd, FALSE, "",
\r
5161 appData.oldSaveStyle ? "pos" : "fen",
\r
5163 "Load Position from File", &number, fileTitle, NULL);
\r
5165 LoadPosition(f, number, fileTitle);
\r
5169 case IDM_LoadNextPosition:
\r
5170 ReloadPosition(1);
\r
5173 case IDM_LoadPrevPosition:
\r
5174 ReloadPosition(-1);
\r
5177 case IDM_ReloadPosition:
\r
5178 ReloadPosition(0);
\r
5181 case IDM_SaveGame:
\r
5182 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5183 f = OpenFileDialog(hwnd, TRUE, defName,
\r
5184 appData.oldSaveStyle ? "gam" : "pgn",
\r
5186 "Save Game to File", NULL, fileTitle, NULL);
\r
5188 SaveGame(f, 0, "");
\r
5192 case IDM_SavePosition:
\r
5193 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5194 f = OpenFileDialog(hwnd, TRUE, defName,
\r
5195 appData.oldSaveStyle ? "pos" : "fen",
\r
5197 "Save Position to File", NULL, fileTitle, NULL);
\r
5199 SavePosition(f, 0, "");
\r
5203 case IDM_CopyGame:
\r
5204 CopyGameToClipboard();
\r
5207 case IDM_PasteGame:
\r
5208 PasteGameFromClipboard();
\r
5211 case IDM_CopyGameListToClipboard:
\r
5212 CopyGameListToClipboard();
\r
5215 /* [AS] Autodetect FEN or PGN data */
\r
5216 case IDM_PasteAny:
\r
5217 PasteGameOrFENFromClipboard();
\r
5220 /* [AS] Move history */
\r
5221 case IDM_ShowMoveHistory:
\r
5222 if( MoveHistoryIsUp() ) {
\r
5223 MoveHistoryPopDown();
\r
5226 MoveHistoryPopUp();
\r
5230 /* [AS] Eval graph */
\r
5231 case IDM_ShowEvalGraph:
\r
5232 if( EvalGraphIsUp() ) {
\r
5233 EvalGraphPopDown();
\r
5240 /* [AS] Engine output */
\r
5241 case IDM_ShowEngineOutput:
\r
5242 if( EngineOutputIsUp() ) {
\r
5243 EngineOutputPopDown();
\r
5246 EngineOutputPopUp();
\r
5250 /* [AS] User adjudication */
\r
5251 case IDM_UserAdjudication_White:
\r
5252 UserAdjudicationEvent( +1 );
\r
5255 case IDM_UserAdjudication_Black:
\r
5256 UserAdjudicationEvent( -1 );
\r
5259 case IDM_UserAdjudication_Draw:
\r
5260 UserAdjudicationEvent( 0 );
\r
5263 /* [AS] Game list options dialog */
\r
5264 case IDM_GameListOptions:
\r
5265 GameListOptions();
\r
5268 case IDM_CopyPosition:
\r
5269 CopyFENToClipboard();
\r
5272 case IDM_PastePosition:
\r
5273 PasteFENFromClipboard();
\r
5276 case IDM_MailMove:
\r
5280 case IDM_ReloadCMailMsg:
\r
5281 Reset(TRUE, TRUE);
\r
5282 ReloadCmailMsgEvent(FALSE);
\r
5285 case IDM_Minimize:
\r
5286 ShowWindow(hwnd, SW_MINIMIZE);
\r
5293 case IDM_MachineWhite:
\r
5294 MachineWhiteEvent();
\r
5296 * refresh the tags dialog only if it's visible
\r
5298 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5300 tags = PGNTags(&gameInfo);
\r
5301 TagsPopUp(tags, CmailMsg());
\r
5306 case IDM_MachineBlack:
\r
5307 MachineBlackEvent();
\r
5309 * refresh the tags dialog only if it's visible
\r
5311 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5313 tags = PGNTags(&gameInfo);
\r
5314 TagsPopUp(tags, CmailMsg());
\r
5319 case IDM_TwoMachines:
\r
5320 TwoMachinesEvent();
\r
5322 * refresh the tags dialog only if it's visible
\r
5324 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5326 tags = PGNTags(&gameInfo);
\r
5327 TagsPopUp(tags, CmailMsg());
\r
5332 case IDM_AnalysisMode:
\r
5333 if (!first.analysisSupport) {
\r
5334 char buf[MSG_SIZ];
\r
5335 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5336 DisplayError(buf, 0);
\r
5338 if (!appData.showThinking) ToggleShowThinking();
\r
5339 AnalyzeModeEvent();
\r
5343 case IDM_AnalyzeFile:
\r
5344 if (!first.analysisSupport) {
\r
5345 char buf[MSG_SIZ];
\r
5346 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5347 DisplayError(buf, 0);
\r
5349 if (!appData.showThinking) ToggleShowThinking();
\r
5350 AnalyzeFileEvent();
\r
5351 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5352 AnalysisPeriodicEvent(1);
\r
5356 case IDM_IcsClient:
\r
5360 case IDM_EditGame:
\r
5364 case IDM_EditPosition:
\r
5365 EditPositionEvent();
\r
5368 case IDM_Training:
\r
5372 case IDM_ShowGameList:
\r
5373 ShowGameListProc();
\r
5376 case IDM_EditTags:
\r
5380 case IDM_EditComment:
\r
5381 if (commentDialogUp && editComment) {
\r
5384 EditCommentEvent();
\r
5404 case IDM_CallFlag:
\r
5424 case IDM_StopObserving:
\r
5425 StopObservingEvent();
\r
5428 case IDM_StopExamining:
\r
5429 StopExaminingEvent();
\r
5432 case IDM_TypeInMove:
\r
5433 PopUpMoveDialog('\000');
\r
5436 case IDM_Backward:
\r
5438 SetFocus(hwndMain);
\r
5443 SetFocus(hwndMain);
\r
5448 SetFocus(hwndMain);
\r
5453 SetFocus(hwndMain);
\r
5460 case IDM_TruncateGame:
\r
5461 TruncateGameEvent();
\r
5468 case IDM_RetractMove:
\r
5469 RetractMoveEvent();
\r
5472 case IDM_FlipView:
\r
5473 flipView = !flipView;
\r
5474 DrawPosition(FALSE, NULL);
\r
5477 case IDM_FlipClock:
\r
5478 flipClock = !flipClock;
\r
5479 DisplayBothClocks();
\r
5482 case IDM_GeneralOptions:
\r
5483 GeneralOptionsPopup(hwnd);
\r
5484 DrawPosition(TRUE, NULL);
\r
5487 case IDM_BoardOptions:
\r
5488 BoardOptionsPopup(hwnd);
\r
5491 case IDM_EnginePlayOptions:
\r
5492 EnginePlayOptionsPopup(hwnd);
\r
5495 case IDM_OptionsUCI:
\r
5496 UciOptionsPopup(hwnd);
\r
5499 case IDM_IcsOptions:
\r
5500 IcsOptionsPopup(hwnd);
\r
5504 FontsOptionsPopup(hwnd);
\r
5508 SoundOptionsPopup(hwnd);
\r
5511 case IDM_CommPort:
\r
5512 CommPortOptionsPopup(hwnd);
\r
5515 case IDM_LoadOptions:
\r
5516 LoadOptionsPopup(hwnd);
\r
5519 case IDM_SaveOptions:
\r
5520 SaveOptionsPopup(hwnd);
\r
5523 case IDM_TimeControl:
\r
5524 TimeControlOptionsPopup(hwnd);
\r
5527 case IDM_SaveSettings:
\r
5528 SaveSettings(settingsFileName);
\r
5531 case IDM_SaveSettingsOnExit:
\r
5532 saveSettingsOnExit = !saveSettingsOnExit;
\r
5533 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5534 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5535 MF_CHECKED : MF_UNCHECKED));
\r
5546 case IDM_AboutGame:
\r
5551 appData.debugMode = !appData.debugMode;
\r
5552 if (appData.debugMode) {
\r
5553 char dir[MSG_SIZ];
\r
5554 GetCurrentDirectory(MSG_SIZ, dir);
\r
5555 SetCurrentDirectory(installDir);
\r
5556 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5557 SetCurrentDirectory(dir);
\r
5558 setbuf(debugFP, NULL);
\r
5565 case IDM_HELPCONTENTS:
\r
5566 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5567 MessageBox (GetFocus(),
\r
5568 "Unable to activate help",
\r
5569 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5573 case IDM_HELPSEARCH:
\r
5574 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5575 MessageBox (GetFocus(),
\r
5576 "Unable to activate help",
\r
5577 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5581 case IDM_HELPHELP:
\r
5582 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5583 MessageBox (GetFocus(),
\r
5584 "Unable to activate help",
\r
5585 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5590 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5592 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5593 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5594 FreeProcInstance(lpProc);
\r
5597 case IDM_DirectCommand1:
\r
5598 AskQuestionEvent("Direct Command",
\r
5599 "Send to chess program:", "", "1");
\r
5601 case IDM_DirectCommand2:
\r
5602 AskQuestionEvent("Direct Command",
\r
5603 "Send to second chess program:", "", "2");
\r
5606 case EP_WhitePawn:
\r
5607 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5608 fromX = fromY = -1;
\r
5611 case EP_WhiteKnight:
\r
5612 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5613 fromX = fromY = -1;
\r
5616 case EP_WhiteBishop:
\r
5617 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5618 fromX = fromY = -1;
\r
5621 case EP_WhiteRook:
\r
5622 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5623 fromX = fromY = -1;
\r
5626 case EP_WhiteQueen:
\r
5627 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5628 fromX = fromY = -1;
\r
5631 case EP_WhiteFerz:
\r
5632 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5633 fromX = fromY = -1;
\r
5636 case EP_WhiteWazir:
\r
5637 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5638 fromX = fromY = -1;
\r
5641 case EP_WhiteAlfil:
\r
5642 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5643 fromX = fromY = -1;
\r
5646 case EP_WhiteCannon:
\r
5647 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5648 fromX = fromY = -1;
\r
5651 case EP_WhiteCardinal:
\r
5652 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5653 fromX = fromY = -1;
\r
5656 case EP_WhiteMarshall:
\r
5657 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5658 fromX = fromY = -1;
\r
5661 case EP_WhiteKing:
\r
5662 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5663 fromX = fromY = -1;
\r
5666 case EP_BlackPawn:
\r
5667 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5668 fromX = fromY = -1;
\r
5671 case EP_BlackKnight:
\r
5672 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5673 fromX = fromY = -1;
\r
5676 case EP_BlackBishop:
\r
5677 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5678 fromX = fromY = -1;
\r
5681 case EP_BlackRook:
\r
5682 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5683 fromX = fromY = -1;
\r
5686 case EP_BlackQueen:
\r
5687 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5688 fromX = fromY = -1;
\r
5691 case EP_BlackFerz:
\r
5692 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5693 fromX = fromY = -1;
\r
5696 case EP_BlackWazir:
\r
5697 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5698 fromX = fromY = -1;
\r
5701 case EP_BlackAlfil:
\r
5702 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5703 fromX = fromY = -1;
\r
5706 case EP_BlackCannon:
\r
5707 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5708 fromX = fromY = -1;
\r
5711 case EP_BlackCardinal:
\r
5712 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5713 fromX = fromY = -1;
\r
5716 case EP_BlackMarshall:
\r
5717 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5718 fromX = fromY = -1;
\r
5721 case EP_BlackKing:
\r
5722 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5723 fromX = fromY = -1;
\r
5726 case EP_EmptySquare:
\r
5727 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5728 fromX = fromY = -1;
\r
5731 case EP_ClearBoard:
\r
5732 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5733 fromX = fromY = -1;
\r
5737 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5738 fromX = fromY = -1;
\r
5742 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5743 fromX = fromY = -1;
\r
5747 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5748 fromX = fromY = -1;
\r
5752 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5753 fromX = fromY = -1;
\r
5757 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5758 fromX = fromY = -1;
\r
5762 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5763 fromX = fromY = -1;
\r
5767 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5768 fromX = fromY = -1;
\r
5772 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5773 fromX = fromY = -1;
\r
5777 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5778 fromX = fromY = -1;
\r
5782 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5788 case CLOCK_TIMER_ID:
\r
5789 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5790 clockTimerEvent = 0;
\r
5791 DecrementClocks(); /* call into back end */
\r
5793 case LOAD_GAME_TIMER_ID:
\r
5794 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5795 loadGameTimerEvent = 0;
\r
5796 AutoPlayGameLoop(); /* call into back end */
\r
5798 case ANALYSIS_TIMER_ID:
\r
5799 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
5800 appData.periodicUpdates) {
\r
5801 AnalysisPeriodicEvent(0);
\r
5803 KillTimer(hwnd, analysisTimerEvent);
\r
5804 analysisTimerEvent = 0;
\r
5807 case DELAYED_TIMER_ID:
\r
5808 KillTimer(hwnd, delayedTimerEvent);
\r
5809 delayedTimerEvent = 0;
\r
5810 delayedTimerCallback();
\r
5815 case WM_USER_Input:
\r
5816 InputEvent(hwnd, message, wParam, lParam);
\r
5819 /* [AS] Also move "attached" child windows */
\r
5820 case WM_WINDOWPOSCHANGING:
\r
5821 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5822 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5824 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
5825 /* Window is moving */
\r
5828 GetWindowRect( hwnd, &rcMain );
\r
5830 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5831 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5832 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5837 /* [AS] Snapping */
\r
5838 case WM_ENTERSIZEMOVE:
\r
5839 if (hwnd == hwndMain) {
\r
5840 doingSizing = TRUE;
\r
5843 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5847 if (hwnd == hwndMain) {
\r
5848 lastSizing = wParam;
\r
5853 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5855 case WM_EXITSIZEMOVE:
\r
5856 if (hwnd == hwndMain) {
\r
5858 doingSizing = FALSE;
\r
5859 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5860 GetClientRect(hwnd, &client);
\r
5861 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5864 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5867 case WM_DESTROY: /* message: window being destroyed */
\r
5868 PostQuitMessage(0);
\r
5872 if (hwnd == hwndMain) {
\r
5877 default: /* Passes it on if unprocessed */
\r
5878 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5883 /*---------------------------------------------------------------------------*\
\r
5885 * Misc utility routines
\r
5887 \*---------------------------------------------------------------------------*/
\r
5890 * Decent random number generator, at least not as bad as Windows
\r
5891 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5893 unsigned int randstate;
\r
5898 randstate = randstate * 1664525 + 1013904223;
\r
5899 return (int) randstate & 0x7fffffff;
\r
5903 mysrandom(unsigned int seed)
\r
5910 * returns TRUE if user selects a different color, FALSE otherwise
\r
5914 ChangeColor(HWND hwnd, COLORREF *which)
\r
5916 static BOOL firstTime = TRUE;
\r
5917 static DWORD customColors[16];
\r
5919 COLORREF newcolor;
\r
5924 /* Make initial colors in use available as custom colors */
\r
5925 /* Should we put the compiled-in defaults here instead? */
\r
5927 customColors[i++] = lightSquareColor & 0xffffff;
\r
5928 customColors[i++] = darkSquareColor & 0xffffff;
\r
5929 customColors[i++] = whitePieceColor & 0xffffff;
\r
5930 customColors[i++] = blackPieceColor & 0xffffff;
\r
5931 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5932 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5934 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5935 customColors[i++] = textAttribs[ccl].color;
\r
5937 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5938 firstTime = FALSE;
\r
5941 cc.lStructSize = sizeof(cc);
\r
5942 cc.hwndOwner = hwnd;
\r
5943 cc.hInstance = NULL;
\r
5944 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5945 cc.lpCustColors = (LPDWORD) customColors;
\r
5946 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5948 if (!ChooseColor(&cc)) return FALSE;
\r
5950 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5951 if (newcolor == *which) return FALSE;
\r
5952 *which = newcolor;
\r
5956 InitDrawingColors();
\r
5957 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5962 MyLoadSound(MySound *ms)
\r
5968 if (ms->data) free(ms->data);
\r
5971 switch (ms->name[0]) {
\r
5977 /* System sound from Control Panel. Don't preload here. */
\r
5981 if (ms->name[1] == NULLCHAR) {
\r
5982 /* "!" alone = silence */
\r
5985 /* Builtin wave resource. Error if not found. */
\r
5986 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5987 if (h == NULL) break;
\r
5988 ms->data = (void *)LoadResource(hInst, h);
\r
5989 if (h == NULL) break;
\r
5994 /* .wav file. Error if not found. */
\r
5995 f = fopen(ms->name, "rb");
\r
5996 if (f == NULL) break;
\r
5997 if (fstat(fileno(f), &st) < 0) break;
\r
5998 ms->data = malloc(st.st_size);
\r
5999 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6005 char buf[MSG_SIZ];
\r
6006 sprintf(buf, "Error loading sound %s", ms->name);
\r
6007 DisplayError(buf, GetLastError());
\r
6013 MyPlaySound(MySound *ms)
\r
6015 BOOLEAN ok = FALSE;
\r
6016 switch (ms->name[0]) {
\r
6022 /* System sound from Control Panel (deprecated feature).
\r
6023 "$" alone or an unset sound name gets default beep (still in use). */
\r
6024 if (ms->name[1]) {
\r
6025 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6027 if (!ok) ok = MessageBeep(MB_OK);
\r
6030 /* Builtin wave resource, or "!" alone for silence */
\r
6031 if (ms->name[1]) {
\r
6032 if (ms->data == NULL) return FALSE;
\r
6033 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6039 /* .wav file. Error if not found. */
\r
6040 if (ms->data == NULL) return FALSE;
\r
6041 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6044 /* Don't print an error: this can happen innocently if the sound driver
\r
6045 is busy; for instance, if another instance of WinBoard is playing
\r
6046 a sound at about the same time. */
\r
6049 char buf[MSG_SIZ];
\r
6050 sprintf(buf, "Error playing sound %s", ms->name);
\r
6051 DisplayError(buf, GetLastError());
\r
6059 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6062 OPENFILENAME *ofn;
\r
6063 static UINT *number; /* gross that this is static */
\r
6065 switch (message) {
\r
6066 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6067 /* Center the dialog over the application window */
\r
6068 ofn = (OPENFILENAME *) lParam;
\r
6069 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6070 number = (UINT *) ofn->lCustData;
\r
6071 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6075 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6076 return FALSE; /* Allow for further processing */
\r
6079 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6080 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6082 return FALSE; /* Allow for further processing */
\r
6088 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6090 static UINT *number;
\r
6091 OPENFILENAME *ofname;
\r
6094 case WM_INITDIALOG:
\r
6095 ofname = (OPENFILENAME *)lParam;
\r
6096 number = (UINT *)(ofname->lCustData);
\r
6099 ofnot = (OFNOTIFY *)lParam;
\r
6100 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6101 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6110 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
6111 char *nameFilt, char *dlgTitle, UINT *number,
\r
6112 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6114 OPENFILENAME openFileName;
\r
6115 char buf1[MSG_SIZ];
\r
6118 if (fileName == NULL) fileName = buf1;
\r
6119 if (defName == NULL) {
\r
6120 strcpy(fileName, "*.");
\r
6121 strcat(fileName, defExt);
\r
6123 strcpy(fileName, defName);
\r
6125 if (fileTitle) strcpy(fileTitle, "");
\r
6126 if (number) *number = 0;
\r
6128 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6129 openFileName.hwndOwner = hwnd;
\r
6130 openFileName.hInstance = (HANDLE) hInst;
\r
6131 openFileName.lpstrFilter = nameFilt;
\r
6132 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6133 openFileName.nMaxCustFilter = 0L;
\r
6134 openFileName.nFilterIndex = 1L;
\r
6135 openFileName.lpstrFile = fileName;
\r
6136 openFileName.nMaxFile = MSG_SIZ;
\r
6137 openFileName.lpstrFileTitle = fileTitle;
\r
6138 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6139 openFileName.lpstrInitialDir = NULL;
\r
6140 openFileName.lpstrTitle = dlgTitle;
\r
6141 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6142 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
6143 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6144 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6145 openFileName.nFileOffset = 0;
\r
6146 openFileName.nFileExtension = 0;
\r
6147 openFileName.lpstrDefExt = defExt;
\r
6148 openFileName.lCustData = (LONG) number;
\r
6149 openFileName.lpfnHook = oldDialog ?
\r
6150 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6151 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6153 if (write ? GetSaveFileName(&openFileName) :
\r
6154 GetOpenFileName(&openFileName)) {
\r
6155 /* open the file */
\r
6156 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
6158 MessageBox(hwnd, "File open failed", NULL,
\r
6159 MB_OK|MB_ICONEXCLAMATION);
\r
6163 int err = CommDlgExtendedError();
\r
6164 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6173 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6175 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6178 * Get the first pop-up menu in the menu template. This is the
\r
6179 * menu that TrackPopupMenu displays.
\r
6181 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6183 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6186 * TrackPopup uses screen coordinates, so convert the
\r
6187 * coordinates of the mouse click to screen coordinates.
\r
6189 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6191 /* Draw and track the floating pop-up menu. */
\r
6192 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6193 pt.x, pt.y, 0, hwnd, NULL);
\r
6195 /* Destroy the menu.*/
\r
6196 DestroyMenu(hmenu);
\r
6201 int sizeX, sizeY, newSizeX, newSizeY;
\r
6203 } ResizeEditPlusButtonsClosure;
\r
6206 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6208 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6212 if (hChild == cl->hText) return TRUE;
\r
6213 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6214 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6215 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6216 ScreenToClient(cl->hDlg, &pt);
\r
6217 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6218 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6222 /* Resize a dialog that has a (rich) edit field filling most of
\r
6223 the top, with a row of buttons below */
\r
6225 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6228 int newTextHeight, newTextWidth;
\r
6229 ResizeEditPlusButtonsClosure cl;
\r
6231 /*if (IsIconic(hDlg)) return;*/
\r
6232 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6234 cl.hdwp = BeginDeferWindowPos(8);
\r
6236 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6237 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6238 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6239 if (newTextHeight < 0) {
\r
6240 newSizeY += -newTextHeight;
\r
6241 newTextHeight = 0;
\r
6243 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6244 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6250 cl.newSizeX = newSizeX;
\r
6251 cl.newSizeY = newSizeY;
\r
6252 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6254 EndDeferWindowPos(cl.hdwp);
\r
6257 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6259 RECT rChild, rParent;
\r
6260 int wChild, hChild, wParent, hParent;
\r
6261 int wScreen, hScreen, xNew, yNew;
\r
6264 /* Get the Height and Width of the child window */
\r
6265 GetWindowRect (hwndChild, &rChild);
\r
6266 wChild = rChild.right - rChild.left;
\r
6267 hChild = rChild.bottom - rChild.top;
\r
6269 /* Get the Height and Width of the parent window */
\r
6270 GetWindowRect (hwndParent, &rParent);
\r
6271 wParent = rParent.right - rParent.left;
\r
6272 hParent = rParent.bottom - rParent.top;
\r
6274 /* Get the display limits */
\r
6275 hdc = GetDC (hwndChild);
\r
6276 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6277 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6278 ReleaseDC(hwndChild, hdc);
\r
6280 /* Calculate new X position, then adjust for screen */
\r
6281 xNew = rParent.left + ((wParent - wChild) /2);
\r
6284 } else if ((xNew+wChild) > wScreen) {
\r
6285 xNew = wScreen - wChild;
\r
6288 /* Calculate new Y position, then adjust for screen */
\r
6290 yNew = rParent.top + ((hParent - hChild) /2);
\r
6293 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6298 } else if ((yNew+hChild) > hScreen) {
\r
6299 yNew = hScreen - hChild;
\r
6302 /* Set it, and return */
\r
6303 return SetWindowPos (hwndChild, NULL,
\r
6304 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6307 /* Center one window over another */
\r
6308 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6310 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6313 /*---------------------------------------------------------------------------*\
\r
6315 * Startup Dialog functions
\r
6317 \*---------------------------------------------------------------------------*/
\r
6319 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6321 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6323 while (*cd != NULL) {
\r
6324 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6330 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6332 char buf1[ARG_MAX];
\r
6335 if (str[0] == '@') {
\r
6336 FILE* f = fopen(str + 1, "r");
\r
6338 DisplayFatalError(str + 1, errno, 2);
\r
6341 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6343 buf1[len] = NULLCHAR;
\r
6347 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6350 char buf[MSG_SIZ];
\r
6351 char *end = strchr(str, '\n');
\r
6352 if (end == NULL) return;
\r
6353 memcpy(buf, str, end - str);
\r
6354 buf[end - str] = NULLCHAR;
\r
6355 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6361 SetStartupDialogEnables(HWND hDlg)
\r
6363 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6364 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6365 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6366 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6367 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6368 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6369 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6370 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6371 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6372 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6373 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6374 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6375 IsDlgButtonChecked(hDlg, OPT_View));
\r
6379 QuoteForFilename(char *filename)
\r
6381 int dquote, space;
\r
6382 dquote = strchr(filename, '"') != NULL;
\r
6383 space = strchr(filename, ' ') != NULL;
\r
6384 if (dquote || space) {
\r
6396 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6398 char buf[MSG_SIZ];
\r
6401 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6402 q = QuoteForFilename(nthcp);
\r
6403 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6404 if (*nthdir != NULLCHAR) {
\r
6405 q = QuoteForFilename(nthdir);
\r
6406 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6408 if (*nthcp == NULLCHAR) {
\r
6409 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6410 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6411 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6412 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6417 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6419 char buf[MSG_SIZ];
\r
6423 switch (message) {
\r
6424 case WM_INITDIALOG:
\r
6425 /* Center the dialog */
\r
6426 CenterWindow (hDlg, GetDesktopWindow());
\r
6427 /* Initialize the dialog items */
\r
6428 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6429 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6430 firstChessProgramNames);
\r
6431 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6432 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6433 secondChessProgramNames);
\r
6434 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6435 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6436 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6437 if (*appData.icsHelper != NULLCHAR) {
\r
6438 char *q = QuoteForFilename(appData.icsHelper);
\r
6439 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6441 if (*appData.icsHost == NULLCHAR) {
\r
6442 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6443 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6444 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6445 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6446 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6449 if (appData.icsActive) {
\r
6450 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6452 else if (appData.noChessProgram) {
\r
6453 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6456 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6459 SetStartupDialogEnables(hDlg);
\r
6463 switch (LOWORD(wParam)) {
\r
6465 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6466 strcpy(buf, "/fcp=");
\r
6467 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6469 ParseArgs(StringGet, &p);
\r
6470 strcpy(buf, "/scp=");
\r
6471 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6473 ParseArgs(StringGet, &p);
\r
6474 appData.noChessProgram = FALSE;
\r
6475 appData.icsActive = FALSE;
\r
6476 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6477 strcpy(buf, "/ics /icshost=");
\r
6478 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6480 ParseArgs(StringGet, &p);
\r
6481 if (appData.zippyPlay) {
\r
6482 strcpy(buf, "/fcp=");
\r
6483 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6485 ParseArgs(StringGet, &p);
\r
6487 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6488 appData.noChessProgram = TRUE;
\r
6489 appData.icsActive = FALSE;
\r
6491 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6492 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6495 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6496 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6498 ParseArgs(StringGet, &p);
\r
6500 EndDialog(hDlg, TRUE);
\r
6507 case IDM_HELPCONTENTS:
\r
6508 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6509 MessageBox (GetFocus(),
\r
6510 "Unable to activate help",
\r
6511 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6516 SetStartupDialogEnables(hDlg);
\r
6524 /*---------------------------------------------------------------------------*\
\r
6526 * About box dialog functions
\r
6528 \*---------------------------------------------------------------------------*/
\r
6530 /* Process messages for "About" dialog box */
\r
6532 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6534 switch (message) {
\r
6535 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6536 /* Center the dialog over the application window */
\r
6537 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6538 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6541 case WM_COMMAND: /* message: received a command */
\r
6542 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6543 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6544 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6552 /*---------------------------------------------------------------------------*\
\r
6554 * Comment Dialog functions
\r
6556 \*---------------------------------------------------------------------------*/
\r
6559 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6561 static HANDLE hwndText = NULL;
\r
6562 int len, newSizeX, newSizeY, flags;
\r
6563 static int sizeX, sizeY;
\r
6568 switch (message) {
\r
6569 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6570 /* Initialize the dialog items */
\r
6571 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6572 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6573 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6574 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6575 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6576 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6577 SetWindowText(hDlg, commentTitle);
\r
6578 if (editComment) {
\r
6579 SetFocus(hwndText);
\r
6581 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6583 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6584 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6585 MAKELPARAM(FALSE, 0));
\r
6586 /* Size and position the dialog */
\r
6587 if (!commentDialog) {
\r
6588 commentDialog = hDlg;
\r
6589 flags = SWP_NOZORDER;
\r
6590 GetClientRect(hDlg, &rect);
\r
6591 sizeX = rect.right;
\r
6592 sizeY = rect.bottom;
\r
6593 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
6594 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
6595 WINDOWPLACEMENT wp;
\r
6596 EnsureOnScreen(&commentX, &commentY);
\r
6597 wp.length = sizeof(WINDOWPLACEMENT);
\r
6599 wp.showCmd = SW_SHOW;
\r
6600 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6601 wp.rcNormalPosition.left = commentX;
\r
6602 wp.rcNormalPosition.right = commentX + commentW;
\r
6603 wp.rcNormalPosition.top = commentY;
\r
6604 wp.rcNormalPosition.bottom = commentY + commentH;
\r
6605 SetWindowPlacement(hDlg, &wp);
\r
6607 GetClientRect(hDlg, &rect);
\r
6608 newSizeX = rect.right;
\r
6609 newSizeY = rect.bottom;
\r
6610 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6611 newSizeX, newSizeY);
\r
6618 case WM_COMMAND: /* message: received a command */
\r
6619 switch (LOWORD(wParam)) {
\r
6621 if (editComment) {
\r
6623 /* Read changed options from the dialog box */
\r
6624 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6625 len = GetWindowTextLength(hwndText);
\r
6626 str = (char *) malloc(len + 1);
\r
6627 GetWindowText(hwndText, str, len + 1);
\r
6636 ReplaceComment(commentIndex, str);
\r
6643 case OPT_CancelComment:
\r
6647 case OPT_ClearComment:
\r
6648 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6651 case OPT_EditComment:
\r
6652 EditCommentEvent();
\r
6661 newSizeX = LOWORD(lParam);
\r
6662 newSizeY = HIWORD(lParam);
\r
6663 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6668 case WM_GETMINMAXINFO:
\r
6669 /* Prevent resizing window too small */
\r
6670 mmi = (MINMAXINFO *) lParam;
\r
6671 mmi->ptMinTrackSize.x = 100;
\r
6672 mmi->ptMinTrackSize.y = 100;
\r
6679 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6684 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6686 if (str == NULL) str = "";
\r
6687 p = (char *) malloc(2 * strlen(str) + 2);
\r
6690 if (*str == '\n') *q++ = '\r';
\r
6694 if (commentText != NULL) free(commentText);
\r
6696 commentIndex = index;
\r
6697 commentTitle = title;
\r
6699 editComment = edit;
\r
6701 if (commentDialog) {
\r
6702 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6703 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
6705 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6706 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6707 hwndMain, (DLGPROC)lpProc);
\r
6708 FreeProcInstance(lpProc);
\r
6710 commentDialogUp = TRUE;
\r
6714 /*---------------------------------------------------------------------------*\
\r
6716 * Type-in move dialog functions
\r
6718 \*---------------------------------------------------------------------------*/
\r
6721 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6723 char move[MSG_SIZ];
\r
6725 ChessMove moveType;
\r
6726 int fromX, fromY, toX, toY;
\r
6729 switch (message) {
\r
6730 case WM_INITDIALOG:
\r
6731 move[0] = (char) lParam;
\r
6732 move[1] = NULLCHAR;
\r
6733 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6734 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6735 SetWindowText(hInput, move);
\r
6737 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6741 switch (LOWORD(wParam)) {
\r
6743 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
6744 gameMode != Training) {
\r
6745 DisplayMoveError("Displayed move is not current");
\r
6747 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6748 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
6749 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
6750 if (gameMode != Training)
\r
6751 forwardMostMove = currentMove;
\r
6752 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
6754 DisplayMoveError("Could not parse move");
\r
6757 EndDialog(hDlg, TRUE);
\r
6760 EndDialog(hDlg, FALSE);
\r
6771 PopUpMoveDialog(char firstchar)
\r
6775 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
6776 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
6777 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
6778 gameMode == EditPosition || gameMode == IcsExamining ||
\r
6779 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
6780 gameMode == Training) {
\r
6781 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6782 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6783 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6784 FreeProcInstance(lpProc);
\r
6788 /*---------------------------------------------------------------------------*\
\r
6792 \*---------------------------------------------------------------------------*/
\r
6794 /* Nonmodal error box */
\r
6795 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6796 WPARAM wParam, LPARAM lParam);
\r
6799 ErrorPopUp(char *title, char *content)
\r
6803 BOOLEAN modal = hwndMain == NULL;
\r
6821 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6822 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6825 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6827 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6828 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6829 hwndMain, (DLGPROC)lpProc);
\r
6830 FreeProcInstance(lpProc);
\r
6837 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6838 if (errorDialog == NULL) return;
\r
6839 DestroyWindow(errorDialog);
\r
6840 errorDialog = NULL;
\r
6844 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6849 switch (message) {
\r
6850 case WM_INITDIALOG:
\r
6851 GetWindowRect(hDlg, &rChild);
\r
6854 SetWindowPos(hDlg, NULL, rChild.left,
\r
6855 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6856 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6860 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6861 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6862 and it doesn't work when you resize the dialog.
\r
6863 For now, just give it a default position.
\r
6865 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6867 errorDialog = hDlg;
\r
6868 SetWindowText(hDlg, errorTitle);
\r
6869 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6870 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6874 switch (LOWORD(wParam)) {
\r
6877 if (errorDialog == hDlg) errorDialog = NULL;
\r
6878 DestroyWindow(hDlg);
\r
6890 HWND gothicDialog = NULL;
\r
6893 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6897 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6899 switch (message) {
\r
6900 case WM_INITDIALOG:
\r
6901 GetWindowRect(hDlg, &rChild);
\r
6903 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
6907 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6908 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6909 and it doesn't work when you resize the dialog.
\r
6910 For now, just give it a default position.
\r
6912 gothicDialog = hDlg;
\r
6913 SetWindowText(hDlg, errorTitle);
\r
6914 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6915 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6919 switch (LOWORD(wParam)) {
\r
6922 if (errorDialog == hDlg) errorDialog = NULL;
\r
6923 DestroyWindow(hDlg);
\r
6935 GothicPopUp(char *title, VariantClass variant)
\r
6939 BOOLEAN modal = hwndMain == NULL;
\r
6940 static char *lastTitle;
\r
6942 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6943 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6945 if(lastTitle != title && gothicDialog != NULL) {
\r
6946 DestroyWindow(gothicDialog);
\r
6947 gothicDialog = NULL;
\r
6949 if(variant != VariantNormal && gothicDialog == NULL) {
\r
6950 title = lastTitle;
\r
6951 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6952 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6953 hwndMain, (DLGPROC)lpProc);
\r
6954 FreeProcInstance(lpProc);
\r
6959 /*---------------------------------------------------------------------------*\
\r
6961 * Ics Interaction console functions
\r
6963 \*---------------------------------------------------------------------------*/
\r
6965 #define HISTORY_SIZE 64
\r
6966 static char *history[HISTORY_SIZE];
\r
6967 int histIn = 0, histP = 0;
\r
6970 SaveInHistory(char *cmd)
\r
6972 if (history[histIn] != NULL) {
\r
6973 free(history[histIn]);
\r
6974 history[histIn] = NULL;
\r
6976 if (*cmd == NULLCHAR) return;
\r
6977 history[histIn] = StrSave(cmd);
\r
6978 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6979 if (history[histIn] != NULL) {
\r
6980 free(history[histIn]);
\r
6981 history[histIn] = NULL;
\r
6987 PrevInHistory(char *cmd)
\r
6990 if (histP == histIn) {
\r
6991 if (history[histIn] != NULL) free(history[histIn]);
\r
6992 history[histIn] = StrSave(cmd);
\r
6994 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6995 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6997 return history[histP];
\r
7003 if (histP == histIn) return NULL;
\r
7004 histP = (histP + 1) % HISTORY_SIZE;
\r
7005 return history[histP];
\r
7012 BOOLEAN immediate;
\r
7013 } IcsTextMenuEntry;
\r
7014 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7015 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7018 ParseIcsTextMenu(char *icsTextMenuString)
\r
7021 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7022 char *p = icsTextMenuString;
\r
7023 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7026 if (e->command != NULL) {
\r
7028 e->command = NULL;
\r
7032 e = icsTextMenuEntry;
\r
7033 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7034 if (*p == ';' || *p == '\n') {
\r
7035 e->item = strdup("-");
\r
7036 e->command = NULL;
\r
7038 } else if (*p == '-') {
\r
7039 e->item = strdup("-");
\r
7040 e->command = NULL;
\r
7044 char *q, *r, *s, *t;
\r
7046 q = strchr(p, ',');
\r
7047 if (q == NULL) break;
\r
7049 r = strchr(q + 1, ',');
\r
7050 if (r == NULL) break;
\r
7052 s = strchr(r + 1, ',');
\r
7053 if (s == NULL) break;
\r
7056 t = strchr(s + 1, c);
\r
7059 t = strchr(s + 1, c);
\r
7061 if (t != NULL) *t = NULLCHAR;
\r
7062 e->item = strdup(p);
\r
7063 e->command = strdup(q + 1);
\r
7064 e->getname = *(r + 1) != '0';
\r
7065 e->immediate = *(s + 1) != '0';
\r
7069 if (t == NULL) break;
\r
7078 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7082 hmenu = LoadMenu(hInst, "TextMenu");
\r
7083 h = GetSubMenu(hmenu, 0);
\r
7085 if (strcmp(e->item, "-") == 0) {
\r
7086 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7088 if (e->item[0] == '|') {
\r
7089 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7090 IDM_CommandX + i, &e->item[1]);
\r
7092 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7101 WNDPROC consoleTextWindowProc;
\r
7104 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7106 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7107 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7111 SetWindowText(hInput, command);
\r
7113 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7115 sel.cpMin = 999999;
\r
7116 sel.cpMax = 999999;
\r
7117 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7122 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7123 if (sel.cpMin == sel.cpMax) {
\r
7124 /* Expand to surrounding word */
\r
7127 tr.chrg.cpMax = sel.cpMin;
\r
7128 tr.chrg.cpMin = --sel.cpMin;
\r
7129 if (sel.cpMin < 0) break;
\r
7130 tr.lpstrText = name;
\r
7131 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7132 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7136 tr.chrg.cpMin = sel.cpMax;
\r
7137 tr.chrg.cpMax = ++sel.cpMax;
\r
7138 tr.lpstrText = name;
\r
7139 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7140 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7143 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7144 MessageBeep(MB_ICONEXCLAMATION);
\r
7148 tr.lpstrText = name;
\r
7149 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7151 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7152 MessageBeep(MB_ICONEXCLAMATION);
\r
7155 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7158 sprintf(buf, "%s %s", command, name);
\r
7159 SetWindowText(hInput, buf);
\r
7160 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7162 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7163 SetWindowText(hInput, buf);
\r
7164 sel.cpMin = 999999;
\r
7165 sel.cpMax = 999999;
\r
7166 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7172 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7177 switch (message) {
\r
7179 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7182 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7185 sel.cpMin = 999999;
\r
7186 sel.cpMax = 999999;
\r
7187 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7188 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7193 if (wParam == '\t') {
\r
7194 if (GetKeyState(VK_SHIFT) < 0) {
\r
7196 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7197 if (buttonDesc[0].hwnd) {
\r
7198 SetFocus(buttonDesc[0].hwnd);
\r
7200 SetFocus(hwndMain);
\r
7204 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7207 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7209 SendMessage(hInput, message, wParam, lParam);
\r
7213 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7215 return SendMessage(hInput, message, wParam, lParam);
\r
7216 case WM_MBUTTONDOWN:
\r
7217 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7218 case WM_RBUTTONDOWN:
\r
7219 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7220 /* Move selection here if it was empty */
\r
7222 pt.x = LOWORD(lParam);
\r
7223 pt.y = HIWORD(lParam);
\r
7224 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7225 if (sel.cpMin == sel.cpMax) {
\r
7226 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7227 sel.cpMax = sel.cpMin;
\r
7228 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7230 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7233 case WM_RBUTTONUP:
\r
7234 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7235 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7236 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7239 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7240 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7241 if (sel.cpMin == sel.cpMax) {
\r
7242 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7243 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7245 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7246 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7248 pt.x = LOWORD(lParam);
\r
7249 pt.y = HIWORD(lParam);
\r
7250 MenuPopup(hwnd, pt, hmenu, -1);
\r
7254 switch (LOWORD(wParam)) {
\r
7255 case IDM_QuickPaste:
\r
7257 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7258 if (sel.cpMin == sel.cpMax) {
\r
7259 MessageBeep(MB_ICONEXCLAMATION);
\r
7262 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7263 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7264 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7269 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7272 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7275 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7279 int i = LOWORD(wParam) - IDM_CommandX;
\r
7280 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7281 icsTextMenuEntry[i].command != NULL) {
\r
7282 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7283 icsTextMenuEntry[i].getname,
\r
7284 icsTextMenuEntry[i].immediate);
\r
7292 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7295 WNDPROC consoleInputWindowProc;
\r
7298 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7300 char buf[MSG_SIZ];
\r
7302 static BOOL sendNextChar = FALSE;
\r
7303 static BOOL quoteNextChar = FALSE;
\r
7304 InputSource *is = consoleInputSource;
\r
7308 switch (message) {
\r
7310 if (!appData.localLineEditing || sendNextChar) {
\r
7311 is->buf[0] = (CHAR) wParam;
\r
7313 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7314 sendNextChar = FALSE;
\r
7317 if (quoteNextChar) {
\r
7318 buf[0] = (char) wParam;
\r
7319 buf[1] = NULLCHAR;
\r
7320 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7321 quoteNextChar = FALSE;
\r
7325 case '\r': /* Enter key */
\r
7326 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7327 if (consoleEcho) SaveInHistory(is->buf);
\r
7328 is->buf[is->count++] = '\n';
\r
7329 is->buf[is->count] = NULLCHAR;
\r
7330 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7331 if (consoleEcho) {
\r
7332 ConsoleOutput(is->buf, is->count, TRUE);
\r
7333 } else if (appData.localLineEditing) {
\r
7334 ConsoleOutput("\n", 1, TRUE);
\r
7337 case '\033': /* Escape key */
\r
7338 SetWindowText(hwnd, "");
\r
7339 cf.cbSize = sizeof(CHARFORMAT);
\r
7340 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7341 if (consoleEcho) {
\r
7342 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7344 cf.crTextColor = COLOR_ECHOOFF;
\r
7346 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7347 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7349 case '\t': /* Tab key */
\r
7350 if (GetKeyState(VK_SHIFT) < 0) {
\r
7352 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7355 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7356 if (buttonDesc[0].hwnd) {
\r
7357 SetFocus(buttonDesc[0].hwnd);
\r
7359 SetFocus(hwndMain);
\r
7363 case '\023': /* Ctrl+S */
\r
7364 sendNextChar = TRUE;
\r
7366 case '\021': /* Ctrl+Q */
\r
7367 quoteNextChar = TRUE;
\r
7376 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7377 p = PrevInHistory(buf);
\r
7379 SetWindowText(hwnd, p);
\r
7380 sel.cpMin = 999999;
\r
7381 sel.cpMax = 999999;
\r
7382 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7387 p = NextInHistory();
\r
7389 SetWindowText(hwnd, p);
\r
7390 sel.cpMin = 999999;
\r
7391 sel.cpMax = 999999;
\r
7392 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7398 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7402 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7406 case WM_MBUTTONDOWN:
\r
7407 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7408 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7410 case WM_RBUTTONUP:
\r
7411 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7412 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7413 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7417 hmenu = LoadMenu(hInst, "InputMenu");
\r
7418 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7419 if (sel.cpMin == sel.cpMax) {
\r
7420 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7421 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7423 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7424 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7426 pt.x = LOWORD(lParam);
\r
7427 pt.y = HIWORD(lParam);
\r
7428 MenuPopup(hwnd, pt, hmenu, -1);
\r
7432 switch (LOWORD(wParam)) {
\r
7434 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7436 case IDM_SelectAll:
\r
7438 sel.cpMax = -1; /*999999?*/
\r
7439 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7442 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7445 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7448 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7453 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7456 #define CO_MAX 100000
\r
7457 #define CO_TRIM 1000
\r
7460 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7462 static SnapData sd;
\r
7463 static HWND hText, hInput, hFocus;
\r
7464 InputSource *is = consoleInputSource;
\r
7466 static int sizeX, sizeY;
\r
7467 int newSizeX, newSizeY;
\r
7470 switch (message) {
\r
7471 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7472 hwndConsole = hDlg;
\r
7473 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7474 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7476 consoleTextWindowProc = (WNDPROC)
\r
7477 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7478 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7479 consoleInputWindowProc = (WNDPROC)
\r
7480 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7481 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7482 Colorize(ColorNormal, TRUE);
\r
7483 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7484 ChangedConsoleFont();
\r
7485 GetClientRect(hDlg, &rect);
\r
7486 sizeX = rect.right;
\r
7487 sizeY = rect.bottom;
\r
7488 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7489 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7490 WINDOWPLACEMENT wp;
\r
7491 EnsureOnScreen(&consoleX, &consoleY);
\r
7492 wp.length = sizeof(WINDOWPLACEMENT);
\r
7494 wp.showCmd = SW_SHOW;
\r
7495 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7496 wp.rcNormalPosition.left = consoleX;
\r
7497 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7498 wp.rcNormalPosition.top = consoleY;
\r
7499 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7500 SetWindowPlacement(hDlg, &wp);
\r
7514 if (IsIconic(hDlg)) break;
\r
7515 newSizeX = LOWORD(lParam);
\r
7516 newSizeY = HIWORD(lParam);
\r
7517 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7518 RECT rectText, rectInput;
\r
7520 int newTextHeight, newTextWidth;
\r
7521 GetWindowRect(hText, &rectText);
\r
7522 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7523 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7524 if (newTextHeight < 0) {
\r
7525 newSizeY += -newTextHeight;
\r
7526 newTextHeight = 0;
\r
7528 SetWindowPos(hText, NULL, 0, 0,
\r
7529 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7530 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7531 pt.x = rectInput.left;
\r
7532 pt.y = rectInput.top + newSizeY - sizeY;
\r
7533 ScreenToClient(hDlg, &pt);
\r
7534 SetWindowPos(hInput, NULL,
\r
7535 pt.x, pt.y, /* needs client coords */
\r
7536 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7537 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7543 case WM_GETMINMAXINFO:
\r
7544 /* Prevent resizing window too small */
\r
7545 mmi = (MINMAXINFO *) lParam;
\r
7546 mmi->ptMinTrackSize.x = 100;
\r
7547 mmi->ptMinTrackSize.y = 100;
\r
7550 /* [AS] Snapping */
\r
7551 case WM_ENTERSIZEMOVE:
\r
7552 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7555 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7558 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7560 case WM_EXITSIZEMOVE:
\r
7561 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7564 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7572 if (hwndConsole) return;
\r
7573 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7574 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7579 ConsoleOutput(char* data, int length, int forceVisible)
\r
7584 char buf[CO_MAX+1];
\r
7587 static int delayLF = 0;
\r
7588 CHARRANGE savesel, sel;
\r
7590 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7598 while (length--) {
\r
7606 } else if (*p == '\007') {
\r
7607 MyPlaySound(&sounds[(int)SoundBell]);
\r
7614 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7615 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7616 /* Save current selection */
\r
7617 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7618 exlen = GetWindowTextLength(hText);
\r
7619 /* Find out whether current end of text is visible */
\r
7620 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7621 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7622 /* Trim existing text if it's too long */
\r
7623 if (exlen + (q - buf) > CO_MAX) {
\r
7624 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7627 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7628 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7630 savesel.cpMin -= trim;
\r
7631 savesel.cpMax -= trim;
\r
7632 if (exlen < 0) exlen = 0;
\r
7633 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7634 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7636 /* Append the new text */
\r
7637 sel.cpMin = exlen;
\r
7638 sel.cpMax = exlen;
\r
7639 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7640 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7641 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7642 if (forceVisible || exlen == 0 ||
\r
7643 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7644 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7645 /* Scroll to make new end of text visible if old end of text
\r
7646 was visible or new text is an echo of user typein */
\r
7647 sel.cpMin = 9999999;
\r
7648 sel.cpMax = 9999999;
\r
7649 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7650 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7651 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7652 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7654 if (savesel.cpMax == exlen || forceVisible) {
\r
7655 /* Move insert point to new end of text if it was at the old
\r
7656 end of text or if the new text is an echo of user typein */
\r
7657 sel.cpMin = 9999999;
\r
7658 sel.cpMax = 9999999;
\r
7659 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7661 /* Restore previous selection */
\r
7662 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7664 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7671 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7675 COLORREF oldFg, oldBg;
\r
7679 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
7681 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7682 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7683 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7686 rect.right = x + squareSize;
\r
7688 rect.bottom = y + squareSize;
\r
7691 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7692 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7693 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7694 &rect, str, strlen(str), NULL);
\r
7696 (void) SetTextColor(hdc, oldFg);
\r
7697 (void) SetBkColor(hdc, oldBg);
\r
7698 (void) SelectObject(hdc, oldFont);
\r
7702 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7703 RECT *rect, char *color, char *flagFell)
\r
7707 COLORREF oldFg, oldBg;
\r
7710 if (appData.clockMode) {
\r
7712 sprintf(buf, "%c %s %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7714 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
7721 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7722 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7724 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7725 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7727 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7729 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7730 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7731 rect, str, strlen(str), NULL);
\r
7733 (void) SetTextColor(hdc, oldFg);
\r
7734 (void) SetBkColor(hdc, oldBg);
\r
7735 (void) SelectObject(hdc, oldFont);
\r
7740 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7746 if( count <= 0 ) {
\r
7747 if (appData.debugMode) {
\r
7748 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7751 return ERROR_INVALID_USER_BUFFER;
\r
7754 ResetEvent(ovl->hEvent);
\r
7755 ovl->Offset = ovl->OffsetHigh = 0;
\r
7756 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7760 err = GetLastError();
\r
7761 if (err == ERROR_IO_PENDING) {
\r
7762 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7766 err = GetLastError();
\r
7773 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7778 ResetEvent(ovl->hEvent);
\r
7779 ovl->Offset = ovl->OffsetHigh = 0;
\r
7780 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7784 err = GetLastError();
\r
7785 if (err == ERROR_IO_PENDING) {
\r
7786 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7790 err = GetLastError();
\r
7796 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7797 void CheckForInputBufferFull( InputSource * is )
\r
7799 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7800 /* Look for end of line */
\r
7801 char * p = is->buf;
\r
7803 while( p < is->next && *p != '\n' ) {
\r
7807 if( p >= is->next ) {
\r
7808 if (appData.debugMode) {
\r
7809 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
\r
7812 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7813 is->count = (DWORD) -1;
\r
7814 is->next = is->buf;
\r
7820 InputThread(LPVOID arg)
\r
7825 is = (InputSource *) arg;
\r
7826 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7827 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7828 while (is->hThread != NULL) {
\r
7829 is->error = DoReadFile(is->hFile, is->next,
\r
7830 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7831 &is->count, &ovl);
\r
7832 if (is->error == NO_ERROR) {
\r
7833 is->next += is->count;
\r
7835 if (is->error == ERROR_BROKEN_PIPE) {
\r
7836 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7839 is->count = (DWORD) -1;
\r
7840 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7845 CheckForInputBufferFull( is );
\r
7847 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7849 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7851 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7854 CloseHandle(ovl.hEvent);
\r
7855 CloseHandle(is->hFile);
\r
7857 if (appData.debugMode) {
\r
7858 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
\r
7865 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7867 NonOvlInputThread(LPVOID arg)
\r
7874 is = (InputSource *) arg;
\r
7875 while (is->hThread != NULL) {
\r
7876 is->error = ReadFile(is->hFile, is->next,
\r
7877 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7878 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7879 if (is->error == NO_ERROR) {
\r
7880 /* Change CRLF to LF */
\r
7881 if (is->next > is->buf) {
\r
7883 i = is->count + 1;
\r
7891 if (prev == '\r' && *p == '\n') {
\r
7903 if (is->error == ERROR_BROKEN_PIPE) {
\r
7904 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7907 is->count = (DWORD) -1;
\r
7911 CheckForInputBufferFull( is );
\r
7913 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7915 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7917 if (is->count < 0) break; /* Quit on error */
\r
7919 CloseHandle(is->hFile);
\r
7924 SocketInputThread(LPVOID arg)
\r
7928 is = (InputSource *) arg;
\r
7929 while (is->hThread != NULL) {
\r
7930 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7931 if ((int)is->count == SOCKET_ERROR) {
\r
7932 is->count = (DWORD) -1;
\r
7933 is->error = WSAGetLastError();
\r
7935 is->error = NO_ERROR;
\r
7936 is->next += is->count;
\r
7937 if (is->count == 0 && is->second == is) {
\r
7938 /* End of file on stderr; quit with no message */
\r
7942 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7944 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7946 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7952 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7956 is = (InputSource *) lParam;
\r
7957 if (is->lineByLine) {
\r
7958 /* Feed in lines one by one */
\r
7959 char *p = is->buf;
\r
7961 while (q < is->next) {
\r
7962 if (*q++ == '\n') {
\r
7963 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7968 /* Move any partial line to the start of the buffer */
\r
7970 while (p < is->next) {
\r
7975 if (is->error != NO_ERROR || is->count == 0) {
\r
7976 /* Notify backend of the error. Note: If there was a partial
\r
7977 line at the end, it is not flushed through. */
\r
7978 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7981 /* Feed in the whole chunk of input at once */
\r
7982 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7983 is->next = is->buf;
\r
7987 /*---------------------------------------------------------------------------*\
\r
7989 * Menu enables. Used when setting various modes.
\r
7991 \*---------------------------------------------------------------------------*/
\r
7999 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8001 while (enab->item > 0) {
\r
8002 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8007 Enables gnuEnables[] = {
\r
8008 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8009 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8010 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8011 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8012 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8013 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8014 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8015 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8016 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8017 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8021 Enables icsEnables[] = {
\r
8022 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8023 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8024 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8025 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8026 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8027 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8028 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8029 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8030 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8031 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8032 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8033 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8038 Enables zippyEnables[] = {
\r
8039 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8040 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8041 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8046 Enables ncpEnables[] = {
\r
8047 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8048 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8049 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8050 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8051 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8052 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8053 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8054 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8055 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8056 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8057 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8058 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8059 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8060 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8061 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8065 Enables trainingOnEnables[] = {
\r
8066 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8067 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8068 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8069 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8070 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8071 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8072 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8073 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8077 Enables trainingOffEnables[] = {
\r
8078 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8079 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8080 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8081 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8082 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8083 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8084 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8085 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8089 /* These modify either ncpEnables or gnuEnables */
\r
8090 Enables cmailEnables[] = {
\r
8091 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8092 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8093 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8094 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8095 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8096 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8097 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8101 Enables machineThinkingEnables[] = {
\r
8102 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8103 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8104 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8105 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8106 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8107 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8108 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8109 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8110 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8111 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8112 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8113 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8114 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8115 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8116 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8120 Enables userThinkingEnables[] = {
\r
8121 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8122 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8123 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8124 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8125 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8126 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8127 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8128 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8129 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8130 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8131 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8132 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8133 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8134 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8135 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8139 /*---------------------------------------------------------------------------*\
\r
8141 * Front-end interface functions exported by XBoard.
\r
8142 * Functions appear in same order as prototypes in frontend.h.
\r
8144 \*---------------------------------------------------------------------------*/
\r
8148 static UINT prevChecked = 0;
\r
8149 static int prevPausing = 0;
\r
8152 if (pausing != prevPausing) {
\r
8153 prevPausing = pausing;
\r
8154 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8155 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8156 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8159 switch (gameMode) {
\r
8160 case BeginningOfGame:
\r
8161 if (appData.icsActive)
\r
8162 nowChecked = IDM_IcsClient;
\r
8163 else if (appData.noChessProgram)
\r
8164 nowChecked = IDM_EditGame;
\r
8166 nowChecked = IDM_MachineBlack;
\r
8168 case MachinePlaysBlack:
\r
8169 nowChecked = IDM_MachineBlack;
\r
8171 case MachinePlaysWhite:
\r
8172 nowChecked = IDM_MachineWhite;
\r
8174 case TwoMachinesPlay:
\r
8175 nowChecked = IDM_TwoMachines;
\r
8178 nowChecked = IDM_AnalysisMode;
\r
8181 nowChecked = IDM_AnalyzeFile;
\r
8184 nowChecked = IDM_EditGame;
\r
8186 case PlayFromGameFile:
\r
8187 nowChecked = IDM_LoadGame;
\r
8189 case EditPosition:
\r
8190 nowChecked = IDM_EditPosition;
\r
8193 nowChecked = IDM_Training;
\r
8195 case IcsPlayingWhite:
\r
8196 case IcsPlayingBlack:
\r
8197 case IcsObserving:
\r
8199 nowChecked = IDM_IcsClient;
\r
8206 if (prevChecked != 0)
\r
8207 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8208 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8209 if (nowChecked != 0)
\r
8210 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8211 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8213 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8214 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8215 MF_BYCOMMAND|MF_ENABLED);
\r
8217 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8218 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8221 prevChecked = nowChecked;
\r
8227 HMENU hmenu = GetMenu(hwndMain);
\r
8228 SetMenuEnables(hmenu, icsEnables);
\r
8229 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8230 MF_BYPOSITION|MF_ENABLED);
\r
8232 if (appData.zippyPlay) {
\r
8233 SetMenuEnables(hmenu, zippyEnables);
\r
8241 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8247 HMENU hmenu = GetMenu(hwndMain);
\r
8248 SetMenuEnables(hmenu, ncpEnables);
\r
8249 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8250 MF_BYPOSITION|MF_GRAYED);
\r
8251 DrawMenuBar(hwndMain);
\r
8257 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8261 SetTrainingModeOn()
\r
8264 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8265 for (i = 0; i < N_BUTTONS; i++) {
\r
8266 if (buttonDesc[i].hwnd != NULL)
\r
8267 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8272 VOID SetTrainingModeOff()
\r
8275 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8276 for (i = 0; i < N_BUTTONS; i++) {
\r
8277 if (buttonDesc[i].hwnd != NULL)
\r
8278 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8284 SetUserThinkingEnables()
\r
8286 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8290 SetMachineThinkingEnables()
\r
8292 HMENU hMenu = GetMenu(hwndMain);
\r
8293 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8295 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8297 if (gameMode == MachinePlaysBlack) {
\r
8298 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8299 } else if (gameMode == MachinePlaysWhite) {
\r
8300 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8301 } else if (gameMode == TwoMachinesPlay) {
\r
8302 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8308 DisplayTitle(char *str)
\r
8310 char title[MSG_SIZ], *host;
\r
8311 if (str[0] != NULLCHAR) {
\r
8312 strcpy(title, str);
\r
8313 } else if (appData.icsActive) {
\r
8314 if (appData.icsCommPort[0] != NULLCHAR)
\r
8317 host = appData.icsHost;
\r
8318 sprintf(title, "%s: %s", szTitle, host);
\r
8319 } else if (appData.noChessProgram) {
\r
8320 strcpy(title, szTitle);
\r
8322 strcpy(title, szTitle);
\r
8323 strcat(title, ": ");
\r
8324 strcat(title, first.tidy);
\r
8326 SetWindowText(hwndMain, title);
\r
8331 DisplayMessage(char *str1, char *str2)
\r
8335 int remain = MESSAGE_TEXT_MAX - 1;
\r
8338 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8339 messageText[0] = NULLCHAR;
\r
8341 len = strlen(str1);
\r
8342 if (len > remain) len = remain;
\r
8343 strncpy(messageText, str1, len);
\r
8344 messageText[len] = NULLCHAR;
\r
8347 if (*str2 && remain >= 2) {
\r
8349 strcat(messageText, " ");
\r
8352 len = strlen(str2);
\r
8353 if (len > remain) len = remain;
\r
8354 strncat(messageText, str2, len);
\r
8356 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8358 if (IsIconic(hwndMain)) return;
\r
8359 hdc = GetDC(hwndMain);
\r
8360 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8361 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8362 &messageRect, messageText, strlen(messageText), NULL);
\r
8363 (void) SelectObject(hdc, oldFont);
\r
8364 (void) ReleaseDC(hwndMain, hdc);
\r
8368 DisplayError(char *str, int error)
\r
8370 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8376 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8377 NULL, error, LANG_NEUTRAL,
\r
8378 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8380 sprintf(buf, "%s:\n%s", str, buf2);
\r
8382 ErrorMap *em = errmap;
\r
8383 while (em->err != 0 && em->err != error) em++;
\r
8384 if (em->err != 0) {
\r
8385 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8387 sprintf(buf, "%s:\nError code %d", str, error);
\r
8392 ErrorPopUp("Error", buf);
\r
8397 DisplayMoveError(char *str)
\r
8399 fromX = fromY = -1;
\r
8400 ClearHighlights();
\r
8401 DrawPosition(FALSE, NULL);
\r
8402 if (appData.popupMoveErrors) {
\r
8403 ErrorPopUp("Error", str);
\r
8405 DisplayMessage(str, "");
\r
8406 moveErrorMessageUp = TRUE;
\r
8411 DisplayFatalError(char *str, int error, int exitStatus)
\r
8413 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8415 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8418 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8419 NULL, error, LANG_NEUTRAL,
\r
8420 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8422 sprintf(buf, "%s:\n%s", str, buf2);
\r
8424 ErrorMap *em = errmap;
\r
8425 while (em->err != 0 && em->err != error) em++;
\r
8426 if (em->err != 0) {
\r
8427 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8429 sprintf(buf, "%s:\nError code %d", str, error);
\r
8434 if (appData.debugMode) {
\r
8435 fprintf(debugFP, "%s: %s\n", label, str);
\r
8437 if (appData.popupExitMessage) {
\r
8438 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8439 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8441 ExitEvent(exitStatus);
\r
8446 DisplayInformation(char *str)
\r
8448 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8453 DisplayNote(char *str)
\r
8455 ErrorPopUp("Note", str);
\r
8460 char *title, *question, *replyPrefix;
\r
8465 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8467 static QuestionParams *qp;
\r
8468 char reply[MSG_SIZ];
\r
8471 switch (message) {
\r
8472 case WM_INITDIALOG:
\r
8473 qp = (QuestionParams *) lParam;
\r
8474 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8475 SetWindowText(hDlg, qp->title);
\r
8476 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8477 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8481 switch (LOWORD(wParam)) {
\r
8483 strcpy(reply, qp->replyPrefix);
\r
8484 if (*reply) strcat(reply, " ");
\r
8485 len = strlen(reply);
\r
8486 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8487 strcat(reply, "\n");
\r
8488 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8489 EndDialog(hDlg, TRUE);
\r
8490 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
8493 EndDialog(hDlg, FALSE);
\r
8504 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8506 QuestionParams qp;
\r
8510 qp.question = question;
\r
8511 qp.replyPrefix = replyPrefix;
\r
8513 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8514 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8515 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8516 FreeProcInstance(lpProc);
\r
8519 /* [AS] Pick FRC position */
\r
8520 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8522 static int * lpIndexFRC;
\r
8528 case WM_INITDIALOG:
\r
8529 lpIndexFRC = (int *) lParam;
\r
8531 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8533 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8534 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8535 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8536 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8541 switch( LOWORD(wParam) ) {
\r
8543 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8544 EndDialog( hDlg, 0 );
\r
8547 EndDialog( hDlg, 1 );
\r
8549 case IDC_NFG_Edit:
\r
8550 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8551 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8553 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8556 case IDC_NFG_Random:
\r
8557 sprintf( buf, "%d", myrandom() % 960 );
\r
8558 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8571 int index = appData.defaultFrcPosition;
\r
8572 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8574 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8576 if( result == 0 ) {
\r
8577 appData.defaultFrcPosition = index;
\r
8583 /* [AS] Game list options */
\r
8589 static GLT_Item GLT_ItemInfo[] = {
\r
8590 { GLT_EVENT, "Event" },
\r
8591 { GLT_SITE, "Site" },
\r
8592 { GLT_DATE, "Date" },
\r
8593 { GLT_ROUND, "Round" },
\r
8594 { GLT_PLAYERS, "Players" },
\r
8595 { GLT_RESULT, "Result" },
\r
8596 { GLT_WHITE_ELO, "White Rating" },
\r
8597 { GLT_BLACK_ELO, "Black Rating" },
\r
8598 { GLT_TIME_CONTROL,"Time Control" },
\r
8599 { GLT_VARIANT, "Variant" },
\r
8600 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
8604 const char * GLT_FindItem( char id )
\r
8606 const char * result = 0;
\r
8608 GLT_Item * list = GLT_ItemInfo;
\r
8610 while( list->id != 0 ) {
\r
8611 if( list->id == id ) {
\r
8612 result = list->name;
\r
8622 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
8624 const char * name = GLT_FindItem( id );
\r
8627 if( index >= 0 ) {
\r
8628 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
8631 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
8636 void GLT_TagsToList( HWND hDlg, char * tags )
\r
8640 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8643 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8647 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
8649 pc = GLT_ALL_TAGS;
\r
8652 if( strchr( tags, *pc ) == 0 ) {
\r
8653 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8658 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8661 char GLT_ListItemToTag( HWND hDlg, int index )
\r
8663 char result = '\0';
\r
8666 GLT_Item * list = GLT_ItemInfo;
\r
8668 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
8669 while( list->id != 0 ) {
\r
8670 if( strcmp( list->name, name ) == 0 ) {
\r
8671 result = list->id;
\r
8682 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8684 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8685 int idx2 = idx1 + delta;
\r
8686 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8688 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8691 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8692 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8693 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8694 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8698 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8700 static char glt[64];
\r
8701 static char * lpUserGLT;
\r
8705 case WM_INITDIALOG:
\r
8706 lpUserGLT = (char *) lParam;
\r
8708 strcpy( glt, lpUserGLT );
\r
8710 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8712 /* Initialize list */
\r
8713 GLT_TagsToList( hDlg, glt );
\r
8715 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8720 switch( LOWORD(wParam) ) {
\r
8723 char * pc = lpUserGLT;
\r
8725 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8729 id = GLT_ListItemToTag( hDlg, idx );
\r
8733 } while( id != '\0' );
\r
8735 EndDialog( hDlg, 0 );
\r
8738 EndDialog( hDlg, 1 );
\r
8741 case IDC_GLT_Default:
\r
8742 strcpy( glt, GLT_DEFAULT_TAGS );
\r
8743 GLT_TagsToList( hDlg, glt );
\r
8746 case IDC_GLT_Restore:
\r
8747 strcpy( glt, lpUserGLT );
\r
8748 GLT_TagsToList( hDlg, glt );
\r
8752 GLT_MoveSelection( hDlg, -1 );
\r
8755 case IDC_GLT_Down:
\r
8756 GLT_MoveSelection( hDlg, +1 );
\r
8766 int GameListOptions()
\r
8770 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8772 strcpy( glt, appData.gameListTags );
\r
8774 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
8776 if( result == 0 ) {
\r
8777 /* [AS] Memory leak here! */
\r
8778 appData.gameListTags = strdup( glt );
\r
8786 DisplayIcsInteractionTitle(char *str)
\r
8788 char consoleTitle[MSG_SIZ];
\r
8790 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8791 SetWindowText(hwndConsole, consoleTitle);
\r
8795 DrawPosition(int fullRedraw, Board board)
\r
8797 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8804 fromX = fromY = -1;
\r
8805 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8806 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8807 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8808 dragInfo.lastpos = dragInfo.pos;
\r
8809 dragInfo.start.x = dragInfo.start.y = -1;
\r
8810 dragInfo.from = dragInfo.start;
\r
8812 DrawPosition(TRUE, NULL);
\r
8818 CommentPopUp(char *title, char *str)
\r
8820 HWND hwnd = GetActiveWindow();
\r
8821 EitherCommentPopUp(0, title, str, FALSE);
\r
8822 SetActiveWindow(hwnd);
\r
8826 CommentPopDown(void)
\r
8828 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8829 if (commentDialog) {
\r
8830 ShowWindow(commentDialog, SW_HIDE);
\r
8832 commentDialogUp = FALSE;
\r
8836 EditCommentPopUp(int index, char *title, char *str)
\r
8838 EitherCommentPopUp(index, title, str, TRUE);
\r
8845 MyPlaySound(&sounds[(int)SoundMove]);
\r
8848 VOID PlayIcsWinSound()
\r
8850 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8853 VOID PlayIcsLossSound()
\r
8855 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8858 VOID PlayIcsDrawSound()
\r
8860 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8863 VOID PlayIcsUnfinishedSound()
\r
8865 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8871 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8879 consoleEcho = TRUE;
\r
8880 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8881 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8882 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8891 consoleEcho = FALSE;
\r
8892 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8893 /* This works OK: set text and background both to the same color */
\r
8895 cf.crTextColor = COLOR_ECHOOFF;
\r
8896 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8897 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8900 /* No Raw()...? */
\r
8902 void Colorize(ColorClass cc, int continuation)
\r
8904 currentColorClass = cc;
\r
8905 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8906 consoleCF.crTextColor = textAttribs[cc].color;
\r
8907 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8908 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8914 static char buf[MSG_SIZ];
\r
8915 DWORD bufsiz = MSG_SIZ;
\r
8917 if (!GetUserName(buf, &bufsiz)) {
\r
8918 /*DisplayError("Error getting user name", GetLastError());*/
\r
8919 strcpy(buf, "User");
\r
8927 static char buf[MSG_SIZ];
\r
8928 DWORD bufsiz = MSG_SIZ;
\r
8930 if (!GetComputerName(buf, &bufsiz)) {
\r
8931 /*DisplayError("Error getting host name", GetLastError());*/
\r
8932 strcpy(buf, "Unknown");
\r
8939 ClockTimerRunning()
\r
8941 return clockTimerEvent != 0;
\r
8947 if (clockTimerEvent == 0) return FALSE;
\r
8948 KillTimer(hwndMain, clockTimerEvent);
\r
8949 clockTimerEvent = 0;
\r
8954 StartClockTimer(long millisec)
\r
8956 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8957 (UINT) millisec, NULL);
\r
8961 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8964 hdc = GetDC(hwndMain);
\r
8965 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8967 if (!IsIconic(hwndMain)) {
\r
8968 DisplayAClock(hdc, timeRemaining, highlight, flipClock ? &blackRect : &whiteRect, "White", flag);
\r
8970 if (highlight && iconCurrent == iconBlack) {
\r
8971 iconCurrent = iconWhite;
\r
8972 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8973 if (IsIconic(hwndMain)) {
\r
8974 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8977 (void) ReleaseDC(hwndMain, hdc);
\r
8979 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8983 DisplayBlackClock(long timeRemaining, int highlight)
\r
8986 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8988 hdc = GetDC(hwndMain);
\r
8989 if (!IsIconic(hwndMain)) {
\r
8990 DisplayAClock(hdc, timeRemaining, highlight, flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
8992 if (highlight && iconCurrent == iconWhite) {
\r
8993 iconCurrent = iconBlack;
\r
8994 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8995 if (IsIconic(hwndMain)) {
\r
8996 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8999 (void) ReleaseDC(hwndMain, hdc);
\r
9001 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9006 LoadGameTimerRunning()
\r
9008 return loadGameTimerEvent != 0;
\r
9012 StopLoadGameTimer()
\r
9014 if (loadGameTimerEvent == 0) return FALSE;
\r
9015 KillTimer(hwndMain, loadGameTimerEvent);
\r
9016 loadGameTimerEvent = 0;
\r
9021 StartLoadGameTimer(long millisec)
\r
9023 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9024 (UINT) millisec, NULL);
\r
9032 char fileTitle[MSG_SIZ];
\r
9034 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9035 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
9036 appData.oldSaveStyle ? "gam" : "pgn",
\r
9038 "Save Game to File", NULL, fileTitle, NULL);
\r
9040 SaveGame(f, 0, "");
\r
9047 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9049 if (delayedTimerEvent != 0) {
\r
9050 if (appData.debugMode) {
\r
9051 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9053 KillTimer(hwndMain, delayedTimerEvent);
\r
9054 delayedTimerEvent = 0;
\r
9055 delayedTimerCallback();
\r
9057 delayedTimerCallback = cb;
\r
9058 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9059 (UINT) millisec, NULL);
\r
9062 DelayedEventCallback
\r
9065 if (delayedTimerEvent) {
\r
9066 return delayedTimerCallback;
\r
9073 CancelDelayedEvent()
\r
9075 if (delayedTimerEvent) {
\r
9076 KillTimer(hwndMain, delayedTimerEvent);
\r
9077 delayedTimerEvent = 0;
\r
9081 /* Start a child process running the given program.
\r
9082 The process's standard output can be read from "from", and its
\r
9083 standard input can be written to "to".
\r
9084 Exit with fatal error if anything goes wrong.
\r
9085 Returns an opaque pointer that can be used to destroy the process
\r
9089 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9091 #define BUFSIZE 4096
\r
9093 HANDLE hChildStdinRd, hChildStdinWr,
\r
9094 hChildStdoutRd, hChildStdoutWr;
\r
9095 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9096 SECURITY_ATTRIBUTES saAttr;
\r
9098 PROCESS_INFORMATION piProcInfo;
\r
9099 STARTUPINFO siStartInfo;
\r
9101 char buf[MSG_SIZ];
\r
9104 if (appData.debugMode) {
\r
9105 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9110 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9111 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9112 saAttr.bInheritHandle = TRUE;
\r
9113 saAttr.lpSecurityDescriptor = NULL;
\r
9116 * The steps for redirecting child's STDOUT:
\r
9117 * 1. Create anonymous pipe to be STDOUT for child.
\r
9118 * 2. Create a noninheritable duplicate of read handle,
\r
9119 * and close the inheritable read handle.
\r
9122 /* Create a pipe for the child's STDOUT. */
\r
9123 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9124 return GetLastError();
\r
9127 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9128 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9129 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9130 FALSE, /* not inherited */
\r
9131 DUPLICATE_SAME_ACCESS);
\r
9133 return GetLastError();
\r
9135 CloseHandle(hChildStdoutRd);
\r
9138 * The steps for redirecting child's STDIN:
\r
9139 * 1. Create anonymous pipe to be STDIN for child.
\r
9140 * 2. Create a noninheritable duplicate of write handle,
\r
9141 * and close the inheritable write handle.
\r
9144 /* Create a pipe for the child's STDIN. */
\r
9145 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9146 return GetLastError();
\r
9149 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9150 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9151 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9152 FALSE, /* not inherited */
\r
9153 DUPLICATE_SAME_ACCESS);
\r
9155 return GetLastError();
\r
9157 CloseHandle(hChildStdinWr);
\r
9159 /* Arrange to (1) look in dir for the child .exe file, and
\r
9160 * (2) have dir be the child's working directory. Interpret
\r
9161 * dir relative to the directory WinBoard loaded from. */
\r
9162 GetCurrentDirectory(MSG_SIZ, buf);
\r
9163 SetCurrentDirectory(installDir);
\r
9164 SetCurrentDirectory(dir);
\r
9166 /* Now create the child process. */
\r
9168 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9169 siStartInfo.lpReserved = NULL;
\r
9170 siStartInfo.lpDesktop = NULL;
\r
9171 siStartInfo.lpTitle = NULL;
\r
9172 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9173 siStartInfo.cbReserved2 = 0;
\r
9174 siStartInfo.lpReserved2 = NULL;
\r
9175 siStartInfo.hStdInput = hChildStdinRd;
\r
9176 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9177 siStartInfo.hStdError = hChildStdoutWr;
\r
9179 fSuccess = CreateProcess(NULL,
\r
9180 cmdLine, /* command line */
\r
9181 NULL, /* process security attributes */
\r
9182 NULL, /* primary thread security attrs */
\r
9183 TRUE, /* handles are inherited */
\r
9184 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9185 NULL, /* use parent's environment */
\r
9187 &siStartInfo, /* STARTUPINFO pointer */
\r
9188 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9190 err = GetLastError();
\r
9191 SetCurrentDirectory(buf); /* return to prev directory */
\r
9196 /* Close the handles we don't need in the parent */
\r
9197 CloseHandle(piProcInfo.hThread);
\r
9198 CloseHandle(hChildStdinRd);
\r
9199 CloseHandle(hChildStdoutWr);
\r
9201 /* Prepare return value */
\r
9202 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9203 cp->kind = CPReal;
\r
9204 cp->hProcess = piProcInfo.hProcess;
\r
9205 cp->pid = piProcInfo.dwProcessId;
\r
9206 cp->hFrom = hChildStdoutRdDup;
\r
9207 cp->hTo = hChildStdinWrDup;
\r
9209 *pr = (void *) cp;
\r
9211 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9212 2000 where engines sometimes don't see the initial command(s)
\r
9213 from WinBoard and hang. I don't understand how that can happen,
\r
9214 but the Sleep is harmless, so I've put it in. Others have also
\r
9215 reported what may be the same problem, so hopefully this will fix
\r
9216 it for them too. */
\r
9224 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9226 ChildProc *cp; int result;
\r
9228 cp = (ChildProc *) pr;
\r
9229 if (cp == NULL) return;
\r
9231 switch (cp->kind) {
\r
9233 /* TerminateProcess is considered harmful, so... */
\r
9234 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9235 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9236 /* The following doesn't work because the chess program
\r
9237 doesn't "have the same console" as WinBoard. Maybe
\r
9238 we could arrange for this even though neither WinBoard
\r
9239 nor the chess program uses a console for stdio? */
\r
9240 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9242 /* [AS] Special termination modes for misbehaving programs... */
\r
9243 if( signal == 9 ) {
\r
9244 result = TerminateProcess( cp->hProcess, 0 );
\r
9246 if ( appData.debugMode) {
\r
9247 fprintf( debugFP, "Terminating process %u, result=%d\n", cp->pid, result );
\r
9250 else if( signal == 10 ) {
\r
9251 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9253 if( dw != WAIT_OBJECT_0 ) {
\r
9254 result = TerminateProcess( cp->hProcess, 0 );
\r
9256 if ( appData.debugMode) {
\r
9257 fprintf( debugFP, "Process %u still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9263 CloseHandle(cp->hProcess);
\r
9267 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9271 closesocket(cp->sock);
\r
9276 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9277 closesocket(cp->sock);
\r
9278 closesocket(cp->sock2);
\r
9286 InterruptChildProcess(ProcRef pr)
\r
9290 cp = (ChildProc *) pr;
\r
9291 if (cp == NULL) return;
\r
9292 switch (cp->kind) {
\r
9294 /* The following doesn't work because the chess program
\r
9295 doesn't "have the same console" as WinBoard. Maybe
\r
9296 we could arrange for this even though neither WinBoard
\r
9297 nor the chess program uses a console for stdio */
\r
9298 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9303 /* Can't interrupt */
\r
9307 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9314 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9316 char cmdLine[MSG_SIZ];
\r
9318 if (port[0] == NULLCHAR) {
\r
9319 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9321 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9323 return StartChildProcess(cmdLine, "", pr);
\r
9327 /* Code to open TCP sockets */
\r
9330 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9335 struct sockaddr_in sa, mysa;
\r
9336 struct hostent FAR *hp;
\r
9337 unsigned short uport;
\r
9338 WORD wVersionRequested;
\r
9341 /* Initialize socket DLL */
\r
9342 wVersionRequested = MAKEWORD(1, 1);
\r
9343 err = WSAStartup(wVersionRequested, &wsaData);
\r
9344 if (err != 0) return err;
\r
9347 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9348 err = WSAGetLastError();
\r
9353 /* Bind local address using (mostly) don't-care values.
\r
9355 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9356 mysa.sin_family = AF_INET;
\r
9357 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9358 uport = (unsigned short) 0;
\r
9359 mysa.sin_port = htons(uport);
\r
9360 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9361 == SOCKET_ERROR) {
\r
9362 err = WSAGetLastError();
\r
9367 /* Resolve remote host name */
\r
9368 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9369 if (!(hp = gethostbyname(host))) {
\r
9370 unsigned int b0, b1, b2, b3;
\r
9372 err = WSAGetLastError();
\r
9374 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9375 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9376 hp->h_addrtype = AF_INET;
\r
9378 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9379 hp->h_addr_list[0] = (char *) malloc(4);
\r
9380 hp->h_addr_list[0][0] = (char) b0;
\r
9381 hp->h_addr_list[0][1] = (char) b1;
\r
9382 hp->h_addr_list[0][2] = (char) b2;
\r
9383 hp->h_addr_list[0][3] = (char) b3;
\r
9389 sa.sin_family = hp->h_addrtype;
\r
9390 uport = (unsigned short) atoi(port);
\r
9391 sa.sin_port = htons(uport);
\r
9392 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9394 /* Make connection */
\r
9395 if (connect(s, (struct sockaddr *) &sa,
\r
9396 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9397 err = WSAGetLastError();
\r
9402 /* Prepare return value */
\r
9403 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9404 cp->kind = CPSock;
\r
9406 *pr = (ProcRef *) cp;
\r
9412 OpenCommPort(char *name, ProcRef *pr)
\r
9417 char fullname[MSG_SIZ];
\r
9419 if (*name != '\\')
\r
9420 sprintf(fullname, "\\\\.\\%s", name);
\r
9422 strcpy(fullname, name);
\r
9424 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9425 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9426 if (h == (HANDLE) -1) {
\r
9427 return GetLastError();
\r
9431 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9433 /* Accumulate characters until a 100ms pause, then parse */
\r
9434 ct.ReadIntervalTimeout = 100;
\r
9435 ct.ReadTotalTimeoutMultiplier = 0;
\r
9436 ct.ReadTotalTimeoutConstant = 0;
\r
9437 ct.WriteTotalTimeoutMultiplier = 0;
\r
9438 ct.WriteTotalTimeoutConstant = 0;
\r
9439 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9441 /* Prepare return value */
\r
9442 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9443 cp->kind = CPComm;
\r
9446 *pr = (ProcRef *) cp;
\r
9452 OpenLoopback(ProcRef *pr)
\r
9454 DisplayFatalError("Not implemented", 0, 1);
\r
9460 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9465 struct sockaddr_in sa, mysa;
\r
9466 struct hostent FAR *hp;
\r
9467 unsigned short uport;
\r
9468 WORD wVersionRequested;
\r
9471 char stderrPortStr[MSG_SIZ];
\r
9473 /* Initialize socket DLL */
\r
9474 wVersionRequested = MAKEWORD(1, 1);
\r
9475 err = WSAStartup(wVersionRequested, &wsaData);
\r
9476 if (err != 0) return err;
\r
9478 /* Resolve remote host name */
\r
9479 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9480 if (!(hp = gethostbyname(host))) {
\r
9481 unsigned int b0, b1, b2, b3;
\r
9483 err = WSAGetLastError();
\r
9485 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9486 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9487 hp->h_addrtype = AF_INET;
\r
9489 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9490 hp->h_addr_list[0] = (char *) malloc(4);
\r
9491 hp->h_addr_list[0][0] = (char) b0;
\r
9492 hp->h_addr_list[0][1] = (char) b1;
\r
9493 hp->h_addr_list[0][2] = (char) b2;
\r
9494 hp->h_addr_list[0][3] = (char) b3;
\r
9500 sa.sin_family = hp->h_addrtype;
\r
9501 uport = (unsigned short) 514;
\r
9502 sa.sin_port = htons(uport);
\r
9503 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9505 /* Bind local socket to unused "privileged" port address
\r
9507 s = INVALID_SOCKET;
\r
9508 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9509 mysa.sin_family = AF_INET;
\r
9510 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9511 for (fromPort = 1023;; fromPort--) {
\r
9512 if (fromPort < 0) {
\r
9514 return WSAEADDRINUSE;
\r
9516 if (s == INVALID_SOCKET) {
\r
9517 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9518 err = WSAGetLastError();
\r
9523 uport = (unsigned short) fromPort;
\r
9524 mysa.sin_port = htons(uport);
\r
9525 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9526 == SOCKET_ERROR) {
\r
9527 err = WSAGetLastError();
\r
9528 if (err == WSAEADDRINUSE) continue;
\r
9532 if (connect(s, (struct sockaddr *) &sa,
\r
9533 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9534 err = WSAGetLastError();
\r
9535 if (err == WSAEADDRINUSE) {
\r
9546 /* Bind stderr local socket to unused "privileged" port address
\r
9548 s2 = INVALID_SOCKET;
\r
9549 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9550 mysa.sin_family = AF_INET;
\r
9551 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9552 for (fromPort = 1023;; fromPort--) {
\r
9553 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9554 if (fromPort < 0) {
\r
9555 (void) closesocket(s);
\r
9557 return WSAEADDRINUSE;
\r
9559 if (s2 == INVALID_SOCKET) {
\r
9560 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9561 err = WSAGetLastError();
\r
9567 uport = (unsigned short) fromPort;
\r
9568 mysa.sin_port = htons(uport);
\r
9569 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9570 == SOCKET_ERROR) {
\r
9571 err = WSAGetLastError();
\r
9572 if (err == WSAEADDRINUSE) continue;
\r
9573 (void) closesocket(s);
\r
9577 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9578 err = WSAGetLastError();
\r
9579 if (err == WSAEADDRINUSE) {
\r
9581 s2 = INVALID_SOCKET;
\r
9584 (void) closesocket(s);
\r
9585 (void) closesocket(s2);
\r
9591 prevStderrPort = fromPort; // remember port used
\r
9592 sprintf(stderrPortStr, "%d", fromPort);
\r
9594 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9595 err = WSAGetLastError();
\r
9596 (void) closesocket(s);
\r
9597 (void) closesocket(s2);
\r
9602 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9603 err = WSAGetLastError();
\r
9604 (void) closesocket(s);
\r
9605 (void) closesocket(s2);
\r
9609 if (*user == NULLCHAR) user = UserName();
\r
9610 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9611 err = WSAGetLastError();
\r
9612 (void) closesocket(s);
\r
9613 (void) closesocket(s2);
\r
9617 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9618 err = WSAGetLastError();
\r
9619 (void) closesocket(s);
\r
9620 (void) closesocket(s2);
\r
9625 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9626 err = WSAGetLastError();
\r
9627 (void) closesocket(s);
\r
9628 (void) closesocket(s2);
\r
9632 (void) closesocket(s2); /* Stop listening */
\r
9634 /* Prepare return value */
\r
9635 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9636 cp->kind = CPRcmd;
\r
9639 *pr = (ProcRef *) cp;
\r
9646 AddInputSource(ProcRef pr, int lineByLine,
\r
9647 InputCallback func, VOIDSTAR closure)
\r
9649 InputSource *is, *is2 = NULL;
\r
9650 ChildProc *cp = (ChildProc *) pr;
\r
9652 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9653 is->lineByLine = lineByLine;
\r
9655 is->closure = closure;
\r
9656 is->second = NULL;
\r
9657 is->next = is->buf;
\r
9658 if (pr == NoProc) {
\r
9659 is->kind = CPReal;
\r
9660 consoleInputSource = is;
\r
9662 is->kind = cp->kind;
\r
9664 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9665 we create all threads suspended so that the is->hThread variable can be
\r
9666 safely assigned, then let the threads start with ResumeThread.
\r
9668 switch (cp->kind) {
\r
9670 is->hFile = cp->hFrom;
\r
9671 cp->hFrom = NULL; /* now owned by InputThread */
\r
9673 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9674 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9678 is->hFile = cp->hFrom;
\r
9679 cp->hFrom = NULL; /* now owned by InputThread */
\r
9681 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9682 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9686 is->sock = cp->sock;
\r
9688 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9689 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9693 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9695 is->sock = cp->sock;
\r
9697 is2->sock = cp->sock2;
\r
9698 is2->second = is2;
\r
9700 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9701 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9703 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9704 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9708 if( is->hThread != NULL ) {
\r
9709 ResumeThread( is->hThread );
\r
9712 if( is2 != NULL && is2->hThread != NULL ) {
\r
9713 ResumeThread( is2->hThread );
\r
9717 return (InputSourceRef) is;
\r
9721 RemoveInputSource(InputSourceRef isr)
\r
9725 is = (InputSource *) isr;
\r
9726 is->hThread = NULL; /* tell thread to stop */
\r
9727 CloseHandle(is->hThread);
\r
9728 if (is->second != NULL) {
\r
9729 is->second->hThread = NULL;
\r
9730 CloseHandle(is->second->hThread);
\r
9736 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9739 int outCount = SOCKET_ERROR;
\r
9740 ChildProc *cp = (ChildProc *) pr;
\r
9741 static OVERLAPPED ovl;
\r
9743 if (pr == NoProc) {
\r
9744 ConsoleOutput(message, count, FALSE);
\r
9748 if (ovl.hEvent == NULL) {
\r
9749 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9751 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9753 switch (cp->kind) {
\r
9756 outCount = send(cp->sock, message, count, 0);
\r
9757 if (outCount == SOCKET_ERROR) {
\r
9758 *outError = WSAGetLastError();
\r
9760 *outError = NO_ERROR;
\r
9765 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9766 &dOutCount, NULL)) {
\r
9767 *outError = NO_ERROR;
\r
9768 outCount = (int) dOutCount;
\r
9770 *outError = GetLastError();
\r
9775 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9776 &dOutCount, &ovl);
\r
9777 if (*outError == NO_ERROR) {
\r
9778 outCount = (int) dOutCount;
\r
9786 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9789 /* Ignore delay, not implemented for WinBoard */
\r
9790 return OutputToProcess(pr, message, count, outError);
\r
9795 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9796 char *buf, int count, int error)
\r
9798 DisplayFatalError("Not implemented", 0, 1);
\r
9801 /* see wgamelist.c for Game List functions */
\r
9802 /* see wedittags.c for Edit Tags functions */
\r
9809 char buf[MSG_SIZ];
\r
9812 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9813 f = fopen(buf, "r");
\r
9815 ProcessICSInitScript(f);
\r
9823 StartAnalysisClock()
\r
9825 if (analysisTimerEvent) return;
\r
9826 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9827 (UINT) 2000, NULL);
\r
9831 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9833 static HANDLE hwndText;
\r
9835 static int sizeX, sizeY;
\r
9836 int newSizeX, newSizeY, flags;
\r
9839 switch (message) {
\r
9840 case WM_INITDIALOG: /* message: initialize dialog box */
\r
9841 /* Initialize the dialog items */
\r
9842 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
9843 SetWindowText(hDlg, analysisTitle);
\r
9844 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
9845 /* Size and position the dialog */
\r
9846 if (!analysisDialog) {
\r
9847 analysisDialog = hDlg;
\r
9848 flags = SWP_NOZORDER;
\r
9849 GetClientRect(hDlg, &rect);
\r
9850 sizeX = rect.right;
\r
9851 sizeY = rect.bottom;
\r
9852 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
9853 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
9854 WINDOWPLACEMENT wp;
\r
9855 EnsureOnScreen(&analysisX, &analysisY);
\r
9856 wp.length = sizeof(WINDOWPLACEMENT);
\r
9858 wp.showCmd = SW_SHOW;
\r
9859 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
9860 wp.rcNormalPosition.left = analysisX;
\r
9861 wp.rcNormalPosition.right = analysisX + analysisW;
\r
9862 wp.rcNormalPosition.top = analysisY;
\r
9863 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
9864 SetWindowPlacement(hDlg, &wp);
\r
9866 GetClientRect(hDlg, &rect);
\r
9867 newSizeX = rect.right;
\r
9868 newSizeY = rect.bottom;
\r
9869 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
9870 newSizeX, newSizeY);
\r
9877 case WM_COMMAND: /* message: received a command */
\r
9878 switch (LOWORD(wParam)) {
\r
9888 newSizeX = LOWORD(lParam);
\r
9889 newSizeY = HIWORD(lParam);
\r
9890 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
9895 case WM_GETMINMAXINFO:
\r
9896 /* Prevent resizing window too small */
\r
9897 mmi = (MINMAXINFO *) lParam;
\r
9898 mmi->ptMinTrackSize.x = 100;
\r
9899 mmi->ptMinTrackSize.y = 100;
\r
9906 AnalysisPopUp(char* title, char* str)
\r
9912 EngineOutputPopUp();
\r
9915 if (str == NULL) str = "";
\r
9916 p = (char *) malloc(2 * strlen(str) + 2);
\r
9919 if (*str == '\n') *q++ = '\r';
\r
9923 if (analysisText != NULL) free(analysisText);
\r
9926 if (analysisDialog) {
\r
9927 SetWindowText(analysisDialog, title);
\r
9928 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
9929 ShowWindow(analysisDialog, SW_SHOW);
\r
9931 analysisTitle = title;
\r
9932 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
9933 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
9934 hwndMain, (DLGPROC)lpProc);
\r
9935 FreeProcInstance(lpProc);
\r
9937 analysisDialogUp = TRUE;
\r
9943 if (analysisDialog) {
\r
9944 ShowWindow(analysisDialog, SW_HIDE);
\r
9946 analysisDialogUp = FALSE;
\r
9951 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9953 highlightInfo.sq[0].x = fromX;
\r
9954 highlightInfo.sq[0].y = fromY;
\r
9955 highlightInfo.sq[1].x = toX;
\r
9956 highlightInfo.sq[1].y = toY;
\r
9962 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9963 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9967 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9969 premoveHighlightInfo.sq[0].x = fromX;
\r
9970 premoveHighlightInfo.sq[0].y = fromY;
\r
9971 premoveHighlightInfo.sq[1].x = toX;
\r
9972 premoveHighlightInfo.sq[1].y = toY;
\r
9976 ClearPremoveHighlights()
\r
9978 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9979 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9983 ShutDownFrontEnd()
\r
9985 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9986 DeleteClipboardTempFiles();
\r
9992 if (IsIconic(hwndMain))
\r
9993 ShowWindow(hwndMain, SW_RESTORE);
\r
9995 SetActiveWindow(hwndMain);
\r
9999 * Prototypes for animation support routines
\r
10001 static void ScreenSquare(int column, int row, POINT * pt);
\r
10002 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10003 POINT frames[], int * nFrames);
\r
10006 #define kFactor 4
\r
10009 AnimateMove(board, fromX, fromY, toX, toY)
\r
10016 ChessSquare piece;
\r
10017 POINT start, finish, mid;
\r
10018 POINT frames[kFactor * 2 + 1];
\r
10021 if (!appData.animate) return;
\r
10022 if (doingSizing) return;
\r
10023 if (fromY < 0 || fromX < 0) return;
\r
10024 piece = board[fromY][fromX];
\r
10025 if (piece >= EmptySquare) return;
\r
10027 ScreenSquare(fromX, fromY, &start);
\r
10028 ScreenSquare(toX, toY, &finish);
\r
10030 /* All pieces except knights move in straight line */
\r
10031 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10032 mid.x = start.x + (finish.x - start.x) / 2;
\r
10033 mid.y = start.y + (finish.y - start.y) / 2;
\r
10035 /* Knight: make diagonal movement then straight */
\r
10036 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10037 mid.x = start.x + (finish.x - start.x) / 2;
\r
10038 mid.y = finish.y;
\r
10040 mid.x = finish.x;
\r
10041 mid.y = start.y + (finish.y - start.y) / 2;
\r
10045 /* Don't use as many frames for very short moves */
\r
10046 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10047 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10049 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10051 animInfo.from.x = fromX;
\r
10052 animInfo.from.y = fromY;
\r
10053 animInfo.to.x = toX;
\r
10054 animInfo.to.y = toY;
\r
10055 animInfo.lastpos = start;
\r
10056 animInfo.piece = piece;
\r
10057 for (n = 0; n < nFrames; n++) {
\r
10058 animInfo.pos = frames[n];
\r
10059 DrawPosition(FALSE, NULL);
\r
10060 animInfo.lastpos = animInfo.pos;
\r
10061 Sleep(appData.animSpeed);
\r
10063 animInfo.pos = finish;
\r
10064 DrawPosition(FALSE, NULL);
\r
10065 animInfo.piece = EmptySquare;
\r
10068 /* Convert board position to corner of screen rect and color */
\r
10071 ScreenSquare(column, row, pt)
\r
10072 int column; int row; POINT * pt;
\r
10075 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10076 pt->y = lineGap + row * (squareSize + lineGap);
\r
10078 pt->x = lineGap + column * (squareSize + lineGap);
\r
10079 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10083 /* Generate a series of frame coords from start->mid->finish.
\r
10084 The movement rate doubles until the half way point is
\r
10085 reached, then halves back down to the final destination,
\r
10086 which gives a nice slow in/out effect. The algorithmn
\r
10087 may seem to generate too many intermediates for short
\r
10088 moves, but remember that the purpose is to attract the
\r
10089 viewers attention to the piece about to be moved and
\r
10090 then to where it ends up. Too few frames would be less
\r
10094 Tween(start, mid, finish, factor, frames, nFrames)
\r
10095 POINT * start; POINT * mid;
\r
10096 POINT * finish; int factor;
\r
10097 POINT frames[]; int * nFrames;
\r
10099 int n, fraction = 1, count = 0;
\r
10101 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10102 for (n = 0; n < factor; n++)
\r
10104 for (n = 0; n < factor; n++) {
\r
10105 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10106 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10108 fraction = fraction / 2;
\r
10112 frames[count] = *mid;
\r
10115 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10117 for (n = 0; n < factor; n++) {
\r
10118 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10119 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10121 fraction = fraction * 2;
\r
10123 *nFrames = count;
\r
10127 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10132 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10133 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10135 OutputDebugString( buf );
\r
10138 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10140 EvalGraphSet( first, last, current, pvInfoList );
\r
10143 void SetProgramStats( FrontEndProgramStats * stats )
\r
10148 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10149 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10151 OutputDebugString( buf );
\r
10154 EngineOutputUpdate( stats );
\r