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 PopUpNameDialog(char firstchar);
\r
392 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
396 int GameListOptions();
\r
398 HWND moveHistoryDialog = NULL;
\r
399 BOOLEAN moveHistoryDialogUp = FALSE;
\r
401 WindowPlacement wpMoveHistory;
\r
403 HWND evalGraphDialog = NULL;
\r
404 BOOLEAN evalGraphDialogUp = FALSE;
\r
406 WindowPlacement wpEvalGraph;
\r
408 HWND engineOutputDialog = NULL;
\r
409 BOOLEAN engineOutputDialogUp = FALSE;
\r
411 WindowPlacement wpEngineOutput;
\r
413 VOID MoveHistoryPopUp();
\r
414 VOID MoveHistoryPopDown();
\r
415 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
416 BOOL MoveHistoryIsUp();
\r
418 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
419 VOID EvalGraphPopUp();
\r
420 VOID EvalGraphPopDown();
\r
421 BOOL EvalGraphIsUp();
\r
423 VOID EngineOutputPopUp();
\r
424 VOID EngineOutputPopDown();
\r
425 BOOL EngineOutputIsUp();
\r
426 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
428 VOID GothicPopUp(char *title, VariantClass variant);
\r
430 * Setting "frozen" should disable all user input other than deleting
\r
431 * the window. We do this while engines are initializing themselves.
\r
433 static int frozen = 0;
\r
434 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
440 if (frozen) return;
\r
442 hmenu = GetMenu(hwndMain);
\r
443 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
444 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
446 DrawMenuBar(hwndMain);
\r
449 /* Undo a FreezeUI */
\r
455 if (!frozen) return;
\r
457 hmenu = GetMenu(hwndMain);
\r
458 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
459 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
461 DrawMenuBar(hwndMain);
\r
464 /*---------------------------------------------------------------------------*\
\r
468 \*---------------------------------------------------------------------------*/
\r
471 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
472 LPSTR lpCmdLine, int nCmdShow)
\r
475 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
479 LoadLibrary("RICHED32.DLL");
\r
480 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
482 if (!InitApplication(hInstance)) {
\r
485 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
489 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
490 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
491 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
493 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
495 while (GetMessage(&msg, /* message structure */
\r
496 NULL, /* handle of window receiving the message */
\r
497 0, /* lowest message to examine */
\r
498 0)) /* highest message to examine */
\r
500 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
501 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
502 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
503 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
504 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
505 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
506 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
507 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
508 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
509 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
510 TranslateMessage(&msg); /* Translates virtual key codes */
\r
511 DispatchMessage(&msg); /* Dispatches message to window */
\r
516 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
519 /*---------------------------------------------------------------------------*\
\r
521 * Initialization functions
\r
523 \*---------------------------------------------------------------------------*/
\r
526 InitApplication(HINSTANCE hInstance)
\r
530 /* Fill in window class structure with parameters that describe the */
\r
533 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
534 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
535 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
536 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
537 wc.hInstance = hInstance; /* Owner of this class */
\r
538 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
539 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
540 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
541 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
542 wc.lpszClassName = szAppName; /* Name to register as */
\r
544 /* Register the window class and return success/failure code. */
\r
545 if (!RegisterClass(&wc)) return FALSE;
\r
547 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
548 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
550 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
551 wc.hInstance = hInstance;
\r
552 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
553 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
554 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
555 wc.lpszMenuName = NULL;
\r
556 wc.lpszClassName = szConsoleName;
\r
558 if (!RegisterClass(&wc)) return FALSE;
\r
563 /* Set by InitInstance, used by EnsureOnScreen */
\r
564 int screenHeight, screenWidth;
\r
567 EnsureOnScreen(int *x, int *y)
\r
569 int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
570 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
571 if (*x > screenWidth - 32) *x = 0;
\r
572 if (*y > screenHeight - 32) *y = 0;
\r
573 if (*x < 10) *x = 10;
\r
574 if (*y < gap) *y = gap;
\r
578 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
580 HWND hwnd; /* Main window handle. */
\r
582 WINDOWPLACEMENT wp;
\r
585 hInst = hInstance; /* Store instance handle in our global variable */
\r
587 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
588 *filepart = NULLCHAR;
\r
590 GetCurrentDirectory(MSG_SIZ, installDir);
\r
592 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
593 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
594 if (appData.debugMode) {
\r
595 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
596 setbuf(debugFP, NULL);
\r
601 InitEngineUCI( installDir, &first );
\r
602 InitEngineUCI( installDir, &second );
\r
604 /* Create a main window for this application instance. */
\r
605 hwnd = CreateWindow(szAppName, szTitle,
\r
606 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
607 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
608 NULL, NULL, hInstance, NULL);
\r
611 /* If window could not be created, return "failure" */
\r
616 iconWhite = LoadIcon(hInstance, "icon_white");
\r
617 iconBlack = LoadIcon(hInstance, "icon_black");
\r
618 iconCurrent = iconWhite;
\r
619 InitDrawingColors();
\r
620 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
621 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
622 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
623 /* Compute window size for each board size, and use the largest
\r
624 size that fits on this screen as the default. */
\r
625 InitDrawingSizes((BoardSize)ibs, 0);
\r
626 if (boardSize == (BoardSize)-1 &&
\r
627 winHeight <= screenHeight
\r
628 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
629 && winWidth <= screenWidth) {
\r
630 boardSize = (BoardSize)ibs;
\r
633 InitDrawingSizes(boardSize, 0);
\r
635 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
637 /* [AS] Load textures if specified */
\r
638 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
640 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
641 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
642 liteBackTextureMode = appData.liteBackTextureMode;
\r
644 if (liteBackTexture == NULL && appData.debugMode) {
\r
645 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
649 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
650 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
651 darkBackTextureMode = appData.darkBackTextureMode;
\r
653 if (darkBackTexture == NULL && appData.debugMode) {
\r
654 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
658 mysrandom( (unsigned) time(NULL) );
\r
660 /* Make a console window if needed */
\r
661 if (appData.icsActive) {
\r
665 /* [AS] Restore layout */
\r
666 if( wpMoveHistory.visible ) {
\r
667 MoveHistoryPopUp();
\r
670 if( wpEvalGraph.visible ) {
\r
674 if( wpEngineOutput.visible ) {
\r
675 EngineOutputPopUp();
\r
680 /* Make the window visible; update its client area; and return "success" */
\r
681 EnsureOnScreen(&boardX, &boardY);
\r
682 wp.length = sizeof(WINDOWPLACEMENT);
\r
684 wp.showCmd = nCmdShow;
\r
685 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
686 wp.rcNormalPosition.left = boardX;
\r
687 wp.rcNormalPosition.right = boardX + winWidth;
\r
688 wp.rcNormalPosition.top = boardY;
\r
689 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
690 SetWindowPlacement(hwndMain, &wp);
\r
692 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
693 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
696 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
697 if( gameInfo.variant != VariantFischeRandom ) {
\r
698 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
703 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
704 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
706 ShowWindow(hwndConsole, nCmdShow);
\r
708 UpdateWindow(hwnd);
\r
716 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
717 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
718 ArgSettingsFilename
\r
726 String *pString; // ArgString
\r
727 int *pInt; // ArgInt
\r
728 float *pFloat; // ArgFloat
\r
729 Boolean *pBoolean; // ArgBoolean
\r
730 COLORREF *pColor; // ArgColor
\r
731 ColorClass cc; // ArgAttribs
\r
732 String *pFilename; // ArgFilename
\r
733 BoardSize *pBoardSize; // ArgBoardSize
\r
734 int whichFont; // ArgFont
\r
735 DCB *pDCB; // ArgCommSettings
\r
736 String *pFilename; // ArgSettingsFilename
\r
744 ArgDescriptor argDescriptors[] = {
\r
745 /* positional arguments */
\r
746 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
747 { "", ArgNone, NULL },
\r
748 /* keyword arguments */
\r
749 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
750 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
751 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
752 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
753 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
754 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
755 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
756 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
757 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
758 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
759 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
760 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
761 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
762 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
763 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
764 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
765 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
766 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
768 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
770 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
772 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
773 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
775 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
776 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
777 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
778 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
779 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
780 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
781 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
782 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
783 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
784 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
785 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
786 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
787 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
788 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
789 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
790 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
791 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
792 /*!!bitmapDirectory?*/
\r
793 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
794 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
795 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
796 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
797 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
798 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
799 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
800 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
801 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
802 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
803 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
804 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
805 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
806 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
807 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
808 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
809 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
810 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
811 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
812 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
813 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
814 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
815 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
816 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
817 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
818 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
819 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
820 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
821 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
822 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
823 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
824 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
825 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
826 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
827 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
828 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
829 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
830 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
831 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
832 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
833 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
834 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
835 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
836 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
837 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
838 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
839 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
840 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
841 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
842 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
843 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
844 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
845 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
846 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
847 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
848 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
849 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
850 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
851 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
852 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
853 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
854 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
855 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
856 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
857 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
858 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
859 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
860 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
861 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
862 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
863 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
864 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
865 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
866 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
867 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
868 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
869 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
870 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
871 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
872 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
873 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
874 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
875 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
876 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
877 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
878 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
879 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
880 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
881 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
882 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
883 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
884 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
885 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
886 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
887 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
888 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
889 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
890 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
891 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
892 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
893 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
894 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
895 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
896 TRUE }, /* must come after all fonts */
\r
897 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
898 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
899 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
900 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
901 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
902 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
903 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
904 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
905 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
906 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
907 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
908 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
909 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
910 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
911 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
912 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
913 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
914 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
915 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
916 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
917 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
918 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
919 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
920 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
921 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
922 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
923 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
924 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
925 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
926 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
927 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
929 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
930 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
932 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
933 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
934 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
935 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
936 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
937 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
938 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
939 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
940 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
941 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
942 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
943 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
944 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
945 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
946 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
947 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
948 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
949 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
950 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
951 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
952 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
953 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
954 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
955 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
956 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
957 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
958 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
959 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
960 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
961 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
962 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
963 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
964 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
965 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
966 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
967 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
968 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
969 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
970 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
971 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
972 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
973 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
974 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
975 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
976 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
977 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
978 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
979 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
980 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
981 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
982 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
983 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
984 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
985 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
986 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
987 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
988 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
989 { "highlightLastMove", ArgBoolean,
\r
990 (LPVOID) &appData.highlightLastMove, TRUE },
\r
991 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
992 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
993 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
994 { "highlightDragging", ArgBoolean,
\r
995 (LPVOID) &appData.highlightDragging, TRUE },
\r
996 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
997 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
998 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
999 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1000 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1001 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1002 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1003 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1004 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1005 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1006 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1007 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1008 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1009 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1010 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1011 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1012 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1013 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1014 { "soundShout", ArgFilename,
\r
1015 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1016 { "soundSShout", ArgFilename,
\r
1017 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1018 { "soundChannel1", ArgFilename,
\r
1019 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1020 { "soundChannel", ArgFilename,
\r
1021 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1022 { "soundKibitz", ArgFilename,
\r
1023 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1024 { "soundTell", ArgFilename,
\r
1025 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1026 { "soundChallenge", ArgFilename,
\r
1027 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1028 { "soundRequest", ArgFilename,
\r
1029 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1030 { "soundSeek", ArgFilename,
\r
1031 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1032 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1033 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1034 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1035 { "soundIcsLoss", ArgFilename,
\r
1036 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1037 { "soundIcsDraw", ArgFilename,
\r
1038 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1039 { "soundIcsUnfinished", ArgFilename,
\r
1040 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1041 { "soundIcsAlarm", ArgFilename,
\r
1042 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1043 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1044 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1045 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1046 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1047 { "reuseChessPrograms", ArgBoolean,
\r
1048 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1049 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1050 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1051 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1052 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1053 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1054 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1055 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1056 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1057 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1058 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1059 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1060 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1061 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1062 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1063 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1064 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1065 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1066 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1067 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1068 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1069 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1070 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1071 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1072 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1073 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1074 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1075 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1076 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1077 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1078 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1079 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1080 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1081 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1082 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1083 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1084 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1085 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1087 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1089 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1090 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1091 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1092 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1093 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1094 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1095 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1096 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1097 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1098 /* [AS] New features */
\r
1099 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1100 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1101 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1102 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1103 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1104 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1105 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1106 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1107 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1108 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1109 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1110 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1111 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1112 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1113 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1114 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1115 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1116 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1117 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1118 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1119 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1120 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1121 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1122 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1123 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1124 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1125 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1126 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1127 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1128 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1129 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1130 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1131 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1132 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1133 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1134 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1135 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1136 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1137 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1138 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1139 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1140 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1141 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1142 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1143 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1144 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1145 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1146 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1148 /* [AS] Layout stuff */
\r
1149 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1150 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1151 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1152 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1153 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1155 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1156 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1157 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1158 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1159 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1161 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1162 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1163 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1164 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1165 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1167 /* [HGM] board-size, adjudication and misc. options */
\r
1168 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1169 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1170 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1171 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1172 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1173 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1174 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1175 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1176 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1177 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1178 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1179 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1180 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1181 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1182 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1183 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1184 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1187 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1188 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1189 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1190 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1191 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1192 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1193 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1194 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1195 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1196 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1197 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1198 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1199 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1201 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1202 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1203 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1204 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1205 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1206 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1207 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1209 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1210 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1211 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1212 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1213 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1214 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1215 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1216 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1217 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1218 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1219 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1220 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1221 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1222 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1223 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1224 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1225 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1226 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1228 /* [HGM] options for broadcasting and time odds */
\r
1229 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1230 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1231 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1232 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1233 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1234 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1235 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1236 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1237 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1238 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1239 { NULL, ArgNone, NULL, FALSE }
\r
1243 /* Kludge for indirection files on command line */
\r
1244 char* lastIndirectionFilename;
\r
1245 ArgDescriptor argDescriptorIndirection =
\r
1246 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1250 ExitArgError(char *msg, char *badArg)
\r
1252 char buf[MSG_SIZ];
\r
1254 sprintf(buf, "%s %s", msg, badArg);
\r
1255 DisplayFatalError(buf, 0, 2);
\r
1259 /* Command line font name parser. NULL name means do nothing.
\r
1260 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1261 For backward compatibility, syntax without the colon is also
\r
1262 accepted, but font names with digits in them won't work in that case.
\r
1265 ParseFontName(char *name, MyFontParams *mfp)
\r
1268 if (name == NULL) return;
\r
1270 q = strchr(p, ':');
\r
1272 if (q - p >= sizeof(mfp->faceName))
\r
1273 ExitArgError("Font name too long:", name);
\r
1274 memcpy(mfp->faceName, p, q - p);
\r
1275 mfp->faceName[q - p] = NULLCHAR;
\r
1278 q = mfp->faceName;
\r
1279 while (*p && !isdigit(*p)) {
\r
1281 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1282 ExitArgError("Font name too long:", name);
\r
1284 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1287 if (!*p) ExitArgError("Font point size missing:", name);
\r
1288 mfp->pointSize = (float) atof(p);
\r
1289 mfp->bold = (strchr(p, 'b') != NULL);
\r
1290 mfp->italic = (strchr(p, 'i') != NULL);
\r
1291 mfp->underline = (strchr(p, 'u') != NULL);
\r
1292 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1295 /* Color name parser.
\r
1296 X version accepts X color names, but this one
\r
1297 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1299 ParseColorName(char *name)
\r
1301 int red, green, blue, count;
\r
1302 char buf[MSG_SIZ];
\r
1304 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1306 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1307 &red, &green, &blue);
\r
1310 sprintf(buf, "Can't parse color name %s", name);
\r
1311 DisplayError(buf, 0);
\r
1312 return RGB(0, 0, 0);
\r
1314 return PALETTERGB(red, green, blue);
\r
1318 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1320 char *e = argValue;
\r
1324 if (*e == 'b') eff |= CFE_BOLD;
\r
1325 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1326 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1327 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1328 else if (*e == '#' || isdigit(*e)) break;
\r
1332 *color = ParseColorName(e);
\r
1337 ParseBoardSize(char *name)
\r
1339 BoardSize bs = SizeTiny;
\r
1340 while (sizeInfo[bs].name != NULL) {
\r
1341 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1344 ExitArgError("Unrecognized board size value", name);
\r
1345 return bs; /* not reached */
\r
1350 StringGet(void *getClosure)
\r
1352 char **p = (char **) getClosure;
\r
1357 FileGet(void *getClosure)
\r
1360 FILE* f = (FILE*) getClosure;
\r
1369 /* Parse settings file named "name". If file found, return the
\r
1370 full name in fullname and return TRUE; else return FALSE */
\r
1372 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1377 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1378 f = fopen(fullname, "r");
\r
1380 ParseArgs(FileGet, f);
\r
1389 ParseArgs(GetFunc get, void *cl)
\r
1391 char argName[ARG_MAX];
\r
1392 char argValue[ARG_MAX];
\r
1393 ArgDescriptor *ad;
\r
1402 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1403 if (ch == NULLCHAR) break;
\r
1405 /* Comment to end of line */
\r
1407 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1409 } else if (ch == '/' || ch == '-') {
\r
1412 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1413 ch != '\n' && ch != '\t') {
\r
1419 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1420 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1422 if (ad->argName == NULL)
\r
1423 ExitArgError("Unrecognized argument", argName);
\r
1425 } else if (ch == '@') {
\r
1426 /* Indirection file */
\r
1427 ad = &argDescriptorIndirection;
\r
1430 /* Positional argument */
\r
1431 ad = &argDescriptors[posarg++];
\r
1432 strcpy(argName, ad->argName);
\r
1435 if (ad->argType == ArgTrue) {
\r
1436 *(Boolean *) ad->argLoc = TRUE;
\r
1439 if (ad->argType == ArgFalse) {
\r
1440 *(Boolean *) ad->argLoc = FALSE;
\r
1444 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1445 if (ch == NULLCHAR || ch == '\n') {
\r
1446 ExitArgError("No value provided for argument", argName);
\r
1450 // Quoting with { }. No characters have to (or can) be escaped.
\r
1451 // Thus the string cannot contain a '}' character.
\r
1471 } else if (ch == '\'' || ch == '"') {
\r
1472 // Quoting with ' ' or " ", with \ as escape character.
\r
1473 // Inconvenient for long strings that may contain Windows filenames.
\r
1490 if (ch == start) {
\r
1499 if (ad->argType == ArgFilename
\r
1500 || ad->argType == ArgSettingsFilename) {
\r
1506 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1530 for (i = 0; i < 3; i++) {
\r
1531 if (ch >= '0' && ch <= '7') {
\r
1532 octval = octval*8 + (ch - '0');
\r
1539 *q++ = (char) octval;
\r
1550 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1557 switch (ad->argType) {
\r
1559 *(int *) ad->argLoc = atoi(argValue);
\r
1563 *(float *) ad->argLoc = (float) atof(argValue);
\r
1568 *(char **) ad->argLoc = strdup(argValue);
\r
1571 case ArgSettingsFilename:
\r
1573 char fullname[MSG_SIZ];
\r
1574 if (ParseSettingsFile(argValue, fullname)) {
\r
1575 if (ad->argLoc != NULL) {
\r
1576 *(char **) ad->argLoc = strdup(fullname);
\r
1579 if (ad->argLoc != NULL) {
\r
1581 ExitArgError("Failed to open indirection file", argValue);
\r
1588 switch (argValue[0]) {
\r
1591 *(Boolean *) ad->argLoc = TRUE;
\r
1595 *(Boolean *) ad->argLoc = FALSE;
\r
1598 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1604 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1607 case ArgAttribs: {
\r
1608 ColorClass cc = (ColorClass)ad->argLoc;
\r
1609 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1613 case ArgBoardSize:
\r
1614 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1618 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1621 case ArgCommSettings:
\r
1622 ParseCommSettings(argValue, &dcb);
\r
1626 ExitArgError("Unrecognized argument", argValue);
\r
1633 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1635 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1636 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1639 lf->lfEscapement = 0;
\r
1640 lf->lfOrientation = 0;
\r
1641 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1642 lf->lfItalic = mfp->italic;
\r
1643 lf->lfUnderline = mfp->underline;
\r
1644 lf->lfStrikeOut = mfp->strikeout;
\r
1645 lf->lfCharSet = DEFAULT_CHARSET;
\r
1646 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1647 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1648 lf->lfQuality = DEFAULT_QUALITY;
\r
1649 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1650 strcpy(lf->lfFaceName, mfp->faceName);
\r
1654 CreateFontInMF(MyFont *mf)
\r
1656 LFfromMFP(&mf->lf, &mf->mfp);
\r
1657 if (mf->hf) DeleteObject(mf->hf);
\r
1658 mf->hf = CreateFontIndirect(&mf->lf);
\r
1662 SetDefaultTextAttribs()
\r
1665 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1666 ParseAttribs(&textAttribs[cc].color,
\r
1667 &textAttribs[cc].effects,
\r
1668 defaultTextAttribs[cc]);
\r
1673 SetDefaultSounds()
\r
1677 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1678 textAttribs[cc].sound.name = strdup("");
\r
1679 textAttribs[cc].sound.data = NULL;
\r
1681 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1682 sounds[sc].name = strdup("");
\r
1683 sounds[sc].data = NULL;
\r
1685 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1693 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1694 MyLoadSound(&textAttribs[cc].sound);
\r
1696 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1697 MyLoadSound(&sounds[sc]);
\r
1702 InitAppData(LPSTR lpCmdLine)
\r
1705 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1708 programName = szAppName;
\r
1710 /* Initialize to defaults */
\r
1711 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1712 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1713 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1714 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1715 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1716 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1717 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1718 SetDefaultTextAttribs();
\r
1719 SetDefaultSounds();
\r
1720 appData.movesPerSession = MOVES_PER_SESSION;
\r
1721 appData.initString = INIT_STRING;
\r
1722 appData.secondInitString = INIT_STRING;
\r
1723 appData.firstComputerString = COMPUTER_STRING;
\r
1724 appData.secondComputerString = COMPUTER_STRING;
\r
1725 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1726 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1727 appData.firstPlaysBlack = FALSE;
\r
1728 appData.noChessProgram = FALSE;
\r
1729 chessProgram = FALSE;
\r
1730 appData.firstHost = FIRST_HOST;
\r
1731 appData.secondHost = SECOND_HOST;
\r
1732 appData.firstDirectory = FIRST_DIRECTORY;
\r
1733 appData.secondDirectory = SECOND_DIRECTORY;
\r
1734 appData.bitmapDirectory = "";
\r
1735 appData.remoteShell = REMOTE_SHELL;
\r
1736 appData.remoteUser = "";
\r
1737 appData.timeDelay = TIME_DELAY;
\r
1738 appData.timeControl = TIME_CONTROL;
\r
1739 appData.timeIncrement = TIME_INCREMENT;
\r
1740 appData.icsActive = FALSE;
\r
1741 appData.icsHost = "";
\r
1742 appData.icsPort = ICS_PORT;
\r
1743 appData.icsCommPort = ICS_COMM_PORT;
\r
1744 appData.icsLogon = ICS_LOGON;
\r
1745 appData.icsHelper = "";
\r
1746 appData.useTelnet = FALSE;
\r
1747 appData.telnetProgram = TELNET_PROGRAM;
\r
1748 appData.gateway = "";
\r
1749 appData.loadGameFile = "";
\r
1750 appData.loadGameIndex = 0;
\r
1751 appData.saveGameFile = "";
\r
1752 appData.autoSaveGames = FALSE;
\r
1753 appData.loadPositionFile = "";
\r
1754 appData.loadPositionIndex = 1;
\r
1755 appData.savePositionFile = "";
\r
1756 appData.matchMode = FALSE;
\r
1757 appData.matchGames = 0;
\r
1758 appData.monoMode = FALSE;
\r
1759 appData.debugMode = FALSE;
\r
1760 appData.clockMode = TRUE;
\r
1761 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1762 appData.Iconic = FALSE; /*unused*/
\r
1763 appData.searchTime = "";
\r
1764 appData.searchDepth = 0;
\r
1765 appData.showCoords = FALSE;
\r
1766 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1767 appData.autoCallFlag = FALSE;
\r
1768 appData.flipView = FALSE;
\r
1769 appData.autoFlipView = TRUE;
\r
1770 appData.cmailGameName = "";
\r
1771 appData.alwaysPromoteToQueen = FALSE;
\r
1772 appData.oldSaveStyle = FALSE;
\r
1773 appData.quietPlay = FALSE;
\r
1774 appData.showThinking = FALSE;
\r
1775 appData.ponderNextMove = TRUE;
\r
1776 appData.periodicUpdates = TRUE;
\r
1777 appData.popupExitMessage = TRUE;
\r
1778 appData.popupMoveErrors = FALSE;
\r
1779 appData.autoObserve = FALSE;
\r
1780 appData.autoComment = FALSE;
\r
1781 appData.animate = TRUE;
\r
1782 appData.animSpeed = 10;
\r
1783 appData.animateDragging = TRUE;
\r
1784 appData.highlightLastMove = TRUE;
\r
1785 appData.getMoveList = TRUE;
\r
1786 appData.testLegality = TRUE;
\r
1787 appData.premove = TRUE;
\r
1788 appData.premoveWhite = FALSE;
\r
1789 appData.premoveWhiteText = "";
\r
1790 appData.premoveBlack = FALSE;
\r
1791 appData.premoveBlackText = "";
\r
1792 appData.icsAlarm = TRUE;
\r
1793 appData.icsAlarmTime = 5000;
\r
1794 appData.autoRaiseBoard = TRUE;
\r
1795 appData.localLineEditing = TRUE;
\r
1796 appData.colorize = TRUE;
\r
1797 appData.reuseFirst = TRUE;
\r
1798 appData.reuseSecond = TRUE;
\r
1799 appData.blindfold = FALSE;
\r
1800 dcb.DCBlength = sizeof(DCB);
\r
1801 dcb.BaudRate = 9600;
\r
1802 dcb.fBinary = TRUE;
\r
1803 dcb.fParity = FALSE;
\r
1804 dcb.fOutxCtsFlow = FALSE;
\r
1805 dcb.fOutxDsrFlow = FALSE;
\r
1806 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1807 dcb.fDsrSensitivity = FALSE;
\r
1808 dcb.fTXContinueOnXoff = TRUE;
\r
1809 dcb.fOutX = FALSE;
\r
1811 dcb.fNull = FALSE;
\r
1812 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1813 dcb.fAbortOnError = FALSE;
\r
1814 dcb.wReserved = 0;
\r
1816 dcb.Parity = SPACEPARITY;
\r
1817 dcb.StopBits = ONESTOPBIT;
\r
1818 settingsFileName = SETTINGS_FILE;
\r
1819 saveSettingsOnExit = TRUE;
\r
1820 boardX = CW_USEDEFAULT;
\r
1821 boardY = CW_USEDEFAULT;
\r
1822 consoleX = CW_USEDEFAULT;
\r
1823 consoleY = CW_USEDEFAULT;
\r
1824 consoleW = CW_USEDEFAULT;
\r
1825 consoleH = CW_USEDEFAULT;
\r
1826 analysisX = CW_USEDEFAULT;
\r
1827 analysisY = CW_USEDEFAULT;
\r
1828 analysisW = CW_USEDEFAULT;
\r
1829 analysisH = CW_USEDEFAULT;
\r
1830 commentX = CW_USEDEFAULT;
\r
1831 commentY = CW_USEDEFAULT;
\r
1832 commentW = CW_USEDEFAULT;
\r
1833 commentH = CW_USEDEFAULT;
\r
1834 editTagsX = CW_USEDEFAULT;
\r
1835 editTagsY = CW_USEDEFAULT;
\r
1836 editTagsW = CW_USEDEFAULT;
\r
1837 editTagsH = CW_USEDEFAULT;
\r
1838 gameListX = CW_USEDEFAULT;
\r
1839 gameListY = CW_USEDEFAULT;
\r
1840 gameListW = CW_USEDEFAULT;
\r
1841 gameListH = CW_USEDEFAULT;
\r
1842 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1843 icsNames = ICS_NAMES;
\r
1844 firstChessProgramNames = FCP_NAMES;
\r
1845 secondChessProgramNames = SCP_NAMES;
\r
1846 appData.initialMode = "";
\r
1847 appData.variant = "normal";
\r
1848 appData.firstProtocolVersion = PROTOVER;
\r
1849 appData.secondProtocolVersion = PROTOVER;
\r
1850 appData.showButtonBar = TRUE;
\r
1852 /* [AS] New properties (see comments in header file) */
\r
1853 appData.firstScoreIsAbsolute = FALSE;
\r
1854 appData.secondScoreIsAbsolute = FALSE;
\r
1855 appData.saveExtendedInfoInPGN = FALSE;
\r
1856 appData.hideThinkingFromHuman = FALSE;
\r
1857 appData.liteBackTextureFile = "";
\r
1858 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1859 appData.darkBackTextureFile = "";
\r
1860 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1861 appData.renderPiecesWithFont = "";
\r
1862 appData.fontToPieceTable = "";
\r
1863 appData.fontBackColorWhite = 0;
\r
1864 appData.fontForeColorWhite = 0;
\r
1865 appData.fontBackColorBlack = 0;
\r
1866 appData.fontForeColorBlack = 0;
\r
1867 appData.fontPieceSize = 80;
\r
1868 appData.overrideLineGap = 1;
\r
1869 appData.adjudicateLossThreshold = 0;
\r
1870 appData.delayBeforeQuit = 0;
\r
1871 appData.delayAfterQuit = 0;
\r
1872 appData.nameOfDebugFile = "winboard.debug";
\r
1873 appData.pgnEventHeader = "Computer Chess Game";
\r
1874 appData.defaultFrcPosition = -1;
\r
1875 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1876 appData.saveOutOfBookInfo = TRUE;
\r
1877 appData.showEvalInMoveHistory = TRUE;
\r
1878 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1879 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1880 appData.highlightMoveWithArrow = FALSE;
\r
1881 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1882 appData.useStickyWindows = TRUE;
\r
1883 appData.adjudicateDrawMoves = 0;
\r
1884 appData.autoDisplayComment = TRUE;
\r
1885 appData.autoDisplayTags = TRUE;
\r
1886 appData.firstIsUCI = FALSE;
\r
1887 appData.secondIsUCI = FALSE;
\r
1888 appData.firstHasOwnBookUCI = TRUE;
\r
1889 appData.secondHasOwnBookUCI = TRUE;
\r
1890 appData.polyglotDir = "";
\r
1891 appData.usePolyglotBook = FALSE;
\r
1892 appData.polyglotBook = "";
\r
1893 appData.defaultHashSize = 64;
\r
1894 appData.defaultCacheSizeEGTB = 4;
\r
1895 appData.defaultPathEGTB = "c:\\egtb";
\r
1897 InitWindowPlacement( &wpMoveHistory );
\r
1898 InitWindowPlacement( &wpEvalGraph );
\r
1899 InitWindowPlacement( &wpEngineOutput );
\r
1901 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1902 appData.NrFiles = -1;
\r
1903 appData.NrRanks = -1;
\r
1904 appData.holdingsSize = -1;
\r
1905 appData.testClaims = FALSE;
\r
1906 appData.checkMates = FALSE;
\r
1907 appData.materialDraws= FALSE;
\r
1908 appData.trivialDraws = FALSE;
\r
1909 appData.ruleMoves = 51;
\r
1910 appData.drawRepeats = 6;
\r
1911 appData.matchPause = 10000;
\r
1912 appData.alphaRank = FALSE;
\r
1913 appData.allWhite = FALSE;
\r
1914 appData.upsideDown = FALSE;
\r
1915 appData.serverPause = 15;
\r
1916 appData.serverMovesName = NULL;
\r
1917 appData.suppressLoadMoves = FALSE;
\r
1918 appData.firstTimeOdds = 1;
\r
1919 appData.secondTimeOdds = 1;
\r
1920 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
1921 appData.secondAccumulateTC = 1;
\r
1922 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
1923 appData.secondNPS = -1;
\r
1924 appData.engineComments = 1;
\r
1928 appData.zippyTalk = ZIPPY_TALK;
\r
1929 appData.zippyPlay = ZIPPY_PLAY;
\r
1930 appData.zippyLines = ZIPPY_LINES;
\r
1931 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1932 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1933 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1934 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1935 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1936 appData.zippyUseI = ZIPPY_USE_I;
\r
1937 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1938 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1939 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1940 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1941 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1942 appData.zippyAbort = ZIPPY_ABORT;
\r
1943 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1944 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1945 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1948 /* Point font array elements to structures and
\r
1949 parse default font names */
\r
1950 for (i=0; i<NUM_FONTS; i++) {
\r
1951 for (j=0; j<NUM_SIZES; j++) {
\r
1952 font[j][i] = &fontRec[j][i];
\r
1953 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1957 /* Parse default settings file if any */
\r
1958 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1959 settingsFileName = strdup(buf);
\r
1962 /* Parse command line */
\r
1963 ParseArgs(StringGet, &lpCmdLine);
\r
1965 /* [HGM] make sure board size is acceptable */
\r
1966 if(appData.NrFiles > BOARD_SIZE ||
\r
1967 appData.NrRanks > BOARD_SIZE )
\r
1968 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
1970 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
1971 * with options from the command line, we now make an even higher priority
\r
1972 * overrule by WB options attached to the engine command line. This so that
\r
1973 * tournament managers can use WB options (such as /timeOdds) that follow
\r
1976 if(appData.firstChessProgram != NULL) {
\r
1977 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
1978 static char *f = "first";
\r
1979 char buf[MSG_SIZ], *q = buf;
\r
1980 if(p != NULL) { // engine command line contains WinBoard options
\r
1981 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
1982 ParseArgs(StringGet, &q);
\r
1983 p[-1] = 0; // cut them offengine command line
\r
1986 // now do same for second chess program
\r
1987 if(appData.secondChessProgram != NULL) {
\r
1988 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
1989 static char *s = "second";
\r
1990 char buf[MSG_SIZ], *q = buf;
\r
1991 if(p != NULL) { // engine command line contains WinBoard options
\r
1992 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
1993 ParseArgs(StringGet, &q);
\r
1994 p[-1] = 0; // cut them offengine command line
\r
1999 /* Propagate options that affect others */
\r
2000 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2001 if (appData.icsActive || appData.noChessProgram) {
\r
2002 chessProgram = FALSE; /* not local chess program mode */
\r
2005 /* Open startup dialog if needed */
\r
2006 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2007 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2008 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2009 *appData.secondChessProgram == NULLCHAR))) {
\r
2012 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2013 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2014 FreeProcInstance(lpProc);
\r
2017 /* Make sure save files land in the right (?) directory */
\r
2018 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2019 appData.saveGameFile = strdup(buf);
\r
2021 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2022 appData.savePositionFile = strdup(buf);
\r
2025 /* Finish initialization for fonts and sounds */
\r
2026 for (i=0; i<NUM_FONTS; i++) {
\r
2027 for (j=0; j<NUM_SIZES; j++) {
\r
2028 CreateFontInMF(font[j][i]);
\r
2031 /* xboard, and older WinBoards, controlled the move sound with the
\r
2032 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2033 always turn the option on (so that the backend will call us),
\r
2034 then let the user turn the sound off by setting it to silence if
\r
2035 desired. To accommodate old winboard.ini files saved by old
\r
2036 versions of WinBoard, we also turn off the sound if the option
\r
2037 was initially set to false. */
\r
2038 if (!appData.ringBellAfterMoves) {
\r
2039 sounds[(int)SoundMove].name = strdup("");
\r
2040 appData.ringBellAfterMoves = TRUE;
\r
2042 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2043 SetCurrentDirectory(installDir);
\r
2045 SetCurrentDirectory(currDir);
\r
2047 p = icsTextMenuString;
\r
2048 if (p[0] == '@') {
\r
2049 FILE* f = fopen(p + 1, "r");
\r
2051 DisplayFatalError(p + 1, errno, 2);
\r
2054 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2056 buf[i] = NULLCHAR;
\r
2059 ParseIcsTextMenu(strdup(p));
\r
2066 HMENU hmenu = GetMenu(hwndMain);
\r
2068 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2069 MF_BYCOMMAND|((appData.icsActive &&
\r
2070 *appData.icsCommPort != NULLCHAR) ?
\r
2071 MF_ENABLED : MF_GRAYED));
\r
2072 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2073 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2074 MF_CHECKED : MF_UNCHECKED));
\r
2079 SaveSettings(char* name)
\r
2082 ArgDescriptor *ad;
\r
2083 WINDOWPLACEMENT wp;
\r
2084 char dir[MSG_SIZ];
\r
2086 if (!hwndMain) return;
\r
2088 GetCurrentDirectory(MSG_SIZ, dir);
\r
2089 SetCurrentDirectory(installDir);
\r
2090 f = fopen(name, "w");
\r
2091 SetCurrentDirectory(dir);
\r
2093 DisplayError(name, errno);
\r
2096 fprintf(f, ";\n");
\r
2097 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2098 fprintf(f, ";\n");
\r
2099 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2100 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2101 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2102 fprintf(f, ";\n");
\r
2104 wp.length = sizeof(WINDOWPLACEMENT);
\r
2105 GetWindowPlacement(hwndMain, &wp);
\r
2106 boardX = wp.rcNormalPosition.left;
\r
2107 boardY = wp.rcNormalPosition.top;
\r
2109 if (hwndConsole) {
\r
2110 GetWindowPlacement(hwndConsole, &wp);
\r
2111 consoleX = wp.rcNormalPosition.left;
\r
2112 consoleY = wp.rcNormalPosition.top;
\r
2113 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2114 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2117 if (analysisDialog) {
\r
2118 GetWindowPlacement(analysisDialog, &wp);
\r
2119 analysisX = wp.rcNormalPosition.left;
\r
2120 analysisY = wp.rcNormalPosition.top;
\r
2121 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2122 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2125 if (commentDialog) {
\r
2126 GetWindowPlacement(commentDialog, &wp);
\r
2127 commentX = wp.rcNormalPosition.left;
\r
2128 commentY = wp.rcNormalPosition.top;
\r
2129 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2130 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2133 if (editTagsDialog) {
\r
2134 GetWindowPlacement(editTagsDialog, &wp);
\r
2135 editTagsX = wp.rcNormalPosition.left;
\r
2136 editTagsY = wp.rcNormalPosition.top;
\r
2137 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2138 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2141 if (gameListDialog) {
\r
2142 GetWindowPlacement(gameListDialog, &wp);
\r
2143 gameListX = wp.rcNormalPosition.left;
\r
2144 gameListY = wp.rcNormalPosition.top;
\r
2145 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2146 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2149 /* [AS] Move history */
\r
2150 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2152 if( moveHistoryDialog ) {
\r
2153 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2154 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2155 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2156 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2157 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2160 /* [AS] Eval graph */
\r
2161 wpEvalGraph.visible = EvalGraphIsUp();
\r
2163 if( evalGraphDialog ) {
\r
2164 GetWindowPlacement(evalGraphDialog, &wp);
\r
2165 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2166 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2167 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2168 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2171 /* [AS] Engine output */
\r
2172 wpEngineOutput.visible = EngineOutputIsUp();
\r
2174 if( engineOutputDialog ) {
\r
2175 GetWindowPlacement(engineOutputDialog, &wp);
\r
2176 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2177 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2178 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2179 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2182 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2183 if (!ad->save) continue;
\r
2184 switch (ad->argType) {
\r
2187 char *p = *(char **)ad->argLoc;
\r
2188 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2189 /* Quote multiline values or \-containing values
\r
2190 with { } if possible */
\r
2191 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2193 /* Else quote with " " */
\r
2194 fprintf(f, "/%s=\"", ad->argName);
\r
2196 if (*p == '\n') fprintf(f, "\n");
\r
2197 else if (*p == '\r') fprintf(f, "\\r");
\r
2198 else if (*p == '\t') fprintf(f, "\\t");
\r
2199 else if (*p == '\b') fprintf(f, "\\b");
\r
2200 else if (*p == '\f') fprintf(f, "\\f");
\r
2201 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2202 else if (*p == '\"') fprintf(f, "\\\"");
\r
2203 else if (*p == '\\') fprintf(f, "\\\\");
\r
2207 fprintf(f, "\"\n");
\r
2212 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2215 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2218 fprintf(f, "/%s=%s\n", ad->argName,
\r
2219 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2222 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2225 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2229 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2230 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2231 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2236 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2237 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2238 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2239 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2240 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2241 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2242 (ta->effects) ? " " : "",
\r
2243 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2247 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2248 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2250 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2253 case ArgBoardSize:
\r
2254 fprintf(f, "/%s=%s\n", ad->argName,
\r
2255 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2260 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2261 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2262 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2263 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2264 ad->argName, mfp->faceName, mfp->pointSize,
\r
2265 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2266 mfp->bold ? "b" : "",
\r
2267 mfp->italic ? "i" : "",
\r
2268 mfp->underline ? "u" : "",
\r
2269 mfp->strikeout ? "s" : "");
\r
2273 case ArgCommSettings:
\r
2274 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2282 /*---------------------------------------------------------------------------*\
\r
2284 * GDI board drawing routines
\r
2286 \*---------------------------------------------------------------------------*/
\r
2288 /* [AS] Draw square using background texture */
\r
2289 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2294 return; /* Should never happen! */
\r
2297 SetGraphicsMode( dst, GM_ADVANCED );
\r
2304 /* X reflection */
\r
2309 x.eDx = (FLOAT) dw + dx - 1;
\r
2312 SetWorldTransform( dst, &x );
\r
2315 /* Y reflection */
\r
2321 x.eDy = (FLOAT) dh + dy - 1;
\r
2323 SetWorldTransform( dst, &x );
\r
2331 x.eDx = (FLOAT) dx;
\r
2332 x.eDy = (FLOAT) dy;
\r
2335 SetWorldTransform( dst, &x );
\r
2339 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2347 SetWorldTransform( dst, &x );
\r
2349 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2352 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2354 PM_WP = (int) WhitePawn,
\r
2355 PM_WN = (int) WhiteKnight,
\r
2356 PM_WB = (int) WhiteBishop,
\r
2357 PM_WR = (int) WhiteRook,
\r
2358 PM_WQ = (int) WhiteQueen,
\r
2359 PM_WF = (int) WhiteFerz,
\r
2360 PM_WW = (int) WhiteWazir,
\r
2361 PM_WE = (int) WhiteAlfil,
\r
2362 PM_WM = (int) WhiteMan,
\r
2363 PM_WO = (int) WhiteCannon,
\r
2364 PM_WU = (int) WhiteUnicorn,
\r
2365 PM_WH = (int) WhiteNightrider,
\r
2366 PM_WA = (int) WhiteAngel,
\r
2367 PM_WC = (int) WhiteMarshall,
\r
2368 PM_WG = (int) WhiteGrasshopper,
\r
2369 PM_WK = (int) WhiteKing,
\r
2370 PM_BP = (int) BlackPawn,
\r
2371 PM_BN = (int) BlackKnight,
\r
2372 PM_BB = (int) BlackBishop,
\r
2373 PM_BR = (int) BlackRook,
\r
2374 PM_BQ = (int) BlackQueen,
\r
2375 PM_BF = (int) BlackFerz,
\r
2376 PM_BW = (int) BlackWazir,
\r
2377 PM_BE = (int) BlackAlfil,
\r
2378 PM_BM = (int) BlackMan,
\r
2379 PM_BO = (int) BlackCannon,
\r
2380 PM_BU = (int) BlackUnicorn,
\r
2381 PM_BH = (int) BlackNightrider,
\r
2382 PM_BA = (int) BlackAngel,
\r
2383 PM_BC = (int) BlackMarshall,
\r
2384 PM_BG = (int) BlackGrasshopper,
\r
2385 PM_BK = (int) BlackKing
\r
2388 static HFONT hPieceFont = NULL;
\r
2389 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2390 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2391 static int fontBitmapSquareSize = 0;
\r
2392 static char pieceToFontChar[(int) EmptySquare] =
\r
2393 { 'p', 'n', 'b', 'r', 'q',
\r
2394 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2395 'k', 'o', 'm', 'v', 't', 'w',
\r
2396 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2399 extern BOOL SetCharTable( char *table, const char * map );
\r
2400 /* [HGM] moved to backend.c */
\r
2402 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2405 BYTE r1 = GetRValue( color );
\r
2406 BYTE g1 = GetGValue( color );
\r
2407 BYTE b1 = GetBValue( color );
\r
2413 /* Create a uniform background first */
\r
2414 hbrush = CreateSolidBrush( color );
\r
2415 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2416 FillRect( hdc, &rc, hbrush );
\r
2417 DeleteObject( hbrush );
\r
2420 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2421 int steps = squareSize / 2;
\r
2424 for( i=0; i<steps; i++ ) {
\r
2425 BYTE r = r1 - (r1-r2) * i / steps;
\r
2426 BYTE g = g1 - (g1-g2) * i / steps;
\r
2427 BYTE b = b1 - (b1-b2) * i / steps;
\r
2429 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2430 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2431 FillRect( hdc, &rc, hbrush );
\r
2432 DeleteObject(hbrush);
\r
2435 else if( mode == 2 ) {
\r
2436 /* Diagonal gradient, good more or less for every piece */
\r
2437 POINT triangle[3];
\r
2438 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2439 HBRUSH hbrush_old;
\r
2440 int steps = squareSize;
\r
2443 triangle[0].x = squareSize - steps;
\r
2444 triangle[0].y = squareSize;
\r
2445 triangle[1].x = squareSize;
\r
2446 triangle[1].y = squareSize;
\r
2447 triangle[2].x = squareSize;
\r
2448 triangle[2].y = squareSize - steps;
\r
2450 for( i=0; i<steps; i++ ) {
\r
2451 BYTE r = r1 - (r1-r2) * i / steps;
\r
2452 BYTE g = g1 - (g1-g2) * i / steps;
\r
2453 BYTE b = b1 - (b1-b2) * i / steps;
\r
2455 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2456 hbrush_old = SelectObject( hdc, hbrush );
\r
2457 Polygon( hdc, triangle, 3 );
\r
2458 SelectObject( hdc, hbrush_old );
\r
2459 DeleteObject(hbrush);
\r
2464 SelectObject( hdc, hpen );
\r
2469 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2470 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2471 piece: follow the steps as explained below.
\r
2473 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2477 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2481 int backColor = whitePieceColor;
\r
2482 int foreColor = blackPieceColor;
\r
2483 int shapeIndex = index < 6 ? index+6 : index;
\r
2485 if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2486 backColor = appData.fontBackColorWhite;
\r
2487 foreColor = appData.fontForeColorWhite;
\r
2489 else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2490 backColor = appData.fontBackColorBlack;
\r
2491 foreColor = appData.fontForeColorBlack;
\r
2495 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2497 hbm_old = SelectObject( hdc, hbm );
\r
2501 rc.right = squareSize;
\r
2502 rc.bottom = squareSize;
\r
2504 /* Step 1: background is now black */
\r
2505 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2507 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2509 pt.x = (squareSize - sz.cx) / 2;
\r
2510 pt.y = (squareSize - sz.cy) / 2;
\r
2512 SetBkMode( hdc, TRANSPARENT );
\r
2513 SetTextColor( hdc, chroma );
\r
2514 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2515 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2517 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2518 /* Step 3: the area outside the piece is filled with white */
\r
2519 FloodFill( hdc, 0, 0, chroma );
\r
2520 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2522 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2523 but if the start point is not inside the piece we're lost!
\r
2524 There should be a better way to do this... if we could create a region or path
\r
2525 from the fill operation we would be fine for example.
\r
2527 FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2529 SetTextColor( hdc, 0 );
\r
2531 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2532 draw the piece again in black for safety.
\r
2534 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2536 SelectObject( hdc, hbm_old );
\r
2538 if( hPieceMask[index] != NULL ) {
\r
2539 DeleteObject( hPieceMask[index] );
\r
2542 hPieceMask[index] = hbm;
\r
2545 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2547 SelectObject( hdc, hbm );
\r
2550 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2551 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2552 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2554 SelectObject( dc1, hPieceMask[index] );
\r
2555 SelectObject( dc2, bm2 );
\r
2556 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2557 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2560 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2561 the piece background and deletes (makes transparent) the rest.
\r
2562 Thanks to that mask, we are free to paint the background with the greates
\r
2563 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2564 We use this, to make gradients and give the pieces a "roundish" look.
\r
2566 SetPieceBackground( hdc, backColor, 2 );
\r
2567 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2571 DeleteObject( bm2 );
\r
2574 SetTextColor( hdc, foreColor );
\r
2575 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2577 SelectObject( hdc, hbm_old );
\r
2579 if( hPieceFace[index] != NULL ) {
\r
2580 DeleteObject( hPieceFace[index] );
\r
2583 hPieceFace[index] = hbm;
\r
2586 static int TranslatePieceToFontPiece( int piece )
\r
2615 case BlackMarshall:
\r
2619 case BlackNightrider:
\r
2625 case BlackUnicorn:
\r
2629 case BlackGrasshopper:
\r
2635 case WhiteMarshall:
\r
2639 case WhiteNightrider:
\r
2645 case WhiteUnicorn:
\r
2649 case WhiteGrasshopper:
\r
2658 void CreatePiecesFromFont()
\r
2661 HDC hdc_window = NULL;
\r
2667 if( fontBitmapSquareSize < 0 ) {
\r
2668 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2672 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2673 fontBitmapSquareSize = -1;
\r
2677 if( fontBitmapSquareSize != squareSize ) {
\r
2678 hdc_window = GetDC( hwndMain );
\r
2679 hdc = CreateCompatibleDC( hdc_window );
\r
2681 if( hPieceFont != NULL ) {
\r
2682 DeleteObject( hPieceFont );
\r
2685 for( i=0; i<12; i++ ) {
\r
2686 hPieceMask[i] = NULL;
\r
2687 hPieceFace[i] = NULL;
\r
2693 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2694 fontHeight = appData.fontPieceSize;
\r
2697 fontHeight = (fontHeight * squareSize) / 100;
\r
2699 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2701 lf.lfEscapement = 0;
\r
2702 lf.lfOrientation = 0;
\r
2703 lf.lfWeight = FW_NORMAL;
\r
2705 lf.lfUnderline = 0;
\r
2706 lf.lfStrikeOut = 0;
\r
2707 lf.lfCharSet = DEFAULT_CHARSET;
\r
2708 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2709 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2710 lf.lfQuality = PROOF_QUALITY;
\r
2711 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2712 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2713 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2715 hPieceFont = CreateFontIndirect( &lf );
\r
2717 if( hPieceFont == NULL ) {
\r
2718 fontBitmapSquareSize = -2;
\r
2721 /* Setup font-to-piece character table */
\r
2722 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2723 /* No (or wrong) global settings, try to detect the font */
\r
2724 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2726 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2728 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2729 /* DiagramTT* family */
\r
2730 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2732 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2733 /* Fairy symbols */
\r
2734 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2736 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2737 /* Good Companion (Some characters get warped as literal :-( */
\r
2738 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2739 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2740 SetCharTable(pieceToFontChar, s);
\r
2743 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2744 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2748 /* Create bitmaps */
\r
2749 hfont_old = SelectObject( hdc, hPieceFont );
\r
2751 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2752 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2753 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2754 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2755 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2756 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2757 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2758 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2759 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2760 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2761 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2762 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2764 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2765 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2766 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2767 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2768 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2769 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2770 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2771 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2772 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2773 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2774 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2775 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2776 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2777 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2778 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2779 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2780 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2781 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2782 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2783 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2786 SelectObject( hdc, hfont_old );
\r
2788 fontBitmapSquareSize = squareSize;
\r
2792 if( hdc != NULL ) {
\r
2796 if( hdc_window != NULL ) {
\r
2797 ReleaseDC( hwndMain, hdc_window );
\r
2802 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2806 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2807 if (gameInfo.event &&
\r
2808 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2809 strcmp(name, "k80s") == 0) {
\r
2810 strcpy(name, "tim");
\r
2812 return LoadBitmap(hinst, name);
\r
2816 /* Insert a color into the program's logical palette
\r
2817 structure. This code assumes the given color is
\r
2818 the result of the RGB or PALETTERGB macro, and it
\r
2819 knows how those macros work (which is documented).
\r
2822 InsertInPalette(COLORREF color)
\r
2824 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2826 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2827 DisplayFatalError("Too many colors", 0, 1);
\r
2828 pLogPal->palNumEntries--;
\r
2832 pe->peFlags = (char) 0;
\r
2833 pe->peRed = (char) (0xFF & color);
\r
2834 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2835 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2841 InitDrawingColors()
\r
2843 if (pLogPal == NULL) {
\r
2844 /* Allocate enough memory for a logical palette with
\r
2845 * PALETTESIZE entries and set the size and version fields
\r
2846 * of the logical palette structure.
\r
2848 pLogPal = (NPLOGPALETTE)
\r
2849 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2850 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2851 pLogPal->palVersion = 0x300;
\r
2853 pLogPal->palNumEntries = 0;
\r
2855 InsertInPalette(lightSquareColor);
\r
2856 InsertInPalette(darkSquareColor);
\r
2857 InsertInPalette(whitePieceColor);
\r
2858 InsertInPalette(blackPieceColor);
\r
2859 InsertInPalette(highlightSquareColor);
\r
2860 InsertInPalette(premoveHighlightColor);
\r
2862 /* create a logical color palette according the information
\r
2863 * in the LOGPALETTE structure.
\r
2865 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2867 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2868 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2869 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2870 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2871 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2872 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2874 /* [AS] Force rendering of the font-based pieces */
\r
2875 if( fontBitmapSquareSize > 0 ) {
\r
2876 fontBitmapSquareSize = 0;
\r
2882 BoardWidth(int boardSize, int n)
\r
2883 { /* [HGM] argument n added to allow different width and height */
\r
2884 int lineGap = sizeInfo[boardSize].lineGap;
\r
2886 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2887 lineGap = appData.overrideLineGap;
\r
2890 return (n + 1) * lineGap +
\r
2891 n * sizeInfo[boardSize].squareSize;
\r
2894 /* Respond to board resize by dragging edge */
\r
2896 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2898 BoardSize newSize = NUM_SIZES - 1;
\r
2899 static int recurse = 0;
\r
2900 if (IsIconic(hwndMain)) return;
\r
2901 if (recurse > 0) return;
\r
2903 while (newSize > 0 &&
\r
2904 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2905 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2908 boardSize = newSize;
\r
2909 InitDrawingSizes(boardSize, flags);
\r
2916 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2918 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2919 ChessSquare piece;
\r
2920 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2922 SIZE clockSize, messageSize;
\r
2924 char buf[MSG_SIZ];
\r
2926 HMENU hmenu = GetMenu(hwndMain);
\r
2927 RECT crect, wrect;
\r
2929 LOGBRUSH logbrush;
\r
2931 /* [HGM] call with -1 uses old size (for if nr of files, ranks changes) */
\r
2932 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2934 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2935 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2936 squareSize = sizeInfo[boardSize].squareSize;
\r
2937 lineGap = sizeInfo[boardSize].lineGap;
\r
2938 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2940 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2941 lineGap = appData.overrideLineGap;
\r
2944 if (tinyLayout != oldTinyLayout) {
\r
2945 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2947 style &= ~WS_SYSMENU;
\r
2948 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2949 "&Minimize\tCtrl+F4");
\r
2951 style |= WS_SYSMENU;
\r
2952 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2954 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2956 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2957 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2958 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2960 DrawMenuBar(hwndMain);
\r
2963 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
2964 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
2966 /* Get text area sizes */
\r
2967 hdc = GetDC(hwndMain);
\r
2968 if (appData.clockMode) {
\r
2969 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2971 sprintf(buf, "White");
\r
2973 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2974 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2975 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2976 str = "We only care about the height here";
\r
2977 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2978 SelectObject(hdc, oldFont);
\r
2979 ReleaseDC(hwndMain, hdc);
\r
2981 /* Compute where everything goes */
\r
2982 whiteRect.left = OUTER_MARGIN;
\r
2983 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2984 whiteRect.top = OUTER_MARGIN;
\r
2985 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2987 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2988 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2989 blackRect.top = whiteRect.top;
\r
2990 blackRect.bottom = whiteRect.bottom;
\r
2992 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2993 if (appData.showButtonBar) {
\r
2994 messageRect.right = blackRect.right
\r
2995 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2997 messageRect.right = blackRect.right;
\r
2999 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3000 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3002 boardRect.left = whiteRect.left;
\r
3003 boardRect.right = boardRect.left + boardWidth;
\r
3004 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3005 boardRect.bottom = boardRect.top + boardHeight;
\r
3007 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3008 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3009 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3010 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3011 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3012 GetWindowRect(hwndMain, &wrect);
\r
3013 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3014 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3015 /* compensate if menu bar wrapped */
\r
3016 GetClientRect(hwndMain, &crect);
\r
3017 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3018 winHeight += offby;
\r
3020 case WMSZ_TOPLEFT:
\r
3021 SetWindowPos(hwndMain, NULL,
\r
3022 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3023 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3026 case WMSZ_TOPRIGHT:
\r
3028 SetWindowPos(hwndMain, NULL,
\r
3029 wrect.left, wrect.bottom - winHeight,
\r
3030 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3033 case WMSZ_BOTTOMLEFT:
\r
3035 SetWindowPos(hwndMain, NULL,
\r
3036 wrect.right - winWidth, wrect.top,
\r
3037 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3040 case WMSZ_BOTTOMRIGHT:
\r
3044 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3045 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3050 for (i = 0; i < N_BUTTONS; i++) {
\r
3051 if (buttonDesc[i].hwnd != NULL) {
\r
3052 DestroyWindow(buttonDesc[i].hwnd);
\r
3053 buttonDesc[i].hwnd = NULL;
\r
3055 if (appData.showButtonBar) {
\r
3056 buttonDesc[i].hwnd =
\r
3057 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3058 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3059 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3060 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3061 (HMENU) buttonDesc[i].id,
\r
3062 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3064 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3065 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3066 MAKELPARAM(FALSE, 0));
\r
3068 if (buttonDesc[i].id == IDM_Pause)
\r
3069 hwndPause = buttonDesc[i].hwnd;
\r
3070 buttonDesc[i].wndproc = (WNDPROC)
\r
3071 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3074 if (gridPen != NULL) DeleteObject(gridPen);
\r
3075 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3076 if (premovePen != NULL) DeleteObject(premovePen);
\r
3077 if (lineGap != 0) {
\r
3078 logbrush.lbStyle = BS_SOLID;
\r
3079 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3081 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3082 lineGap, &logbrush, 0, NULL);
\r
3083 logbrush.lbColor = highlightSquareColor;
\r
3085 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3086 lineGap, &logbrush, 0, NULL);
\r
3088 logbrush.lbColor = premoveHighlightColor;
\r
3090 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3091 lineGap, &logbrush, 0, NULL);
\r
3093 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3094 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3095 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3096 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3097 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3098 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3099 BOARD_WIDTH * (squareSize + lineGap);
\r
3100 lineGap / 2 + (i * (squareSize + lineGap));
\r
3101 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3103 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3104 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3105 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3106 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3107 lineGap / 2 + (i * (squareSize + lineGap));
\r
3108 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3109 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3110 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3114 /* [HGM] Licensing requirement */
\r
3116 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3119 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3121 GothicPopUp( "", VariantNormal);
\r
3124 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3125 oldBoardSize = boardSize;
\r
3126 oldTinyLayout = tinyLayout;
\r
3128 /* Load piece bitmaps for this board size */
\r
3129 for (i=0; i<=2; i++) {
\r
3130 for (piece = WhitePawn;
\r
3131 (int) piece < (int) BlackPawn;
\r
3132 piece = (ChessSquare) ((int) piece + 1)) {
\r
3133 if (pieceBitmap[i][piece] != NULL)
\r
3134 DeleteObject(pieceBitmap[i][piece]);
\r
3138 // Orthodox Chess pieces
\r
3139 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3140 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3141 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3142 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3143 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3144 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3145 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3146 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3147 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3148 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3149 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3150 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3151 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3152 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3153 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3154 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3155 // in Shogi, Hijack the unused Queen for Lance
\r
3156 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3157 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3158 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3160 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3161 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3162 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3165 if(squareSize <= 72 && squareSize >= 33) {
\r
3166 /* A & C are available in most sizes now */
\r
3167 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3168 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3169 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3170 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3171 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3172 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3173 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3174 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3175 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3176 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3177 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3178 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3179 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3180 } else { // Smirf-like
\r
3181 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3182 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3183 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3185 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3186 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3187 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3188 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3189 } else { // WinBoard standard
\r
3190 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3191 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3192 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3197 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3198 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3199 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3200 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3201 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3202 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3203 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3204 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3205 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3206 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3207 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3208 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3209 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3210 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3211 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3212 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3213 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3214 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3215 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3216 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3217 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3218 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3219 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3220 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3221 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3222 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3223 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3224 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3225 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3226 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3227 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3229 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3230 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3231 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3232 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3233 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3234 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3235 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3236 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3237 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3238 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3239 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3240 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3241 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3243 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3244 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3245 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3246 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3247 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3248 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3249 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3250 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3251 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3252 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3253 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3254 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3257 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3258 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3259 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3260 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3261 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3262 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3263 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3264 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3265 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3266 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3267 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3268 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3269 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3270 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3271 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3275 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3276 /* special Shogi support in this size */
\r
3277 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3278 for (piece = WhitePawn;
\r
3279 (int) piece < (int) BlackPawn;
\r
3280 piece = (ChessSquare) ((int) piece + 1)) {
\r
3281 if (pieceBitmap[i][piece] != NULL)
\r
3282 DeleteObject(pieceBitmap[i][piece]);
\r
3285 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3286 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3287 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3288 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3289 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3290 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3291 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3292 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3293 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3294 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3295 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3296 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3297 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3298 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3299 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3300 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3301 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3302 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3303 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3304 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3305 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3306 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3307 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3308 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3309 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3310 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3311 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3312 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3313 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3314 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3315 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3316 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3317 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3318 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3319 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3320 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3321 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3322 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3323 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3324 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3325 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3326 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3332 PieceBitmap(ChessSquare p, int kind)
\r
3334 if ((int) p >= (int) BlackPawn)
\r
3335 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3337 return pieceBitmap[kind][(int) p];
\r
3340 /***************************************************************/
\r
3342 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3343 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3345 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3346 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3350 SquareToPos(int row, int column, int * x, int * y)
\r
3353 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3354 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3356 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3357 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3362 DrawCoordsOnDC(HDC hdc)
\r
3364 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
3365 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
3366 char str[2] = { NULLCHAR, NULLCHAR };
\r
3367 int oldMode, oldAlign, x, y, start, i;
\r
3371 if (!appData.showCoords)
\r
3374 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3376 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3377 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3378 oldAlign = GetTextAlign(hdc);
\r
3379 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3381 y = boardRect.top + lineGap;
\r
3382 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3384 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3385 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3386 str[0] = files[start + i];
\r
3387 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3388 y += squareSize + lineGap;
\r
3391 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3393 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3394 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3395 str[0] = ranks[start + i];
\r
3396 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3397 x += squareSize + lineGap;
\r
3400 SelectObject(hdc, oldBrush);
\r
3401 SetBkMode(hdc, oldMode);
\r
3402 SetTextAlign(hdc, oldAlign);
\r
3403 SelectObject(hdc, oldFont);
\r
3407 DrawGridOnDC(HDC hdc)
\r
3411 if (lineGap != 0) {
\r
3412 oldPen = SelectObject(hdc, gridPen);
\r
3413 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3414 SelectObject(hdc, oldPen);
\r
3418 #define HIGHLIGHT_PEN 0
\r
3419 #define PREMOVE_PEN 1
\r
3422 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3425 HPEN oldPen, hPen;
\r
3426 if (lineGap == 0) return;
\r
3428 x1 = boardRect.left +
\r
3429 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3430 y1 = boardRect.top +
\r
3431 lineGap/2 + y * (squareSize + lineGap);
\r
3433 x1 = boardRect.left +
\r
3434 lineGap/2 + x * (squareSize + lineGap);
\r
3435 y1 = boardRect.top +
\r
3436 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3438 hPen = pen ? premovePen : highlightPen;
\r
3439 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3440 MoveToEx(hdc, x1, y1, NULL);
\r
3441 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3442 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3443 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3444 LineTo(hdc, x1, y1);
\r
3445 SelectObject(hdc, oldPen);
\r
3449 DrawHighlightsOnDC(HDC hdc)
\r
3452 for (i=0; i<2; i++) {
\r
3453 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3454 DrawHighlightOnDC(hdc, TRUE,
\r
3455 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3458 for (i=0; i<2; i++) {
\r
3459 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3460 premoveHighlightInfo.sq[i].y >= 0) {
\r
3461 DrawHighlightOnDC(hdc, TRUE,
\r
3462 premoveHighlightInfo.sq[i].x,
\r
3463 premoveHighlightInfo.sq[i].y,
\r
3469 /* Note: sqcolor is used only in monoMode */
\r
3470 /* Note that this code is largely duplicated in woptions.c,
\r
3471 function DrawSampleSquare, so that needs to be updated too */
\r
3473 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3475 HBITMAP oldBitmap;
\r
3479 if (appData.blindfold) return;
\r
3481 /* [AS] Use font-based pieces if needed */
\r
3482 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3483 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3484 CreatePiecesFromFont();
\r
3486 if( fontBitmapSquareSize == squareSize ) {
\r
3487 int index = TranslatePieceToFontPiece( piece );
\r
3489 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3493 squareSize, squareSize,
\r
3498 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3502 squareSize, squareSize,
\r
3511 if (appData.monoMode) {
\r
3512 SelectObject(tmphdc, PieceBitmap(piece,
\r
3513 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3514 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3515 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3517 tmpSize = squareSize;
\r
3519 (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||
\r
3520 piece >= (int)BlackNightrider && piece <= BlackGrasshopper) ) {
\r
3521 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3522 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3523 x += (squareSize - minorSize)>>1;
\r
3524 y += squareSize - minorSize - 2;
\r
3525 tmpSize = minorSize;
\r
3527 if (color || appData.allWhite ) {
\r
3528 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3530 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3531 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3532 if(appData.upsideDown && color==flipView)
\r
3533 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3535 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3537 /* Use black piece color for outline of white pieces */
\r
3538 /* Not sure this looks really good (though xboard does it).
\r
3539 Maybe better to have another selectable color, default black */
\r
3540 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3541 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3542 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3544 /* Use black for outline of white pieces */
\r
3545 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3546 if(appData.upsideDown && color==flipView)
\r
3547 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3549 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3553 /* Use white piece color for details of black pieces */
\r
3554 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3555 WHITE_PIECE ones aren't always the right shape. */
\r
3556 /* Not sure this looks really good (though xboard does it).
\r
3557 Maybe better to have another selectable color, default medium gray? */
\r
3558 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3559 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3560 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3561 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3562 SelectObject(hdc, blackPieceBrush);
\r
3563 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3565 /* Use square color for details of black pieces */
\r
3566 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3567 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3568 if(appData.upsideDown && !flipView)
\r
3569 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3571 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3574 SelectObject(hdc, oldBrush);
\r
3575 SelectObject(tmphdc, oldBitmap);
\r
3579 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3580 int GetBackTextureMode( int algo )
\r
3582 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3586 case BACK_TEXTURE_MODE_PLAIN:
\r
3587 result = 1; /* Always use identity map */
\r
3589 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3590 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3598 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3599 to handle redraws cleanly (as random numbers would always be different).
\r
3601 VOID RebuildTextureSquareInfo()
\r
3611 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3613 if( liteBackTexture != NULL ) {
\r
3614 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3615 lite_w = bi.bmWidth;
\r
3616 lite_h = bi.bmHeight;
\r
3620 if( darkBackTexture != NULL ) {
\r
3621 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3622 dark_w = bi.bmWidth;
\r
3623 dark_h = bi.bmHeight;
\r
3627 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3628 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3629 if( (col + row) & 1 ) {
\r
3631 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3632 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_WIDTH;
\r
3633 backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_HEIGHT;
\r
3634 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3639 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3640 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_WIDTH;
\r
3641 backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_HEIGHT;
\r
3642 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3649 /* [AS] Arrow highlighting support */
\r
3651 static int A_WIDTH = 5; /* Width of arrow body */
\r
3653 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3654 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3656 static double Sqr( double x )
\r
3661 static int Round( double x )
\r
3663 return (int) (x + 0.5);
\r
3666 /* Draw an arrow between two points using current settings */
\r
3667 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3670 double dx, dy, j, k, x, y;
\r
3672 if( d_x == s_x ) {
\r
3673 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3675 arrow[0].x = s_x + A_WIDTH;
\r
3678 arrow[1].x = s_x + A_WIDTH;
\r
3679 arrow[1].y = d_y - h;
\r
3681 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3682 arrow[2].y = d_y - h;
\r
3687 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3688 arrow[4].y = d_y - h;
\r
3690 arrow[5].x = s_x - A_WIDTH;
\r
3691 arrow[5].y = d_y - h;
\r
3693 arrow[6].x = s_x - A_WIDTH;
\r
3696 else if( d_y == s_y ) {
\r
3697 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3700 arrow[0].y = s_y + A_WIDTH;
\r
3702 arrow[1].x = d_x - w;
\r
3703 arrow[1].y = s_y + A_WIDTH;
\r
3705 arrow[2].x = d_x - w;
\r
3706 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3711 arrow[4].x = d_x - w;
\r
3712 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3714 arrow[5].x = d_x - w;
\r
3715 arrow[5].y = s_y - A_WIDTH;
\r
3718 arrow[6].y = s_y - A_WIDTH;
\r
3721 /* [AS] Needed a lot of paper for this! :-) */
\r
3722 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3723 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3725 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3727 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3732 arrow[0].x = Round(x - j);
\r
3733 arrow[0].y = Round(y + j*dx);
\r
3735 arrow[1].x = Round(x + j);
\r
3736 arrow[1].y = Round(y - j*dx);
\r
3739 x = (double) d_x - k;
\r
3740 y = (double) d_y - k*dy;
\r
3743 x = (double) d_x + k;
\r
3744 y = (double) d_y + k*dy;
\r
3747 arrow[2].x = Round(x + j);
\r
3748 arrow[2].y = Round(y - j*dx);
\r
3750 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3751 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3756 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3757 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3759 arrow[6].x = Round(x - j);
\r
3760 arrow[6].y = Round(y + j*dx);
\r
3763 Polygon( hdc, arrow, 7 );
\r
3766 /* [AS] Draw an arrow between two squares */
\r
3767 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3769 int s_x, s_y, d_x, d_y;
\r
3776 if( s_col == d_col && s_row == d_row ) {
\r
3780 /* Get source and destination points */
\r
3781 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3782 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3785 d_y += squareSize / 4;
\r
3787 else if( d_y < s_y ) {
\r
3788 d_y += 3 * squareSize / 4;
\r
3791 d_y += squareSize / 2;
\r
3795 d_x += squareSize / 4;
\r
3797 else if( d_x < s_x ) {
\r
3798 d_x += 3 * squareSize / 4;
\r
3801 d_x += squareSize / 2;
\r
3804 s_x += squareSize / 2;
\r
3805 s_y += squareSize / 2;
\r
3807 /* Adjust width */
\r
3808 A_WIDTH = squareSize / 14;
\r
3811 stLB.lbStyle = BS_SOLID;
\r
3812 stLB.lbColor = appData.highlightArrowColor;
\r
3815 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3816 holdpen = SelectObject( hdc, hpen );
\r
3817 hbrush = CreateBrushIndirect( &stLB );
\r
3818 holdbrush = SelectObject( hdc, hbrush );
\r
3820 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3822 SelectObject( hdc, holdpen );
\r
3823 SelectObject( hdc, holdbrush );
\r
3824 DeleteObject( hpen );
\r
3825 DeleteObject( hbrush );
\r
3828 BOOL HasHighlightInfo()
\r
3830 BOOL result = FALSE;
\r
3832 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3833 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3841 BOOL IsDrawArrowEnabled()
\r
3843 BOOL result = FALSE;
\r
3845 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3852 VOID DrawArrowHighlight( HDC hdc )
\r
3854 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3855 DrawArrowBetweenSquares( hdc,
\r
3856 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3857 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3861 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3863 HRGN result = NULL;
\r
3865 if( HasHighlightInfo() ) {
\r
3866 int x1, y1, x2, y2;
\r
3867 int sx, sy, dx, dy;
\r
3869 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3870 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3872 sx = MIN( x1, x2 );
\r
3873 sy = MIN( y1, y2 );
\r
3874 dx = MAX( x1, x2 ) + squareSize;
\r
3875 dy = MAX( y1, y2 ) + squareSize;
\r
3877 result = CreateRectRgn( sx, sy, dx, dy );
\r
3884 Warning: this function modifies the behavior of several other functions.
\r
3886 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3887 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3888 repaint is scattered all over the place, which is not good for features such as
\r
3889 "arrow highlighting" that require a full repaint of the board.
\r
3891 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3892 user interaction, when speed is not so important) but especially to avoid errors
\r
3893 in the displayed graphics.
\r
3895 In such patched places, I always try refer to this function so there is a single
\r
3896 place to maintain knowledge.
\r
3898 To restore the original behavior, just return FALSE unconditionally.
\r
3900 BOOL IsFullRepaintPreferrable()
\r
3902 BOOL result = FALSE;
\r
3904 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3905 /* Arrow may appear on the board */
\r
3913 This function is called by DrawPosition to know whether a full repaint must
\r
3916 Only DrawPosition may directly call this function, which makes use of
\r
3917 some state information. Other function should call DrawPosition specifying
\r
3918 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3920 BOOL DrawPositionNeedsFullRepaint()
\r
3922 BOOL result = FALSE;
\r
3925 Probably a slightly better policy would be to trigger a full repaint
\r
3926 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3927 but animation is fast enough that it's difficult to notice.
\r
3929 if( animInfo.piece == EmptySquare ) {
\r
3930 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3939 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3941 int row, column, x, y, square_color, piece_color;
\r
3942 ChessSquare piece;
\r
3944 HDC texture_hdc = NULL;
\r
3946 /* [AS] Initialize background textures if needed */
\r
3947 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3948 if( backTextureSquareSize != squareSize ) {
\r
3949 backTextureSquareSize = squareSize;
\r
3950 RebuildTextureSquareInfo();
\r
3953 texture_hdc = CreateCompatibleDC( hdc );
\r
3956 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3957 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3959 SquareToPos(row, column, &x, &y);
\r
3961 piece = board[row][column];
\r
3963 square_color = ((column + row) % 2) == 1;
\r
3964 if(!strcmp(appData.variant, "xiangqi") ) {
\r
3965 square_color = !InPalace(row, column);
\r
3966 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3967 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3969 piece_color = (int) piece < (int) BlackPawn;
\r
3972 /* [HGM] holdings file: light square or black */
\r
3973 if(column == BOARD_LEFT-2) {
\r
3974 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3977 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3981 if(column == BOARD_RGHT + 1 ) {
\r
3982 if( row < gameInfo.holdingsSize )
\r
3985 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3989 if(column == BOARD_LEFT-1 ) /* left align */
\r
3990 DisplayHoldingsCount(hdc, x, y, 0, (int) board[row][column]);
\r
3991 else if( column == BOARD_RGHT) /* right align */
\r
3992 DisplayHoldingsCount(hdc, x, y, 1, (int) board[row][column]);
\r
3994 if (appData.monoMode) {
\r
3995 if (piece == EmptySquare) {
\r
3996 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3997 square_color ? WHITENESS : BLACKNESS);
\r
3999 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4002 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4003 /* [AS] Draw the square using a texture bitmap */
\r
4004 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4007 squareSize, squareSize,
\r
4010 backTextureSquareInfo[row][column].mode,
\r
4011 backTextureSquareInfo[row][column].x,
\r
4012 backTextureSquareInfo[row][column].y );
\r
4014 SelectObject( texture_hdc, hbm );
\r
4016 if (piece != EmptySquare) {
\r
4017 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4021 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4023 oldBrush = SelectObject(hdc, brush );
\r
4024 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4025 SelectObject(hdc, oldBrush);
\r
4026 if (piece != EmptySquare)
\r
4027 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4032 if( texture_hdc != NULL ) {
\r
4033 DeleteDC( texture_hdc );
\r
4037 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4038 void fputDW(FILE *f, int x)
\r
4040 fputc(x & 255, f);
\r
4041 fputc(x>>8 & 255, f);
\r
4042 fputc(x>>16 & 255, f);
\r
4043 fputc(x>>24 & 255, f);
\r
4046 #define MAX_CLIPS 200 /* more than enough */
\r
4049 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4051 static Board lastReq, lastDrawn;
\r
4052 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4053 static int lastDrawnFlipView = 0;
\r
4054 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4055 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4058 HBITMAP bufferBitmap;
\r
4059 HBITMAP oldBitmap;
\r
4061 HRGN clips[MAX_CLIPS];
\r
4062 ChessSquare dragged_piece = EmptySquare;
\r
4064 /* I'm undecided on this - this function figures out whether a full
\r
4065 * repaint is necessary on its own, so there's no real reason to have the
\r
4066 * caller tell it that. I think this can safely be set to FALSE - but
\r
4067 * if we trust the callers not to request full repaints unnessesarily, then
\r
4068 * we could skip some clipping work. In other words, only request a full
\r
4069 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4070 * gamestart and similar) --Hawk
\r
4072 Boolean fullrepaint = repaint;
\r
4074 if( DrawPositionNeedsFullRepaint() ) {
\r
4075 fullrepaint = TRUE;
\r
4079 if( fullrepaint ) {
\r
4080 static int repaint_count = 0;
\r
4084 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4085 OutputDebugString( buf );
\r
4089 if (board == NULL) {
\r
4090 if (!lastReqValid) {
\r
4095 CopyBoard(lastReq, board);
\r
4099 if (doingSizing) {
\r
4103 if (IsIconic(hwndMain)) {
\r
4107 if (hdc == NULL) {
\r
4108 hdc = GetDC(hwndMain);
\r
4109 if (!appData.monoMode) {
\r
4110 SelectPalette(hdc, hPal, FALSE);
\r
4111 RealizePalette(hdc);
\r
4115 releaseDC = FALSE;
\r
4119 fprintf(debugFP, "*******************************\n"
\r
4121 "dragInfo.from (%d,%d)\n"
\r
4122 "dragInfo.start (%d,%d)\n"
\r
4123 "dragInfo.pos (%d,%d)\n"
\r
4124 "dragInfo.lastpos (%d,%d)\n",
\r
4125 repaint ? "TRUE" : "FALSE",
\r
4126 dragInfo.from.x, dragInfo.from.y,
\r
4127 dragInfo.start.x, dragInfo.start.y,
\r
4128 dragInfo.pos.x, dragInfo.pos.y,
\r
4129 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4130 fprintf(debugFP, "prev: ");
\r
4131 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4132 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4133 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4136 fprintf(debugFP, "\n");
\r
4137 fprintf(debugFP, "board: ");
\r
4138 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4139 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4140 fprintf(debugFP, "%d ", board[row][column]);
\r
4143 fprintf(debugFP, "\n");
\r
4147 /* Create some work-DCs */
\r
4148 hdcmem = CreateCompatibleDC(hdc);
\r
4149 tmphdc = CreateCompatibleDC(hdc);
\r
4151 /* If dragging is in progress, we temporarely remove the piece */
\r
4152 /* [HGM] or temporarily decrease count if stacked */
\r
4153 /* !! Moved to before board compare !! */
\r
4154 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4155 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4156 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4157 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4158 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4160 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4161 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4162 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4164 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4167 /* Figure out which squares need updating by comparing the
\r
4168 * newest board with the last drawn board and checking if
\r
4169 * flipping has changed.
\r
4171 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4172 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4173 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4174 if (lastDrawn[row][column] != board[row][column]) {
\r
4175 SquareToPos(row, column, &x, &y);
\r
4176 clips[num_clips++] =
\r
4177 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4181 for (i=0; i<2; i++) {
\r
4182 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4183 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4184 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4185 lastDrawnHighlight.sq[i].y >= 0) {
\r
4186 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4187 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4188 clips[num_clips++] =
\r
4189 CreateRectRgn(x - lineGap, y - lineGap,
\r
4190 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4192 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4193 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4194 clips[num_clips++] =
\r
4195 CreateRectRgn(x - lineGap, y - lineGap,
\r
4196 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4200 for (i=0; i<2; i++) {
\r
4201 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4202 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4203 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4204 lastDrawnPremove.sq[i].y >= 0) {
\r
4205 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4206 lastDrawnPremove.sq[i].x, &x, &y);
\r
4207 clips[num_clips++] =
\r
4208 CreateRectRgn(x - lineGap, y - lineGap,
\r
4209 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4211 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4212 premoveHighlightInfo.sq[i].y >= 0) {
\r
4213 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4214 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4215 clips[num_clips++] =
\r
4216 CreateRectRgn(x - lineGap, y - lineGap,
\r
4217 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4222 fullrepaint = TRUE;
\r
4225 /* Create a buffer bitmap - this is the actual bitmap
\r
4226 * being written to. When all the work is done, we can
\r
4227 * copy it to the real DC (the screen). This avoids
\r
4228 * the problems with flickering.
\r
4230 GetClientRect(hwndMain, &Rect);
\r
4231 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4232 Rect.bottom-Rect.top+1);
\r
4233 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4234 if (!appData.monoMode) {
\r
4235 SelectPalette(hdcmem, hPal, FALSE);
\r
4238 /* Create clips for dragging */
\r
4239 if (!fullrepaint) {
\r
4240 if (dragInfo.from.x >= 0) {
\r
4241 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4242 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4244 if (dragInfo.start.x >= 0) {
\r
4245 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4246 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4248 if (dragInfo.pos.x >= 0) {
\r
4249 x = dragInfo.pos.x - squareSize / 2;
\r
4250 y = dragInfo.pos.y - squareSize / 2;
\r
4251 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4253 if (dragInfo.lastpos.x >= 0) {
\r
4254 x = dragInfo.lastpos.x - squareSize / 2;
\r
4255 y = dragInfo.lastpos.y - squareSize / 2;
\r
4256 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4260 /* Are we animating a move?
\r
4262 * - remove the piece from the board (temporarely)
\r
4263 * - calculate the clipping region
\r
4265 if (!fullrepaint) {
\r
4266 if (animInfo.piece != EmptySquare) {
\r
4267 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4268 x = boardRect.left + animInfo.lastpos.x;
\r
4269 y = boardRect.top + animInfo.lastpos.y;
\r
4270 x2 = boardRect.left + animInfo.pos.x;
\r
4271 y2 = boardRect.top + animInfo.pos.y;
\r
4272 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4273 /* Slight kludge. The real problem is that after AnimateMove is
\r
4274 done, the position on the screen does not match lastDrawn.
\r
4275 This currently causes trouble only on e.p. captures in
\r
4276 atomic, where the piece moves to an empty square and then
\r
4277 explodes. The old and new positions both had an empty square
\r
4278 at the destination, but animation has drawn a piece there and
\r
4279 we have to remember to erase it. */
\r
4280 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4284 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4285 if (num_clips == 0)
\r
4286 fullrepaint = TRUE;
\r
4288 /* Set clipping on the memory DC */
\r
4289 if (!fullrepaint) {
\r
4290 SelectClipRgn(hdcmem, clips[0]);
\r
4291 for (x = 1; x < num_clips; x++) {
\r
4292 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4293 abort(); // this should never ever happen!
\r
4297 /* Do all the drawing to the memory DC */
\r
4298 DrawGridOnDC(hdcmem);
\r
4299 DrawHighlightsOnDC(hdcmem);
\r
4300 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4302 if( appData.highlightMoveWithArrow ) {
\r
4303 DrawArrowHighlight(hdcmem);
\r
4306 DrawCoordsOnDC(hdcmem);
\r
4308 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4309 /* to make sure lastDrawn contains what is actually drawn */
\r
4311 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4312 if (dragged_piece != EmptySquare) {
\r
4313 /* [HGM] or restack */
\r
4314 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4315 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4317 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4318 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4319 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4320 x = dragInfo.pos.x - squareSize / 2;
\r
4321 y = dragInfo.pos.y - squareSize / 2;
\r
4322 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4323 ((int) dragged_piece < (int) BlackPawn),
\r
4324 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4327 /* Put the animated piece back into place and draw it */
\r
4328 if (animInfo.piece != EmptySquare) {
\r
4329 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4330 x = boardRect.left + animInfo.pos.x;
\r
4331 y = boardRect.top + animInfo.pos.y;
\r
4332 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4333 ((int) animInfo.piece < (int) BlackPawn),
\r
4334 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4337 /* Release the bufferBitmap by selecting in the old bitmap
\r
4338 * and delete the memory DC
\r
4340 SelectObject(hdcmem, oldBitmap);
\r
4343 /* Set clipping on the target DC */
\r
4344 if (!fullrepaint) {
\r
4345 SelectClipRgn(hdc, clips[0]);
\r
4346 for (x = 1; x < num_clips; x++) {
\r
4347 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4348 abort(); // this should never ever happen!
\r
4352 /* Copy the new bitmap onto the screen in one go.
\r
4353 * This way we avoid any flickering
\r
4355 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4356 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4357 boardRect.right - boardRect.left,
\r
4358 boardRect.bottom - boardRect.top,
\r
4359 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4361 if(saveDiagFlag) {
\r
4362 BITMAP b; int i, j, m, w, wb, fac=0; char pData[1000000];
\r
4363 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4365 GetObject(bufferBitmap, sizeof(b), &b);
\r
4366 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4367 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4368 bih.biWidth = b.bmWidth;
\r
4369 bih.biHeight = b.bmHeight;
\r
4371 bih.biBitCount = b.bmBitsPixel;
\r
4372 bih.biCompression = 0;
\r
4373 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4374 bih.biXPelsPerMeter = 0;
\r
4375 bih.biYPelsPerMeter = 0;
\r
4376 bih.biClrUsed = 0;
\r
4377 bih.biClrImportant = 0;
\r
4378 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4379 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4380 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4381 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4384 wb = b.bmWidthBytes;
\r
4386 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4387 int k = ((int*) pData)[i];
\r
4388 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4389 if(j >= 16) break;
\r
4391 if(j >= nrColors) nrColors = j+1;
\r
4393 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4395 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4396 for(w=0; w<(wb>>2); w+=2) {
\r
4397 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4398 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4399 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4400 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4401 pData[p++] = m | j<<4;
\r
4403 while(p&3) pData[p++] = 0;
\r
4406 wb = (wb+31>>5)<<2;
\r
4408 // write BITMAPFILEHEADER
\r
4409 fprintf(diagFile, "BM");
\r
4410 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4411 fputDW(diagFile, 0);
\r
4412 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4413 // write BITMAPINFOHEADER
\r
4414 fputDW(diagFile, 40);
\r
4415 fputDW(diagFile, b.bmWidth);
\r
4416 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4417 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4418 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4419 fputDW(diagFile, 0);
\r
4420 fputDW(diagFile, 0);
\r
4421 fputDW(diagFile, 0);
\r
4422 fputDW(diagFile, 0);
\r
4423 fputDW(diagFile, 0);
\r
4424 fputDW(diagFile, 0);
\r
4425 // write color table
\r
4427 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4428 // write bitmap data
\r
4429 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4430 fputc(pData[i], diagFile);
\r
4435 SelectObject(tmphdc, oldBitmap);
\r
4437 /* Massive cleanup */
\r
4438 for (x = 0; x < num_clips; x++)
\r
4439 DeleteObject(clips[x]);
\r
4442 DeleteObject(bufferBitmap);
\r
4445 ReleaseDC(hwndMain, hdc);
\r
4447 if (lastDrawnFlipView != flipView) {
\r
4449 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4451 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4454 /* CopyBoard(lastDrawn, board);*/
\r
4455 lastDrawnHighlight = highlightInfo;
\r
4456 lastDrawnPremove = premoveHighlightInfo;
\r
4457 lastDrawnFlipView = flipView;
\r
4458 lastDrawnValid = 1;
\r
4461 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4469 saveDiagFlag = 1; diagFile = f;
\r
4470 HDCDrawPosition(NULL, TRUE, NULL);
\r
4474 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4481 /*---------------------------------------------------------------------------*\
\r
4482 | CLIENT PAINT PROCEDURE
\r
4483 | This is the main event-handler for the WM_PAINT message.
\r
4485 \*---------------------------------------------------------------------------*/
\r
4487 PaintProc(HWND hwnd)
\r
4493 if(hdc = BeginPaint(hwnd, &ps)) {
\r
4494 if (IsIconic(hwnd)) {
\r
4495 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4497 if (!appData.monoMode) {
\r
4498 SelectPalette(hdc, hPal, FALSE);
\r
4499 RealizePalette(hdc);
\r
4501 HDCDrawPosition(hdc, 1, NULL);
\r
4503 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4504 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4505 ETO_CLIPPED|ETO_OPAQUE,
\r
4506 &messageRect, messageText, strlen(messageText), NULL);
\r
4507 SelectObject(hdc, oldFont);
\r
4508 DisplayBothClocks();
\r
4510 EndPaint(hwnd,&ps);
\r
4518 * If the user selects on a border boundary, return -1; if off the board,
\r
4519 * return -2. Otherwise map the event coordinate to the square.
\r
4520 * The offset boardRect.left or boardRect.top must already have been
\r
4521 * subtracted from x.
\r
4524 EventToSquare(int x)
\r
4531 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4533 x /= (squareSize + lineGap);
\r
4534 if (x >= BOARD_SIZE)
\r
4545 DropEnable dropEnables[] = {
\r
4546 { 'P', DP_Pawn, "Pawn" },
\r
4547 { 'N', DP_Knight, "Knight" },
\r
4548 { 'B', DP_Bishop, "Bishop" },
\r
4549 { 'R', DP_Rook, "Rook" },
\r
4550 { 'Q', DP_Queen, "Queen" },
\r
4554 SetupDropMenu(HMENU hmenu)
\r
4556 int i, count, enable;
\r
4558 extern char white_holding[], black_holding[];
\r
4559 char item[MSG_SIZ];
\r
4561 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4562 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4563 dropEnables[i].piece);
\r
4565 while (p && *p++ == dropEnables[i].piece) count++;
\r
4566 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4567 enable = count > 0 || !appData.testLegality
\r
4568 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4569 && !appData.icsActive);
\r
4570 ModifyMenu(hmenu, dropEnables[i].command,
\r
4571 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4572 dropEnables[i].command, item);
\r
4576 static int fromX = -1, fromY = -1, toX, toY;
\r
4578 /* Event handler for mouse messages */
\r
4580 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4584 static int recursive = 0;
\r
4586 BOOLEAN needsRedraw = FALSE;
\r
4587 BOOLEAN saveAnimate;
\r
4588 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4589 static BOOLEAN sameAgain = FALSE;
\r
4590 ChessMove moveType;
\r
4593 if (message == WM_MBUTTONUP) {
\r
4594 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4595 to the middle button: we simulate pressing the left button too!
\r
4597 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4598 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4604 pt.x = LOWORD(lParam);
\r
4605 pt.y = HIWORD(lParam);
\r
4606 x = EventToSquare(pt.x - boardRect.left);
\r
4607 y = EventToSquare(pt.y - boardRect.top);
\r
4608 if (!flipView && y >= 0) {
\r
4609 y = BOARD_HEIGHT - 1 - y;
\r
4611 if (flipView && x >= 0) {
\r
4612 x = BOARD_WIDTH - 1 - x;
\r
4615 switch (message) {
\r
4616 case WM_LBUTTONDOWN:
\r
4618 sameAgain = FALSE;
\r
4620 /* Downclick vertically off board; check if on clock */
\r
4621 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4622 if (gameMode == EditPosition) {
\r
4623 SetWhiteToPlayEvent();
\r
4624 } else if (gameMode == IcsPlayingBlack ||
\r
4625 gameMode == MachinePlaysWhite) {
\r
4627 } else if (gameMode == EditGame) {
\r
4628 AdjustClock(flipClock, -1);
\r
4630 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4631 if (gameMode == EditPosition) {
\r
4632 SetBlackToPlayEvent();
\r
4633 } else if (gameMode == IcsPlayingWhite ||
\r
4634 gameMode == MachinePlaysBlack) {
\r
4636 } else if (gameMode == EditGame) {
\r
4637 AdjustClock(!flipClock, -1);
\r
4640 if (!appData.highlightLastMove) {
\r
4641 ClearHighlights();
\r
4642 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4644 fromX = fromY = -1;
\r
4645 dragInfo.start.x = dragInfo.start.y = -1;
\r
4646 dragInfo.from = dragInfo.start;
\r
4648 } else if (x < 0 || y < 0
\r
4649 /* [HGM] block clicks between board and holdings */
\r
4650 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4651 || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
\r
4652 || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize
\r
4653 /* EditPosition, empty square, or different color piece;
\r
4654 click-click move is possible */
\r
4657 } else if (fromX == x && fromY == y) {
\r
4658 /* Downclick on same square again */
\r
4659 ClearHighlights();
\r
4660 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4661 sameAgain = TRUE;
\r
4662 } else if (fromX != -1 &&
\r
4663 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4665 /* Downclick on different square. */
\r
4666 /* [HGM] if on holdings file, should count as new first click ! */
\r
4667 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4670 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4671 to make sure move is legal before showing promotion popup */
\r
4672 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4673 if(moveType != ImpossibleMove) {
\r
4674 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4675 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4676 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4677 appData.alwaysPromoteToQueen) {
\r
4678 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4679 if (!appData.highlightLastMove) {
\r
4680 ClearHighlights();
\r
4681 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4684 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4685 SetHighlights(fromX, fromY, toX, toY);
\r
4686 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4687 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4688 If promotion to Q is legal, all are legal! */
\r
4689 PromotionPopup(hwnd);
\r
4690 } else { /* not a promotion */
\r
4691 if (appData.animate || appData.highlightLastMove) {
\r
4692 SetHighlights(fromX, fromY, toX, toY);
\r
4694 ClearHighlights();
\r
4696 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4697 if (appData.animate && !appData.highlightLastMove) {
\r
4698 ClearHighlights();
\r
4699 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4705 /* [HGM] it seemed that braces were missing here */
\r
4706 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4707 fromX = fromY = -1;
\r
4711 ClearHighlights();
\r
4712 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4714 /* First downclick, or restart on a square with same color piece */
\r
4715 if (!frozen && OKToStartUserMove(x, y)) {
\r
4718 dragInfo.lastpos = pt;
\r
4719 dragInfo.from.x = fromX;
\r
4720 dragInfo.from.y = fromY;
\r
4721 dragInfo.start = dragInfo.from;
\r
4722 SetCapture(hwndMain);
\r
4724 fromX = fromY = -1;
\r
4725 dragInfo.start.x = dragInfo.start.y = -1;
\r
4726 dragInfo.from = dragInfo.start;
\r
4727 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4731 case WM_LBUTTONUP:
\r
4733 if (fromX == -1) break;
\r
4734 if (x == fromX && y == fromY) {
\r
4735 dragInfo.from.x = dragInfo.from.y = -1;
\r
4736 /* Upclick on same square */
\r
4738 /* Clicked same square twice: abort click-click move */
\r
4739 fromX = fromY = -1;
\r
4741 ClearPremoveHighlights();
\r
4743 /* First square clicked: start click-click move */
\r
4744 SetHighlights(fromX, fromY, -1, -1);
\r
4746 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4747 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4748 /* Errant click; ignore */
\r
4751 /* Finish drag move. */
\r
4752 if (appData.debugMode) {
\r
4753 fprintf(debugFP, "release\n");
\r
4755 dragInfo.from.x = dragInfo.from.y = -1;
\r
4758 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4759 appData.animate = appData.animate && !appData.animateDragging;
\r
4760 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4761 if(moveType != ImpossibleMove) {
\r
4762 /* [HGM] use move type to determine if move is promotion.
\r
4763 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
4764 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4765 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4766 appData.alwaysPromoteToQueen)
\r
4767 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4769 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4770 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4771 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
4772 } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4774 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4775 appData.animate = saveAnimate;
\r
4776 fromX = fromY = -1;
\r
4777 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
4778 ClearHighlights();
\r
4780 if (appData.animate || appData.animateDragging ||
\r
4781 appData.highlightDragging || gotPremove) {
\r
4782 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4785 dragInfo.start.x = dragInfo.start.y = -1;
\r
4786 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4789 case WM_MOUSEMOVE:
\r
4790 if ((appData.animateDragging || appData.highlightDragging)
\r
4791 && (wParam & MK_LBUTTON)
\r
4792 && dragInfo.from.x >= 0)
\r
4794 BOOL full_repaint = FALSE;
\r
4796 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
4797 if (appData.animateDragging) {
\r
4798 dragInfo.pos = pt;
\r
4800 if (appData.highlightDragging) {
\r
4801 SetHighlights(fromX, fromY, x, y);
\r
4802 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4803 full_repaint = TRUE;
\r
4807 DrawPosition( full_repaint, NULL);
\r
4809 dragInfo.lastpos = dragInfo.pos;
\r
4813 case WM_MBUTTONDOWN:
\r
4814 case WM_RBUTTONDOWN:
\r
4817 fromX = fromY = -1;
\r
4818 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4819 dragInfo.start.x = dragInfo.start.y = -1;
\r
4820 dragInfo.from = dragInfo.start;
\r
4821 dragInfo.lastpos = dragInfo.pos;
\r
4822 if (appData.highlightDragging) {
\r
4823 ClearHighlights();
\r
4826 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4827 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4828 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
4829 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4830 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
4833 DrawPosition(TRUE, NULL);
\r
4835 switch (gameMode) {
\r
4836 case EditPosition:
\r
4837 case IcsExamining:
\r
4838 if (x < 0 || y < 0) break;
\r
4841 if (message == WM_MBUTTONDOWN) {
\r
4842 buttonCount = 3; /* even if system didn't think so */
\r
4843 if (wParam & MK_SHIFT)
\r
4844 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4846 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4847 } else { /* message == WM_RBUTTONDOWN */
\r
4849 if (buttonCount == 3) {
\r
4850 if (wParam & MK_SHIFT)
\r
4851 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4853 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4855 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4858 /* Just have one menu, on the right button. Windows users don't
\r
4859 think to try the middle one, and sometimes other software steals
\r
4860 it, or it doesn't really exist. */
\r
4861 if(gameInfo.variant != VariantShogi)
\r
4862 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4864 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4868 case IcsPlayingWhite:
\r
4869 case IcsPlayingBlack:
\r
4871 case MachinePlaysWhite:
\r
4872 case MachinePlaysBlack:
\r
4873 if (appData.testLegality &&
\r
4874 gameInfo.variant != VariantBughouse &&
\r
4875 gameInfo.variant != VariantCrazyhouse) break;
\r
4876 if (x < 0 || y < 0) break;
\r
4879 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4880 SetupDropMenu(hmenu);
\r
4881 MenuPopup(hwnd, pt, hmenu, -1);
\r
4892 /* Preprocess messages for buttons in main window */
\r
4894 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4896 int id = GetWindowLong(hwnd, GWL_ID);
\r
4899 for (i=0; i<N_BUTTONS; i++) {
\r
4900 if (buttonDesc[i].id == id) break;
\r
4902 if (i == N_BUTTONS) return 0;
\r
4903 switch (message) {
\r
4908 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4909 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4916 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4919 if (appData.icsActive) {
\r
4920 if (GetKeyState(VK_SHIFT) < 0) {
\r
4922 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4923 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4927 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4928 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4935 if (appData.icsActive) {
\r
4936 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4937 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4939 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4941 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4942 PopUpMoveDialog((char)wParam);
\r
4948 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4951 /* Process messages for Promotion dialog box */
\r
4953 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4957 switch (message) {
\r
4958 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4959 /* Center the dialog over the application window */
\r
4960 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4961 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4962 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4963 gameInfo.variant == VariantGiveaway) ?
\r
4964 SW_SHOW : SW_HIDE);
\r
4965 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4966 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4967 (PieceToChar(WhiteAngel) >= 'A' &&
\r
4968 PieceToChar(WhiteAngel) != '~' ||
\r
4969 PieceToChar(BlackAngel) >= 'A' &&
\r
4970 PieceToChar(BlackAngel) != '~' ) ?
\r
4971 SW_SHOW : SW_HIDE);
\r
4972 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4973 (PieceToChar(WhiteMarshall) >= 'A' &&
\r
4974 PieceToChar(WhiteMarshall) != '~' ||
\r
4975 PieceToChar(BlackMarshall) >= 'A' &&
\r
4976 PieceToChar(BlackMarshall) != '~' ) ?
\r
4977 SW_SHOW : SW_HIDE);
\r
4978 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4979 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
4980 gameInfo.variant != VariantShogi ?
\r
4981 SW_SHOW : SW_HIDE);
\r
4982 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
4983 gameInfo.variant != VariantShogi ?
\r
4984 SW_SHOW : SW_HIDE);
\r
4985 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
4986 gameInfo.variant == VariantShogi ?
\r
4987 SW_SHOW : SW_HIDE);
\r
4988 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
4989 gameInfo.variant == VariantShogi ?
\r
4990 SW_SHOW : SW_HIDE);
\r
4993 case WM_COMMAND: /* message: received a command */
\r
4994 switch (LOWORD(wParam)) {
\r
4996 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4997 ClearHighlights();
\r
4998 DrawPosition(FALSE, NULL);
\r
5001 promoChar = PieceToChar(BlackKing);
\r
5004 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5007 promoChar = PieceToChar(BlackRook);
\r
5010 promoChar = PieceToChar(BlackBishop);
\r
5012 case PB_Chancellor:
\r
5013 promoChar = PieceToChar(BlackMarshall);
\r
5015 case PB_Archbishop:
\r
5016 promoChar = PieceToChar(BlackAngel);
\r
5019 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5024 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5025 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5026 only show the popup when we are already sure the move is valid or
\r
5027 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5028 will figure out it is a promotion from the promoChar. */
\r
5029 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5030 if (!appData.highlightLastMove) {
\r
5031 ClearHighlights();
\r
5032 DrawPosition(FALSE, NULL);
\r
5039 /* Pop up promotion dialog */
\r
5041 PromotionPopup(HWND hwnd)
\r
5045 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5046 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5047 hwnd, (DLGPROC)lpProc);
\r
5048 FreeProcInstance(lpProc);
\r
5051 /* Toggle ShowThinking */
\r
5053 ToggleShowThinking()
\r
5055 ShowThinkingEvent(!appData.showThinking);
\r
5059 LoadGameDialog(HWND hwnd, char* title)
\r
5063 char fileTitle[MSG_SIZ];
\r
5064 f = OpenFileDialog(hwnd, "rb", "",
\r
5065 appData.oldSaveStyle ? "gam" : "pgn",
\r
5067 title, &number, fileTitle, NULL);
\r
5069 cmailMsgLoaded = FALSE;
\r
5070 if (number == 0) {
\r
5071 int error = GameListBuild(f);
\r
5073 DisplayError("Cannot build game list", error);
\r
5074 } else if (!ListEmpty(&gameList) &&
\r
5075 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5076 GameListPopUp(f, fileTitle);
\r
5079 GameListDestroy();
\r
5082 LoadGame(f, number, fileTitle, FALSE);
\r
5087 ChangedConsoleFont()
\r
5090 CHARRANGE tmpsel, sel;
\r
5091 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5092 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5093 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5096 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5097 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5098 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5099 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5100 * size. This was undocumented in the version of MSVC++ that I had
\r
5101 * when I wrote the code, but is apparently documented now.
\r
5103 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5104 cfmt.bCharSet = f->lf.lfCharSet;
\r
5105 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5106 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5107 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5108 /* Why are the following seemingly needed too? */
\r
5109 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5110 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5111 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5113 tmpsel.cpMax = -1; /*999999?*/
\r
5114 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5115 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5116 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5117 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5119 paraf.cbSize = sizeof(paraf);
\r
5120 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5121 paraf.dxStartIndent = 0;
\r
5122 paraf.dxOffset = WRAP_INDENT;
\r
5123 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5124 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5127 /*---------------------------------------------------------------------------*\
\r
5129 * Window Proc for main window
\r
5131 \*---------------------------------------------------------------------------*/
\r
5133 /* Process messages for main window, etc. */
\r
5135 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5138 int wmId, wmEvent;
\r
5142 char fileTitle[MSG_SIZ];
\r
5143 static SnapData sd;
\r
5145 switch (message) {
\r
5147 case WM_PAINT: /* message: repaint portion of window */
\r
5151 case WM_ERASEBKGND:
\r
5152 if (IsIconic(hwnd)) {
\r
5153 /* Cheat; change the message */
\r
5154 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5156 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5160 case WM_LBUTTONDOWN:
\r
5161 case WM_MBUTTONDOWN:
\r
5162 case WM_RBUTTONDOWN:
\r
5163 case WM_LBUTTONUP:
\r
5164 case WM_MBUTTONUP:
\r
5165 case WM_RBUTTONUP:
\r
5166 case WM_MOUSEMOVE:
\r
5167 MouseEvent(hwnd, message, wParam, lParam);
\r
5172 if (appData.icsActive) {
\r
5173 if (wParam == '\t') {
\r
5174 if (GetKeyState(VK_SHIFT) < 0) {
\r
5176 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5177 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5181 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5182 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5186 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5187 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5189 SendMessage(h, message, wParam, lParam);
\r
5191 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5192 PopUpMoveDialog((char)wParam);
\r
5196 case WM_PALETTECHANGED:
\r
5197 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5199 HDC hdc = GetDC(hwndMain);
\r
5200 SelectPalette(hdc, hPal, TRUE);
\r
5201 nnew = RealizePalette(hdc);
\r
5203 paletteChanged = TRUE;
\r
5205 UpdateColors(hdc);
\r
5207 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5210 ReleaseDC(hwnd, hdc);
\r
5214 case WM_QUERYNEWPALETTE:
\r
5215 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5217 HDC hdc = GetDC(hwndMain);
\r
5218 paletteChanged = FALSE;
\r
5219 SelectPalette(hdc, hPal, FALSE);
\r
5220 nnew = RealizePalette(hdc);
\r
5222 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5224 ReleaseDC(hwnd, hdc);
\r
5229 case WM_COMMAND: /* message: command from application menu */
\r
5230 wmId = LOWORD(wParam);
\r
5231 wmEvent = HIWORD(wParam);
\r
5236 AnalysisPopDown();
\r
5239 case IDM_NewGameFRC:
\r
5240 if( NewGameFRC() == 0 ) {
\r
5242 AnalysisPopDown();
\r
5246 case IDM_NewVariant:
\r
5247 NewVariantPopup(hwnd);
\r
5250 case IDM_LoadGame:
\r
5251 LoadGameDialog(hwnd, "Load Game from File");
\r
5254 case IDM_LoadNextGame:
\r
5258 case IDM_LoadPrevGame:
\r
5262 case IDM_ReloadGame:
\r
5266 case IDM_LoadPosition:
\r
5267 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5268 Reset(FALSE, TRUE);
\r
5271 f = OpenFileDialog(hwnd, "rb", "",
\r
5272 appData.oldSaveStyle ? "pos" : "fen",
\r
5274 "Load Position from File", &number, fileTitle, NULL);
\r
5276 LoadPosition(f, number, fileTitle);
\r
5280 case IDM_LoadNextPosition:
\r
5281 ReloadPosition(1);
\r
5284 case IDM_LoadPrevPosition:
\r
5285 ReloadPosition(-1);
\r
5288 case IDM_ReloadPosition:
\r
5289 ReloadPosition(0);
\r
5292 case IDM_SaveGame:
\r
5293 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5294 f = OpenFileDialog(hwnd, "a", defName,
\r
5295 appData.oldSaveStyle ? "gam" : "pgn",
\r
5297 "Save Game to File", NULL, fileTitle, NULL);
\r
5299 SaveGame(f, 0, "");
\r
5303 case IDM_SavePosition:
\r
5304 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5305 f = OpenFileDialog(hwnd, "a", defName,
\r
5306 appData.oldSaveStyle ? "pos" : "fen",
\r
5308 "Save Position to File", NULL, fileTitle, NULL);
\r
5310 SavePosition(f, 0, "");
\r
5314 case IDM_SaveDiagram:
\r
5315 defName = "diagram";
\r
5316 f = OpenFileDialog(hwnd, "wb", defName,
\r
5319 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5325 case IDM_CopyGame:
\r
5326 CopyGameToClipboard();
\r
5329 case IDM_PasteGame:
\r
5330 PasteGameFromClipboard();
\r
5333 case IDM_CopyGameListToClipboard:
\r
5334 CopyGameListToClipboard();
\r
5337 /* [AS] Autodetect FEN or PGN data */
\r
5338 case IDM_PasteAny:
\r
5339 PasteGameOrFENFromClipboard();
\r
5342 /* [AS] Move history */
\r
5343 case IDM_ShowMoveHistory:
\r
5344 if( MoveHistoryIsUp() ) {
\r
5345 MoveHistoryPopDown();
\r
5348 MoveHistoryPopUp();
\r
5352 /* [AS] Eval graph */
\r
5353 case IDM_ShowEvalGraph:
\r
5354 if( EvalGraphIsUp() ) {
\r
5355 EvalGraphPopDown();
\r
5362 /* [AS] Engine output */
\r
5363 case IDM_ShowEngineOutput:
\r
5364 if( EngineOutputIsUp() ) {
\r
5365 EngineOutputPopDown();
\r
5368 EngineOutputPopUp();
\r
5372 /* [AS] User adjudication */
\r
5373 case IDM_UserAdjudication_White:
\r
5374 UserAdjudicationEvent( +1 );
\r
5377 case IDM_UserAdjudication_Black:
\r
5378 UserAdjudicationEvent( -1 );
\r
5381 case IDM_UserAdjudication_Draw:
\r
5382 UserAdjudicationEvent( 0 );
\r
5385 /* [AS] Game list options dialog */
\r
5386 case IDM_GameListOptions:
\r
5387 GameListOptions();
\r
5390 case IDM_CopyPosition:
\r
5391 CopyFENToClipboard();
\r
5394 case IDM_PastePosition:
\r
5395 PasteFENFromClipboard();
\r
5398 case IDM_MailMove:
\r
5402 case IDM_ReloadCMailMsg:
\r
5403 Reset(TRUE, TRUE);
\r
5404 ReloadCmailMsgEvent(FALSE);
\r
5407 case IDM_Minimize:
\r
5408 ShowWindow(hwnd, SW_MINIMIZE);
\r
5415 case IDM_MachineWhite:
\r
5416 MachineWhiteEvent();
\r
5418 * refresh the tags dialog only if it's visible
\r
5420 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5422 tags = PGNTags(&gameInfo);
\r
5423 TagsPopUp(tags, CmailMsg());
\r
5428 case IDM_MachineBlack:
\r
5429 MachineBlackEvent();
\r
5431 * refresh the tags dialog only if it's visible
\r
5433 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5435 tags = PGNTags(&gameInfo);
\r
5436 TagsPopUp(tags, CmailMsg());
\r
5441 case IDM_TwoMachines:
\r
5442 TwoMachinesEvent();
\r
5444 * refresh the tags dialog only if it's visible
\r
5446 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5448 tags = PGNTags(&gameInfo);
\r
5449 TagsPopUp(tags, CmailMsg());
\r
5454 case IDM_AnalysisMode:
\r
5455 if (!first.analysisSupport) {
\r
5456 char buf[MSG_SIZ];
\r
5457 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5458 DisplayError(buf, 0);
\r
5460 if (!appData.showThinking) ToggleShowThinking();
\r
5461 AnalyzeModeEvent();
\r
5465 case IDM_AnalyzeFile:
\r
5466 if (!first.analysisSupport) {
\r
5467 char buf[MSG_SIZ];
\r
5468 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5469 DisplayError(buf, 0);
\r
5471 if (!appData.showThinking) ToggleShowThinking();
\r
5472 AnalyzeFileEvent();
\r
5473 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5474 AnalysisPeriodicEvent(1);
\r
5478 case IDM_IcsClient:
\r
5482 case IDM_EditGame:
\r
5486 case IDM_EditPosition:
\r
5487 EditPositionEvent();
\r
5490 case IDM_Training:
\r
5494 case IDM_ShowGameList:
\r
5495 ShowGameListProc();
\r
5498 case IDM_EditTags:
\r
5502 case IDM_EditComment:
\r
5503 if (commentDialogUp && editComment) {
\r
5506 EditCommentEvent();
\r
5526 case IDM_CallFlag:
\r
5546 case IDM_StopObserving:
\r
5547 StopObservingEvent();
\r
5550 case IDM_StopExamining:
\r
5551 StopExaminingEvent();
\r
5554 case IDM_TypeInMove:
\r
5555 PopUpMoveDialog('\000');
\r
5558 case IDM_TypeInName:
\r
5559 PopUpNameDialog('\000');
\r
5562 case IDM_Backward:
\r
5564 SetFocus(hwndMain);
\r
5569 SetFocus(hwndMain);
\r
5574 SetFocus(hwndMain);
\r
5579 SetFocus(hwndMain);
\r
5586 case IDM_TruncateGame:
\r
5587 TruncateGameEvent();
\r
5594 case IDM_RetractMove:
\r
5595 RetractMoveEvent();
\r
5598 case IDM_FlipView:
\r
5599 flipView = !flipView;
\r
5600 DrawPosition(FALSE, NULL);
\r
5603 case IDM_FlipClock:
\r
5604 flipClock = !flipClock;
\r
5605 DisplayBothClocks();
\r
5608 case IDM_GeneralOptions:
\r
5609 GeneralOptionsPopup(hwnd);
\r
5610 DrawPosition(TRUE, NULL);
\r
5613 case IDM_BoardOptions:
\r
5614 BoardOptionsPopup(hwnd);
\r
5617 case IDM_EnginePlayOptions:
\r
5618 EnginePlayOptionsPopup(hwnd);
\r
5621 case IDM_OptionsUCI:
\r
5622 UciOptionsPopup(hwnd);
\r
5625 case IDM_IcsOptions:
\r
5626 IcsOptionsPopup(hwnd);
\r
5630 FontsOptionsPopup(hwnd);
\r
5634 SoundOptionsPopup(hwnd);
\r
5637 case IDM_CommPort:
\r
5638 CommPortOptionsPopup(hwnd);
\r
5641 case IDM_LoadOptions:
\r
5642 LoadOptionsPopup(hwnd);
\r
5645 case IDM_SaveOptions:
\r
5646 SaveOptionsPopup(hwnd);
\r
5649 case IDM_TimeControl:
\r
5650 TimeControlOptionsPopup(hwnd);
\r
5653 case IDM_SaveSettings:
\r
5654 SaveSettings(settingsFileName);
\r
5657 case IDM_SaveSettingsOnExit:
\r
5658 saveSettingsOnExit = !saveSettingsOnExit;
\r
5659 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5660 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5661 MF_CHECKED : MF_UNCHECKED));
\r
5672 case IDM_AboutGame:
\r
5677 appData.debugMode = !appData.debugMode;
\r
5678 if (appData.debugMode) {
\r
5679 char dir[MSG_SIZ];
\r
5680 GetCurrentDirectory(MSG_SIZ, dir);
\r
5681 SetCurrentDirectory(installDir);
\r
5682 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5683 SetCurrentDirectory(dir);
\r
5684 setbuf(debugFP, NULL);
\r
5691 case IDM_HELPCONTENTS:
\r
5692 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5693 MessageBox (GetFocus(),
\r
5694 "Unable to activate help",
\r
5695 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5699 case IDM_HELPSEARCH:
\r
5700 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5701 MessageBox (GetFocus(),
\r
5702 "Unable to activate help",
\r
5703 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5707 case IDM_HELPHELP:
\r
5708 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5709 MessageBox (GetFocus(),
\r
5710 "Unable to activate help",
\r
5711 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5716 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5718 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5719 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5720 FreeProcInstance(lpProc);
\r
5723 case IDM_DirectCommand1:
\r
5724 AskQuestionEvent("Direct Command",
\r
5725 "Send to chess program:", "", "1");
\r
5727 case IDM_DirectCommand2:
\r
5728 AskQuestionEvent("Direct Command",
\r
5729 "Send to second chess program:", "", "2");
\r
5732 case EP_WhitePawn:
\r
5733 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5734 fromX = fromY = -1;
\r
5737 case EP_WhiteKnight:
\r
5738 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5739 fromX = fromY = -1;
\r
5742 case EP_WhiteBishop:
\r
5743 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5744 fromX = fromY = -1;
\r
5747 case EP_WhiteRook:
\r
5748 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5749 fromX = fromY = -1;
\r
5752 case EP_WhiteQueen:
\r
5753 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5754 fromX = fromY = -1;
\r
5757 case EP_WhiteFerz:
\r
5758 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5759 fromX = fromY = -1;
\r
5762 case EP_WhiteWazir:
\r
5763 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5764 fromX = fromY = -1;
\r
5767 case EP_WhiteAlfil:
\r
5768 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5769 fromX = fromY = -1;
\r
5772 case EP_WhiteCannon:
\r
5773 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5774 fromX = fromY = -1;
\r
5777 case EP_WhiteCardinal:
\r
5778 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5779 fromX = fromY = -1;
\r
5782 case EP_WhiteMarshall:
\r
5783 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5784 fromX = fromY = -1;
\r
5787 case EP_WhiteKing:
\r
5788 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5789 fromX = fromY = -1;
\r
5792 case EP_BlackPawn:
\r
5793 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5794 fromX = fromY = -1;
\r
5797 case EP_BlackKnight:
\r
5798 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5799 fromX = fromY = -1;
\r
5802 case EP_BlackBishop:
\r
5803 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5804 fromX = fromY = -1;
\r
5807 case EP_BlackRook:
\r
5808 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5809 fromX = fromY = -1;
\r
5812 case EP_BlackQueen:
\r
5813 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5814 fromX = fromY = -1;
\r
5817 case EP_BlackFerz:
\r
5818 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5819 fromX = fromY = -1;
\r
5822 case EP_BlackWazir:
\r
5823 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5824 fromX = fromY = -1;
\r
5827 case EP_BlackAlfil:
\r
5828 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5829 fromX = fromY = -1;
\r
5832 case EP_BlackCannon:
\r
5833 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5834 fromX = fromY = -1;
\r
5837 case EP_BlackCardinal:
\r
5838 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5839 fromX = fromY = -1;
\r
5842 case EP_BlackMarshall:
\r
5843 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5844 fromX = fromY = -1;
\r
5847 case EP_BlackKing:
\r
5848 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5849 fromX = fromY = -1;
\r
5852 case EP_EmptySquare:
\r
5853 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5854 fromX = fromY = -1;
\r
5857 case EP_ClearBoard:
\r
5858 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5859 fromX = fromY = -1;
\r
5863 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5864 fromX = fromY = -1;
\r
5868 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5869 fromX = fromY = -1;
\r
5873 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5874 fromX = fromY = -1;
\r
5878 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5879 fromX = fromY = -1;
\r
5883 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5884 fromX = fromY = -1;
\r
5888 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5889 fromX = fromY = -1;
\r
5893 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5894 fromX = fromY = -1;
\r
5898 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5899 fromX = fromY = -1;
\r
5903 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5904 fromX = fromY = -1;
\r
5908 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5914 case CLOCK_TIMER_ID:
\r
5915 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5916 clockTimerEvent = 0;
\r
5917 DecrementClocks(); /* call into back end */
\r
5919 case LOAD_GAME_TIMER_ID:
\r
5920 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5921 loadGameTimerEvent = 0;
\r
5922 AutoPlayGameLoop(); /* call into back end */
\r
5924 case ANALYSIS_TIMER_ID:
\r
5925 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
5926 appData.periodicUpdates) {
\r
5927 AnalysisPeriodicEvent(0);
\r
5929 KillTimer(hwnd, analysisTimerEvent);
\r
5930 analysisTimerEvent = 0;
\r
5933 case DELAYED_TIMER_ID:
\r
5934 KillTimer(hwnd, delayedTimerEvent);
\r
5935 delayedTimerEvent = 0;
\r
5936 delayedTimerCallback();
\r
5941 case WM_USER_Input:
\r
5942 InputEvent(hwnd, message, wParam, lParam);
\r
5945 /* [AS] Also move "attached" child windows */
\r
5946 case WM_WINDOWPOSCHANGING:
\r
5947 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5948 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5950 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
5951 /* Window is moving */
\r
5954 GetWindowRect( hwnd, &rcMain );
\r
5956 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5957 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5958 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5963 /* [AS] Snapping */
\r
5964 case WM_ENTERSIZEMOVE:
\r
5965 if (hwnd == hwndMain) {
\r
5966 doingSizing = TRUE;
\r
5969 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5973 if (hwnd == hwndMain) {
\r
5974 lastSizing = wParam;
\r
5979 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5981 case WM_EXITSIZEMOVE:
\r
5982 if (hwnd == hwndMain) {
\r
5984 doingSizing = FALSE;
\r
5985 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5986 GetClientRect(hwnd, &client);
\r
5987 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5990 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5993 case WM_DESTROY: /* message: window being destroyed */
\r
5994 PostQuitMessage(0);
\r
5998 if (hwnd == hwndMain) {
\r
6003 default: /* Passes it on if unprocessed */
\r
6004 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6009 /*---------------------------------------------------------------------------*\
\r
6011 * Misc utility routines
\r
6013 \*---------------------------------------------------------------------------*/
\r
6016 * Decent random number generator, at least not as bad as Windows
\r
6017 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6019 unsigned int randstate;
\r
6024 randstate = randstate * 1664525 + 1013904223;
\r
6025 return (int) randstate & 0x7fffffff;
\r
6029 mysrandom(unsigned int seed)
\r
6036 * returns TRUE if user selects a different color, FALSE otherwise
\r
6040 ChangeColor(HWND hwnd, COLORREF *which)
\r
6042 static BOOL firstTime = TRUE;
\r
6043 static DWORD customColors[16];
\r
6045 COLORREF newcolor;
\r
6050 /* Make initial colors in use available as custom colors */
\r
6051 /* Should we put the compiled-in defaults here instead? */
\r
6053 customColors[i++] = lightSquareColor & 0xffffff;
\r
6054 customColors[i++] = darkSquareColor & 0xffffff;
\r
6055 customColors[i++] = whitePieceColor & 0xffffff;
\r
6056 customColors[i++] = blackPieceColor & 0xffffff;
\r
6057 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6058 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6060 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6061 customColors[i++] = textAttribs[ccl].color;
\r
6063 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6064 firstTime = FALSE;
\r
6067 cc.lStructSize = sizeof(cc);
\r
6068 cc.hwndOwner = hwnd;
\r
6069 cc.hInstance = NULL;
\r
6070 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6071 cc.lpCustColors = (LPDWORD) customColors;
\r
6072 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6074 if (!ChooseColor(&cc)) return FALSE;
\r
6076 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6077 if (newcolor == *which) return FALSE;
\r
6078 *which = newcolor;
\r
6082 InitDrawingColors();
\r
6083 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6088 MyLoadSound(MySound *ms)
\r
6094 if (ms->data) free(ms->data);
\r
6097 switch (ms->name[0]) {
\r
6103 /* System sound from Control Panel. Don't preload here. */
\r
6107 if (ms->name[1] == NULLCHAR) {
\r
6108 /* "!" alone = silence */
\r
6111 /* Builtin wave resource. Error if not found. */
\r
6112 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6113 if (h == NULL) break;
\r
6114 ms->data = (void *)LoadResource(hInst, h);
\r
6115 if (h == NULL) break;
\r
6120 /* .wav file. Error if not found. */
\r
6121 f = fopen(ms->name, "rb");
\r
6122 if (f == NULL) break;
\r
6123 if (fstat(fileno(f), &st) < 0) break;
\r
6124 ms->data = malloc(st.st_size);
\r
6125 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6131 char buf[MSG_SIZ];
\r
6132 sprintf(buf, "Error loading sound %s", ms->name);
\r
6133 DisplayError(buf, GetLastError());
\r
6139 MyPlaySound(MySound *ms)
\r
6141 BOOLEAN ok = FALSE;
\r
6142 switch (ms->name[0]) {
\r
6148 /* System sound from Control Panel (deprecated feature).
\r
6149 "$" alone or an unset sound name gets default beep (still in use). */
\r
6150 if (ms->name[1]) {
\r
6151 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6153 if (!ok) ok = MessageBeep(MB_OK);
\r
6156 /* Builtin wave resource, or "!" alone for silence */
\r
6157 if (ms->name[1]) {
\r
6158 if (ms->data == NULL) return FALSE;
\r
6159 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6165 /* .wav file. Error if not found. */
\r
6166 if (ms->data == NULL) return FALSE;
\r
6167 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6170 /* Don't print an error: this can happen innocently if the sound driver
\r
6171 is busy; for instance, if another instance of WinBoard is playing
\r
6172 a sound at about the same time. */
\r
6175 char buf[MSG_SIZ];
\r
6176 sprintf(buf, "Error playing sound %s", ms->name);
\r
6177 DisplayError(buf, GetLastError());
\r
6185 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6188 OPENFILENAME *ofn;
\r
6189 static UINT *number; /* gross that this is static */
\r
6191 switch (message) {
\r
6192 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6193 /* Center the dialog over the application window */
\r
6194 ofn = (OPENFILENAME *) lParam;
\r
6195 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6196 number = (UINT *) ofn->lCustData;
\r
6197 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6201 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6202 return FALSE; /* Allow for further processing */
\r
6205 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6206 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6208 return FALSE; /* Allow for further processing */
\r
6214 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6216 static UINT *number;
\r
6217 OPENFILENAME *ofname;
\r
6220 case WM_INITDIALOG:
\r
6221 ofname = (OPENFILENAME *)lParam;
\r
6222 number = (UINT *)(ofname->lCustData);
\r
6225 ofnot = (OFNOTIFY *)lParam;
\r
6226 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6227 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6236 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6237 char *nameFilt, char *dlgTitle, UINT *number,
\r
6238 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6240 OPENFILENAME openFileName;
\r
6241 char buf1[MSG_SIZ];
\r
6244 if (fileName == NULL) fileName = buf1;
\r
6245 if (defName == NULL) {
\r
6246 strcpy(fileName, "*.");
\r
6247 strcat(fileName, defExt);
\r
6249 strcpy(fileName, defName);
\r
6251 if (fileTitle) strcpy(fileTitle, "");
\r
6252 if (number) *number = 0;
\r
6254 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6255 openFileName.hwndOwner = hwnd;
\r
6256 openFileName.hInstance = (HANDLE) hInst;
\r
6257 openFileName.lpstrFilter = nameFilt;
\r
6258 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6259 openFileName.nMaxCustFilter = 0L;
\r
6260 openFileName.nFilterIndex = 1L;
\r
6261 openFileName.lpstrFile = fileName;
\r
6262 openFileName.nMaxFile = MSG_SIZ;
\r
6263 openFileName.lpstrFileTitle = fileTitle;
\r
6264 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6265 openFileName.lpstrInitialDir = NULL;
\r
6266 openFileName.lpstrTitle = dlgTitle;
\r
6267 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6268 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6269 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6270 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6271 openFileName.nFileOffset = 0;
\r
6272 openFileName.nFileExtension = 0;
\r
6273 openFileName.lpstrDefExt = defExt;
\r
6274 openFileName.lCustData = (LONG) number;
\r
6275 openFileName.lpfnHook = oldDialog ?
\r
6276 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6277 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6279 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6280 GetOpenFileName(&openFileName)) {
\r
6281 /* open the file */
\r
6282 f = fopen(openFileName.lpstrFile, write);
\r
6284 MessageBox(hwnd, "File open failed", NULL,
\r
6285 MB_OK|MB_ICONEXCLAMATION);
\r
6289 int err = CommDlgExtendedError();
\r
6290 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6299 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6301 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6304 * Get the first pop-up menu in the menu template. This is the
\r
6305 * menu that TrackPopupMenu displays.
\r
6307 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6309 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6312 * TrackPopup uses screen coordinates, so convert the
\r
6313 * coordinates of the mouse click to screen coordinates.
\r
6315 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6317 /* Draw and track the floating pop-up menu. */
\r
6318 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6319 pt.x, pt.y, 0, hwnd, NULL);
\r
6321 /* Destroy the menu.*/
\r
6322 DestroyMenu(hmenu);
\r
6327 int sizeX, sizeY, newSizeX, newSizeY;
\r
6329 } ResizeEditPlusButtonsClosure;
\r
6332 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6334 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6338 if (hChild == cl->hText) return TRUE;
\r
6339 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6340 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6341 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6342 ScreenToClient(cl->hDlg, &pt);
\r
6343 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6344 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6348 /* Resize a dialog that has a (rich) edit field filling most of
\r
6349 the top, with a row of buttons below */
\r
6351 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6354 int newTextHeight, newTextWidth;
\r
6355 ResizeEditPlusButtonsClosure cl;
\r
6357 /*if (IsIconic(hDlg)) return;*/
\r
6358 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6360 cl.hdwp = BeginDeferWindowPos(8);
\r
6362 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6363 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6364 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6365 if (newTextHeight < 0) {
\r
6366 newSizeY += -newTextHeight;
\r
6367 newTextHeight = 0;
\r
6369 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6370 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6376 cl.newSizeX = newSizeX;
\r
6377 cl.newSizeY = newSizeY;
\r
6378 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6380 EndDeferWindowPos(cl.hdwp);
\r
6383 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6385 RECT rChild, rParent;
\r
6386 int wChild, hChild, wParent, hParent;
\r
6387 int wScreen, hScreen, xNew, yNew;
\r
6390 /* Get the Height and Width of the child window */
\r
6391 GetWindowRect (hwndChild, &rChild);
\r
6392 wChild = rChild.right - rChild.left;
\r
6393 hChild = rChild.bottom - rChild.top;
\r
6395 /* Get the Height and Width of the parent window */
\r
6396 GetWindowRect (hwndParent, &rParent);
\r
6397 wParent = rParent.right - rParent.left;
\r
6398 hParent = rParent.bottom - rParent.top;
\r
6400 /* Get the display limits */
\r
6401 hdc = GetDC (hwndChild);
\r
6402 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6403 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6404 ReleaseDC(hwndChild, hdc);
\r
6406 /* Calculate new X position, then adjust for screen */
\r
6407 xNew = rParent.left + ((wParent - wChild) /2);
\r
6410 } else if ((xNew+wChild) > wScreen) {
\r
6411 xNew = wScreen - wChild;
\r
6414 /* Calculate new Y position, then adjust for screen */
\r
6416 yNew = rParent.top + ((hParent - hChild) /2);
\r
6419 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6424 } else if ((yNew+hChild) > hScreen) {
\r
6425 yNew = hScreen - hChild;
\r
6428 /* Set it, and return */
\r
6429 return SetWindowPos (hwndChild, NULL,
\r
6430 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6433 /* Center one window over another */
\r
6434 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6436 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6439 /*---------------------------------------------------------------------------*\
\r
6441 * Startup Dialog functions
\r
6443 \*---------------------------------------------------------------------------*/
\r
6445 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6447 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6449 while (*cd != NULL) {
\r
6450 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6456 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6458 char buf1[ARG_MAX];
\r
6461 if (str[0] == '@') {
\r
6462 FILE* f = fopen(str + 1, "r");
\r
6464 DisplayFatalError(str + 1, errno, 2);
\r
6467 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6469 buf1[len] = NULLCHAR;
\r
6473 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6476 char buf[MSG_SIZ];
\r
6477 char *end = strchr(str, '\n');
\r
6478 if (end == NULL) return;
\r
6479 memcpy(buf, str, end - str);
\r
6480 buf[end - str] = NULLCHAR;
\r
6481 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6487 SetStartupDialogEnables(HWND hDlg)
\r
6489 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6490 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6491 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6492 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6493 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6494 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6495 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6496 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6497 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6498 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6499 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6500 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6501 IsDlgButtonChecked(hDlg, OPT_View));
\r
6505 QuoteForFilename(char *filename)
\r
6507 int dquote, space;
\r
6508 dquote = strchr(filename, '"') != NULL;
\r
6509 space = strchr(filename, ' ') != NULL;
\r
6510 if (dquote || space) {
\r
6522 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6524 char buf[MSG_SIZ];
\r
6527 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6528 q = QuoteForFilename(nthcp);
\r
6529 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6530 if (*nthdir != NULLCHAR) {
\r
6531 q = QuoteForFilename(nthdir);
\r
6532 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6534 if (*nthcp == NULLCHAR) {
\r
6535 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6536 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6537 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6538 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6543 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6545 char buf[MSG_SIZ];
\r
6549 switch (message) {
\r
6550 case WM_INITDIALOG:
\r
6551 /* Center the dialog */
\r
6552 CenterWindow (hDlg, GetDesktopWindow());
\r
6553 /* Initialize the dialog items */
\r
6554 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6555 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6556 firstChessProgramNames);
\r
6557 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6558 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6559 secondChessProgramNames);
\r
6560 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6561 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6562 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6563 if (*appData.icsHelper != NULLCHAR) {
\r
6564 char *q = QuoteForFilename(appData.icsHelper);
\r
6565 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6567 if (*appData.icsHost == NULLCHAR) {
\r
6568 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6569 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6570 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6571 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6572 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6575 if (appData.icsActive) {
\r
6576 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6578 else if (appData.noChessProgram) {
\r
6579 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6582 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6585 SetStartupDialogEnables(hDlg);
\r
6589 switch (LOWORD(wParam)) {
\r
6591 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6592 strcpy(buf, "/fcp=");
\r
6593 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6595 ParseArgs(StringGet, &p);
\r
6596 strcpy(buf, "/scp=");
\r
6597 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6599 ParseArgs(StringGet, &p);
\r
6600 appData.noChessProgram = FALSE;
\r
6601 appData.icsActive = FALSE;
\r
6602 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6603 strcpy(buf, "/ics /icshost=");
\r
6604 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6606 ParseArgs(StringGet, &p);
\r
6607 if (appData.zippyPlay) {
\r
6608 strcpy(buf, "/fcp=");
\r
6609 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6611 ParseArgs(StringGet, &p);
\r
6613 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6614 appData.noChessProgram = TRUE;
\r
6615 appData.icsActive = FALSE;
\r
6617 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6618 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6621 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6622 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6624 ParseArgs(StringGet, &p);
\r
6626 EndDialog(hDlg, TRUE);
\r
6633 case IDM_HELPCONTENTS:
\r
6634 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6635 MessageBox (GetFocus(),
\r
6636 "Unable to activate help",
\r
6637 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6642 SetStartupDialogEnables(hDlg);
\r
6650 /*---------------------------------------------------------------------------*\
\r
6652 * About box dialog functions
\r
6654 \*---------------------------------------------------------------------------*/
\r
6656 /* Process messages for "About" dialog box */
\r
6658 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6660 switch (message) {
\r
6661 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6662 /* Center the dialog over the application window */
\r
6663 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6664 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6667 case WM_COMMAND: /* message: received a command */
\r
6668 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6669 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6670 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6678 /*---------------------------------------------------------------------------*\
\r
6680 * Comment Dialog functions
\r
6682 \*---------------------------------------------------------------------------*/
\r
6685 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6687 static HANDLE hwndText = NULL;
\r
6688 int len, newSizeX, newSizeY, flags;
\r
6689 static int sizeX, sizeY;
\r
6694 switch (message) {
\r
6695 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6696 /* Initialize the dialog items */
\r
6697 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6698 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6699 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6700 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6701 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6702 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6703 SetWindowText(hDlg, commentTitle);
\r
6704 if (editComment) {
\r
6705 SetFocus(hwndText);
\r
6707 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6709 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6710 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6711 MAKELPARAM(FALSE, 0));
\r
6712 /* Size and position the dialog */
\r
6713 if (!commentDialog) {
\r
6714 commentDialog = hDlg;
\r
6715 flags = SWP_NOZORDER;
\r
6716 GetClientRect(hDlg, &rect);
\r
6717 sizeX = rect.right;
\r
6718 sizeY = rect.bottom;
\r
6719 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
6720 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
6721 WINDOWPLACEMENT wp;
\r
6722 EnsureOnScreen(&commentX, &commentY);
\r
6723 wp.length = sizeof(WINDOWPLACEMENT);
\r
6725 wp.showCmd = SW_SHOW;
\r
6726 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6727 wp.rcNormalPosition.left = commentX;
\r
6728 wp.rcNormalPosition.right = commentX + commentW;
\r
6729 wp.rcNormalPosition.top = commentY;
\r
6730 wp.rcNormalPosition.bottom = commentY + commentH;
\r
6731 SetWindowPlacement(hDlg, &wp);
\r
6733 GetClientRect(hDlg, &rect);
\r
6734 newSizeX = rect.right;
\r
6735 newSizeY = rect.bottom;
\r
6736 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6737 newSizeX, newSizeY);
\r
6744 case WM_COMMAND: /* message: received a command */
\r
6745 switch (LOWORD(wParam)) {
\r
6747 if (editComment) {
\r
6749 /* Read changed options from the dialog box */
\r
6750 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6751 len = GetWindowTextLength(hwndText);
\r
6752 str = (char *) malloc(len + 1);
\r
6753 GetWindowText(hwndText, str, len + 1);
\r
6762 ReplaceComment(commentIndex, str);
\r
6769 case OPT_CancelComment:
\r
6773 case OPT_ClearComment:
\r
6774 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6777 case OPT_EditComment:
\r
6778 EditCommentEvent();
\r
6787 newSizeX = LOWORD(lParam);
\r
6788 newSizeY = HIWORD(lParam);
\r
6789 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6794 case WM_GETMINMAXINFO:
\r
6795 /* Prevent resizing window too small */
\r
6796 mmi = (MINMAXINFO *) lParam;
\r
6797 mmi->ptMinTrackSize.x = 100;
\r
6798 mmi->ptMinTrackSize.y = 100;
\r
6805 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6810 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6812 if (str == NULL) str = "";
\r
6813 p = (char *) malloc(2 * strlen(str) + 2);
\r
6816 if (*str == '\n') *q++ = '\r';
\r
6820 if (commentText != NULL) free(commentText);
\r
6822 commentIndex = index;
\r
6823 commentTitle = title;
\r
6825 editComment = edit;
\r
6827 if (commentDialog) {
\r
6828 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6829 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
6831 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6832 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6833 hwndMain, (DLGPROC)lpProc);
\r
6834 FreeProcInstance(lpProc);
\r
6836 commentDialogUp = TRUE;
\r
6840 /*---------------------------------------------------------------------------*\
\r
6842 * Type-in move dialog functions
\r
6844 \*---------------------------------------------------------------------------*/
\r
6847 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6849 char move[MSG_SIZ];
\r
6851 ChessMove moveType;
\r
6852 int fromX, fromY, toX, toY;
\r
6855 switch (message) {
\r
6856 case WM_INITDIALOG:
\r
6857 move[0] = (char) lParam;
\r
6858 move[1] = NULLCHAR;
\r
6859 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6860 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6861 SetWindowText(hInput, move);
\r
6863 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6867 switch (LOWORD(wParam)) {
\r
6869 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
6870 gameMode != Training) {
\r
6871 DisplayMoveError("Displayed move is not current");
\r
6873 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6874 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
6875 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
6876 if (gameMode != Training)
\r
6877 forwardMostMove = currentMove;
\r
6878 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
6880 DisplayMoveError("Could not parse move");
\r
6883 EndDialog(hDlg, TRUE);
\r
6886 EndDialog(hDlg, FALSE);
\r
6897 PopUpMoveDialog(char firstchar)
\r
6901 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
6902 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
6903 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
6904 gameMode == EditPosition || gameMode == IcsExamining ||
\r
6905 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
6906 gameMode == Training) {
\r
6907 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6908 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6909 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6910 FreeProcInstance(lpProc);
\r
6914 /*---------------------------------------------------------------------------*\
\r
6916 * Type-in name dialog functions
\r
6918 \*---------------------------------------------------------------------------*/
\r
6921 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6923 char move[MSG_SIZ];
\r
6926 switch (message) {
\r
6927 case WM_INITDIALOG:
\r
6928 move[0] = (char) lParam;
\r
6929 move[1] = NULLCHAR;
\r
6930 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6931 hInput = GetDlgItem(hDlg, OPT_Name);
\r
6932 SetWindowText(hInput, move);
\r
6934 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6938 switch (LOWORD(wParam)) {
\r
6940 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
6941 appData.userName = strdup(move);
\r
6943 EndDialog(hDlg, TRUE);
\r
6946 EndDialog(hDlg, FALSE);
\r
6957 PopUpNameDialog(char firstchar)
\r
6961 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
6962 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
6963 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6964 FreeProcInstance(lpProc);
\r
6967 /*---------------------------------------------------------------------------*\
\r
6971 \*---------------------------------------------------------------------------*/
\r
6973 /* Nonmodal error box */
\r
6974 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6975 WPARAM wParam, LPARAM lParam);
\r
6978 ErrorPopUp(char *title, char *content)
\r
6982 BOOLEAN modal = hwndMain == NULL;
\r
7000 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7001 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7004 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7006 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7007 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7008 hwndMain, (DLGPROC)lpProc);
\r
7009 FreeProcInstance(lpProc);
\r
7016 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7017 if (errorDialog == NULL) return;
\r
7018 DestroyWindow(errorDialog);
\r
7019 errorDialog = NULL;
\r
7023 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7028 switch (message) {
\r
7029 case WM_INITDIALOG:
\r
7030 GetWindowRect(hDlg, &rChild);
\r
7033 SetWindowPos(hDlg, NULL, rChild.left,
\r
7034 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7035 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7039 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7040 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7041 and it doesn't work when you resize the dialog.
\r
7042 For now, just give it a default position.
\r
7044 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7046 errorDialog = hDlg;
\r
7047 SetWindowText(hDlg, errorTitle);
\r
7048 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7049 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7053 switch (LOWORD(wParam)) {
\r
7056 if (errorDialog == hDlg) errorDialog = NULL;
\r
7057 DestroyWindow(hDlg);
\r
7069 HWND gothicDialog = NULL;
\r
7072 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7076 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7078 switch (message) {
\r
7079 case WM_INITDIALOG:
\r
7080 GetWindowRect(hDlg, &rChild);
\r
7082 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7086 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7087 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7088 and it doesn't work when you resize the dialog.
\r
7089 For now, just give it a default position.
\r
7091 gothicDialog = hDlg;
\r
7092 SetWindowText(hDlg, errorTitle);
\r
7093 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7094 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7098 switch (LOWORD(wParam)) {
\r
7101 if (errorDialog == hDlg) errorDialog = NULL;
\r
7102 DestroyWindow(hDlg);
\r
7114 GothicPopUp(char *title, VariantClass variant)
\r
7118 BOOLEAN modal = hwndMain == NULL;
\r
7119 static char *lastTitle;
\r
7121 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7122 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7124 if(lastTitle != title && gothicDialog != NULL) {
\r
7125 DestroyWindow(gothicDialog);
\r
7126 gothicDialog = NULL;
\r
7128 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7129 title = lastTitle;
\r
7130 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7131 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7132 hwndMain, (DLGPROC)lpProc);
\r
7133 FreeProcInstance(lpProc);
\r
7138 /*---------------------------------------------------------------------------*\
\r
7140 * Ics Interaction console functions
\r
7142 \*---------------------------------------------------------------------------*/
\r
7144 #define HISTORY_SIZE 64
\r
7145 static char *history[HISTORY_SIZE];
\r
7146 int histIn = 0, histP = 0;
\r
7149 SaveInHistory(char *cmd)
\r
7151 if (history[histIn] != NULL) {
\r
7152 free(history[histIn]);
\r
7153 history[histIn] = NULL;
\r
7155 if (*cmd == NULLCHAR) return;
\r
7156 history[histIn] = StrSave(cmd);
\r
7157 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7158 if (history[histIn] != NULL) {
\r
7159 free(history[histIn]);
\r
7160 history[histIn] = NULL;
\r
7166 PrevInHistory(char *cmd)
\r
7169 if (histP == histIn) {
\r
7170 if (history[histIn] != NULL) free(history[histIn]);
\r
7171 history[histIn] = StrSave(cmd);
\r
7173 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7174 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7176 return history[histP];
\r
7182 if (histP == histIn) return NULL;
\r
7183 histP = (histP + 1) % HISTORY_SIZE;
\r
7184 return history[histP];
\r
7191 BOOLEAN immediate;
\r
7192 } IcsTextMenuEntry;
\r
7193 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7194 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7197 ParseIcsTextMenu(char *icsTextMenuString)
\r
7200 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7201 char *p = icsTextMenuString;
\r
7202 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7205 if (e->command != NULL) {
\r
7207 e->command = NULL;
\r
7211 e = icsTextMenuEntry;
\r
7212 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7213 if (*p == ';' || *p == '\n') {
\r
7214 e->item = strdup("-");
\r
7215 e->command = NULL;
\r
7217 } else if (*p == '-') {
\r
7218 e->item = strdup("-");
\r
7219 e->command = NULL;
\r
7223 char *q, *r, *s, *t;
\r
7225 q = strchr(p, ',');
\r
7226 if (q == NULL) break;
\r
7228 r = strchr(q + 1, ',');
\r
7229 if (r == NULL) break;
\r
7231 s = strchr(r + 1, ',');
\r
7232 if (s == NULL) break;
\r
7235 t = strchr(s + 1, c);
\r
7238 t = strchr(s + 1, c);
\r
7240 if (t != NULL) *t = NULLCHAR;
\r
7241 e->item = strdup(p);
\r
7242 e->command = strdup(q + 1);
\r
7243 e->getname = *(r + 1) != '0';
\r
7244 e->immediate = *(s + 1) != '0';
\r
7248 if (t == NULL) break;
\r
7257 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7261 hmenu = LoadMenu(hInst, "TextMenu");
\r
7262 h = GetSubMenu(hmenu, 0);
\r
7264 if (strcmp(e->item, "-") == 0) {
\r
7265 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7267 if (e->item[0] == '|') {
\r
7268 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7269 IDM_CommandX + i, &e->item[1]);
\r
7271 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7280 WNDPROC consoleTextWindowProc;
\r
7283 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7285 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7286 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7290 SetWindowText(hInput, command);
\r
7292 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7294 sel.cpMin = 999999;
\r
7295 sel.cpMax = 999999;
\r
7296 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7301 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7302 if (sel.cpMin == sel.cpMax) {
\r
7303 /* Expand to surrounding word */
\r
7306 tr.chrg.cpMax = sel.cpMin;
\r
7307 tr.chrg.cpMin = --sel.cpMin;
\r
7308 if (sel.cpMin < 0) break;
\r
7309 tr.lpstrText = name;
\r
7310 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7311 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7315 tr.chrg.cpMin = sel.cpMax;
\r
7316 tr.chrg.cpMax = ++sel.cpMax;
\r
7317 tr.lpstrText = name;
\r
7318 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7319 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7322 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7323 MessageBeep(MB_ICONEXCLAMATION);
\r
7327 tr.lpstrText = name;
\r
7328 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7330 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7331 MessageBeep(MB_ICONEXCLAMATION);
\r
7334 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7337 sprintf(buf, "%s %s", command, name);
\r
7338 SetWindowText(hInput, buf);
\r
7339 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7341 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7342 SetWindowText(hInput, buf);
\r
7343 sel.cpMin = 999999;
\r
7344 sel.cpMax = 999999;
\r
7345 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7351 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7356 switch (message) {
\r
7358 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7361 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7364 sel.cpMin = 999999;
\r
7365 sel.cpMax = 999999;
\r
7366 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7367 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7372 if (wParam == '\t') {
\r
7373 if (GetKeyState(VK_SHIFT) < 0) {
\r
7375 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7376 if (buttonDesc[0].hwnd) {
\r
7377 SetFocus(buttonDesc[0].hwnd);
\r
7379 SetFocus(hwndMain);
\r
7383 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7386 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7388 SendMessage(hInput, message, wParam, lParam);
\r
7392 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7394 return SendMessage(hInput, message, wParam, lParam);
\r
7395 case WM_MBUTTONDOWN:
\r
7396 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7397 case WM_RBUTTONDOWN:
\r
7398 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7399 /* Move selection here if it was empty */
\r
7401 pt.x = LOWORD(lParam);
\r
7402 pt.y = HIWORD(lParam);
\r
7403 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7404 if (sel.cpMin == sel.cpMax) {
\r
7405 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7406 sel.cpMax = sel.cpMin;
\r
7407 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7409 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7412 case WM_RBUTTONUP:
\r
7413 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7414 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7415 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7418 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7419 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7420 if (sel.cpMin == sel.cpMax) {
\r
7421 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7422 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7424 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7425 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7427 pt.x = LOWORD(lParam);
\r
7428 pt.y = HIWORD(lParam);
\r
7429 MenuPopup(hwnd, pt, hmenu, -1);
\r
7433 switch (LOWORD(wParam)) {
\r
7434 case IDM_QuickPaste:
\r
7436 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7437 if (sel.cpMin == sel.cpMax) {
\r
7438 MessageBeep(MB_ICONEXCLAMATION);
\r
7441 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7442 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7443 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7448 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7451 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7454 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7458 int i = LOWORD(wParam) - IDM_CommandX;
\r
7459 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7460 icsTextMenuEntry[i].command != NULL) {
\r
7461 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7462 icsTextMenuEntry[i].getname,
\r
7463 icsTextMenuEntry[i].immediate);
\r
7471 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7474 WNDPROC consoleInputWindowProc;
\r
7477 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7479 char buf[MSG_SIZ];
\r
7481 static BOOL sendNextChar = FALSE;
\r
7482 static BOOL quoteNextChar = FALSE;
\r
7483 InputSource *is = consoleInputSource;
\r
7487 switch (message) {
\r
7489 if (!appData.localLineEditing || sendNextChar) {
\r
7490 is->buf[0] = (CHAR) wParam;
\r
7492 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7493 sendNextChar = FALSE;
\r
7496 if (quoteNextChar) {
\r
7497 buf[0] = (char) wParam;
\r
7498 buf[1] = NULLCHAR;
\r
7499 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7500 quoteNextChar = FALSE;
\r
7504 case '\r': /* Enter key */
\r
7505 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7506 if (consoleEcho) SaveInHistory(is->buf);
\r
7507 is->buf[is->count++] = '\n';
\r
7508 is->buf[is->count] = NULLCHAR;
\r
7509 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7510 if (consoleEcho) {
\r
7511 ConsoleOutput(is->buf, is->count, TRUE);
\r
7512 } else if (appData.localLineEditing) {
\r
7513 ConsoleOutput("\n", 1, TRUE);
\r
7516 case '\033': /* Escape key */
\r
7517 SetWindowText(hwnd, "");
\r
7518 cf.cbSize = sizeof(CHARFORMAT);
\r
7519 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7520 if (consoleEcho) {
\r
7521 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7523 cf.crTextColor = COLOR_ECHOOFF;
\r
7525 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7526 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7528 case '\t': /* Tab key */
\r
7529 if (GetKeyState(VK_SHIFT) < 0) {
\r
7531 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7534 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7535 if (buttonDesc[0].hwnd) {
\r
7536 SetFocus(buttonDesc[0].hwnd);
\r
7538 SetFocus(hwndMain);
\r
7542 case '\023': /* Ctrl+S */
\r
7543 sendNextChar = TRUE;
\r
7545 case '\021': /* Ctrl+Q */
\r
7546 quoteNextChar = TRUE;
\r
7555 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7556 p = PrevInHistory(buf);
\r
7558 SetWindowText(hwnd, p);
\r
7559 sel.cpMin = 999999;
\r
7560 sel.cpMax = 999999;
\r
7561 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7566 p = NextInHistory();
\r
7568 SetWindowText(hwnd, p);
\r
7569 sel.cpMin = 999999;
\r
7570 sel.cpMax = 999999;
\r
7571 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7577 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7581 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7585 case WM_MBUTTONDOWN:
\r
7586 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7587 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7589 case WM_RBUTTONUP:
\r
7590 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7591 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7592 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7596 hmenu = LoadMenu(hInst, "InputMenu");
\r
7597 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7598 if (sel.cpMin == sel.cpMax) {
\r
7599 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7600 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7602 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7603 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7605 pt.x = LOWORD(lParam);
\r
7606 pt.y = HIWORD(lParam);
\r
7607 MenuPopup(hwnd, pt, hmenu, -1);
\r
7611 switch (LOWORD(wParam)) {
\r
7613 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7615 case IDM_SelectAll:
\r
7617 sel.cpMax = -1; /*999999?*/
\r
7618 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7621 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7624 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7627 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7632 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7635 #define CO_MAX 100000
\r
7636 #define CO_TRIM 1000
\r
7639 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7641 static SnapData sd;
\r
7642 static HWND hText, hInput, hFocus;
\r
7643 InputSource *is = consoleInputSource;
\r
7645 static int sizeX, sizeY;
\r
7646 int newSizeX, newSizeY;
\r
7649 switch (message) {
\r
7650 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7651 hwndConsole = hDlg;
\r
7652 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7653 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7655 consoleTextWindowProc = (WNDPROC)
\r
7656 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7657 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7658 consoleInputWindowProc = (WNDPROC)
\r
7659 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7660 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7661 Colorize(ColorNormal, TRUE);
\r
7662 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7663 ChangedConsoleFont();
\r
7664 GetClientRect(hDlg, &rect);
\r
7665 sizeX = rect.right;
\r
7666 sizeY = rect.bottom;
\r
7667 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7668 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7669 WINDOWPLACEMENT wp;
\r
7670 EnsureOnScreen(&consoleX, &consoleY);
\r
7671 wp.length = sizeof(WINDOWPLACEMENT);
\r
7673 wp.showCmd = SW_SHOW;
\r
7674 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7675 wp.rcNormalPosition.left = consoleX;
\r
7676 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7677 wp.rcNormalPosition.top = consoleY;
\r
7678 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7679 SetWindowPlacement(hDlg, &wp);
\r
7693 if (IsIconic(hDlg)) break;
\r
7694 newSizeX = LOWORD(lParam);
\r
7695 newSizeY = HIWORD(lParam);
\r
7696 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7697 RECT rectText, rectInput;
\r
7699 int newTextHeight, newTextWidth;
\r
7700 GetWindowRect(hText, &rectText);
\r
7701 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7702 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7703 if (newTextHeight < 0) {
\r
7704 newSizeY += -newTextHeight;
\r
7705 newTextHeight = 0;
\r
7707 SetWindowPos(hText, NULL, 0, 0,
\r
7708 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7709 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7710 pt.x = rectInput.left;
\r
7711 pt.y = rectInput.top + newSizeY - sizeY;
\r
7712 ScreenToClient(hDlg, &pt);
\r
7713 SetWindowPos(hInput, NULL,
\r
7714 pt.x, pt.y, /* needs client coords */
\r
7715 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7716 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7722 case WM_GETMINMAXINFO:
\r
7723 /* Prevent resizing window too small */
\r
7724 mmi = (MINMAXINFO *) lParam;
\r
7725 mmi->ptMinTrackSize.x = 100;
\r
7726 mmi->ptMinTrackSize.y = 100;
\r
7729 /* [AS] Snapping */
\r
7730 case WM_ENTERSIZEMOVE:
\r
7731 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7734 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7737 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7739 case WM_EXITSIZEMOVE:
\r
7740 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7743 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7751 if (hwndConsole) return;
\r
7752 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7753 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7758 ConsoleOutput(char* data, int length, int forceVisible)
\r
7763 char buf[CO_MAX+1];
\r
7766 static int delayLF = 0;
\r
7767 CHARRANGE savesel, sel;
\r
7769 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7777 while (length--) {
\r
7785 } else if (*p == '\007') {
\r
7786 MyPlaySound(&sounds[(int)SoundBell]);
\r
7793 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7794 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7795 /* Save current selection */
\r
7796 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7797 exlen = GetWindowTextLength(hText);
\r
7798 /* Find out whether current end of text is visible */
\r
7799 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7800 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7801 /* Trim existing text if it's too long */
\r
7802 if (exlen + (q - buf) > CO_MAX) {
\r
7803 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7806 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7807 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7809 savesel.cpMin -= trim;
\r
7810 savesel.cpMax -= trim;
\r
7811 if (exlen < 0) exlen = 0;
\r
7812 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7813 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7815 /* Append the new text */
\r
7816 sel.cpMin = exlen;
\r
7817 sel.cpMax = exlen;
\r
7818 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7819 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7820 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7821 if (forceVisible || exlen == 0 ||
\r
7822 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7823 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7824 /* Scroll to make new end of text visible if old end of text
\r
7825 was visible or new text is an echo of user typein */
\r
7826 sel.cpMin = 9999999;
\r
7827 sel.cpMax = 9999999;
\r
7828 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7829 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7830 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7831 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7833 if (savesel.cpMax == exlen || forceVisible) {
\r
7834 /* Move insert point to new end of text if it was at the old
\r
7835 end of text or if the new text is an echo of user typein */
\r
7836 sel.cpMin = 9999999;
\r
7837 sel.cpMax = 9999999;
\r
7838 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7840 /* Restore previous selection */
\r
7841 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7843 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7850 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7854 COLORREF oldFg, oldBg;
\r
7858 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
7860 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7861 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7862 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7865 rect.right = x + squareSize;
\r
7867 rect.bottom = y + squareSize;
\r
7870 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7871 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7872 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7873 &rect, str, strlen(str), NULL);
\r
7875 (void) SetTextColor(hdc, oldFg);
\r
7876 (void) SetBkColor(hdc, oldBg);
\r
7877 (void) SelectObject(hdc, oldFont);
\r
7881 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7882 RECT *rect, char *color, char *flagFell)
\r
7886 COLORREF oldFg, oldBg;
\r
7889 if (appData.clockMode) {
\r
7891 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7893 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
7900 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7901 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7903 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7904 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7906 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7908 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7909 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7910 rect, str, strlen(str), NULL);
\r
7912 (void) SetTextColor(hdc, oldFg);
\r
7913 (void) SetBkColor(hdc, oldBg);
\r
7914 (void) SelectObject(hdc, oldFont);
\r
7919 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7925 if( count <= 0 ) {
\r
7926 if (appData.debugMode) {
\r
7927 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7930 return ERROR_INVALID_USER_BUFFER;
\r
7933 ResetEvent(ovl->hEvent);
\r
7934 ovl->Offset = ovl->OffsetHigh = 0;
\r
7935 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7939 err = GetLastError();
\r
7940 if (err == ERROR_IO_PENDING) {
\r
7941 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7945 err = GetLastError();
\r
7952 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7957 ResetEvent(ovl->hEvent);
\r
7958 ovl->Offset = ovl->OffsetHigh = 0;
\r
7959 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7963 err = GetLastError();
\r
7964 if (err == ERROR_IO_PENDING) {
\r
7965 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7969 err = GetLastError();
\r
7975 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7976 void CheckForInputBufferFull( InputSource * is )
\r
7978 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7979 /* Look for end of line */
\r
7980 char * p = is->buf;
\r
7982 while( p < is->next && *p != '\n' ) {
\r
7986 if( p >= is->next ) {
\r
7987 if (appData.debugMode) {
\r
7988 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
\r
7991 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7992 is->count = (DWORD) -1;
\r
7993 is->next = is->buf;
\r
7999 InputThread(LPVOID arg)
\r
8004 is = (InputSource *) arg;
\r
8005 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8006 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8007 while (is->hThread != NULL) {
\r
8008 is->error = DoReadFile(is->hFile, is->next,
\r
8009 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8010 &is->count, &ovl);
\r
8011 if (is->error == NO_ERROR) {
\r
8012 is->next += is->count;
\r
8014 if (is->error == ERROR_BROKEN_PIPE) {
\r
8015 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8018 is->count = (DWORD) -1;
\r
8019 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8024 CheckForInputBufferFull( is );
\r
8026 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8028 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8030 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8033 CloseHandle(ovl.hEvent);
\r
8034 CloseHandle(is->hFile);
\r
8036 if (appData.debugMode) {
\r
8037 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
\r
8044 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8046 NonOvlInputThread(LPVOID arg)
\r
8053 is = (InputSource *) arg;
\r
8054 while (is->hThread != NULL) {
\r
8055 is->error = ReadFile(is->hFile, is->next,
\r
8056 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8057 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8058 if (is->error == NO_ERROR) {
\r
8059 /* Change CRLF to LF */
\r
8060 if (is->next > is->buf) {
\r
8062 i = is->count + 1;
\r
8070 if (prev == '\r' && *p == '\n') {
\r
8082 if (is->error == ERROR_BROKEN_PIPE) {
\r
8083 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8086 is->count = (DWORD) -1;
\r
8090 CheckForInputBufferFull( is );
\r
8092 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8094 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8096 if (is->count < 0) break; /* Quit on error */
\r
8098 CloseHandle(is->hFile);
\r
8103 SocketInputThread(LPVOID arg)
\r
8107 is = (InputSource *) arg;
\r
8108 while (is->hThread != NULL) {
\r
8109 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8110 if ((int)is->count == SOCKET_ERROR) {
\r
8111 is->count = (DWORD) -1;
\r
8112 is->error = WSAGetLastError();
\r
8114 is->error = NO_ERROR;
\r
8115 is->next += is->count;
\r
8116 if (is->count == 0 && is->second == is) {
\r
8117 /* End of file on stderr; quit with no message */
\r
8121 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8123 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8125 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8131 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8135 is = (InputSource *) lParam;
\r
8136 if (is->lineByLine) {
\r
8137 /* Feed in lines one by one */
\r
8138 char *p = is->buf;
\r
8140 while (q < is->next) {
\r
8141 if (*q++ == '\n') {
\r
8142 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8147 /* Move any partial line to the start of the buffer */
\r
8149 while (p < is->next) {
\r
8154 if (is->error != NO_ERROR || is->count == 0) {
\r
8155 /* Notify backend of the error. Note: If there was a partial
\r
8156 line at the end, it is not flushed through. */
\r
8157 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8160 /* Feed in the whole chunk of input at once */
\r
8161 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8162 is->next = is->buf;
\r
8166 /*---------------------------------------------------------------------------*\
\r
8168 * Menu enables. Used when setting various modes.
\r
8170 \*---------------------------------------------------------------------------*/
\r
8178 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8180 while (enab->item > 0) {
\r
8181 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8186 Enables gnuEnables[] = {
\r
8187 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8188 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8189 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8190 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8191 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8192 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8193 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8194 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8195 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8196 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8200 Enables icsEnables[] = {
\r
8201 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8202 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8203 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8204 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8205 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8206 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8207 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8208 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8209 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8210 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8211 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8212 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8217 Enables zippyEnables[] = {
\r
8218 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8219 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8220 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8225 Enables ncpEnables[] = {
\r
8226 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8227 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8228 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8229 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8230 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8231 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8232 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8233 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8234 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8235 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8236 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8237 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8238 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8239 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8240 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8244 Enables trainingOnEnables[] = {
\r
8245 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8246 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8247 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8248 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8249 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8250 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8251 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8252 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8256 Enables trainingOffEnables[] = {
\r
8257 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8258 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8259 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8260 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8261 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8262 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8263 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8264 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8268 /* These modify either ncpEnables or gnuEnables */
\r
8269 Enables cmailEnables[] = {
\r
8270 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8271 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8272 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8273 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8274 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8275 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8276 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8280 Enables machineThinkingEnables[] = {
\r
8281 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8282 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8283 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8284 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8285 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8286 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8287 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8288 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8289 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8290 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8291 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8292 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8293 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8294 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8295 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8299 Enables userThinkingEnables[] = {
\r
8300 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8301 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8302 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8303 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8304 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8305 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8306 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8307 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8308 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8309 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8310 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8311 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8312 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8313 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8314 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8318 /*---------------------------------------------------------------------------*\
\r
8320 * Front-end interface functions exported by XBoard.
\r
8321 * Functions appear in same order as prototypes in frontend.h.
\r
8323 \*---------------------------------------------------------------------------*/
\r
8327 static UINT prevChecked = 0;
\r
8328 static int prevPausing = 0;
\r
8331 if (pausing != prevPausing) {
\r
8332 prevPausing = pausing;
\r
8333 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8334 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8335 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8338 switch (gameMode) {
\r
8339 case BeginningOfGame:
\r
8340 if (appData.icsActive)
\r
8341 nowChecked = IDM_IcsClient;
\r
8342 else if (appData.noChessProgram)
\r
8343 nowChecked = IDM_EditGame;
\r
8345 nowChecked = IDM_MachineBlack;
\r
8347 case MachinePlaysBlack:
\r
8348 nowChecked = IDM_MachineBlack;
\r
8350 case MachinePlaysWhite:
\r
8351 nowChecked = IDM_MachineWhite;
\r
8353 case TwoMachinesPlay:
\r
8354 nowChecked = IDM_TwoMachines;
\r
8357 nowChecked = IDM_AnalysisMode;
\r
8360 nowChecked = IDM_AnalyzeFile;
\r
8363 nowChecked = IDM_EditGame;
\r
8365 case PlayFromGameFile:
\r
8366 nowChecked = IDM_LoadGame;
\r
8368 case EditPosition:
\r
8369 nowChecked = IDM_EditPosition;
\r
8372 nowChecked = IDM_Training;
\r
8374 case IcsPlayingWhite:
\r
8375 case IcsPlayingBlack:
\r
8376 case IcsObserving:
\r
8378 nowChecked = IDM_IcsClient;
\r
8385 if (prevChecked != 0)
\r
8386 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8387 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8388 if (nowChecked != 0)
\r
8389 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8390 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8392 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8393 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8394 MF_BYCOMMAND|MF_ENABLED);
\r
8396 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8397 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8400 prevChecked = nowChecked;
\r
8406 HMENU hmenu = GetMenu(hwndMain);
\r
8407 SetMenuEnables(hmenu, icsEnables);
\r
8408 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8409 MF_BYPOSITION|MF_ENABLED);
\r
8411 if (appData.zippyPlay) {
\r
8412 SetMenuEnables(hmenu, zippyEnables);
\r
8420 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8426 HMENU hmenu = GetMenu(hwndMain);
\r
8427 SetMenuEnables(hmenu, ncpEnables);
\r
8428 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8429 MF_BYPOSITION|MF_GRAYED);
\r
8430 DrawMenuBar(hwndMain);
\r
8436 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8440 SetTrainingModeOn()
\r
8443 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8444 for (i = 0; i < N_BUTTONS; i++) {
\r
8445 if (buttonDesc[i].hwnd != NULL)
\r
8446 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8451 VOID SetTrainingModeOff()
\r
8454 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8455 for (i = 0; i < N_BUTTONS; i++) {
\r
8456 if (buttonDesc[i].hwnd != NULL)
\r
8457 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8463 SetUserThinkingEnables()
\r
8465 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8469 SetMachineThinkingEnables()
\r
8471 HMENU hMenu = GetMenu(hwndMain);
\r
8472 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8474 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8476 if (gameMode == MachinePlaysBlack) {
\r
8477 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8478 } else if (gameMode == MachinePlaysWhite) {
\r
8479 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8480 } else if (gameMode == TwoMachinesPlay) {
\r
8481 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8487 DisplayTitle(char *str)
\r
8489 char title[MSG_SIZ], *host;
\r
8490 if (str[0] != NULLCHAR) {
\r
8491 strcpy(title, str);
\r
8492 } else if (appData.icsActive) {
\r
8493 if (appData.icsCommPort[0] != NULLCHAR)
\r
8496 host = appData.icsHost;
\r
8497 sprintf(title, "%s: %s", szTitle, host);
\r
8498 } else if (appData.noChessProgram) {
\r
8499 strcpy(title, szTitle);
\r
8501 strcpy(title, szTitle);
\r
8502 strcat(title, ": ");
\r
8503 strcat(title, first.tidy);
\r
8505 SetWindowText(hwndMain, title);
\r
8510 DisplayMessage(char *str1, char *str2)
\r
8514 int remain = MESSAGE_TEXT_MAX - 1;
\r
8517 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8518 messageText[0] = NULLCHAR;
\r
8520 len = strlen(str1);
\r
8521 if (len > remain) len = remain;
\r
8522 strncpy(messageText, str1, len);
\r
8523 messageText[len] = NULLCHAR;
\r
8526 if (*str2 && remain >= 2) {
\r
8528 strcat(messageText, " ");
\r
8531 len = strlen(str2);
\r
8532 if (len > remain) len = remain;
\r
8533 strncat(messageText, str2, len);
\r
8535 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8537 if (IsIconic(hwndMain)) return;
\r
8538 hdc = GetDC(hwndMain);
\r
8539 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8540 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8541 &messageRect, messageText, strlen(messageText), NULL);
\r
8542 (void) SelectObject(hdc, oldFont);
\r
8543 (void) ReleaseDC(hwndMain, hdc);
\r
8547 DisplayError(char *str, int error)
\r
8549 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8555 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8556 NULL, error, LANG_NEUTRAL,
\r
8557 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8559 sprintf(buf, "%s:\n%s", str, buf2);
\r
8561 ErrorMap *em = errmap;
\r
8562 while (em->err != 0 && em->err != error) em++;
\r
8563 if (em->err != 0) {
\r
8564 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8566 sprintf(buf, "%s:\nError code %d", str, error);
\r
8571 ErrorPopUp("Error", buf);
\r
8576 DisplayMoveError(char *str)
\r
8578 fromX = fromY = -1;
\r
8579 ClearHighlights();
\r
8580 DrawPosition(FALSE, NULL);
\r
8581 if (appData.popupMoveErrors) {
\r
8582 ErrorPopUp("Error", str);
\r
8584 DisplayMessage(str, "");
\r
8585 moveErrorMessageUp = TRUE;
\r
8590 DisplayFatalError(char *str, int error, int exitStatus)
\r
8592 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8594 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8597 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8598 NULL, error, LANG_NEUTRAL,
\r
8599 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8601 sprintf(buf, "%s:\n%s", str, buf2);
\r
8603 ErrorMap *em = errmap;
\r
8604 while (em->err != 0 && em->err != error) em++;
\r
8605 if (em->err != 0) {
\r
8606 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8608 sprintf(buf, "%s:\nError code %d", str, error);
\r
8613 if (appData.debugMode) {
\r
8614 fprintf(debugFP, "%s: %s\n", label, str);
\r
8616 if (appData.popupExitMessage) {
\r
8617 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8618 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8620 ExitEvent(exitStatus);
\r
8625 DisplayInformation(char *str)
\r
8627 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8632 DisplayNote(char *str)
\r
8634 ErrorPopUp("Note", str);
\r
8639 char *title, *question, *replyPrefix;
\r
8644 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8646 static QuestionParams *qp;
\r
8647 char reply[MSG_SIZ];
\r
8650 switch (message) {
\r
8651 case WM_INITDIALOG:
\r
8652 qp = (QuestionParams *) lParam;
\r
8653 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8654 SetWindowText(hDlg, qp->title);
\r
8655 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8656 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8660 switch (LOWORD(wParam)) {
\r
8662 strcpy(reply, qp->replyPrefix);
\r
8663 if (*reply) strcat(reply, " ");
\r
8664 len = strlen(reply);
\r
8665 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8666 strcat(reply, "\n");
\r
8667 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8668 EndDialog(hDlg, TRUE);
\r
8669 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
8672 EndDialog(hDlg, FALSE);
\r
8683 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8685 QuestionParams qp;
\r
8689 qp.question = question;
\r
8690 qp.replyPrefix = replyPrefix;
\r
8692 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8693 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8694 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8695 FreeProcInstance(lpProc);
\r
8698 /* [AS] Pick FRC position */
\r
8699 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8701 static int * lpIndexFRC;
\r
8707 case WM_INITDIALOG:
\r
8708 lpIndexFRC = (int *) lParam;
\r
8710 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8712 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8713 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8714 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8715 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8720 switch( LOWORD(wParam) ) {
\r
8722 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8723 EndDialog( hDlg, 0 );
\r
8724 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8727 EndDialog( hDlg, 1 );
\r
8729 case IDC_NFG_Edit:
\r
8730 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8731 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8733 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8736 case IDC_NFG_Random:
\r
8737 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8738 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8751 int index = appData.defaultFrcPosition;
\r
8752 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8754 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8756 if( result == 0 ) {
\r
8757 appData.defaultFrcPosition = index;
\r
8763 /* [AS] Game list options */
\r
8769 static GLT_Item GLT_ItemInfo[] = {
\r
8770 { GLT_EVENT, "Event" },
\r
8771 { GLT_SITE, "Site" },
\r
8772 { GLT_DATE, "Date" },
\r
8773 { GLT_ROUND, "Round" },
\r
8774 { GLT_PLAYERS, "Players" },
\r
8775 { GLT_RESULT, "Result" },
\r
8776 { GLT_WHITE_ELO, "White Rating" },
\r
8777 { GLT_BLACK_ELO, "Black Rating" },
\r
8778 { GLT_TIME_CONTROL,"Time Control" },
\r
8779 { GLT_VARIANT, "Variant" },
\r
8780 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
8784 const char * GLT_FindItem( char id )
\r
8786 const char * result = 0;
\r
8788 GLT_Item * list = GLT_ItemInfo;
\r
8790 while( list->id != 0 ) {
\r
8791 if( list->id == id ) {
\r
8792 result = list->name;
\r
8802 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
8804 const char * name = GLT_FindItem( id );
\r
8807 if( index >= 0 ) {
\r
8808 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
8811 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
8816 void GLT_TagsToList( HWND hDlg, char * tags )
\r
8820 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8823 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8827 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
8829 pc = GLT_ALL_TAGS;
\r
8832 if( strchr( tags, *pc ) == 0 ) {
\r
8833 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8838 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8841 char GLT_ListItemToTag( HWND hDlg, int index )
\r
8843 char result = '\0';
\r
8846 GLT_Item * list = GLT_ItemInfo;
\r
8848 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
8849 while( list->id != 0 ) {
\r
8850 if( strcmp( list->name, name ) == 0 ) {
\r
8851 result = list->id;
\r
8862 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8864 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8865 int idx2 = idx1 + delta;
\r
8866 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8868 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8871 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8872 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8873 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8874 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8878 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8880 static char glt[64];
\r
8881 static char * lpUserGLT;
\r
8885 case WM_INITDIALOG:
\r
8886 lpUserGLT = (char *) lParam;
\r
8888 strcpy( glt, lpUserGLT );
\r
8890 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8892 /* Initialize list */
\r
8893 GLT_TagsToList( hDlg, glt );
\r
8895 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8900 switch( LOWORD(wParam) ) {
\r
8903 char * pc = lpUserGLT;
\r
8905 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8909 id = GLT_ListItemToTag( hDlg, idx );
\r
8913 } while( id != '\0' );
\r
8915 EndDialog( hDlg, 0 );
\r
8918 EndDialog( hDlg, 1 );
\r
8921 case IDC_GLT_Default:
\r
8922 strcpy( glt, GLT_DEFAULT_TAGS );
\r
8923 GLT_TagsToList( hDlg, glt );
\r
8926 case IDC_GLT_Restore:
\r
8927 strcpy( glt, lpUserGLT );
\r
8928 GLT_TagsToList( hDlg, glt );
\r
8932 GLT_MoveSelection( hDlg, -1 );
\r
8935 case IDC_GLT_Down:
\r
8936 GLT_MoveSelection( hDlg, +1 );
\r
8946 int GameListOptions()
\r
8950 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8952 strcpy( glt, appData.gameListTags );
\r
8954 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
8956 if( result == 0 ) {
\r
8957 /* [AS] Memory leak here! */
\r
8958 appData.gameListTags = strdup( glt );
\r
8966 DisplayIcsInteractionTitle(char *str)
\r
8968 char consoleTitle[MSG_SIZ];
\r
8970 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8971 SetWindowText(hwndConsole, consoleTitle);
\r
8975 DrawPosition(int fullRedraw, Board board)
\r
8977 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8984 fromX = fromY = -1;
\r
8985 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8986 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8987 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8988 dragInfo.lastpos = dragInfo.pos;
\r
8989 dragInfo.start.x = dragInfo.start.y = -1;
\r
8990 dragInfo.from = dragInfo.start;
\r
8992 DrawPosition(TRUE, NULL);
\r
8998 CommentPopUp(char *title, char *str)
\r
9000 HWND hwnd = GetActiveWindow();
\r
9001 EitherCommentPopUp(0, title, str, FALSE);
\r
9002 SetActiveWindow(hwnd);
\r
9006 CommentPopDown(void)
\r
9008 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9009 if (commentDialog) {
\r
9010 ShowWindow(commentDialog, SW_HIDE);
\r
9012 commentDialogUp = FALSE;
\r
9016 EditCommentPopUp(int index, char *title, char *str)
\r
9018 EitherCommentPopUp(index, title, str, TRUE);
\r
9025 MyPlaySound(&sounds[(int)SoundMove]);
\r
9028 VOID PlayIcsWinSound()
\r
9030 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9033 VOID PlayIcsLossSound()
\r
9035 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9038 VOID PlayIcsDrawSound()
\r
9040 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9043 VOID PlayIcsUnfinishedSound()
\r
9045 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9051 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9059 consoleEcho = TRUE;
\r
9060 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9061 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9062 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9071 consoleEcho = FALSE;
\r
9072 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9073 /* This works OK: set text and background both to the same color */
\r
9075 cf.crTextColor = COLOR_ECHOOFF;
\r
9076 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9077 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9080 /* No Raw()...? */
\r
9082 void Colorize(ColorClass cc, int continuation)
\r
9084 currentColorClass = cc;
\r
9085 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9086 consoleCF.crTextColor = textAttribs[cc].color;
\r
9087 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9088 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9094 static char buf[MSG_SIZ];
\r
9095 DWORD bufsiz = MSG_SIZ;
\r
9097 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9098 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9100 if (!GetUserName(buf, &bufsiz)) {
\r
9101 /*DisplayError("Error getting user name", GetLastError());*/
\r
9102 strcpy(buf, "User");
\r
9110 static char buf[MSG_SIZ];
\r
9111 DWORD bufsiz = MSG_SIZ;
\r
9113 if (!GetComputerName(buf, &bufsiz)) {
\r
9114 /*DisplayError("Error getting host name", GetLastError());*/
\r
9115 strcpy(buf, "Unknown");
\r
9122 ClockTimerRunning()
\r
9124 return clockTimerEvent != 0;
\r
9130 if (clockTimerEvent == 0) return FALSE;
\r
9131 KillTimer(hwndMain, clockTimerEvent);
\r
9132 clockTimerEvent = 0;
\r
9137 StartClockTimer(long millisec)
\r
9139 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9140 (UINT) millisec, NULL);
\r
9144 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9147 hdc = GetDC(hwndMain);
\r
9148 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9150 if (!IsIconic(hwndMain)) {
\r
9151 DisplayAClock(hdc, timeRemaining, highlight, flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9153 if (highlight && iconCurrent == iconBlack) {
\r
9154 iconCurrent = iconWhite;
\r
9155 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9156 if (IsIconic(hwndMain)) {
\r
9157 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9160 (void) ReleaseDC(hwndMain, hdc);
\r
9162 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9166 DisplayBlackClock(long timeRemaining, int highlight)
\r
9169 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9171 hdc = GetDC(hwndMain);
\r
9172 if (!IsIconic(hwndMain)) {
\r
9173 DisplayAClock(hdc, timeRemaining, highlight, flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9175 if (highlight && iconCurrent == iconWhite) {
\r
9176 iconCurrent = iconBlack;
\r
9177 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9178 if (IsIconic(hwndMain)) {
\r
9179 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9182 (void) ReleaseDC(hwndMain, hdc);
\r
9184 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9189 LoadGameTimerRunning()
\r
9191 return loadGameTimerEvent != 0;
\r
9195 StopLoadGameTimer()
\r
9197 if (loadGameTimerEvent == 0) return FALSE;
\r
9198 KillTimer(hwndMain, loadGameTimerEvent);
\r
9199 loadGameTimerEvent = 0;
\r
9204 StartLoadGameTimer(long millisec)
\r
9206 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9207 (UINT) millisec, NULL);
\r
9215 char fileTitle[MSG_SIZ];
\r
9217 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9218 f = OpenFileDialog(hwndMain, "a", defName,
\r
9219 appData.oldSaveStyle ? "gam" : "pgn",
\r
9221 "Save Game to File", NULL, fileTitle, NULL);
\r
9223 SaveGame(f, 0, "");
\r
9230 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9232 if (delayedTimerEvent != 0) {
\r
9233 if (appData.debugMode) {
\r
9234 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9236 KillTimer(hwndMain, delayedTimerEvent);
\r
9237 delayedTimerEvent = 0;
\r
9238 delayedTimerCallback();
\r
9240 delayedTimerCallback = cb;
\r
9241 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9242 (UINT) millisec, NULL);
\r
9245 DelayedEventCallback
\r
9248 if (delayedTimerEvent) {
\r
9249 return delayedTimerCallback;
\r
9256 CancelDelayedEvent()
\r
9258 if (delayedTimerEvent) {
\r
9259 KillTimer(hwndMain, delayedTimerEvent);
\r
9260 delayedTimerEvent = 0;
\r
9264 /* Start a child process running the given program.
\r
9265 The process's standard output can be read from "from", and its
\r
9266 standard input can be written to "to".
\r
9267 Exit with fatal error if anything goes wrong.
\r
9268 Returns an opaque pointer that can be used to destroy the process
\r
9272 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9274 #define BUFSIZE 4096
\r
9276 HANDLE hChildStdinRd, hChildStdinWr,
\r
9277 hChildStdoutRd, hChildStdoutWr;
\r
9278 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9279 SECURITY_ATTRIBUTES saAttr;
\r
9281 PROCESS_INFORMATION piProcInfo;
\r
9282 STARTUPINFO siStartInfo;
\r
9284 char buf[MSG_SIZ];
\r
9287 if (appData.debugMode) {
\r
9288 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9293 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9294 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9295 saAttr.bInheritHandle = TRUE;
\r
9296 saAttr.lpSecurityDescriptor = NULL;
\r
9299 * The steps for redirecting child's STDOUT:
\r
9300 * 1. Create anonymous pipe to be STDOUT for child.
\r
9301 * 2. Create a noninheritable duplicate of read handle,
\r
9302 * and close the inheritable read handle.
\r
9305 /* Create a pipe for the child's STDOUT. */
\r
9306 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9307 return GetLastError();
\r
9310 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9311 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9312 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9313 FALSE, /* not inherited */
\r
9314 DUPLICATE_SAME_ACCESS);
\r
9316 return GetLastError();
\r
9318 CloseHandle(hChildStdoutRd);
\r
9321 * The steps for redirecting child's STDIN:
\r
9322 * 1. Create anonymous pipe to be STDIN for child.
\r
9323 * 2. Create a noninheritable duplicate of write handle,
\r
9324 * and close the inheritable write handle.
\r
9327 /* Create a pipe for the child's STDIN. */
\r
9328 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9329 return GetLastError();
\r
9332 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9333 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9334 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9335 FALSE, /* not inherited */
\r
9336 DUPLICATE_SAME_ACCESS);
\r
9338 return GetLastError();
\r
9340 CloseHandle(hChildStdinWr);
\r
9342 /* Arrange to (1) look in dir for the child .exe file, and
\r
9343 * (2) have dir be the child's working directory. Interpret
\r
9344 * dir relative to the directory WinBoard loaded from. */
\r
9345 GetCurrentDirectory(MSG_SIZ, buf);
\r
9346 SetCurrentDirectory(installDir);
\r
9347 SetCurrentDirectory(dir);
\r
9349 /* Now create the child process. */
\r
9351 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9352 siStartInfo.lpReserved = NULL;
\r
9353 siStartInfo.lpDesktop = NULL;
\r
9354 siStartInfo.lpTitle = NULL;
\r
9355 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9356 siStartInfo.cbReserved2 = 0;
\r
9357 siStartInfo.lpReserved2 = NULL;
\r
9358 siStartInfo.hStdInput = hChildStdinRd;
\r
9359 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9360 siStartInfo.hStdError = hChildStdoutWr;
\r
9362 fSuccess = CreateProcess(NULL,
\r
9363 cmdLine, /* command line */
\r
9364 NULL, /* process security attributes */
\r
9365 NULL, /* primary thread security attrs */
\r
9366 TRUE, /* handles are inherited */
\r
9367 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9368 NULL, /* use parent's environment */
\r
9370 &siStartInfo, /* STARTUPINFO pointer */
\r
9371 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9373 err = GetLastError();
\r
9374 SetCurrentDirectory(buf); /* return to prev directory */
\r
9379 /* Close the handles we don't need in the parent */
\r
9380 CloseHandle(piProcInfo.hThread);
\r
9381 CloseHandle(hChildStdinRd);
\r
9382 CloseHandle(hChildStdoutWr);
\r
9384 /* Prepare return value */
\r
9385 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9386 cp->kind = CPReal;
\r
9387 cp->hProcess = piProcInfo.hProcess;
\r
9388 cp->pid = piProcInfo.dwProcessId;
\r
9389 cp->hFrom = hChildStdoutRdDup;
\r
9390 cp->hTo = hChildStdinWrDup;
\r
9392 *pr = (void *) cp;
\r
9394 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9395 2000 where engines sometimes don't see the initial command(s)
\r
9396 from WinBoard and hang. I don't understand how that can happen,
\r
9397 but the Sleep is harmless, so I've put it in. Others have also
\r
9398 reported what may be the same problem, so hopefully this will fix
\r
9399 it for them too. */
\r
9407 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9409 ChildProc *cp; int result;
\r
9411 cp = (ChildProc *) pr;
\r
9412 if (cp == NULL) return;
\r
9414 switch (cp->kind) {
\r
9416 /* TerminateProcess is considered harmful, so... */
\r
9417 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9418 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9419 /* The following doesn't work because the chess program
\r
9420 doesn't "have the same console" as WinBoard. Maybe
\r
9421 we could arrange for this even though neither WinBoard
\r
9422 nor the chess program uses a console for stdio? */
\r
9423 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9425 /* [AS] Special termination modes for misbehaving programs... */
\r
9426 if( signal == 9 ) {
\r
9427 result = TerminateProcess( cp->hProcess, 0 );
\r
9429 if ( appData.debugMode) {
\r
9430 fprintf( debugFP, "Terminating process %u, result=%d\n", cp->pid, result );
\r
9433 else if( signal == 10 ) {
\r
9434 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9436 if( dw != WAIT_OBJECT_0 ) {
\r
9437 result = TerminateProcess( cp->hProcess, 0 );
\r
9439 if ( appData.debugMode) {
\r
9440 fprintf( debugFP, "Process %u still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9446 CloseHandle(cp->hProcess);
\r
9450 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9454 closesocket(cp->sock);
\r
9459 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9460 closesocket(cp->sock);
\r
9461 closesocket(cp->sock2);
\r
9469 InterruptChildProcess(ProcRef pr)
\r
9473 cp = (ChildProc *) pr;
\r
9474 if (cp == NULL) return;
\r
9475 switch (cp->kind) {
\r
9477 /* The following doesn't work because the chess program
\r
9478 doesn't "have the same console" as WinBoard. Maybe
\r
9479 we could arrange for this even though neither WinBoard
\r
9480 nor the chess program uses a console for stdio */
\r
9481 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9486 /* Can't interrupt */
\r
9490 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9497 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9499 char cmdLine[MSG_SIZ];
\r
9501 if (port[0] == NULLCHAR) {
\r
9502 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9504 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9506 return StartChildProcess(cmdLine, "", pr);
\r
9510 /* Code to open TCP sockets */
\r
9513 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9518 struct sockaddr_in sa, mysa;
\r
9519 struct hostent FAR *hp;
\r
9520 unsigned short uport;
\r
9521 WORD wVersionRequested;
\r
9524 /* Initialize socket DLL */
\r
9525 wVersionRequested = MAKEWORD(1, 1);
\r
9526 err = WSAStartup(wVersionRequested, &wsaData);
\r
9527 if (err != 0) return err;
\r
9530 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9531 err = WSAGetLastError();
\r
9536 /* Bind local address using (mostly) don't-care values.
\r
9538 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9539 mysa.sin_family = AF_INET;
\r
9540 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9541 uport = (unsigned short) 0;
\r
9542 mysa.sin_port = htons(uport);
\r
9543 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9544 == SOCKET_ERROR) {
\r
9545 err = WSAGetLastError();
\r
9550 /* Resolve remote host name */
\r
9551 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9552 if (!(hp = gethostbyname(host))) {
\r
9553 unsigned int b0, b1, b2, b3;
\r
9555 err = WSAGetLastError();
\r
9557 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9558 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9559 hp->h_addrtype = AF_INET;
\r
9561 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9562 hp->h_addr_list[0] = (char *) malloc(4);
\r
9563 hp->h_addr_list[0][0] = (char) b0;
\r
9564 hp->h_addr_list[0][1] = (char) b1;
\r
9565 hp->h_addr_list[0][2] = (char) b2;
\r
9566 hp->h_addr_list[0][3] = (char) b3;
\r
9572 sa.sin_family = hp->h_addrtype;
\r
9573 uport = (unsigned short) atoi(port);
\r
9574 sa.sin_port = htons(uport);
\r
9575 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9577 /* Make connection */
\r
9578 if (connect(s, (struct sockaddr *) &sa,
\r
9579 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9580 err = WSAGetLastError();
\r
9585 /* Prepare return value */
\r
9586 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9587 cp->kind = CPSock;
\r
9589 *pr = (ProcRef *) cp;
\r
9595 OpenCommPort(char *name, ProcRef *pr)
\r
9600 char fullname[MSG_SIZ];
\r
9602 if (*name != '\\')
\r
9603 sprintf(fullname, "\\\\.\\%s", name);
\r
9605 strcpy(fullname, name);
\r
9607 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9608 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9609 if (h == (HANDLE) -1) {
\r
9610 return GetLastError();
\r
9614 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9616 /* Accumulate characters until a 100ms pause, then parse */
\r
9617 ct.ReadIntervalTimeout = 100;
\r
9618 ct.ReadTotalTimeoutMultiplier = 0;
\r
9619 ct.ReadTotalTimeoutConstant = 0;
\r
9620 ct.WriteTotalTimeoutMultiplier = 0;
\r
9621 ct.WriteTotalTimeoutConstant = 0;
\r
9622 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9624 /* Prepare return value */
\r
9625 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9626 cp->kind = CPComm;
\r
9629 *pr = (ProcRef *) cp;
\r
9635 OpenLoopback(ProcRef *pr)
\r
9637 DisplayFatalError("Not implemented", 0, 1);
\r
9643 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9648 struct sockaddr_in sa, mysa;
\r
9649 struct hostent FAR *hp;
\r
9650 unsigned short uport;
\r
9651 WORD wVersionRequested;
\r
9654 char stderrPortStr[MSG_SIZ];
\r
9656 /* Initialize socket DLL */
\r
9657 wVersionRequested = MAKEWORD(1, 1);
\r
9658 err = WSAStartup(wVersionRequested, &wsaData);
\r
9659 if (err != 0) return err;
\r
9661 /* Resolve remote host name */
\r
9662 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9663 if (!(hp = gethostbyname(host))) {
\r
9664 unsigned int b0, b1, b2, b3;
\r
9666 err = WSAGetLastError();
\r
9668 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9669 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9670 hp->h_addrtype = AF_INET;
\r
9672 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9673 hp->h_addr_list[0] = (char *) malloc(4);
\r
9674 hp->h_addr_list[0][0] = (char) b0;
\r
9675 hp->h_addr_list[0][1] = (char) b1;
\r
9676 hp->h_addr_list[0][2] = (char) b2;
\r
9677 hp->h_addr_list[0][3] = (char) b3;
\r
9683 sa.sin_family = hp->h_addrtype;
\r
9684 uport = (unsigned short) 514;
\r
9685 sa.sin_port = htons(uport);
\r
9686 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9688 /* Bind local socket to unused "privileged" port address
\r
9690 s = INVALID_SOCKET;
\r
9691 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9692 mysa.sin_family = AF_INET;
\r
9693 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9694 for (fromPort = 1023;; fromPort--) {
\r
9695 if (fromPort < 0) {
\r
9697 return WSAEADDRINUSE;
\r
9699 if (s == INVALID_SOCKET) {
\r
9700 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9701 err = WSAGetLastError();
\r
9706 uport = (unsigned short) fromPort;
\r
9707 mysa.sin_port = htons(uport);
\r
9708 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9709 == SOCKET_ERROR) {
\r
9710 err = WSAGetLastError();
\r
9711 if (err == WSAEADDRINUSE) continue;
\r
9715 if (connect(s, (struct sockaddr *) &sa,
\r
9716 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9717 err = WSAGetLastError();
\r
9718 if (err == WSAEADDRINUSE) {
\r
9729 /* Bind stderr local socket to unused "privileged" port address
\r
9731 s2 = INVALID_SOCKET;
\r
9732 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9733 mysa.sin_family = AF_INET;
\r
9734 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9735 for (fromPort = 1023;; fromPort--) {
\r
9736 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9737 if (fromPort < 0) {
\r
9738 (void) closesocket(s);
\r
9740 return WSAEADDRINUSE;
\r
9742 if (s2 == INVALID_SOCKET) {
\r
9743 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9744 err = WSAGetLastError();
\r
9750 uport = (unsigned short) fromPort;
\r
9751 mysa.sin_port = htons(uport);
\r
9752 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9753 == SOCKET_ERROR) {
\r
9754 err = WSAGetLastError();
\r
9755 if (err == WSAEADDRINUSE) continue;
\r
9756 (void) closesocket(s);
\r
9760 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9761 err = WSAGetLastError();
\r
9762 if (err == WSAEADDRINUSE) {
\r
9764 s2 = INVALID_SOCKET;
\r
9767 (void) closesocket(s);
\r
9768 (void) closesocket(s2);
\r
9774 prevStderrPort = fromPort; // remember port used
\r
9775 sprintf(stderrPortStr, "%d", fromPort);
\r
9777 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9778 err = WSAGetLastError();
\r
9779 (void) closesocket(s);
\r
9780 (void) closesocket(s2);
\r
9785 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9786 err = WSAGetLastError();
\r
9787 (void) closesocket(s);
\r
9788 (void) closesocket(s2);
\r
9792 if (*user == NULLCHAR) user = UserName();
\r
9793 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9794 err = WSAGetLastError();
\r
9795 (void) closesocket(s);
\r
9796 (void) closesocket(s2);
\r
9800 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9801 err = WSAGetLastError();
\r
9802 (void) closesocket(s);
\r
9803 (void) closesocket(s2);
\r
9808 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9809 err = WSAGetLastError();
\r
9810 (void) closesocket(s);
\r
9811 (void) closesocket(s2);
\r
9815 (void) closesocket(s2); /* Stop listening */
\r
9817 /* Prepare return value */
\r
9818 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9819 cp->kind = CPRcmd;
\r
9822 *pr = (ProcRef *) cp;
\r
9829 AddInputSource(ProcRef pr, int lineByLine,
\r
9830 InputCallback func, VOIDSTAR closure)
\r
9832 InputSource *is, *is2 = NULL;
\r
9833 ChildProc *cp = (ChildProc *) pr;
\r
9835 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9836 is->lineByLine = lineByLine;
\r
9838 is->closure = closure;
\r
9839 is->second = NULL;
\r
9840 is->next = is->buf;
\r
9841 if (pr == NoProc) {
\r
9842 is->kind = CPReal;
\r
9843 consoleInputSource = is;
\r
9845 is->kind = cp->kind;
\r
9847 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9848 we create all threads suspended so that the is->hThread variable can be
\r
9849 safely assigned, then let the threads start with ResumeThread.
\r
9851 switch (cp->kind) {
\r
9853 is->hFile = cp->hFrom;
\r
9854 cp->hFrom = NULL; /* now owned by InputThread */
\r
9856 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9857 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9861 is->hFile = cp->hFrom;
\r
9862 cp->hFrom = NULL; /* now owned by InputThread */
\r
9864 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9865 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9869 is->sock = cp->sock;
\r
9871 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9872 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9876 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9878 is->sock = cp->sock;
\r
9880 is2->sock = cp->sock2;
\r
9881 is2->second = is2;
\r
9883 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9884 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9886 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9887 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9891 if( is->hThread != NULL ) {
\r
9892 ResumeThread( is->hThread );
\r
9895 if( is2 != NULL && is2->hThread != NULL ) {
\r
9896 ResumeThread( is2->hThread );
\r
9900 return (InputSourceRef) is;
\r
9904 RemoveInputSource(InputSourceRef isr)
\r
9908 is = (InputSource *) isr;
\r
9909 is->hThread = NULL; /* tell thread to stop */
\r
9910 CloseHandle(is->hThread);
\r
9911 if (is->second != NULL) {
\r
9912 is->second->hThread = NULL;
\r
9913 CloseHandle(is->second->hThread);
\r
9919 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9922 int outCount = SOCKET_ERROR;
\r
9923 ChildProc *cp = (ChildProc *) pr;
\r
9924 static OVERLAPPED ovl;
\r
9926 if (pr == NoProc) {
\r
9927 ConsoleOutput(message, count, FALSE);
\r
9931 if (ovl.hEvent == NULL) {
\r
9932 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9934 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9936 switch (cp->kind) {
\r
9939 outCount = send(cp->sock, message, count, 0);
\r
9940 if (outCount == SOCKET_ERROR) {
\r
9941 *outError = WSAGetLastError();
\r
9943 *outError = NO_ERROR;
\r
9948 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9949 &dOutCount, NULL)) {
\r
9950 *outError = NO_ERROR;
\r
9951 outCount = (int) dOutCount;
\r
9953 *outError = GetLastError();
\r
9958 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9959 &dOutCount, &ovl);
\r
9960 if (*outError == NO_ERROR) {
\r
9961 outCount = (int) dOutCount;
\r
9969 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9972 /* Ignore delay, not implemented for WinBoard */
\r
9973 return OutputToProcess(pr, message, count, outError);
\r
9978 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9979 char *buf, int count, int error)
\r
9981 DisplayFatalError("Not implemented", 0, 1);
\r
9984 /* see wgamelist.c for Game List functions */
\r
9985 /* see wedittags.c for Edit Tags functions */
\r
9992 char buf[MSG_SIZ];
\r
9995 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9996 f = fopen(buf, "r");
\r
9998 ProcessICSInitScript(f);
\r
10006 StartAnalysisClock()
\r
10008 if (analysisTimerEvent) return;
\r
10009 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10010 (UINT) 2000, NULL);
\r
10014 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10016 static HANDLE hwndText;
\r
10018 static int sizeX, sizeY;
\r
10019 int newSizeX, newSizeY, flags;
\r
10022 switch (message) {
\r
10023 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10024 /* Initialize the dialog items */
\r
10025 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10026 SetWindowText(hDlg, analysisTitle);
\r
10027 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10028 /* Size and position the dialog */
\r
10029 if (!analysisDialog) {
\r
10030 analysisDialog = hDlg;
\r
10031 flags = SWP_NOZORDER;
\r
10032 GetClientRect(hDlg, &rect);
\r
10033 sizeX = rect.right;
\r
10034 sizeY = rect.bottom;
\r
10035 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10036 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10037 WINDOWPLACEMENT wp;
\r
10038 EnsureOnScreen(&analysisX, &analysisY);
\r
10039 wp.length = sizeof(WINDOWPLACEMENT);
\r
10041 wp.showCmd = SW_SHOW;
\r
10042 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10043 wp.rcNormalPosition.left = analysisX;
\r
10044 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10045 wp.rcNormalPosition.top = analysisY;
\r
10046 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10047 SetWindowPlacement(hDlg, &wp);
\r
10049 GetClientRect(hDlg, &rect);
\r
10050 newSizeX = rect.right;
\r
10051 newSizeY = rect.bottom;
\r
10052 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10053 newSizeX, newSizeY);
\r
10054 sizeX = newSizeX;
\r
10055 sizeY = newSizeY;
\r
10060 case WM_COMMAND: /* message: received a command */
\r
10061 switch (LOWORD(wParam)) {
\r
10071 newSizeX = LOWORD(lParam);
\r
10072 newSizeY = HIWORD(lParam);
\r
10073 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10074 sizeX = newSizeX;
\r
10075 sizeY = newSizeY;
\r
10078 case WM_GETMINMAXINFO:
\r
10079 /* Prevent resizing window too small */
\r
10080 mmi = (MINMAXINFO *) lParam;
\r
10081 mmi->ptMinTrackSize.x = 100;
\r
10082 mmi->ptMinTrackSize.y = 100;
\r
10089 AnalysisPopUp(char* title, char* str)
\r
10095 EngineOutputPopUp();
\r
10098 if (str == NULL) str = "";
\r
10099 p = (char *) malloc(2 * strlen(str) + 2);
\r
10102 if (*str == '\n') *q++ = '\r';
\r
10106 if (analysisText != NULL) free(analysisText);
\r
10107 analysisText = p;
\r
10109 if (analysisDialog) {
\r
10110 SetWindowText(analysisDialog, title);
\r
10111 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10112 ShowWindow(analysisDialog, SW_SHOW);
\r
10114 analysisTitle = title;
\r
10115 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10116 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10117 hwndMain, (DLGPROC)lpProc);
\r
10118 FreeProcInstance(lpProc);
\r
10120 analysisDialogUp = TRUE;
\r
10124 AnalysisPopDown()
\r
10126 if (analysisDialog) {
\r
10127 ShowWindow(analysisDialog, SW_HIDE);
\r
10129 analysisDialogUp = FALSE;
\r
10134 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10136 highlightInfo.sq[0].x = fromX;
\r
10137 highlightInfo.sq[0].y = fromY;
\r
10138 highlightInfo.sq[1].x = toX;
\r
10139 highlightInfo.sq[1].y = toY;
\r
10143 ClearHighlights()
\r
10145 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10146 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10150 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10152 premoveHighlightInfo.sq[0].x = fromX;
\r
10153 premoveHighlightInfo.sq[0].y = fromY;
\r
10154 premoveHighlightInfo.sq[1].x = toX;
\r
10155 premoveHighlightInfo.sq[1].y = toY;
\r
10159 ClearPremoveHighlights()
\r
10161 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10162 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10166 ShutDownFrontEnd()
\r
10168 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10169 DeleteClipboardTempFiles();
\r
10175 if (IsIconic(hwndMain))
\r
10176 ShowWindow(hwndMain, SW_RESTORE);
\r
10178 SetActiveWindow(hwndMain);
\r
10182 * Prototypes for animation support routines
\r
10184 static void ScreenSquare(int column, int row, POINT * pt);
\r
10185 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10186 POINT frames[], int * nFrames);
\r
10189 #define kFactor 4
\r
10192 AnimateMove(board, fromX, fromY, toX, toY)
\r
10199 ChessSquare piece;
\r
10200 POINT start, finish, mid;
\r
10201 POINT frames[kFactor * 2 + 1];
\r
10204 if (!appData.animate) return;
\r
10205 if (doingSizing) return;
\r
10206 if (fromY < 0 || fromX < 0) return;
\r
10207 piece = board[fromY][fromX];
\r
10208 if (piece >= EmptySquare) return;
\r
10210 ScreenSquare(fromX, fromY, &start);
\r
10211 ScreenSquare(toX, toY, &finish);
\r
10213 /* All pieces except knights move in straight line */
\r
10214 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10215 mid.x = start.x + (finish.x - start.x) / 2;
\r
10216 mid.y = start.y + (finish.y - start.y) / 2;
\r
10218 /* Knight: make diagonal movement then straight */
\r
10219 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10220 mid.x = start.x + (finish.x - start.x) / 2;
\r
10221 mid.y = finish.y;
\r
10223 mid.x = finish.x;
\r
10224 mid.y = start.y + (finish.y - start.y) / 2;
\r
10228 /* Don't use as many frames for very short moves */
\r
10229 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10230 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10232 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10234 animInfo.from.x = fromX;
\r
10235 animInfo.from.y = fromY;
\r
10236 animInfo.to.x = toX;
\r
10237 animInfo.to.y = toY;
\r
10238 animInfo.lastpos = start;
\r
10239 animInfo.piece = piece;
\r
10240 for (n = 0; n < nFrames; n++) {
\r
10241 animInfo.pos = frames[n];
\r
10242 DrawPosition(FALSE, NULL);
\r
10243 animInfo.lastpos = animInfo.pos;
\r
10244 Sleep(appData.animSpeed);
\r
10246 animInfo.pos = finish;
\r
10247 DrawPosition(FALSE, NULL);
\r
10248 animInfo.piece = EmptySquare;
\r
10251 /* Convert board position to corner of screen rect and color */
\r
10254 ScreenSquare(column, row, pt)
\r
10255 int column; int row; POINT * pt;
\r
10258 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10259 pt->y = lineGap + row * (squareSize + lineGap);
\r
10261 pt->x = lineGap + column * (squareSize + lineGap);
\r
10262 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10266 /* Generate a series of frame coords from start->mid->finish.
\r
10267 The movement rate doubles until the half way point is
\r
10268 reached, then halves back down to the final destination,
\r
10269 which gives a nice slow in/out effect. The algorithmn
\r
10270 may seem to generate too many intermediates for short
\r
10271 moves, but remember that the purpose is to attract the
\r
10272 viewers attention to the piece about to be moved and
\r
10273 then to where it ends up. Too few frames would be less
\r
10277 Tween(start, mid, finish, factor, frames, nFrames)
\r
10278 POINT * start; POINT * mid;
\r
10279 POINT * finish; int factor;
\r
10280 POINT frames[]; int * nFrames;
\r
10282 int n, fraction = 1, count = 0;
\r
10284 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10285 for (n = 0; n < factor; n++)
\r
10287 for (n = 0; n < factor; n++) {
\r
10288 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10289 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10291 fraction = fraction / 2;
\r
10295 frames[count] = *mid;
\r
10298 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10300 for (n = 0; n < factor; n++) {
\r
10301 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10302 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10304 fraction = fraction * 2;
\r
10306 *nFrames = count;
\r
10310 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10315 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10316 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10318 OutputDebugString( buf );
\r
10321 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10323 EvalGraphSet( first, last, current, pvInfoList );
\r
10326 void SetProgramStats( FrontEndProgramStats * stats )
\r
10331 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10332 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10334 OutputDebugString( buf );
\r
10337 EngineOutputUpdate( stats );
\r