2 * WinBoard.c -- Windows NT front end to XBoard
\r
3 * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
\r
5 * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
\r
6 * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.
\r
8 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
9 * which was written and is copyrighted by Wayne Christopher.
\r
11 * The following terms apply to Digital Equipment Corporation's copyright
\r
12 * interest in XBoard:
\r
13 * ------------------------------------------------------------------------
\r
14 * All Rights Reserved
\r
16 * Permission to use, copy, modify, and distribute this software and its
\r
17 * documentation for any purpose and without fee is hereby granted,
\r
18 * provided that the above copyright notice appear in all copies and that
\r
19 * both that copyright notice and this permission notice appear in
\r
20 * supporting documentation, and that the name of Digital not be
\r
21 * used in advertising or publicity pertaining to distribution of the
\r
22 * software without specific, written prior permission.
\r
24 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
25 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
26 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
27 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
28 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
29 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
31 * ------------------------------------------------------------------------
\r
33 * The following terms apply to the enhanced version of XBoard distributed
\r
34 * by the Free Software Foundation:
\r
35 * ------------------------------------------------------------------------
\r
36 * This program is free software; you can redistribute it and/or modify
\r
37 * it under the terms of the GNU General Public License as published by
\r
38 * the Free Software Foundation; either version 2 of the License, or
\r
39 * (at your option) any later version.
\r
41 * This program is distributed in the hope that it will be useful,
\r
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
44 * GNU General Public License for more details.
\r
46 * You should have received a copy of the GNU General Public License
\r
47 * along with this program; if not, write to the Free Software
\r
48 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
\r
49 * ------------------------------------------------------------------------
\r
54 #include <windows.h>
\r
55 #include <winuser.h>
\r
56 #include <winsock.h>
\r
62 #include <sys/stat.h>
\r
65 #include <commdlg.h>
\r
67 #include <richedit.h>
\r
68 #include <mmsystem.h>
\r
76 #include "winboard.h"
\r
77 #include "frontend.h"
\r
78 #include "backend.h"
\r
80 #include "wclipbrd.h"
\r
81 #include "wgamelist.h"
\r
82 #include "wedittags.h"
\r
83 #include "woptions.h"
\r
84 #include "wsockerr.h"
\r
85 #include "defaults.h"
\r
89 void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
92 void mysrandom(unsigned int seed);
\r
94 extern int whiteFlag, blackFlag;
\r
95 Boolean flipClock = FALSE;
\r
97 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
100 ChessSquare piece;
\r
101 POINT pos; /* window coordinates of current pos */
\r
102 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
103 POINT from; /* board coordinates of the piece's orig pos */
\r
104 POINT to; /* board coordinates of the piece's new pos */
\r
107 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
110 POINT start; /* window coordinates of start pos */
\r
111 POINT pos; /* window coordinates of current pos */
\r
112 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
113 POINT from; /* board coordinates of the piece's orig pos */
\r
116 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
119 POINT sq[2]; /* board coordinates of from, to squares */
\r
122 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
123 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
125 /* Window class names */
\r
126 char szAppName[] = "WinBoard";
\r
127 char szConsoleName[] = "WBConsole";
\r
129 /* Title bar text */
\r
130 char szTitle[] = "WinBoard";
\r
131 char szConsoleTitle[] = "ICS Interaction";
\r
134 char *settingsFileName;
\r
135 BOOLEAN saveSettingsOnExit;
\r
136 char installDir[MSG_SIZ];
\r
138 BoardSize boardSize;
\r
139 BOOLEAN chessProgram;
\r
140 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
141 static int squareSize, lineGap, minorSize;
\r
142 static int winWidth, winHeight;
\r
143 static RECT messageRect, whiteRect, blackRect;
\r
144 static char messageText[MESSAGE_TEXT_MAX];
\r
145 static int clockTimerEvent = 0;
\r
146 static int loadGameTimerEvent = 0;
\r
147 static int analysisTimerEvent = 0;
\r
148 static DelayedEventCallback delayedTimerCallback;
\r
149 static int delayedTimerEvent = 0;
\r
150 static int buttonCount = 2;
\r
151 char *icsTextMenuString;
\r
153 char *firstChessProgramNames;
\r
154 char *secondChessProgramNames;
\r
156 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
158 #define PALETTESIZE 256
\r
160 HINSTANCE hInst; /* current instance */
\r
161 HWND hwndMain = NULL; /* root window*/
\r
162 HWND hwndConsole = NULL;
\r
163 BOOLEAN alwaysOnTop = FALSE;
\r
165 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
166 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
168 ColorClass currentColorClass;
\r
170 HWND hCommPort = NULL; /* currently open comm port */
\r
171 static HWND hwndPause; /* pause button */
\r
172 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
173 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
174 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
175 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
176 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
177 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
178 static HPEN gridPen = NULL;
\r
179 static HPEN highlightPen = NULL;
\r
180 static HPEN premovePen = NULL;
\r
181 static NPLOGPALETTE pLogPal;
\r
182 static BOOL paletteChanged = FALSE;
\r
183 static HICON iconWhite, iconBlack, iconCurrent;
\r
184 static int doingSizing = FALSE;
\r
185 static int lastSizing = 0;
\r
186 static int prevStderrPort;
\r
188 /* [AS] Support for background textures */
\r
189 #define BACK_TEXTURE_MODE_DISABLED 0
\r
190 #define BACK_TEXTURE_MODE_PLAIN 1
\r
191 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
193 static HBITMAP liteBackTexture = NULL;
\r
194 static HBITMAP darkBackTexture = NULL;
\r
195 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
196 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
197 static int backTextureSquareSize = 0;
\r
198 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
200 #if __GNUC__ && !defined(_winmajor)
\r
201 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
203 #define oldDialog (_winmajor < 4)
\r
206 char *defaultTextAttribs[] =
\r
208 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
209 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
219 int cliWidth, cliHeight;
\r
222 SizeInfo sizeInfo[] =
\r
224 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
225 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
226 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
227 { "petite", 33, 1, 1, 1, 0, 0 },
\r
228 { "slim", 37, 2, 1, 0, 0, 0 },
\r
229 { "small", 40, 2, 1, 0, 0, 0 },
\r
230 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
231 { "middling", 49, 2, 0, 0, 0, 0 },
\r
232 { "average", 54, 2, 0, 0, 0, 0 },
\r
233 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
234 { "medium", 64, 3, 0, 0, 0, 0 },
\r
235 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
236 { "large", 80, 3, 0, 0, 0, 0 },
\r
237 { "big", 87, 3, 0, 0, 0, 0 },
\r
238 { "huge", 95, 3, 0, 0, 0, 0 },
\r
239 { "giant", 108, 3, 0, 0, 0, 0 },
\r
240 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
241 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
242 { NULL, 0, 0, 0, 0, 0, 0 }
\r
245 #define MF(x) {x, {0, }, {0, }, 0}
\r
246 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
248 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
249 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
250 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
251 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
252 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
253 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
254 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
255 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
256 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
257 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
258 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
259 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
260 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
261 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
262 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
263 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
264 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
265 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
268 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
277 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
278 #define N_BUTTONS 5
\r
280 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
282 {"<<", IDM_ToStart, NULL, NULL},
\r
283 {"<", IDM_Backward, NULL, NULL},
\r
284 {"P", IDM_Pause, NULL, NULL},
\r
285 {">", IDM_Forward, NULL, NULL},
\r
286 {">>", IDM_ToEnd, NULL, NULL},
\r
289 int tinyLayout = 0, smallLayout = 0;
\r
290 #define MENU_BAR_ITEMS 6
\r
291 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
292 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
293 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
297 MySound sounds[(int)NSoundClasses];
\r
298 MyTextAttribs textAttribs[(int)NColorClasses];
\r
300 MyColorizeAttribs colorizeAttribs[] = {
\r
301 { (COLORREF)0, 0, "Shout Text" },
\r
302 { (COLORREF)0, 0, "SShout/CShout" },
\r
303 { (COLORREF)0, 0, "Channel 1 Text" },
\r
304 { (COLORREF)0, 0, "Channel Text" },
\r
305 { (COLORREF)0, 0, "Kibitz Text" },
\r
306 { (COLORREF)0, 0, "Tell Text" },
\r
307 { (COLORREF)0, 0, "Challenge Text" },
\r
308 { (COLORREF)0, 0, "Request Text" },
\r
309 { (COLORREF)0, 0, "Seek Text" },
\r
310 { (COLORREF)0, 0, "Normal Text" },
\r
311 { (COLORREF)0, 0, "None" }
\r
316 static char *commentTitle;
\r
317 static char *commentText;
\r
318 static int commentIndex;
\r
319 static Boolean editComment = FALSE;
\r
320 HWND commentDialog = NULL;
\r
321 BOOLEAN commentDialogUp = FALSE;
\r
322 static int commentX, commentY, commentH, commentW;
\r
324 static char *analysisTitle;
\r
325 static char *analysisText;
\r
326 HWND analysisDialog = NULL;
\r
327 BOOLEAN analysisDialogUp = FALSE;
\r
328 static int analysisX, analysisY, analysisH, analysisW;
\r
330 char errorTitle[MSG_SIZ];
\r
331 char errorMessage[2*MSG_SIZ];
\r
332 HWND errorDialog = NULL;
\r
333 BOOLEAN moveErrorMessageUp = FALSE;
\r
334 BOOLEAN consoleEcho = TRUE;
\r
335 CHARFORMAT consoleCF;
\r
336 COLORREF consoleBackgroundColor;
\r
338 char *programVersion;
\r
344 typedef int CPKind;
\r
353 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
356 #define INPUT_SOURCE_BUF_SIZE 4096
\r
358 typedef struct _InputSource {
\r
365 char buf[INPUT_SOURCE_BUF_SIZE];
\r
369 InputCallback func;
\r
370 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
374 InputSource *consoleInputSource;
\r
379 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
380 VOID ConsoleCreate();
\r
382 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
383 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
384 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
385 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
387 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
388 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
389 void ParseIcsTextMenu(char *icsTextMenuString);
\r
390 VOID PopUpMoveDialog(char firstchar);
\r
391 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
395 int GameListOptions();
\r
397 HWND moveHistoryDialog = NULL;
\r
398 BOOLEAN moveHistoryDialogUp = FALSE;
\r
400 WindowPlacement wpMoveHistory;
\r
402 HWND evalGraphDialog = NULL;
\r
403 BOOLEAN evalGraphDialogUp = FALSE;
\r
405 WindowPlacement wpEvalGraph;
\r
407 HWND engineOutputDialog = NULL;
\r
408 BOOLEAN engineOutputDialogUp = FALSE;
\r
410 WindowPlacement wpEngineOutput;
\r
412 VOID MoveHistoryPopUp();
\r
413 VOID MoveHistoryPopDown();
\r
414 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
415 BOOL MoveHistoryIsUp();
\r
417 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
418 VOID EvalGraphPopUp();
\r
419 VOID EvalGraphPopDown();
\r
420 BOOL EvalGraphIsUp();
\r
422 VOID EngineOutputPopUp();
\r
423 VOID EngineOutputPopDown();
\r
424 BOOL EngineOutputIsUp();
\r
425 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
427 VOID GothicPopUp(char *title, char up);
\r
429 * Setting "frozen" should disable all user input other than deleting
\r
430 * the window. We do this while engines are initializing themselves.
\r
432 static int frozen = 0;
\r
433 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
439 if (frozen) return;
\r
441 hmenu = GetMenu(hwndMain);
\r
442 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
443 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
445 DrawMenuBar(hwndMain);
\r
448 /* Undo a FreezeUI */
\r
454 if (!frozen) return;
\r
456 hmenu = GetMenu(hwndMain);
\r
457 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
458 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
460 DrawMenuBar(hwndMain);
\r
463 /*---------------------------------------------------------------------------*\
\r
467 \*---------------------------------------------------------------------------*/
\r
470 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
471 LPSTR lpCmdLine, int nCmdShow)
\r
474 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
478 LoadLibrary("RICHED32.DLL");
\r
479 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
481 if (!InitApplication(hInstance)) {
\r
484 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
488 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
489 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
490 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
492 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
494 while (GetMessage(&msg, /* message structure */
\r
495 NULL, /* handle of window receiving the message */
\r
496 0, /* lowest message to examine */
\r
497 0)) /* highest message to examine */
\r
499 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
500 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
501 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
502 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
503 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
504 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
505 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
506 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
507 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
508 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
509 TranslateMessage(&msg); /* Translates virtual key codes */
\r
510 DispatchMessage(&msg); /* Dispatches message to window */
\r
515 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
518 /*---------------------------------------------------------------------------*\
\r
520 * Initialization functions
\r
522 \*---------------------------------------------------------------------------*/
\r
525 InitApplication(HINSTANCE hInstance)
\r
529 /* Fill in window class structure with parameters that describe the */
\r
532 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
533 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
534 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
535 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
536 wc.hInstance = hInstance; /* Owner of this class */
\r
537 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
538 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
539 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
540 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
541 wc.lpszClassName = szAppName; /* Name to register as */
\r
543 /* Register the window class and return success/failure code. */
\r
544 if (!RegisterClass(&wc)) return FALSE;
\r
546 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
547 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
549 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
550 wc.hInstance = hInstance;
\r
551 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
552 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
553 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
554 wc.lpszMenuName = NULL;
\r
555 wc.lpszClassName = szConsoleName;
\r
557 if (!RegisterClass(&wc)) return FALSE;
\r
562 /* Set by InitInstance, used by EnsureOnScreen */
\r
563 int screenHeight, screenWidth;
\r
566 EnsureOnScreen(int *x, int *y)
\r
568 int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
569 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
570 if (*x > screenWidth - 32) *x = 0;
\r
571 if (*y > screenHeight - 32) *y = 0;
\r
572 if (*x < 10) *x = 10;
\r
573 if (*y < gap) *y = gap;
\r
577 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
579 HWND hwnd; /* Main window handle. */
\r
581 WINDOWPLACEMENT wp;
\r
584 hInst = hInstance; /* Store instance handle in our global variable */
\r
586 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
587 *filepart = NULLCHAR;
\r
589 GetCurrentDirectory(MSG_SIZ, installDir);
\r
591 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
592 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
593 if (appData.debugMode) {
\r
594 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
595 setbuf(debugFP, NULL);
\r
600 InitEngineUCI( installDir, &first );
\r
601 InitEngineUCI( installDir, &second );
\r
603 /* Create a main window for this application instance. */
\r
604 hwnd = CreateWindow(szAppName, szTitle,
\r
605 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
606 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
607 NULL, NULL, hInstance, NULL);
\r
610 /* If window could not be created, return "failure" */
\r
615 iconWhite = LoadIcon(hInstance, "icon_white");
\r
616 iconBlack = LoadIcon(hInstance, "icon_black");
\r
617 iconCurrent = iconWhite;
\r
618 InitDrawingColors();
\r
619 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
620 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
621 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
622 /* Compute window size for each board size, and use the largest
\r
623 size that fits on this screen as the default. */
\r
624 InitDrawingSizes((BoardSize)ibs, 0);
\r
625 if (boardSize == (BoardSize)-1 &&
\r
626 winHeight <= screenHeight
\r
627 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
628 && winWidth <= screenWidth) {
\r
629 boardSize = (BoardSize)ibs;
\r
632 InitDrawingSizes(boardSize, 0);
\r
634 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
636 /* [AS] Load textures if specified */
\r
637 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
639 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
640 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
641 liteBackTextureMode = appData.liteBackTextureMode;
\r
643 if (liteBackTexture == NULL && appData.debugMode) {
\r
644 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
648 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
649 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
650 darkBackTextureMode = appData.darkBackTextureMode;
\r
652 if (darkBackTexture == NULL && appData.debugMode) {
\r
653 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
657 mysrandom( (unsigned) time(NULL) );
\r
659 /* Make a console window if needed */
\r
660 if (appData.icsActive) {
\r
664 /* [AS] Restore layout */
\r
665 if( wpMoveHistory.visible ) {
\r
666 MoveHistoryPopUp();
\r
669 if( wpEvalGraph.visible ) {
\r
673 if( wpEngineOutput.visible ) {
\r
674 EngineOutputPopUp();
\r
679 /* Make the window visible; update its client area; and return "success" */
\r
680 EnsureOnScreen(&boardX, &boardY);
\r
681 wp.length = sizeof(WINDOWPLACEMENT);
\r
683 wp.showCmd = nCmdShow;
\r
684 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
685 wp.rcNormalPosition.left = boardX;
\r
686 wp.rcNormalPosition.right = boardX + winWidth;
\r
687 wp.rcNormalPosition.top = boardY;
\r
688 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
689 SetWindowPlacement(hwndMain, &wp);
\r
691 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
692 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
694 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
695 if( gameInfo.variant != VariantFischeRandom ) {
\r
696 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
701 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
702 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
704 ShowWindow(hwndConsole, nCmdShow);
\r
706 UpdateWindow(hwnd);
\r
714 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
715 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
716 ArgSettingsFilename
\r
724 String *pString; // ArgString
\r
725 int *pInt; // ArgInt
\r
726 float *pFloat; // ArgFloat
\r
727 Boolean *pBoolean; // ArgBoolean
\r
728 COLORREF *pColor; // ArgColor
\r
729 ColorClass cc; // ArgAttribs
\r
730 String *pFilename; // ArgFilename
\r
731 BoardSize *pBoardSize; // ArgBoardSize
\r
732 int whichFont; // ArgFont
\r
733 DCB *pDCB; // ArgCommSettings
\r
734 String *pFilename; // ArgSettingsFilename
\r
742 ArgDescriptor argDescriptors[] = {
\r
743 /* positional arguments */
\r
744 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
745 { "", ArgNone, NULL },
\r
746 /* keyword arguments */
\r
747 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
748 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
749 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
750 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
751 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
752 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
753 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
754 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
755 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
756 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
757 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
758 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
759 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
760 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
761 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
762 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
763 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
764 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
766 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
768 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
770 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
771 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
773 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
774 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
775 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
776 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
777 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
778 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
779 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
780 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
781 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
782 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
783 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
784 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
785 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
786 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
787 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
788 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
789 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
790 /*!!bitmapDirectory?*/
\r
791 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
792 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
793 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
794 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
795 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
796 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
797 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
798 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
799 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
800 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
801 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
802 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
803 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
804 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
805 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
806 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
807 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
808 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
809 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
810 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
811 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
812 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
813 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
814 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
815 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
816 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
817 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
818 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
819 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
820 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
821 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
822 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
823 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
824 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
825 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
826 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
827 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
828 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
829 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
830 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
831 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
832 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
833 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
834 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
835 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
836 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
837 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
838 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
839 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
840 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
841 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
842 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
843 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
844 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
845 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
846 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
847 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
848 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
849 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
850 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
851 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
852 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
853 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
854 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
855 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
856 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
857 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
858 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
859 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
860 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
861 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
862 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
863 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
864 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
865 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
866 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
867 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
868 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
869 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
870 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
871 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
872 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
873 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
874 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
875 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
876 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
877 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
878 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
879 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
880 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
881 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
882 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
883 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
884 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
885 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
886 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
887 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
888 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
889 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
890 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
891 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
892 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
893 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
894 TRUE }, /* must come after all fonts */
\r
895 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
896 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
897 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
898 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
899 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
900 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
901 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
902 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
903 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
904 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
905 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
906 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
907 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
908 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
909 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
910 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
911 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
912 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
913 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
914 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
915 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
916 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
917 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
918 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
919 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
920 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
921 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
922 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
923 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
924 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
925 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
927 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
928 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
930 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
931 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
932 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
933 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
934 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
935 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
936 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
937 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
938 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
939 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
940 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
941 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
942 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
943 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
944 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
945 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
946 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
947 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
948 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
949 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
950 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
951 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
952 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
953 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
954 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
955 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
956 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
957 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
958 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
959 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
960 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
961 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
962 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
963 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
964 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
965 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
966 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
967 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
968 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
969 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
970 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
971 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
972 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
973 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
974 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
975 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
976 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
977 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
978 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
979 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
980 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
981 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
982 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
983 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
984 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
985 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
986 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
987 { "highlightLastMove", ArgBoolean,
\r
988 (LPVOID) &appData.highlightLastMove, TRUE },
\r
989 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
990 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
991 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
992 { "highlightDragging", ArgBoolean,
\r
993 (LPVOID) &appData.highlightDragging, TRUE },
\r
994 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
995 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
996 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
997 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
998 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
999 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1000 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1001 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1002 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1003 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1004 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1005 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1006 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1007 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1008 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1009 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1010 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1011 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1012 { "soundShout", ArgFilename,
\r
1013 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1014 { "soundSShout", ArgFilename,
\r
1015 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1016 { "soundChannel1", ArgFilename,
\r
1017 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1018 { "soundChannel", ArgFilename,
\r
1019 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1020 { "soundKibitz", ArgFilename,
\r
1021 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1022 { "soundTell", ArgFilename,
\r
1023 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1024 { "soundChallenge", ArgFilename,
\r
1025 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1026 { "soundRequest", ArgFilename,
\r
1027 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1028 { "soundSeek", ArgFilename,
\r
1029 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1030 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1031 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1032 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1033 { "soundIcsLoss", ArgFilename,
\r
1034 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1035 { "soundIcsDraw", ArgFilename,
\r
1036 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1037 { "soundIcsUnfinished", ArgFilename,
\r
1038 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1039 { "soundIcsAlarm", ArgFilename,
\r
1040 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1041 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1042 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1043 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1044 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1045 { "reuseChessPrograms", ArgBoolean,
\r
1046 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1047 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1048 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1049 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1050 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1051 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1052 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1053 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1054 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1055 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1056 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1057 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1058 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1059 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1060 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1061 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1062 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1063 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1064 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1065 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1066 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1067 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1068 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1069 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1070 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1071 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1072 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1073 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1074 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1075 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1076 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1077 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1078 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1079 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1080 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1081 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1082 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1083 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1085 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1087 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1088 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1089 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1090 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1091 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1092 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1093 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1094 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1095 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1096 /* [AS] New features */
\r
1097 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1098 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1099 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1100 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1101 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1102 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1103 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1104 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1105 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1106 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1107 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1108 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1109 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1110 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1111 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1112 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1113 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1114 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1115 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1116 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1117 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1118 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1119 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1120 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1121 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1122 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1123 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1124 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1125 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1126 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1127 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1128 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1129 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1130 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1131 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1132 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1133 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1134 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1135 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1136 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1137 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1138 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1139 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1140 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1141 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1142 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1143 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1144 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1146 /* [AS] Layout stuff */
\r
1147 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1148 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1149 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1150 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1151 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1153 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1154 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1155 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1156 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1157 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1159 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1160 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1161 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1162 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1163 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1165 /* [HGM] board-size, adjudication and misc. options */
\r
1166 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1167 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1168 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1169 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1170 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1171 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1172 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1173 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1174 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1175 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1176 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1177 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1178 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1179 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1182 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1183 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1184 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1185 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1186 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1187 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1188 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1189 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1190 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1191 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1192 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1193 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1194 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1196 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1197 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1198 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1199 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1200 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1201 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1202 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1204 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1205 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1206 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1207 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1208 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1209 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1210 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1211 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1212 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1213 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1214 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1215 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1216 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1217 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1218 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1219 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1220 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1221 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1223 { NULL, ArgNone, NULL, FALSE }
\r
1227 /* Kludge for indirection files on command line */
\r
1228 char* lastIndirectionFilename;
\r
1229 ArgDescriptor argDescriptorIndirection =
\r
1230 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1234 ExitArgError(char *msg, char *badArg)
\r
1236 char buf[MSG_SIZ];
\r
1238 sprintf(buf, "%s %s", msg, badArg);
\r
1239 DisplayFatalError(buf, 0, 2);
\r
1243 /* Command line font name parser. NULL name means do nothing.
\r
1244 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1245 For backward compatibility, syntax without the colon is also
\r
1246 accepted, but font names with digits in them won't work in that case.
\r
1249 ParseFontName(char *name, MyFontParams *mfp)
\r
1252 if (name == NULL) return;
\r
1254 q = strchr(p, ':');
\r
1256 if (q - p >= sizeof(mfp->faceName))
\r
1257 ExitArgError("Font name too long:", name);
\r
1258 memcpy(mfp->faceName, p, q - p);
\r
1259 mfp->faceName[q - p] = NULLCHAR;
\r
1262 q = mfp->faceName;
\r
1263 while (*p && !isdigit(*p)) {
\r
1265 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1266 ExitArgError("Font name too long:", name);
\r
1268 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1271 if (!*p) ExitArgError("Font point size missing:", name);
\r
1272 mfp->pointSize = (float) atof(p);
\r
1273 mfp->bold = (strchr(p, 'b') != NULL);
\r
1274 mfp->italic = (strchr(p, 'i') != NULL);
\r
1275 mfp->underline = (strchr(p, 'u') != NULL);
\r
1276 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1279 /* Color name parser.
\r
1280 X version accepts X color names, but this one
\r
1281 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1283 ParseColorName(char *name)
\r
1285 int red, green, blue, count;
\r
1286 char buf[MSG_SIZ];
\r
1288 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1290 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1291 &red, &green, &blue);
\r
1294 sprintf(buf, "Can't parse color name %s", name);
\r
1295 DisplayError(buf, 0);
\r
1296 return RGB(0, 0, 0);
\r
1298 return PALETTERGB(red, green, blue);
\r
1302 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1304 char *e = argValue;
\r
1308 if (*e == 'b') eff |= CFE_BOLD;
\r
1309 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1310 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1311 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1312 else if (*e == '#' || isdigit(*e)) break;
\r
1316 *color = ParseColorName(e);
\r
1321 ParseBoardSize(char *name)
\r
1323 BoardSize bs = SizeTiny;
\r
1324 while (sizeInfo[bs].name != NULL) {
\r
1325 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1328 ExitArgError("Unrecognized board size value", name);
\r
1329 return bs; /* not reached */
\r
1334 StringGet(void *getClosure)
\r
1336 char **p = (char **) getClosure;
\r
1341 FileGet(void *getClosure)
\r
1344 FILE* f = (FILE*) getClosure;
\r
1353 /* Parse settings file named "name". If file found, return the
\r
1354 full name in fullname and return TRUE; else return FALSE */
\r
1356 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1361 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1362 f = fopen(fullname, "r");
\r
1364 ParseArgs(FileGet, f);
\r
1373 ParseArgs(GetFunc get, void *cl)
\r
1375 char argName[ARG_MAX];
\r
1376 char argValue[ARG_MAX];
\r
1377 ArgDescriptor *ad;
\r
1386 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1387 if (ch == NULLCHAR) break;
\r
1389 /* Comment to end of line */
\r
1391 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1393 } else if (ch == '/' || ch == '-') {
\r
1396 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1397 ch != '\n' && ch != '\t') {
\r
1403 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1404 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1406 if (ad->argName == NULL)
\r
1407 ExitArgError("Unrecognized argument", argName);
\r
1409 } else if (ch == '@') {
\r
1410 /* Indirection file */
\r
1411 ad = &argDescriptorIndirection;
\r
1414 /* Positional argument */
\r
1415 ad = &argDescriptors[posarg++];
\r
1416 strcpy(argName, ad->argName);
\r
1419 if (ad->argType == ArgTrue) {
\r
1420 *(Boolean *) ad->argLoc = TRUE;
\r
1423 if (ad->argType == ArgFalse) {
\r
1424 *(Boolean *) ad->argLoc = FALSE;
\r
1428 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1429 if (ch == NULLCHAR || ch == '\n') {
\r
1430 ExitArgError("No value provided for argument", argName);
\r
1434 // Quoting with { }. No characters have to (or can) be escaped.
\r
1435 // Thus the string cannot contain a '}' character.
\r
1455 } else if (ch == '\'' || ch == '"') {
\r
1456 // Quoting with ' ' or " ", with \ as escape character.
\r
1457 // Inconvenient for long strings that may contain Windows filenames.
\r
1474 if (ch == start) {
\r
1483 if (ad->argType == ArgFilename
\r
1484 || ad->argType == ArgSettingsFilename) {
\r
1490 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1514 for (i = 0; i < 3; i++) {
\r
1515 if (ch >= '0' && ch <= '7') {
\r
1516 octval = octval*8 + (ch - '0');
\r
1523 *q++ = (char) octval;
\r
1534 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1541 switch (ad->argType) {
\r
1543 *(int *) ad->argLoc = atoi(argValue);
\r
1547 *(float *) ad->argLoc = (float) atof(argValue);
\r
1552 *(char **) ad->argLoc = strdup(argValue);
\r
1555 case ArgSettingsFilename:
\r
1557 char fullname[MSG_SIZ];
\r
1558 if (ParseSettingsFile(argValue, fullname)) {
\r
1559 if (ad->argLoc != NULL) {
\r
1560 *(char **) ad->argLoc = strdup(fullname);
\r
1563 if (ad->argLoc != NULL) {
\r
1565 ExitArgError("Failed to open indirection file", argValue);
\r
1572 switch (argValue[0]) {
\r
1575 *(Boolean *) ad->argLoc = TRUE;
\r
1579 *(Boolean *) ad->argLoc = FALSE;
\r
1582 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1588 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1591 case ArgAttribs: {
\r
1592 ColorClass cc = (ColorClass)ad->argLoc;
\r
1593 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1597 case ArgBoardSize:
\r
1598 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1602 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1605 case ArgCommSettings:
\r
1606 ParseCommSettings(argValue, &dcb);
\r
1610 ExitArgError("Unrecognized argument", argValue);
\r
1617 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1619 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1620 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1623 lf->lfEscapement = 0;
\r
1624 lf->lfOrientation = 0;
\r
1625 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1626 lf->lfItalic = mfp->italic;
\r
1627 lf->lfUnderline = mfp->underline;
\r
1628 lf->lfStrikeOut = mfp->strikeout;
\r
1629 lf->lfCharSet = DEFAULT_CHARSET;
\r
1630 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1631 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1632 lf->lfQuality = DEFAULT_QUALITY;
\r
1633 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1634 strcpy(lf->lfFaceName, mfp->faceName);
\r
1638 CreateFontInMF(MyFont *mf)
\r
1640 LFfromMFP(&mf->lf, &mf->mfp);
\r
1641 if (mf->hf) DeleteObject(mf->hf);
\r
1642 mf->hf = CreateFontIndirect(&mf->lf);
\r
1646 SetDefaultTextAttribs()
\r
1649 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1650 ParseAttribs(&textAttribs[cc].color,
\r
1651 &textAttribs[cc].effects,
\r
1652 defaultTextAttribs[cc]);
\r
1657 SetDefaultSounds()
\r
1661 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1662 textAttribs[cc].sound.name = strdup("");
\r
1663 textAttribs[cc].sound.data = NULL;
\r
1665 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1666 sounds[sc].name = strdup("");
\r
1667 sounds[sc].data = NULL;
\r
1669 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1677 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1678 MyLoadSound(&textAttribs[cc].sound);
\r
1680 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1681 MyLoadSound(&sounds[sc]);
\r
1686 InitAppData(LPSTR lpCmdLine)
\r
1689 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1692 programName = szAppName;
\r
1694 /* Initialize to defaults */
\r
1695 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1696 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1697 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1698 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1699 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1700 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1701 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1702 SetDefaultTextAttribs();
\r
1703 SetDefaultSounds();
\r
1704 appData.movesPerSession = MOVES_PER_SESSION;
\r
1705 appData.initString = INIT_STRING;
\r
1706 appData.secondInitString = INIT_STRING;
\r
1707 appData.firstComputerString = COMPUTER_STRING;
\r
1708 appData.secondComputerString = COMPUTER_STRING;
\r
1709 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1710 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1711 appData.firstPlaysBlack = FALSE;
\r
1712 appData.noChessProgram = FALSE;
\r
1713 chessProgram = FALSE;
\r
1714 appData.firstHost = FIRST_HOST;
\r
1715 appData.secondHost = SECOND_HOST;
\r
1716 appData.firstDirectory = FIRST_DIRECTORY;
\r
1717 appData.secondDirectory = SECOND_DIRECTORY;
\r
1718 appData.bitmapDirectory = "";
\r
1719 appData.remoteShell = REMOTE_SHELL;
\r
1720 appData.remoteUser = "";
\r
1721 appData.timeDelay = TIME_DELAY;
\r
1722 appData.timeControl = TIME_CONTROL;
\r
1723 appData.timeIncrement = TIME_INCREMENT;
\r
1724 appData.icsActive = FALSE;
\r
1725 appData.icsHost = "";
\r
1726 appData.icsPort = ICS_PORT;
\r
1727 appData.icsCommPort = ICS_COMM_PORT;
\r
1728 appData.icsLogon = ICS_LOGON;
\r
1729 appData.icsHelper = "";
\r
1730 appData.useTelnet = FALSE;
\r
1731 appData.telnetProgram = TELNET_PROGRAM;
\r
1732 appData.gateway = "";
\r
1733 appData.loadGameFile = "";
\r
1734 appData.loadGameIndex = 0;
\r
1735 appData.saveGameFile = "";
\r
1736 appData.autoSaveGames = FALSE;
\r
1737 appData.loadPositionFile = "";
\r
1738 appData.loadPositionIndex = 1;
\r
1739 appData.savePositionFile = "";
\r
1740 appData.matchMode = FALSE;
\r
1741 appData.matchGames = 0;
\r
1742 appData.monoMode = FALSE;
\r
1743 appData.debugMode = FALSE;
\r
1744 appData.clockMode = TRUE;
\r
1745 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1746 appData.Iconic = FALSE; /*unused*/
\r
1747 appData.searchTime = "";
\r
1748 appData.searchDepth = 0;
\r
1749 appData.showCoords = FALSE;
\r
1750 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1751 appData.autoCallFlag = FALSE;
\r
1752 appData.flipView = FALSE;
\r
1753 appData.autoFlipView = TRUE;
\r
1754 appData.cmailGameName = "";
\r
1755 appData.alwaysPromoteToQueen = FALSE;
\r
1756 appData.oldSaveStyle = FALSE;
\r
1757 appData.quietPlay = FALSE;
\r
1758 appData.showThinking = FALSE;
\r
1759 appData.ponderNextMove = TRUE;
\r
1760 appData.periodicUpdates = TRUE;
\r
1761 appData.popupExitMessage = TRUE;
\r
1762 appData.popupMoveErrors = FALSE;
\r
1763 appData.autoObserve = FALSE;
\r
1764 appData.autoComment = FALSE;
\r
1765 appData.animate = TRUE;
\r
1766 appData.animSpeed = 10;
\r
1767 appData.animateDragging = TRUE;
\r
1768 appData.highlightLastMove = TRUE;
\r
1769 appData.getMoveList = TRUE;
\r
1770 appData.testLegality = TRUE;
\r
1771 appData.premove = TRUE;
\r
1772 appData.premoveWhite = FALSE;
\r
1773 appData.premoveWhiteText = "";
\r
1774 appData.premoveBlack = FALSE;
\r
1775 appData.premoveBlackText = "";
\r
1776 appData.icsAlarm = TRUE;
\r
1777 appData.icsAlarmTime = 5000;
\r
1778 appData.autoRaiseBoard = TRUE;
\r
1779 appData.localLineEditing = TRUE;
\r
1780 appData.colorize = TRUE;
\r
1781 appData.reuseFirst = TRUE;
\r
1782 appData.reuseSecond = TRUE;
\r
1783 appData.blindfold = FALSE;
\r
1784 dcb.DCBlength = sizeof(DCB);
\r
1785 dcb.BaudRate = 9600;
\r
1786 dcb.fBinary = TRUE;
\r
1787 dcb.fParity = FALSE;
\r
1788 dcb.fOutxCtsFlow = FALSE;
\r
1789 dcb.fOutxDsrFlow = FALSE;
\r
1790 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1791 dcb.fDsrSensitivity = FALSE;
\r
1792 dcb.fTXContinueOnXoff = TRUE;
\r
1793 dcb.fOutX = FALSE;
\r
1795 dcb.fNull = FALSE;
\r
1796 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1797 dcb.fAbortOnError = FALSE;
\r
1798 dcb.wReserved = 0;
\r
1800 dcb.Parity = SPACEPARITY;
\r
1801 dcb.StopBits = ONESTOPBIT;
\r
1802 settingsFileName = SETTINGS_FILE;
\r
1803 saveSettingsOnExit = TRUE;
\r
1804 boardX = CW_USEDEFAULT;
\r
1805 boardY = CW_USEDEFAULT;
\r
1806 consoleX = CW_USEDEFAULT;
\r
1807 consoleY = CW_USEDEFAULT;
\r
1808 consoleW = CW_USEDEFAULT;
\r
1809 consoleH = CW_USEDEFAULT;
\r
1810 analysisX = CW_USEDEFAULT;
\r
1811 analysisY = CW_USEDEFAULT;
\r
1812 analysisW = CW_USEDEFAULT;
\r
1813 analysisH = CW_USEDEFAULT;
\r
1814 commentX = CW_USEDEFAULT;
\r
1815 commentY = CW_USEDEFAULT;
\r
1816 commentW = CW_USEDEFAULT;
\r
1817 commentH = CW_USEDEFAULT;
\r
1818 editTagsX = CW_USEDEFAULT;
\r
1819 editTagsY = CW_USEDEFAULT;
\r
1820 editTagsW = CW_USEDEFAULT;
\r
1821 editTagsH = CW_USEDEFAULT;
\r
1822 gameListX = CW_USEDEFAULT;
\r
1823 gameListY = CW_USEDEFAULT;
\r
1824 gameListW = CW_USEDEFAULT;
\r
1825 gameListH = CW_USEDEFAULT;
\r
1826 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1827 icsNames = ICS_NAMES;
\r
1828 firstChessProgramNames = FCP_NAMES;
\r
1829 secondChessProgramNames = SCP_NAMES;
\r
1830 appData.initialMode = "";
\r
1831 appData.variant = "normal";
\r
1832 appData.firstProtocolVersion = PROTOVER;
\r
1833 appData.secondProtocolVersion = PROTOVER;
\r
1834 appData.showButtonBar = TRUE;
\r
1836 /* [AS] New properties (see comments in header file) */
\r
1837 appData.firstScoreIsAbsolute = FALSE;
\r
1838 appData.secondScoreIsAbsolute = FALSE;
\r
1839 appData.saveExtendedInfoInPGN = FALSE;
\r
1840 appData.hideThinkingFromHuman = FALSE;
\r
1841 appData.liteBackTextureFile = "";
\r
1842 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1843 appData.darkBackTextureFile = "";
\r
1844 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1845 appData.renderPiecesWithFont = "";
\r
1846 appData.fontToPieceTable = "";
\r
1847 appData.fontBackColorWhite = 0;
\r
1848 appData.fontForeColorWhite = 0;
\r
1849 appData.fontBackColorBlack = 0;
\r
1850 appData.fontForeColorBlack = 0;
\r
1851 appData.fontPieceSize = 80;
\r
1852 appData.overrideLineGap = 1;
\r
1853 appData.adjudicateLossThreshold = 0;
\r
1854 appData.delayBeforeQuit = 0;
\r
1855 appData.delayAfterQuit = 0;
\r
1856 appData.nameOfDebugFile = "winboard.debug";
\r
1857 appData.pgnEventHeader = "Computer Chess Game";
\r
1858 appData.defaultFrcPosition = -1;
\r
1859 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1860 appData.saveOutOfBookInfo = TRUE;
\r
1861 appData.showEvalInMoveHistory = TRUE;
\r
1862 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1863 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1864 appData.highlightMoveWithArrow = FALSE;
\r
1865 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1866 appData.useStickyWindows = TRUE;
\r
1867 appData.adjudicateDrawMoves = 0;
\r
1868 appData.autoDisplayComment = TRUE;
\r
1869 appData.autoDisplayTags = TRUE;
\r
1870 appData.firstIsUCI = FALSE;
\r
1871 appData.secondIsUCI = FALSE;
\r
1872 appData.firstHasOwnBookUCI = TRUE;
\r
1873 appData.secondHasOwnBookUCI = TRUE;
\r
1874 appData.polyglotDir = "";
\r
1875 appData.usePolyglotBook = FALSE;
\r
1876 appData.polyglotBook = "";
\r
1877 appData.defaultHashSize = 64;
\r
1878 appData.defaultCacheSizeEGTB = 4;
\r
1879 appData.defaultPathEGTB = "c:\\egtb";
\r
1881 InitWindowPlacement( &wpMoveHistory );
\r
1882 InitWindowPlacement( &wpEvalGraph );
\r
1883 InitWindowPlacement( &wpEngineOutput );
\r
1885 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1886 appData.NrFiles = -1;
\r
1887 appData.NrRanks = -1;
\r
1888 appData.holdingsSize = -1;
\r
1889 appData.testClaims = FALSE;
\r
1890 appData.checkMates = FALSE;
\r
1891 appData.materialDraws= FALSE;
\r
1892 appData.trivialDraws = FALSE;
\r
1893 appData.ruleMoves = 51;
\r
1894 appData.drawRepeats = 6;
\r
1895 appData.matchPause = 10000;
\r
1896 appData.alphaRank = FALSE;
\r
1897 appData.allWhite = FALSE;
\r
1898 appData.upsideDown = FALSE;
\r
1901 appData.zippyTalk = ZIPPY_TALK;
\r
1902 appData.zippyPlay = ZIPPY_PLAY;
\r
1903 appData.zippyLines = ZIPPY_LINES;
\r
1904 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1905 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1906 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1907 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1908 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1909 appData.zippyUseI = ZIPPY_USE_I;
\r
1910 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1911 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1912 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1913 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1914 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1915 appData.zippyAbort = ZIPPY_ABORT;
\r
1916 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1917 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1918 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1921 /* Point font array elements to structures and
\r
1922 parse default font names */
\r
1923 for (i=0; i<NUM_FONTS; i++) {
\r
1924 for (j=0; j<NUM_SIZES; j++) {
\r
1925 font[j][i] = &fontRec[j][i];
\r
1926 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1930 /* Parse default settings file if any */
\r
1931 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1932 settingsFileName = strdup(buf);
\r
1935 /* Parse command line */
\r
1936 ParseArgs(StringGet, &lpCmdLine);
\r
1938 /* [HGM] make sure board size is acceptable */
\r
1939 if(appData.NrFiles > BOARD_SIZE ||
\r
1940 appData.NrRanks > BOARD_SIZE )
\r
1941 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
1943 /* Propagate options that affect others */
\r
1944 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1945 if (appData.icsActive || appData.noChessProgram) {
\r
1946 chessProgram = FALSE; /* not local chess program mode */
\r
1949 /* Open startup dialog if needed */
\r
1950 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1951 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1952 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1953 *appData.secondChessProgram == NULLCHAR))) {
\r
1956 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1957 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1958 FreeProcInstance(lpProc);
\r
1961 /* Make sure save files land in the right (?) directory */
\r
1962 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1963 appData.saveGameFile = strdup(buf);
\r
1965 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1966 appData.savePositionFile = strdup(buf);
\r
1969 /* Finish initialization for fonts and sounds */
\r
1970 for (i=0; i<NUM_FONTS; i++) {
\r
1971 for (j=0; j<NUM_SIZES; j++) {
\r
1972 CreateFontInMF(font[j][i]);
\r
1975 /* xboard, and older WinBoards, controlled the move sound with the
\r
1976 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1977 always turn the option on (so that the backend will call us),
\r
1978 then let the user turn the sound off by setting it to silence if
\r
1979 desired. To accommodate old winboard.ini files saved by old
\r
1980 versions of WinBoard, we also turn off the sound if the option
\r
1981 was initially set to false. */
\r
1982 if (!appData.ringBellAfterMoves) {
\r
1983 sounds[(int)SoundMove].name = strdup("");
\r
1984 appData.ringBellAfterMoves = TRUE;
\r
1986 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1987 SetCurrentDirectory(installDir);
\r
1989 SetCurrentDirectory(currDir);
\r
1991 p = icsTextMenuString;
\r
1992 if (p[0] == '@') {
\r
1993 FILE* f = fopen(p + 1, "r");
\r
1995 DisplayFatalError(p + 1, errno, 2);
\r
1998 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2000 buf[i] = NULLCHAR;
\r
2003 ParseIcsTextMenu(strdup(p));
\r
2010 HMENU hmenu = GetMenu(hwndMain);
\r
2012 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2013 MF_BYCOMMAND|((appData.icsActive &&
\r
2014 *appData.icsCommPort != NULLCHAR) ?
\r
2015 MF_ENABLED : MF_GRAYED));
\r
2016 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2017 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2018 MF_CHECKED : MF_UNCHECKED));
\r
2023 SaveSettings(char* name)
\r
2026 ArgDescriptor *ad;
\r
2027 WINDOWPLACEMENT wp;
\r
2028 char dir[MSG_SIZ];
\r
2030 if (!hwndMain) return;
\r
2032 GetCurrentDirectory(MSG_SIZ, dir);
\r
2033 SetCurrentDirectory(installDir);
\r
2034 f = fopen(name, "w");
\r
2035 SetCurrentDirectory(dir);
\r
2037 DisplayError(name, errno);
\r
2040 fprintf(f, ";\n");
\r
2041 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2042 fprintf(f, ";\n");
\r
2043 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2044 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2045 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2046 fprintf(f, ";\n");
\r
2048 wp.length = sizeof(WINDOWPLACEMENT);
\r
2049 GetWindowPlacement(hwndMain, &wp);
\r
2050 boardX = wp.rcNormalPosition.left;
\r
2051 boardY = wp.rcNormalPosition.top;
\r
2053 if (hwndConsole) {
\r
2054 GetWindowPlacement(hwndConsole, &wp);
\r
2055 consoleX = wp.rcNormalPosition.left;
\r
2056 consoleY = wp.rcNormalPosition.top;
\r
2057 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2058 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2061 if (analysisDialog) {
\r
2062 GetWindowPlacement(analysisDialog, &wp);
\r
2063 analysisX = wp.rcNormalPosition.left;
\r
2064 analysisY = wp.rcNormalPosition.top;
\r
2065 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2066 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2069 if (commentDialog) {
\r
2070 GetWindowPlacement(commentDialog, &wp);
\r
2071 commentX = wp.rcNormalPosition.left;
\r
2072 commentY = wp.rcNormalPosition.top;
\r
2073 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2074 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2077 if (editTagsDialog) {
\r
2078 GetWindowPlacement(editTagsDialog, &wp);
\r
2079 editTagsX = wp.rcNormalPosition.left;
\r
2080 editTagsY = wp.rcNormalPosition.top;
\r
2081 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2082 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2085 if (gameListDialog) {
\r
2086 GetWindowPlacement(gameListDialog, &wp);
\r
2087 gameListX = wp.rcNormalPosition.left;
\r
2088 gameListY = wp.rcNormalPosition.top;
\r
2089 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2090 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2093 /* [AS] Move history */
\r
2094 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2096 if( moveHistoryDialog ) {
\r
2097 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2098 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2099 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2100 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2101 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2104 /* [AS] Eval graph */
\r
2105 wpEvalGraph.visible = EvalGraphIsUp();
\r
2107 if( evalGraphDialog ) {
\r
2108 GetWindowPlacement(evalGraphDialog, &wp);
\r
2109 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2110 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2111 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2112 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2115 /* [AS] Engine output */
\r
2116 wpEngineOutput.visible = EngineOutputIsUp();
\r
2118 if( engineOutputDialog ) {
\r
2119 GetWindowPlacement(engineOutputDialog, &wp);
\r
2120 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2121 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2122 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2123 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2126 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2127 if (!ad->save) continue;
\r
2128 switch (ad->argType) {
\r
2131 char *p = *(char **)ad->argLoc;
\r
2132 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2133 /* Quote multiline values or \-containing values
\r
2134 with { } if possible */
\r
2135 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2137 /* Else quote with " " */
\r
2138 fprintf(f, "/%s=\"", ad->argName);
\r
2140 if (*p == '\n') fprintf(f, "\n");
\r
2141 else if (*p == '\r') fprintf(f, "\\r");
\r
2142 else if (*p == '\t') fprintf(f, "\\t");
\r
2143 else if (*p == '\b') fprintf(f, "\\b");
\r
2144 else if (*p == '\f') fprintf(f, "\\f");
\r
2145 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2146 else if (*p == '\"') fprintf(f, "\\\"");
\r
2147 else if (*p == '\\') fprintf(f, "\\\\");
\r
2151 fprintf(f, "\"\n");
\r
2156 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2159 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2162 fprintf(f, "/%s=%s\n", ad->argName,
\r
2163 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2166 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2169 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2173 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2174 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2175 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2180 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2181 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2182 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2183 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2184 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2185 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2186 (ta->effects) ? " " : "",
\r
2187 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2191 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2192 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2194 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2197 case ArgBoardSize:
\r
2198 fprintf(f, "/%s=%s\n", ad->argName,
\r
2199 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2204 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2205 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2206 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2207 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2208 ad->argName, mfp->faceName, mfp->pointSize,
\r
2209 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2210 mfp->bold ? "b" : "",
\r
2211 mfp->italic ? "i" : "",
\r
2212 mfp->underline ? "u" : "",
\r
2213 mfp->strikeout ? "s" : "");
\r
2217 case ArgCommSettings:
\r
2218 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2226 /*---------------------------------------------------------------------------*\
\r
2228 * GDI board drawing routines
\r
2230 \*---------------------------------------------------------------------------*/
\r
2232 /* [AS] Draw square using background texture */
\r
2233 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2238 return; /* Should never happen! */
\r
2241 SetGraphicsMode( dst, GM_ADVANCED );
\r
2248 /* X reflection */
\r
2253 x.eDx = (FLOAT) dw + dx - 1;
\r
2256 SetWorldTransform( dst, &x );
\r
2259 /* Y reflection */
\r
2265 x.eDy = (FLOAT) dh + dy - 1;
\r
2267 SetWorldTransform( dst, &x );
\r
2275 x.eDx = (FLOAT) dx;
\r
2276 x.eDy = (FLOAT) dy;
\r
2279 SetWorldTransform( dst, &x );
\r
2283 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2291 SetWorldTransform( dst, &x );
\r
2293 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2296 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2298 PM_WP = (int) WhitePawn,
\r
2299 PM_WN = (int) WhiteKnight,
\r
2300 PM_WB = (int) WhiteBishop,
\r
2301 PM_WR = (int) WhiteRook,
\r
2302 PM_WQ = (int) WhiteQueen,
\r
2303 PM_WF = (int) WhiteFerz,
\r
2304 PM_WW = (int) WhiteWazir,
\r
2305 PM_WE = (int) WhiteAlfil,
\r
2306 PM_WM = (int) WhiteMan,
\r
2307 PM_WO = (int) WhiteCannon,
\r
2308 PM_WU = (int) WhiteUnicorn,
\r
2309 PM_WH = (int) WhiteNightrider,
\r
2310 PM_WA = (int) WhiteCardinal,
\r
2311 PM_WC = (int) WhiteMarshall,
\r
2312 PM_WG = (int) WhiteGrasshopper,
\r
2313 PM_WK = (int) WhiteKing,
\r
2314 PM_BP = (int) BlackPawn,
\r
2315 PM_BN = (int) BlackKnight,
\r
2316 PM_BB = (int) BlackBishop,
\r
2317 PM_BR = (int) BlackRook,
\r
2318 PM_BQ = (int) BlackQueen,
\r
2319 PM_BF = (int) BlackFerz,
\r
2320 PM_BW = (int) BlackWazir,
\r
2321 PM_BE = (int) BlackAlfil,
\r
2322 PM_BM = (int) BlackMan,
\r
2323 PM_BO = (int) BlackCannon,
\r
2324 PM_BU = (int) BlackUnicorn,
\r
2325 PM_BH = (int) BlackNightrider,
\r
2326 PM_BA = (int) BlackCardinal,
\r
2327 PM_BC = (int) BlackMarshall,
\r
2328 PM_BG = (int) BlackGrasshopper,
\r
2329 PM_BK = (int) BlackKing
\r
2332 static HFONT hPieceFont = NULL;
\r
2333 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2334 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2335 static int fontBitmapSquareSize = 0;
\r
2336 static char pieceToFontChar[(int) EmptySquare] =
\r
2337 { 'p', 'n', 'b', 'r', 'q',
\r
2338 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2339 'k', 'o', 'm', 'v', 't', 'w',
\r
2340 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2343 extern BOOL SetCharTable( char *table, const char * map );
\r
2344 /* [HGM] moved to backend.c */
\r
2346 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2349 BYTE r1 = GetRValue( color );
\r
2350 BYTE g1 = GetGValue( color );
\r
2351 BYTE b1 = GetBValue( color );
\r
2357 /* Create a uniform background first */
\r
2358 hbrush = CreateSolidBrush( color );
\r
2359 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2360 FillRect( hdc, &rc, hbrush );
\r
2361 DeleteObject( hbrush );
\r
2364 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2365 int steps = squareSize / 2;
\r
2368 for( i=0; i<steps; i++ ) {
\r
2369 BYTE r = r1 - (r1-r2) * i / steps;
\r
2370 BYTE g = g1 - (g1-g2) * i / steps;
\r
2371 BYTE b = b1 - (b1-b2) * i / steps;
\r
2373 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2374 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2375 FillRect( hdc, &rc, hbrush );
\r
2376 DeleteObject(hbrush);
\r
2379 else if( mode == 2 ) {
\r
2380 /* Diagonal gradient, good more or less for every piece */
\r
2381 POINT triangle[3];
\r
2382 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2383 HBRUSH hbrush_old;
\r
2384 int steps = squareSize;
\r
2387 triangle[0].x = squareSize - steps;
\r
2388 triangle[0].y = squareSize;
\r
2389 triangle[1].x = squareSize;
\r
2390 triangle[1].y = squareSize;
\r
2391 triangle[2].x = squareSize;
\r
2392 triangle[2].y = squareSize - steps;
\r
2394 for( i=0; i<steps; i++ ) {
\r
2395 BYTE r = r1 - (r1-r2) * i / steps;
\r
2396 BYTE g = g1 - (g1-g2) * i / steps;
\r
2397 BYTE b = b1 - (b1-b2) * i / steps;
\r
2399 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2400 hbrush_old = SelectObject( hdc, hbrush );
\r
2401 Polygon( hdc, triangle, 3 );
\r
2402 SelectObject( hdc, hbrush_old );
\r
2403 DeleteObject(hbrush);
\r
2408 SelectObject( hdc, hpen );
\r
2413 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2414 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2415 piece: follow the steps as explained below.
\r
2417 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2421 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2425 int backColor = whitePieceColor;
\r
2426 int foreColor = blackPieceColor;
\r
2427 int shapeIndex = index < 6 ? index+6 : index;
\r
2429 if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2430 backColor = appData.fontBackColorWhite;
\r
2431 foreColor = appData.fontForeColorWhite;
\r
2433 else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2434 backColor = appData.fontBackColorBlack;
\r
2435 foreColor = appData.fontForeColorBlack;
\r
2439 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2441 hbm_old = SelectObject( hdc, hbm );
\r
2445 rc.right = squareSize;
\r
2446 rc.bottom = squareSize;
\r
2448 /* Step 1: background is now black */
\r
2449 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2451 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2453 pt.x = (squareSize - sz.cx) / 2;
\r
2454 pt.y = (squareSize - sz.cy) / 2;
\r
2456 SetBkMode( hdc, TRANSPARENT );
\r
2457 SetTextColor( hdc, chroma );
\r
2458 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2459 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2461 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2462 /* Step 3: the area outside the piece is filled with white */
\r
2463 FloodFill( hdc, 0, 0, chroma );
\r
2464 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2466 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2467 but if the start point is not inside the piece we're lost!
\r
2468 There should be a better way to do this... if we could create a region or path
\r
2469 from the fill operation we would be fine for example.
\r
2471 FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2473 SetTextColor( hdc, 0 );
\r
2475 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2476 draw the piece again in black for safety.
\r
2478 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2480 SelectObject( hdc, hbm_old );
\r
2482 if( hPieceMask[index] != NULL ) {
\r
2483 DeleteObject( hPieceMask[index] );
\r
2486 hPieceMask[index] = hbm;
\r
2489 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2491 SelectObject( hdc, hbm );
\r
2494 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2495 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2496 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2498 SelectObject( dc1, hPieceMask[index] );
\r
2499 SelectObject( dc2, bm2 );
\r
2500 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2501 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2504 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2505 the piece background and deletes (makes transparent) the rest.
\r
2506 Thanks to that mask, we are free to paint the background with the greates
\r
2507 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2508 We use this, to make gradients and give the pieces a "roundish" look.
\r
2510 SetPieceBackground( hdc, backColor, 2 );
\r
2511 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2515 DeleteObject( bm2 );
\r
2518 SetTextColor( hdc, foreColor );
\r
2519 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2521 SelectObject( hdc, hbm_old );
\r
2523 if( hPieceFace[index] != NULL ) {
\r
2524 DeleteObject( hPieceFace[index] );
\r
2527 hPieceFace[index] = hbm;
\r
2530 static int TranslatePieceToFontPiece( int piece )
\r
2558 case BlackCardinal:
\r
2560 case BlackMarshall:
\r
2564 case BlackNightrider:
\r
2570 case BlackUnicorn:
\r
2574 case BlackGrasshopper:
\r
2578 case WhiteCardinal:
\r
2580 case WhiteMarshall:
\r
2584 case WhiteNightrider:
\r
2590 case WhiteUnicorn:
\r
2594 case WhiteGrasshopper:
\r
2604 void CreatePiecesFromFont()
\r
2607 HDC hdc_window = NULL;
\r
2613 if( fontBitmapSquareSize < 0 ) {
\r
2614 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2618 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2619 fontBitmapSquareSize = -1;
\r
2623 if( fontBitmapSquareSize != squareSize ) {
\r
2624 hdc_window = GetDC( hwndMain );
\r
2625 hdc = CreateCompatibleDC( hdc_window );
\r
2627 if( hPieceFont != NULL ) {
\r
2628 DeleteObject( hPieceFont );
\r
2631 for( i=0; i<12; i++ ) {
\r
2632 hPieceMask[i] = NULL;
\r
2633 hPieceFace[i] = NULL;
\r
2639 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2640 fontHeight = appData.fontPieceSize;
\r
2643 fontHeight = (fontHeight * squareSize) / 100;
\r
2645 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2647 lf.lfEscapement = 0;
\r
2648 lf.lfOrientation = 0;
\r
2649 lf.lfWeight = FW_NORMAL;
\r
2651 lf.lfUnderline = 0;
\r
2652 lf.lfStrikeOut = 0;
\r
2653 lf.lfCharSet = DEFAULT_CHARSET;
\r
2654 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2655 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2656 lf.lfQuality = PROOF_QUALITY;
\r
2657 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2658 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2659 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2661 hPieceFont = CreateFontIndirect( &lf );
\r
2663 if( hPieceFont == NULL ) {
\r
2664 fontBitmapSquareSize = -2;
\r
2667 /* Setup font-to-piece character table */
\r
2668 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2669 /* No (or wrong) global settings, try to detect the font */
\r
2670 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2672 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2674 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2675 /* DiagramTT* family */
\r
2676 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2678 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2679 /* Fairy symbols */
\r
2680 SetCharTable(pieceToFontChar, "PNBRQFWEMOUHACGSKpnbrqfwemouhacgsk");
\r
2682 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2683 /* Good Companion (Some characters get warped as literal :-( */
\r
2684 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2685 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2686 SetCharTable(pieceToFontChar, s);
\r
2689 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2690 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2694 /* Create bitmaps */
\r
2695 hfont_old = SelectObject( hdc, hPieceFont );
\r
2697 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2698 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2699 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2700 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2701 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2702 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2703 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2704 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2705 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2706 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2707 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2708 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2710 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2711 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2712 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2713 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2714 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2715 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2716 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2717 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2718 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2719 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2720 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2721 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2722 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2723 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2724 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2725 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2726 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2727 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2728 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2729 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2732 SelectObject( hdc, hfont_old );
\r
2734 fontBitmapSquareSize = squareSize;
\r
2738 if( hdc != NULL ) {
\r
2742 if( hdc_window != NULL ) {
\r
2743 ReleaseDC( hwndMain, hdc_window );
\r
2748 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2752 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2753 if (gameInfo.event &&
\r
2754 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2755 strcmp(name, "k80s") == 0) {
\r
2756 strcpy(name, "tim");
\r
2758 return LoadBitmap(hinst, name);
\r
2762 /* Insert a color into the program's logical palette
\r
2763 structure. This code assumes the given color is
\r
2764 the result of the RGB or PALETTERGB macro, and it
\r
2765 knows how those macros work (which is documented).
\r
2768 InsertInPalette(COLORREF color)
\r
2770 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2772 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2773 DisplayFatalError("Too many colors", 0, 1);
\r
2774 pLogPal->palNumEntries--;
\r
2778 pe->peFlags = (char) 0;
\r
2779 pe->peRed = (char) (0xFF & color);
\r
2780 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2781 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2787 InitDrawingColors()
\r
2789 if (pLogPal == NULL) {
\r
2790 /* Allocate enough memory for a logical palette with
\r
2791 * PALETTESIZE entries and set the size and version fields
\r
2792 * of the logical palette structure.
\r
2794 pLogPal = (NPLOGPALETTE)
\r
2795 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2796 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2797 pLogPal->palVersion = 0x300;
\r
2799 pLogPal->palNumEntries = 0;
\r
2801 InsertInPalette(lightSquareColor);
\r
2802 InsertInPalette(darkSquareColor);
\r
2803 InsertInPalette(whitePieceColor);
\r
2804 InsertInPalette(blackPieceColor);
\r
2805 InsertInPalette(highlightSquareColor);
\r
2806 InsertInPalette(premoveHighlightColor);
\r
2808 /* create a logical color palette according the information
\r
2809 * in the LOGPALETTE structure.
\r
2811 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2813 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2814 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2815 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2816 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2817 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2818 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2820 /* [AS] Force rendering of the font-based pieces */
\r
2821 if( fontBitmapSquareSize > 0 ) {
\r
2822 fontBitmapSquareSize = 0;
\r
2828 BoardWidth(int boardSize, int n)
\r
2829 { /* [HGM] argument n added to allow different width and height */
\r
2830 int lineGap = sizeInfo[boardSize].lineGap;
\r
2832 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2833 lineGap = appData.overrideLineGap;
\r
2836 return (n + 1) * lineGap +
\r
2837 n * sizeInfo[boardSize].squareSize;
\r
2840 /* Respond to board resize by dragging edge */
\r
2842 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2844 BoardSize newSize = NUM_SIZES - 1;
\r
2845 static int recurse = 0;
\r
2846 if (IsIconic(hwndMain)) return;
\r
2847 if (recurse > 0) return;
\r
2849 while (newSize > 0 &&
\r
2850 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2851 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2854 boardSize = newSize;
\r
2855 InitDrawingSizes(boardSize, flags);
\r
2862 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2864 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2865 ChessSquare piece;
\r
2866 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2868 SIZE clockSize, messageSize;
\r
2870 char buf[MSG_SIZ];
\r
2872 HMENU hmenu = GetMenu(hwndMain);
\r
2873 RECT crect, wrect;
\r
2875 LOGBRUSH logbrush;
\r
2877 /* [HGM] call with -1 uses old size (for if nr of files, ranks changes) */
\r
2878 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2880 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2881 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2882 squareSize = sizeInfo[boardSize].squareSize;
\r
2883 lineGap = sizeInfo[boardSize].lineGap;
\r
2884 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2886 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2887 lineGap = appData.overrideLineGap;
\r
2890 if (tinyLayout != oldTinyLayout) {
\r
2891 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2893 style &= ~WS_SYSMENU;
\r
2894 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2895 "&Minimize\tCtrl+F4");
\r
2897 style |= WS_SYSMENU;
\r
2898 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2900 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2902 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2903 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2904 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2906 DrawMenuBar(hwndMain);
\r
2909 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
2910 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
2912 /* Get text area sizes */
\r
2913 hdc = GetDC(hwndMain);
\r
2914 if (appData.clockMode) {
\r
2915 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2917 sprintf(buf, "White");
\r
2919 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2920 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2921 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2922 str = "We only care about the height here";
\r
2923 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2924 SelectObject(hdc, oldFont);
\r
2925 ReleaseDC(hwndMain, hdc);
\r
2927 /* Compute where everything goes */
\r
2928 whiteRect.left = OUTER_MARGIN;
\r
2929 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2930 whiteRect.top = OUTER_MARGIN;
\r
2931 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2933 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2934 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2935 blackRect.top = whiteRect.top;
\r
2936 blackRect.bottom = whiteRect.bottom;
\r
2938 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2939 if (appData.showButtonBar) {
\r
2940 messageRect.right = blackRect.right
\r
2941 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2943 messageRect.right = blackRect.right;
\r
2945 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2946 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2948 boardRect.left = whiteRect.left;
\r
2949 boardRect.right = boardRect.left + boardWidth;
\r
2950 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2951 boardRect.bottom = boardRect.top + boardHeight;
\r
2953 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2954 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2955 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2956 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2957 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2958 GetWindowRect(hwndMain, &wrect);
\r
2959 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2960 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2961 /* compensate if menu bar wrapped */
\r
2962 GetClientRect(hwndMain, &crect);
\r
2963 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2964 winHeight += offby;
\r
2966 case WMSZ_TOPLEFT:
\r
2967 SetWindowPos(hwndMain, NULL,
\r
2968 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2969 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2972 case WMSZ_TOPRIGHT:
\r
2974 SetWindowPos(hwndMain, NULL,
\r
2975 wrect.left, wrect.bottom - winHeight,
\r
2976 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2979 case WMSZ_BOTTOMLEFT:
\r
2981 SetWindowPos(hwndMain, NULL,
\r
2982 wrect.right - winWidth, wrect.top,
\r
2983 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2986 case WMSZ_BOTTOMRIGHT:
\r
2990 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2991 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2996 for (i = 0; i < N_BUTTONS; i++) {
\r
2997 if (buttonDesc[i].hwnd != NULL) {
\r
2998 DestroyWindow(buttonDesc[i].hwnd);
\r
2999 buttonDesc[i].hwnd = NULL;
\r
3001 if (appData.showButtonBar) {
\r
3002 buttonDesc[i].hwnd =
\r
3003 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3004 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3005 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3006 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3007 (HMENU) buttonDesc[i].id,
\r
3008 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3010 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3011 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3012 MAKELPARAM(FALSE, 0));
\r
3014 if (buttonDesc[i].id == IDM_Pause)
\r
3015 hwndPause = buttonDesc[i].hwnd;
\r
3016 buttonDesc[i].wndproc = (WNDPROC)
\r
3017 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3020 if (gridPen != NULL) DeleteObject(gridPen);
\r
3021 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3022 if (premovePen != NULL) DeleteObject(premovePen);
\r
3023 if (lineGap != 0) {
\r
3024 logbrush.lbStyle = BS_SOLID;
\r
3025 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3027 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3028 lineGap, &logbrush, 0, NULL);
\r
3029 logbrush.lbColor = highlightSquareColor;
\r
3031 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3032 lineGap, &logbrush, 0, NULL);
\r
3034 logbrush.lbColor = premoveHighlightColor;
\r
3036 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3037 lineGap, &logbrush, 0, NULL);
\r
3039 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3040 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3041 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3042 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3043 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3044 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3045 BOARD_WIDTH * (squareSize + lineGap);
\r
3046 lineGap / 2 + (i * (squareSize + lineGap));
\r
3047 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3049 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3050 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3051 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3052 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3053 lineGap / 2 + (i * (squareSize + lineGap));
\r
3054 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3055 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3056 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3061 /* [HGM] Gothic licensing requirement */
\r
3062 GothicPopUp( GOTHIC, gameInfo.variant == VariantGothic );
\r
3065 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3066 oldBoardSize = boardSize;
\r
3067 oldTinyLayout = tinyLayout;
\r
3069 /* Load piece bitmaps for this board size */
\r
3070 for (i=0; i<=2; i++) {
\r
3071 for (piece = WhitePawn;
\r
3072 (int) piece < (int) BlackPawn;
\r
3073 piece = (ChessSquare) ((int) piece + 1)) {
\r
3074 if (pieceBitmap[i][piece] != NULL)
\r
3075 DeleteObject(pieceBitmap[i][piece]);
\r
3079 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3080 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3081 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3082 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3083 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3084 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3085 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3086 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3087 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3088 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3089 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3090 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3091 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3092 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3093 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3094 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3095 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3096 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3097 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3099 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3100 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3101 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3103 if(squareSize==72 || squareSize==49) { /* experiment with some home-made bitmaps */
\r
3104 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3105 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3106 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3107 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3108 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3109 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3110 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3111 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3112 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3113 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3114 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3115 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3116 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3117 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3118 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3119 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3120 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3121 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3122 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3123 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3124 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3125 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3126 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3127 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3128 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3129 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3130 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3131 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3132 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3133 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3134 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3136 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3137 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3138 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3139 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3140 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3141 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3142 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3143 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3144 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3145 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3146 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3147 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3149 if(gameInfo.variant != VariantCrazyhouse && gameInfo.variant != VariantShogi) {
\r
3150 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3151 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3152 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3154 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3155 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3156 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3158 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3159 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3160 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3161 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3162 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3163 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3164 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3165 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3166 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3167 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3168 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3169 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3170 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3171 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3172 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3174 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3175 /* special Shogi support in this size */
\r
3176 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3177 for (piece = WhitePawn;
\r
3178 (int) piece < (int) BlackPawn;
\r
3179 piece = (ChessSquare) ((int) piece + 1)) {
\r
3180 if (pieceBitmap[i][piece] != NULL)
\r
3181 DeleteObject(pieceBitmap[i][piece]);
\r
3184 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3185 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3186 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3187 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3188 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3189 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3190 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3191 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3192 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3193 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3194 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3195 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3196 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3197 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3198 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3199 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3200 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3201 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3202 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3203 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3204 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3205 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3206 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3207 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3208 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3209 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3210 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3211 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3212 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3213 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3214 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3215 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3216 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3217 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3218 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3219 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3220 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3221 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3222 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3223 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3224 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3225 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3231 PieceBitmap(ChessSquare p, int kind)
\r
3233 if ((int) p >= (int) BlackPawn)
\r
3234 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3236 return pieceBitmap[kind][(int) p];
\r
3239 /***************************************************************/
\r
3241 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3242 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3244 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3245 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3249 SquareToPos(int row, int column, int * x, int * y)
\r
3252 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3253 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3255 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3256 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3261 DrawCoordsOnDC(HDC hdc)
\r
3263 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
3264 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
3265 char str[2] = { NULLCHAR, NULLCHAR };
\r
3266 int oldMode, oldAlign, x, y, start, i;
\r
3270 if (!appData.showCoords)
\r
3273 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3275 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3276 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3277 oldAlign = GetTextAlign(hdc);
\r
3278 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3280 y = boardRect.top + lineGap;
\r
3281 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3283 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3284 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3285 str[0] = files[start + i];
\r
3286 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3287 y += squareSize + lineGap;
\r
3290 start = flipView ? 12-BOARD_WIDTH : 12;
\r
3292 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3293 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3294 str[0] = ranks[start + i];
\r
3295 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3296 x += squareSize + lineGap;
\r
3299 SelectObject(hdc, oldBrush);
\r
3300 SetBkMode(hdc, oldMode);
\r
3301 SetTextAlign(hdc, oldAlign);
\r
3302 SelectObject(hdc, oldFont);
\r
3306 DrawGridOnDC(HDC hdc)
\r
3310 if (lineGap != 0) {
\r
3311 oldPen = SelectObject(hdc, gridPen);
\r
3312 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3313 SelectObject(hdc, oldPen);
\r
3317 #define HIGHLIGHT_PEN 0
\r
3318 #define PREMOVE_PEN 1
\r
3321 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3324 HPEN oldPen, hPen;
\r
3325 if (lineGap == 0) return;
\r
3327 x1 = boardRect.left +
\r
3328 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3329 y1 = boardRect.top +
\r
3330 lineGap/2 + y * (squareSize + lineGap);
\r
3332 x1 = boardRect.left +
\r
3333 lineGap/2 + x * (squareSize + lineGap);
\r
3334 y1 = boardRect.top +
\r
3335 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3337 hPen = pen ? premovePen : highlightPen;
\r
3338 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3339 MoveToEx(hdc, x1, y1, NULL);
\r
3340 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3341 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3342 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3343 LineTo(hdc, x1, y1);
\r
3344 SelectObject(hdc, oldPen);
\r
3348 DrawHighlightsOnDC(HDC hdc)
\r
3351 for (i=0; i<2; i++) {
\r
3352 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3353 DrawHighlightOnDC(hdc, TRUE,
\r
3354 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3357 for (i=0; i<2; i++) {
\r
3358 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3359 premoveHighlightInfo.sq[i].y >= 0) {
\r
3360 DrawHighlightOnDC(hdc, TRUE,
\r
3361 premoveHighlightInfo.sq[i].x,
\r
3362 premoveHighlightInfo.sq[i].y,
\r
3368 /* Note: sqcolor is used only in monoMode */
\r
3369 /* Note that this code is largely duplicated in woptions.c,
\r
3370 function DrawSampleSquare, so that needs to be updated too */
\r
3372 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3374 HBITMAP oldBitmap;
\r
3378 if (appData.blindfold) return;
\r
3380 /* [AS] Use font-based pieces if needed */
\r
3381 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3382 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3383 CreatePiecesFromFont();
\r
3385 if( fontBitmapSquareSize == squareSize ) {
\r
3386 int index = TranslatePieceToFontPiece( piece );
\r
3388 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3392 squareSize, squareSize,
\r
3397 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3401 squareSize, squareSize,
\r
3410 if (appData.monoMode) {
\r
3411 SelectObject(tmphdc, PieceBitmap(piece,
\r
3412 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3413 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3414 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3416 tmpSize = squareSize;
\r
3418 (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||
\r
3419 piece >= (int)BlackNightrider && piece <= BlackGrasshopper) ) {
\r
3420 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3421 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3422 x += (squareSize - minorSize)>>1;
\r
3423 y += squareSize - minorSize - 2;
\r
3424 tmpSize = minorSize;
\r
3426 if (color || appData.allWhite ) {
\r
3427 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3429 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3430 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3431 if(appData.upsideDown && !color)
\r
3432 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3434 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3436 /* Use black piece color for outline of white pieces */
\r
3437 /* Not sure this looks really good (though xboard does it).
\r
3438 Maybe better to have another selectable color, default black */
\r
3439 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3440 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3441 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3443 /* Use black for outline of white pieces */
\r
3444 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3445 if(appData.upsideDown && !color)
\r
3446 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3448 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3452 /* Use white piece color for details of black pieces */
\r
3453 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3454 WHITE_PIECE ones aren't always the right shape. */
\r
3455 /* Not sure this looks really good (though xboard does it).
\r
3456 Maybe better to have another selectable color, default medium gray? */
\r
3457 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3458 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3459 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3460 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3461 SelectObject(hdc, blackPieceBrush);
\r
3462 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3464 /* Use square color for details of black pieces */
\r
3465 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3466 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3467 if(appData.upsideDown)
\r
3468 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3470 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3473 SelectObject(hdc, oldBrush);
\r
3474 SelectObject(tmphdc, oldBitmap);
\r
3478 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3479 int GetBackTextureMode( int algo )
\r
3481 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3485 case BACK_TEXTURE_MODE_PLAIN:
\r
3486 result = 1; /* Always use identity map */
\r
3488 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3489 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3497 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3498 to handle redraws cleanly (as random numbers would always be different).
\r
3500 VOID RebuildTextureSquareInfo()
\r
3510 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3512 if( liteBackTexture != NULL ) {
\r
3513 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3514 lite_w = bi.bmWidth;
\r
3515 lite_h = bi.bmHeight;
\r
3519 if( darkBackTexture != NULL ) {
\r
3520 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3521 dark_w = bi.bmWidth;
\r
3522 dark_h = bi.bmHeight;
\r
3526 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3527 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3528 if( (col + row) & 1 ) {
\r
3530 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3531 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_WIDTH;
\r
3532 backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_HEIGHT;
\r
3533 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3538 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3539 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_WIDTH;
\r
3540 backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_HEIGHT;
\r
3541 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3548 /* [AS] Arrow highlighting support */
\r
3550 static int A_WIDTH = 5; /* Width of arrow body */
\r
3552 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3553 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3555 static double Sqr( double x )
\r
3560 static int Round( double x )
\r
3562 return (int) (x + 0.5);
\r
3565 /* Draw an arrow between two points using current settings */
\r
3566 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3569 double dx, dy, j, k, x, y;
\r
3571 if( d_x == s_x ) {
\r
3572 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3574 arrow[0].x = s_x + A_WIDTH;
\r
3577 arrow[1].x = s_x + A_WIDTH;
\r
3578 arrow[1].y = d_y - h;
\r
3580 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3581 arrow[2].y = d_y - h;
\r
3586 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3587 arrow[4].y = d_y - h;
\r
3589 arrow[5].x = s_x - A_WIDTH;
\r
3590 arrow[5].y = d_y - h;
\r
3592 arrow[6].x = s_x - A_WIDTH;
\r
3595 else if( d_y == s_y ) {
\r
3596 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3599 arrow[0].y = s_y + A_WIDTH;
\r
3601 arrow[1].x = d_x - w;
\r
3602 arrow[1].y = s_y + A_WIDTH;
\r
3604 arrow[2].x = d_x - w;
\r
3605 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3610 arrow[4].x = d_x - w;
\r
3611 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3613 arrow[5].x = d_x - w;
\r
3614 arrow[5].y = s_y - A_WIDTH;
\r
3617 arrow[6].y = s_y - A_WIDTH;
\r
3620 /* [AS] Needed a lot of paper for this! :-) */
\r
3621 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3622 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3624 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3626 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3631 arrow[0].x = Round(x - j);
\r
3632 arrow[0].y = Round(y + j*dx);
\r
3634 arrow[1].x = Round(x + j);
\r
3635 arrow[1].y = Round(y - j*dx);
\r
3638 x = (double) d_x - k;
\r
3639 y = (double) d_y - k*dy;
\r
3642 x = (double) d_x + k;
\r
3643 y = (double) d_y + k*dy;
\r
3646 arrow[2].x = Round(x + j);
\r
3647 arrow[2].y = Round(y - j*dx);
\r
3649 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3650 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3655 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3656 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3658 arrow[6].x = Round(x - j);
\r
3659 arrow[6].y = Round(y + j*dx);
\r
3662 Polygon( hdc, arrow, 7 );
\r
3665 /* [AS] Draw an arrow between two squares */
\r
3666 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3668 int s_x, s_y, d_x, d_y;
\r
3675 if( s_col == d_col && s_row == d_row ) {
\r
3679 /* Get source and destination points */
\r
3680 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3681 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3684 d_y += squareSize / 4;
\r
3686 else if( d_y < s_y ) {
\r
3687 d_y += 3 * squareSize / 4;
\r
3690 d_y += squareSize / 2;
\r
3694 d_x += squareSize / 4;
\r
3696 else if( d_x < s_x ) {
\r
3697 d_x += 3 * squareSize / 4;
\r
3700 d_x += squareSize / 2;
\r
3703 s_x += squareSize / 2;
\r
3704 s_y += squareSize / 2;
\r
3706 /* Adjust width */
\r
3707 A_WIDTH = squareSize / 14;
\r
3710 stLB.lbStyle = BS_SOLID;
\r
3711 stLB.lbColor = appData.highlightArrowColor;
\r
3714 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3715 holdpen = SelectObject( hdc, hpen );
\r
3716 hbrush = CreateBrushIndirect( &stLB );
\r
3717 holdbrush = SelectObject( hdc, hbrush );
\r
3719 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3721 SelectObject( hdc, holdpen );
\r
3722 SelectObject( hdc, holdbrush );
\r
3723 DeleteObject( hpen );
\r
3724 DeleteObject( hbrush );
\r
3727 BOOL HasHighlightInfo()
\r
3729 BOOL result = FALSE;
\r
3731 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3732 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3740 BOOL IsDrawArrowEnabled()
\r
3742 BOOL result = FALSE;
\r
3744 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3751 VOID DrawArrowHighlight( HDC hdc )
\r
3753 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3754 DrawArrowBetweenSquares( hdc,
\r
3755 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3756 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3760 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3762 HRGN result = NULL;
\r
3764 if( HasHighlightInfo() ) {
\r
3765 int x1, y1, x2, y2;
\r
3766 int sx, sy, dx, dy;
\r
3768 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3769 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3771 sx = MIN( x1, x2 );
\r
3772 sy = MIN( y1, y2 );
\r
3773 dx = MAX( x1, x2 ) + squareSize;
\r
3774 dy = MAX( y1, y2 ) + squareSize;
\r
3776 result = CreateRectRgn( sx, sy, dx, dy );
\r
3783 Warning: this function modifies the behavior of several other functions.
\r
3785 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3786 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3787 repaint is scattered all over the place, which is not good for features such as
\r
3788 "arrow highlighting" that require a full repaint of the board.
\r
3790 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3791 user interaction, when speed is not so important) but especially to avoid errors
\r
3792 in the displayed graphics.
\r
3794 In such patched places, I always try refer to this function so there is a single
\r
3795 place to maintain knowledge.
\r
3797 To restore the original behavior, just return FALSE unconditionally.
\r
3799 BOOL IsFullRepaintPreferrable()
\r
3801 BOOL result = FALSE;
\r
3803 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3804 /* Arrow may appear on the board */
\r
3812 This function is called by DrawPosition to know whether a full repaint must
\r
3815 Only DrawPosition may directly call this function, which makes use of
\r
3816 some state information. Other function should call DrawPosition specifying
\r
3817 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3819 BOOL DrawPositionNeedsFullRepaint()
\r
3821 BOOL result = FALSE;
\r
3824 Probably a slightly better policy would be to trigger a full repaint
\r
3825 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3826 but animation is fast enough that it's difficult to notice.
\r
3828 if( animInfo.piece == EmptySquare ) {
\r
3829 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3838 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3840 int row, column, x, y, square_color, piece_color;
\r
3841 ChessSquare piece;
\r
3843 HDC texture_hdc = NULL;
\r
3845 /* [AS] Initialize background textures if needed */
\r
3846 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3847 if( backTextureSquareSize != squareSize ) {
\r
3848 backTextureSquareSize = squareSize;
\r
3849 RebuildTextureSquareInfo();
\r
3852 texture_hdc = CreateCompatibleDC( hdc );
\r
3855 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3856 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3858 SquareToPos(row, column, &x, &y);
\r
3860 piece = board[row][column];
\r
3862 square_color = ((column + row) % 2) == 1;
\r
3863 if(!strcmp(appData.variant, "xiangqi") ) {
\r
3864 square_color = !InPalace(row, column);
\r
3865 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3866 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3868 piece_color = (int) piece < (int) BlackPawn;
\r
3872 /* [HGM] holdings file: light square or black */
\r
3873 if(column == BOARD_LEFT-2) {
\r
3874 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3877 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3881 if(column == BOARD_RGHT + 1 ) {
\r
3882 if( row < gameInfo.holdingsSize )
\r
3885 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3889 if(column == BOARD_LEFT-1 ) /* left align */
\r
3890 DisplayHoldingsCount(hdc, x, y, 0, (int) board[row][column]);
\r
3891 else if( column == BOARD_RGHT) /* right align */
\r
3892 DisplayHoldingsCount(hdc, x, y, 1, (int) board[row][column]);
\r
3895 if (appData.monoMode) {
\r
3896 if (piece == EmptySquare) {
\r
3897 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3898 square_color ? WHITENESS : BLACKNESS);
\r
3900 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3903 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
3904 /* [AS] Draw the square using a texture bitmap */
\r
3905 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3908 squareSize, squareSize,
\r
3911 backTextureSquareInfo[row][column].mode,
\r
3912 backTextureSquareInfo[row][column].x,
\r
3913 backTextureSquareInfo[row][column].y );
\r
3915 SelectObject( texture_hdc, hbm );
\r
3917 if (piece != EmptySquare) {
\r
3918 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3922 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3924 oldBrush = SelectObject(hdc, brush );
\r
3925 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3926 SelectObject(hdc, oldBrush);
\r
3927 if (piece != EmptySquare)
\r
3928 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3933 if( texture_hdc != NULL ) {
\r
3934 DeleteDC( texture_hdc );
\r
3938 #define MAX_CLIPS 200 /* more than enough */
\r
3941 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3943 static Board lastReq, lastDrawn;
\r
3944 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3945 static int lastDrawnFlipView = 0;
\r
3946 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3947 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3950 HBITMAP bufferBitmap;
\r
3951 HBITMAP oldBitmap;
\r
3953 HRGN clips[MAX_CLIPS];
\r
3954 ChessSquare dragged_piece = EmptySquare;
\r
3956 /* I'm undecided on this - this function figures out whether a full
\r
3957 * repaint is necessary on its own, so there's no real reason to have the
\r
3958 * caller tell it that. I think this can safely be set to FALSE - but
\r
3959 * if we trust the callers not to request full repaints unnessesarily, then
\r
3960 * we could skip some clipping work. In other words, only request a full
\r
3961 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3962 * gamestart and similar) --Hawk
\r
3964 Boolean fullrepaint = repaint;
\r
3966 if( DrawPositionNeedsFullRepaint() ) {
\r
3967 fullrepaint = TRUE;
\r
3971 if( fullrepaint ) {
\r
3972 static int repaint_count = 0;
\r
3976 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
3977 OutputDebugString( buf );
\r
3981 if (board == NULL) {
\r
3982 if (!lastReqValid) {
\r
3987 CopyBoard(lastReq, board);
\r
3991 if (doingSizing) {
\r
3995 if (IsIconic(hwndMain)) {
\r
3999 if (hdc == NULL) {
\r
4000 hdc = GetDC(hwndMain);
\r
4001 if (!appData.monoMode) {
\r
4002 SelectPalette(hdc, hPal, FALSE);
\r
4003 RealizePalette(hdc);
\r
4007 releaseDC = FALSE;
\r
4011 fprintf(debugFP, "*******************************\n"
\r
4013 "dragInfo.from (%d,%d)\n"
\r
4014 "dragInfo.start (%d,%d)\n"
\r
4015 "dragInfo.pos (%d,%d)\n"
\r
4016 "dragInfo.lastpos (%d,%d)\n",
\r
4017 repaint ? "TRUE" : "FALSE",
\r
4018 dragInfo.from.x, dragInfo.from.y,
\r
4019 dragInfo.start.x, dragInfo.start.y,
\r
4020 dragInfo.pos.x, dragInfo.pos.y,
\r
4021 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4022 fprintf(debugFP, "prev: ");
\r
4023 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4024 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4025 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4028 fprintf(debugFP, "\n");
\r
4029 fprintf(debugFP, "board: ");
\r
4030 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4031 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4032 fprintf(debugFP, "%d ", board[row][column]);
\r
4035 fprintf(debugFP, "\n");
\r
4039 /* Create some work-DCs */
\r
4040 hdcmem = CreateCompatibleDC(hdc);
\r
4041 tmphdc = CreateCompatibleDC(hdc);
\r
4043 /* If dragging is in progress, we temporarely remove the piece */
\r
4044 /* [HGM] or temporarily decrease count if stacked */
\r
4045 /* !! Moved to before board compare !! */
\r
4046 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4047 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4048 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4049 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4050 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4052 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4053 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4054 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4056 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4059 /* Figure out which squares need updating by comparing the
\r
4060 * newest board with the last drawn board and checking if
\r
4061 * flipping has changed.
\r
4063 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4064 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4065 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4066 if (lastDrawn[row][column] != board[row][column]) {
\r
4067 SquareToPos(row, column, &x, &y);
\r
4068 clips[num_clips++] =
\r
4069 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4073 for (i=0; i<2; i++) {
\r
4074 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4075 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4076 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4077 lastDrawnHighlight.sq[i].y >= 0) {
\r
4078 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4079 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4080 clips[num_clips++] =
\r
4081 CreateRectRgn(x - lineGap, y - lineGap,
\r
4082 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4084 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4085 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4086 clips[num_clips++] =
\r
4087 CreateRectRgn(x - lineGap, y - lineGap,
\r
4088 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4092 for (i=0; i<2; i++) {
\r
4093 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4094 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4095 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4096 lastDrawnPremove.sq[i].y >= 0) {
\r
4097 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4098 lastDrawnPremove.sq[i].x, &x, &y);
\r
4099 clips[num_clips++] =
\r
4100 CreateRectRgn(x - lineGap, y - lineGap,
\r
4101 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4103 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4104 premoveHighlightInfo.sq[i].y >= 0) {
\r
4105 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4106 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4107 clips[num_clips++] =
\r
4108 CreateRectRgn(x - lineGap, y - lineGap,
\r
4109 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4114 fullrepaint = TRUE;
\r
4117 /* Create a buffer bitmap - this is the actual bitmap
\r
4118 * being written to. When all the work is done, we can
\r
4119 * copy it to the real DC (the screen). This avoids
\r
4120 * the problems with flickering.
\r
4122 GetClientRect(hwndMain, &Rect);
\r
4123 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4124 Rect.bottom-Rect.top+1);
\r
4125 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4126 if (!appData.monoMode) {
\r
4127 SelectPalette(hdcmem, hPal, FALSE);
\r
4130 /* Create clips for dragging */
\r
4131 if (!fullrepaint) {
\r
4132 if (dragInfo.from.x >= 0) {
\r
4133 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4134 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4136 if (dragInfo.start.x >= 0) {
\r
4137 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4138 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4140 if (dragInfo.pos.x >= 0) {
\r
4141 x = dragInfo.pos.x - squareSize / 2;
\r
4142 y = dragInfo.pos.y - squareSize / 2;
\r
4143 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4145 if (dragInfo.lastpos.x >= 0) {
\r
4146 x = dragInfo.lastpos.x - squareSize / 2;
\r
4147 y = dragInfo.lastpos.y - squareSize / 2;
\r
4148 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4152 /* Are we animating a move?
\r
4154 * - remove the piece from the board (temporarely)
\r
4155 * - calculate the clipping region
\r
4157 if (!fullrepaint) {
\r
4158 if (animInfo.piece != EmptySquare) {
\r
4159 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4160 x = boardRect.left + animInfo.lastpos.x;
\r
4161 y = boardRect.top + animInfo.lastpos.y;
\r
4162 x2 = boardRect.left + animInfo.pos.x;
\r
4163 y2 = boardRect.top + animInfo.pos.y;
\r
4164 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4165 /* Slight kludge. The real problem is that after AnimateMove is
\r
4166 done, the position on the screen does not match lastDrawn.
\r
4167 This currently causes trouble only on e.p. captures in
\r
4168 atomic, where the piece moves to an empty square and then
\r
4169 explodes. The old and new positions both had an empty square
\r
4170 at the destination, but animation has drawn a piece there and
\r
4171 we have to remember to erase it. */
\r
4172 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4176 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4177 if (num_clips == 0)
\r
4178 fullrepaint = TRUE;
\r
4180 /* Set clipping on the memory DC */
\r
4181 if (!fullrepaint) {
\r
4182 SelectClipRgn(hdcmem, clips[0]);
\r
4183 for (x = 1; x < num_clips; x++) {
\r
4184 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4185 abort(); // this should never ever happen!
\r
4189 /* Do all the drawing to the memory DC */
\r
4190 DrawGridOnDC(hdcmem);
\r
4191 DrawHighlightsOnDC(hdcmem);
\r
4192 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4194 if( appData.highlightMoveWithArrow ) {
\r
4195 DrawArrowHighlight(hdcmem);
\r
4198 DrawCoordsOnDC(hdcmem);
\r
4200 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4201 /* to make sure lastDrawn contains what is actually drawn */
\r
4203 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4204 if (dragged_piece != EmptySquare) {
\r
4205 /* [HGM] or restack */
\r
4206 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4207 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4209 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4210 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4211 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4212 x = dragInfo.pos.x - squareSize / 2;
\r
4213 y = dragInfo.pos.y - squareSize / 2;
\r
4214 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4215 ((int) dragged_piece < (int) BlackPawn),
\r
4216 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4219 /* Put the animated piece back into place and draw it */
\r
4220 if (animInfo.piece != EmptySquare) {
\r
4221 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4222 x = boardRect.left + animInfo.pos.x;
\r
4223 y = boardRect.top + animInfo.pos.y;
\r
4224 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4225 ((int) animInfo.piece < (int) BlackPawn),
\r
4226 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4229 /* Release the bufferBitmap by selecting in the old bitmap
\r
4230 * and delete the memory DC
\r
4232 SelectObject(hdcmem, oldBitmap);
\r
4235 /* Set clipping on the target DC */
\r
4236 if (!fullrepaint) {
\r
4237 SelectClipRgn(hdc, clips[0]);
\r
4238 for (x = 1; x < num_clips; x++) {
\r
4239 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4240 abort(); // this should never ever happen!
\r
4244 /* Copy the new bitmap onto the screen in one go.
\r
4245 * This way we avoid any flickering
\r
4247 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4248 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4249 boardRect.right - boardRect.left,
\r
4250 boardRect.bottom - boardRect.top,
\r
4251 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4252 SelectObject(tmphdc, oldBitmap);
\r
4254 /* Massive cleanup */
\r
4255 for (x = 0; x < num_clips; x++)
\r
4256 DeleteObject(clips[x]);
\r
4259 DeleteObject(bufferBitmap);
\r
4262 ReleaseDC(hwndMain, hdc);
\r
4264 if (lastDrawnFlipView != flipView) {
\r
4266 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4268 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4271 /* CopyBoard(lastDrawn, board);*/
\r
4272 lastDrawnHighlight = highlightInfo;
\r
4273 lastDrawnPremove = premoveHighlightInfo;
\r
4274 lastDrawnFlipView = flipView;
\r
4275 lastDrawnValid = 1;
\r
4279 /*---------------------------------------------------------------------------*\
\r
4280 | CLIENT PAINT PROCEDURE
\r
4281 | This is the main event-handler for the WM_PAINT message.
\r
4283 \*---------------------------------------------------------------------------*/
\r
4285 PaintProc(HWND hwnd)
\r
4291 if(hdc = BeginPaint(hwnd, &ps)) {
\r
4292 if (IsIconic(hwnd)) {
\r
4293 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4295 if (!appData.monoMode) {
\r
4296 SelectPalette(hdc, hPal, FALSE);
\r
4297 RealizePalette(hdc);
\r
4299 HDCDrawPosition(hdc, 1, NULL);
\r
4301 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4302 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4303 ETO_CLIPPED|ETO_OPAQUE,
\r
4304 &messageRect, messageText, strlen(messageText), NULL);
\r
4305 SelectObject(hdc, oldFont);
\r
4306 DisplayBothClocks();
\r
4308 EndPaint(hwnd,&ps);
\r
4316 * If the user selects on a border boundary, return -1; if off the board,
\r
4317 * return -2. Otherwise map the event coordinate to the square.
\r
4318 * The offset boardRect.left or boardRect.top must already have been
\r
4319 * subtracted from x.
\r
4322 EventToSquare(int x)
\r
4329 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4331 x /= (squareSize + lineGap);
\r
4332 if (x >= BOARD_SIZE)
\r
4343 DropEnable dropEnables[] = {
\r
4344 { 'P', DP_Pawn, "Pawn" },
\r
4345 { 'N', DP_Knight, "Knight" },
\r
4346 { 'B', DP_Bishop, "Bishop" },
\r
4347 { 'R', DP_Rook, "Rook" },
\r
4348 { 'Q', DP_Queen, "Queen" },
\r
4352 SetupDropMenu(HMENU hmenu)
\r
4354 int i, count, enable;
\r
4356 extern char white_holding[], black_holding[];
\r
4357 char item[MSG_SIZ];
\r
4359 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4360 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4361 dropEnables[i].piece);
\r
4363 while (p && *p++ == dropEnables[i].piece) count++;
\r
4364 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4365 enable = count > 0 || !appData.testLegality
\r
4366 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4367 && !appData.icsActive);
\r
4368 ModifyMenu(hmenu, dropEnables[i].command,
\r
4369 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4370 dropEnables[i].command, item);
\r
4374 static int fromX = -1, fromY = -1, toX, toY;
\r
4376 /* Event handler for mouse messages */
\r
4378 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4382 static int recursive = 0;
\r
4384 BOOLEAN needsRedraw = FALSE;
\r
4385 BOOLEAN saveAnimate;
\r
4386 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4387 static BOOLEAN sameAgain = FALSE;
\r
4388 ChessMove moveType;
\r
4391 if (message == WM_MBUTTONUP) {
\r
4392 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4393 to the middle button: we simulate pressing the left button too!
\r
4395 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4396 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4402 pt.x = LOWORD(lParam);
\r
4403 pt.y = HIWORD(lParam);
\r
4404 x = EventToSquare(pt.x - boardRect.left);
\r
4405 y = EventToSquare(pt.y - boardRect.top);
\r
4406 if (!flipView && y >= 0) {
\r
4407 y = BOARD_HEIGHT - 1 - y;
\r
4409 if (flipView && x >= 0) {
\r
4410 x = BOARD_WIDTH - 1 - x;
\r
4413 switch (message) {
\r
4414 case WM_LBUTTONDOWN:
\r
4416 sameAgain = FALSE;
\r
4418 /* Downclick vertically off board; check if on clock */
\r
4419 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4420 if (gameMode == EditPosition) {
\r
4421 SetWhiteToPlayEvent();
\r
4422 } else if (gameMode == IcsPlayingBlack ||
\r
4423 gameMode == MachinePlaysWhite) {
\r
4425 } else if (gameMode == EditGame) {
\r
4426 AdjustClock(flipClock, -1);
\r
4428 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4429 if (gameMode == EditPosition) {
\r
4430 SetBlackToPlayEvent();
\r
4431 } else if (gameMode == IcsPlayingWhite ||
\r
4432 gameMode == MachinePlaysBlack) {
\r
4434 } else if (gameMode == EditGame) {
\r
4435 AdjustClock(!flipClock, -1);
\r
4438 if (!appData.highlightLastMove) {
\r
4439 ClearHighlights();
\r
4440 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4442 fromX = fromY = -1;
\r
4443 dragInfo.start.x = dragInfo.start.y = -1;
\r
4444 dragInfo.from = dragInfo.start;
\r
4446 } else if (x < 0 || y < 0
\r
4447 /* [HGM] block clicks between board and holdings */
\r
4448 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4449 || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
\r
4450 || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize
\r
4451 /* EditPosition, empty square, or different color piece;
\r
4452 click-click move is possible */
\r
4455 } else if (fromX == x && fromY == y) {
\r
4456 /* Downclick on same square again */
\r
4457 ClearHighlights();
\r
4458 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4459 sameAgain = TRUE;
\r
4460 } else if (fromX != -1 &&
\r
4461 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4463 /* Downclick on different square. */
\r
4464 /* [HGM] if on holdings file, should count as new first click ! */
\r
4465 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4468 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4469 to make sure move is legal before showing promotion popup */
\r
4470 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4471 if(moveType != ImpossibleMove) {
\r
4472 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4473 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4474 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4475 appData.alwaysPromoteToQueen) {
\r
4476 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4477 if (!appData.highlightLastMove) {
\r
4478 ClearHighlights();
\r
4479 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4482 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4483 SetHighlights(fromX, fromY, toX, toY);
\r
4484 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4485 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4486 If promotion to Q is legal, all are legal! */
\r
4487 PromotionPopup(hwnd);
\r
4488 } else { /* not a promotion */
\r
4489 if (appData.animate || appData.highlightLastMove) {
\r
4490 SetHighlights(fromX, fromY, toX, toY);
\r
4492 ClearHighlights();
\r
4494 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4495 if (appData.animate && !appData.highlightLastMove) {
\r
4496 ClearHighlights();
\r
4497 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4503 /* [HGM] it seemed that braces were missing here */
\r
4504 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4505 fromX = fromY = -1;
\r
4509 ClearHighlights();
\r
4510 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4512 /* First downclick, or restart on a square with same color piece */
\r
4513 if (!frozen && OKToStartUserMove(x, y)) {
\r
4516 dragInfo.lastpos = pt;
\r
4517 dragInfo.from.x = fromX;
\r
4518 dragInfo.from.y = fromY;
\r
4519 dragInfo.start = dragInfo.from;
\r
4520 SetCapture(hwndMain);
\r
4522 fromX = fromY = -1;
\r
4523 dragInfo.start.x = dragInfo.start.y = -1;
\r
4524 dragInfo.from = dragInfo.start;
\r
4525 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4529 case WM_LBUTTONUP:
\r
4531 if (fromX == -1) break;
\r
4532 if (x == fromX && y == fromY) {
\r
4533 dragInfo.from.x = dragInfo.from.y = -1;
\r
4534 /* Upclick on same square */
\r
4536 /* Clicked same square twice: abort click-click move */
\r
4537 fromX = fromY = -1;
\r
4539 ClearPremoveHighlights();
\r
4541 /* First square clicked: start click-click move */
\r
4542 SetHighlights(fromX, fromY, -1, -1);
\r
4544 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4545 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4546 /* Errant click; ignore */
\r
4549 /* Finish drag move. */
\r
4550 if (appData.debugMode) {
\r
4551 fprintf(debugFP, "release\n");
\r
4553 dragInfo.from.x = dragInfo.from.y = -1;
\r
4556 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4557 appData.animate = appData.animate && !appData.animateDragging;
\r
4558 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4559 if(moveType != ImpossibleMove) {
\r
4560 /* [HGM] use move type to determine if move is promotion.
\r
4561 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
4562 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4563 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4564 appData.alwaysPromoteToQueen)
\r
4565 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4567 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4568 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4569 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
4570 } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4572 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4573 appData.animate = saveAnimate;
\r
4574 fromX = fromY = -1;
\r
4575 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
4576 ClearHighlights();
\r
4578 if (appData.animate || appData.animateDragging ||
\r
4579 appData.highlightDragging || gotPremove) {
\r
4580 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4583 dragInfo.start.x = dragInfo.start.y = -1;
\r
4584 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4587 case WM_MOUSEMOVE:
\r
4588 if ((appData.animateDragging || appData.highlightDragging)
\r
4589 && (wParam & MK_LBUTTON)
\r
4590 && dragInfo.from.x >= 0)
\r
4592 BOOL full_repaint = FALSE;
\r
4594 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
4595 if (appData.animateDragging) {
\r
4596 dragInfo.pos = pt;
\r
4598 if (appData.highlightDragging) {
\r
4599 SetHighlights(fromX, fromY, x, y);
\r
4600 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4601 full_repaint = TRUE;
\r
4605 DrawPosition( full_repaint, NULL);
\r
4607 dragInfo.lastpos = dragInfo.pos;
\r
4611 case WM_MBUTTONDOWN:
\r
4612 case WM_RBUTTONDOWN:
\r
4615 fromX = fromY = -1;
\r
4616 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4617 dragInfo.start.x = dragInfo.start.y = -1;
\r
4618 dragInfo.from = dragInfo.start;
\r
4619 dragInfo.lastpos = dragInfo.pos;
\r
4620 if (appData.highlightDragging) {
\r
4621 ClearHighlights();
\r
4624 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4625 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4626 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
4627 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4628 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
4631 DrawPosition(TRUE, NULL);
\r
4633 switch (gameMode) {
\r
4634 case EditPosition:
\r
4635 case IcsExamining:
\r
4636 if (x < 0 || y < 0) break;
\r
4639 if (message == WM_MBUTTONDOWN) {
\r
4640 buttonCount = 3; /* even if system didn't think so */
\r
4641 if (wParam & MK_SHIFT)
\r
4642 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4644 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4645 } else { /* message == WM_RBUTTONDOWN */
\r
4647 if (buttonCount == 3) {
\r
4648 if (wParam & MK_SHIFT)
\r
4649 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4651 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4653 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4656 /* Just have one menu, on the right button. Windows users don't
\r
4657 think to try the middle one, and sometimes other software steals
\r
4658 it, or it doesn't really exist. */
\r
4659 if(gameInfo.variant != VariantShogi)
\r
4660 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4662 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4666 case IcsPlayingWhite:
\r
4667 case IcsPlayingBlack:
\r
4669 case MachinePlaysWhite:
\r
4670 case MachinePlaysBlack:
\r
4671 if (appData.testLegality &&
\r
4672 gameInfo.variant != VariantBughouse &&
\r
4673 gameInfo.variant != VariantCrazyhouse) break;
\r
4674 if (x < 0 || y < 0) break;
\r
4677 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4678 SetupDropMenu(hmenu);
\r
4679 MenuPopup(hwnd, pt, hmenu, -1);
\r
4690 /* Preprocess messages for buttons in main window */
\r
4692 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4694 int id = GetWindowLong(hwnd, GWL_ID);
\r
4697 for (i=0; i<N_BUTTONS; i++) {
\r
4698 if (buttonDesc[i].id == id) break;
\r
4700 if (i == N_BUTTONS) return 0;
\r
4701 switch (message) {
\r
4706 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4707 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4714 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4717 if (appData.icsActive) {
\r
4718 if (GetKeyState(VK_SHIFT) < 0) {
\r
4720 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4721 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4725 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4726 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4733 if (appData.icsActive) {
\r
4734 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4735 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4737 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4739 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4740 PopUpMoveDialog((char)wParam);
\r
4746 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4749 /* Process messages for Promotion dialog box */
\r
4751 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4755 switch (message) {
\r
4756 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4757 /* Center the dialog over the application window */
\r
4758 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4759 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4760 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4761 gameInfo.variant == VariantGiveaway) ?
\r
4762 SW_SHOW : SW_HIDE);
\r
4763 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4764 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4765 (PieceToChar(WhiteCardinal) >= 'A' &&
\r
4766 PieceToChar(WhiteCardinal) != '~' ||
\r
4767 PieceToChar(BlackCardinal) >= 'A' &&
\r
4768 PieceToChar(BlackCardinal) != '~' ) ?
\r
4769 SW_SHOW : SW_HIDE);
\r
4770 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4771 (PieceToChar(WhiteMarshall) >= 'A' &&
\r
4772 PieceToChar(WhiteMarshall) != '~' ||
\r
4773 PieceToChar(BlackMarshall) >= 'A' &&
\r
4774 PieceToChar(BlackMarshall) != '~' ) ?
\r
4775 SW_SHOW : SW_HIDE);
\r
4776 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4777 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
4778 gameInfo.variant != VariantShogi ?
\r
4779 SW_SHOW : SW_HIDE);
\r
4780 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
4781 gameInfo.variant != VariantShogi ?
\r
4782 SW_SHOW : SW_HIDE);
\r
4783 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
4784 gameInfo.variant == VariantShogi ?
\r
4785 SW_SHOW : SW_HIDE);
\r
4786 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
4787 gameInfo.variant == VariantShogi ?
\r
4788 SW_SHOW : SW_HIDE);
\r
4791 case WM_COMMAND: /* message: received a command */
\r
4792 switch (LOWORD(wParam)) {
\r
4794 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4795 ClearHighlights();
\r
4796 DrawPosition(FALSE, NULL);
\r
4799 promoChar = PieceToChar(BlackKing);
\r
4802 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
4805 promoChar = PieceToChar(BlackRook);
\r
4808 promoChar = PieceToChar(BlackBishop);
\r
4810 case PB_Chancellor:
\r
4811 promoChar = PieceToChar(BlackMarshall);
\r
4813 case PB_Archbishop:
\r
4814 promoChar = PieceToChar(BlackCardinal);
\r
4817 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
4822 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4823 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
4824 only show the popup when we are already sure the move is valid or
\r
4825 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
4826 will figure out it is a promotion from the promoChar. */
\r
4827 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
4828 if (!appData.highlightLastMove) {
\r
4829 ClearHighlights();
\r
4830 DrawPosition(FALSE, NULL);
\r
4837 /* Pop up promotion dialog */
\r
4839 PromotionPopup(HWND hwnd)
\r
4843 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4844 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4845 hwnd, (DLGPROC)lpProc);
\r
4846 FreeProcInstance(lpProc);
\r
4849 /* Toggle ShowThinking */
\r
4851 ToggleShowThinking()
\r
4853 ShowThinkingEvent(!appData.showThinking);
\r
4857 LoadGameDialog(HWND hwnd, char* title)
\r
4861 char fileTitle[MSG_SIZ];
\r
4862 f = OpenFileDialog(hwnd, FALSE, "",
\r
4863 appData.oldSaveStyle ? "gam" : "pgn",
\r
4865 title, &number, fileTitle, NULL);
\r
4867 cmailMsgLoaded = FALSE;
\r
4868 if (number == 0) {
\r
4869 int error = GameListBuild(f);
\r
4871 DisplayError("Cannot build game list", error);
\r
4872 } else if (!ListEmpty(&gameList) &&
\r
4873 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4874 GameListPopUp(f, fileTitle);
\r
4877 GameListDestroy();
\r
4880 LoadGame(f, number, fileTitle, FALSE);
\r
4885 ChangedConsoleFont()
\r
4888 CHARRANGE tmpsel, sel;
\r
4889 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4890 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4891 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4894 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4895 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4896 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4897 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4898 * size. This was undocumented in the version of MSVC++ that I had
\r
4899 * when I wrote the code, but is apparently documented now.
\r
4901 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4902 cfmt.bCharSet = f->lf.lfCharSet;
\r
4903 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4904 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4905 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4906 /* Why are the following seemingly needed too? */
\r
4907 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4908 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4909 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4911 tmpsel.cpMax = -1; /*999999?*/
\r
4912 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4913 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4914 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4915 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4917 paraf.cbSize = sizeof(paraf);
\r
4918 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4919 paraf.dxStartIndent = 0;
\r
4920 paraf.dxOffset = WRAP_INDENT;
\r
4921 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4922 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4925 /*---------------------------------------------------------------------------*\
\r
4927 * Window Proc for main window
\r
4929 \*---------------------------------------------------------------------------*/
\r
4931 /* Process messages for main window, etc. */
\r
4933 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4936 int wmId, wmEvent;
\r
4940 char fileTitle[MSG_SIZ];
\r
4941 static SnapData sd;
\r
4943 switch (message) {
\r
4945 case WM_PAINT: /* message: repaint portion of window */
\r
4949 case WM_ERASEBKGND:
\r
4950 if (IsIconic(hwnd)) {
\r
4951 /* Cheat; change the message */
\r
4952 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4954 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4958 case WM_LBUTTONDOWN:
\r
4959 case WM_MBUTTONDOWN:
\r
4960 case WM_RBUTTONDOWN:
\r
4961 case WM_LBUTTONUP:
\r
4962 case WM_MBUTTONUP:
\r
4963 case WM_RBUTTONUP:
\r
4964 case WM_MOUSEMOVE:
\r
4965 MouseEvent(hwnd, message, wParam, lParam);
\r
4970 if (appData.icsActive) {
\r
4971 if (wParam == '\t') {
\r
4972 if (GetKeyState(VK_SHIFT) < 0) {
\r
4974 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4975 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4979 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4980 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4984 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4985 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4987 SendMessage(h, message, wParam, lParam);
\r
4989 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4990 PopUpMoveDialog((char)wParam);
\r
4994 case WM_PALETTECHANGED:
\r
4995 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4997 HDC hdc = GetDC(hwndMain);
\r
4998 SelectPalette(hdc, hPal, TRUE);
\r
4999 nnew = RealizePalette(hdc);
\r
5001 paletteChanged = TRUE;
\r
5003 UpdateColors(hdc);
\r
5005 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5008 ReleaseDC(hwnd, hdc);
\r
5012 case WM_QUERYNEWPALETTE:
\r
5013 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5015 HDC hdc = GetDC(hwndMain);
\r
5016 paletteChanged = FALSE;
\r
5017 SelectPalette(hdc, hPal, FALSE);
\r
5018 nnew = RealizePalette(hdc);
\r
5020 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5022 ReleaseDC(hwnd, hdc);
\r
5027 case WM_COMMAND: /* message: command from application menu */
\r
5028 wmId = LOWORD(wParam);
\r
5029 wmEvent = HIWORD(wParam);
\r
5034 AnalysisPopDown();
\r
5037 case IDM_NewGameFRC:
\r
5038 if( NewGameFRC() == 0 ) {
\r
5040 AnalysisPopDown();
\r
5044 case IDM_NewVariant:
\r
5045 NewVariantPopup(hwnd);
\r
5048 case IDM_LoadGame:
\r
5049 LoadGameDialog(hwnd, "Load Game from File");
\r
5052 case IDM_LoadNextGame:
\r
5056 case IDM_LoadPrevGame:
\r
5060 case IDM_ReloadGame:
\r
5064 case IDM_LoadPosition:
\r
5065 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5066 Reset(FALSE, TRUE);
\r
5069 f = OpenFileDialog(hwnd, FALSE, "",
\r
5070 appData.oldSaveStyle ? "pos" : "fen",
\r
5072 "Load Position from File", &number, fileTitle, NULL);
\r
5074 LoadPosition(f, number, fileTitle);
\r
5078 case IDM_LoadNextPosition:
\r
5079 ReloadPosition(1);
\r
5082 case IDM_LoadPrevPosition:
\r
5083 ReloadPosition(-1);
\r
5086 case IDM_ReloadPosition:
\r
5087 ReloadPosition(0);
\r
5090 case IDM_SaveGame:
\r
5091 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5092 f = OpenFileDialog(hwnd, TRUE, defName,
\r
5093 appData.oldSaveStyle ? "gam" : "pgn",
\r
5095 "Save Game to File", NULL, fileTitle, NULL);
\r
5097 SaveGame(f, 0, "");
\r
5101 case IDM_SavePosition:
\r
5102 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5103 f = OpenFileDialog(hwnd, TRUE, defName,
\r
5104 appData.oldSaveStyle ? "pos" : "fen",
\r
5106 "Save Position to File", NULL, fileTitle, NULL);
\r
5108 SavePosition(f, 0, "");
\r
5112 case IDM_CopyGame:
\r
5113 CopyGameToClipboard();
\r
5116 case IDM_PasteGame:
\r
5117 PasteGameFromClipboard();
\r
5120 case IDM_CopyGameListToClipboard:
\r
5121 CopyGameListToClipboard();
\r
5124 /* [AS] Autodetect FEN or PGN data */
\r
5125 case IDM_PasteAny:
\r
5126 PasteGameOrFENFromClipboard();
\r
5129 /* [AS] Move history */
\r
5130 case IDM_ShowMoveHistory:
\r
5131 if( MoveHistoryIsUp() ) {
\r
5132 MoveHistoryPopDown();
\r
5135 MoveHistoryPopUp();
\r
5139 /* [AS] Eval graph */
\r
5140 case IDM_ShowEvalGraph:
\r
5141 if( EvalGraphIsUp() ) {
\r
5142 EvalGraphPopDown();
\r
5149 /* [AS] Engine output */
\r
5150 case IDM_ShowEngineOutput:
\r
5151 if( EngineOutputIsUp() ) {
\r
5152 EngineOutputPopDown();
\r
5155 EngineOutputPopUp();
\r
5159 /* [AS] User adjudication */
\r
5160 case IDM_UserAdjudication_White:
\r
5161 UserAdjudicationEvent( +1 );
\r
5164 case IDM_UserAdjudication_Black:
\r
5165 UserAdjudicationEvent( -1 );
\r
5168 case IDM_UserAdjudication_Draw:
\r
5169 UserAdjudicationEvent( 0 );
\r
5172 /* [AS] Game list options dialog */
\r
5173 case IDM_GameListOptions:
\r
5174 GameListOptions();
\r
5177 case IDM_CopyPosition:
\r
5178 CopyFENToClipboard();
\r
5181 case IDM_PastePosition:
\r
5182 PasteFENFromClipboard();
\r
5185 case IDM_MailMove:
\r
5189 case IDM_ReloadCMailMsg:
\r
5190 Reset(TRUE, TRUE);
\r
5191 ReloadCmailMsgEvent(FALSE);
\r
5194 case IDM_Minimize:
\r
5195 ShowWindow(hwnd, SW_MINIMIZE);
\r
5202 case IDM_MachineWhite:
\r
5203 MachineWhiteEvent();
\r
5205 * refresh the tags dialog only if it's visible
\r
5207 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5209 tags = PGNTags(&gameInfo);
\r
5210 TagsPopUp(tags, CmailMsg());
\r
5215 case IDM_MachineBlack:
\r
5216 MachineBlackEvent();
\r
5218 * refresh the tags dialog only if it's visible
\r
5220 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5222 tags = PGNTags(&gameInfo);
\r
5223 TagsPopUp(tags, CmailMsg());
\r
5228 case IDM_TwoMachines:
\r
5229 TwoMachinesEvent();
\r
5231 * refresh the tags dialog only if it's visible
\r
5233 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5235 tags = PGNTags(&gameInfo);
\r
5236 TagsPopUp(tags, CmailMsg());
\r
5241 case IDM_AnalysisMode:
\r
5242 if (!first.analysisSupport) {
\r
5243 char buf[MSG_SIZ];
\r
5244 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5245 DisplayError(buf, 0);
\r
5247 if (!appData.showThinking) ToggleShowThinking();
\r
5248 AnalyzeModeEvent();
\r
5252 case IDM_AnalyzeFile:
\r
5253 if (!first.analysisSupport) {
\r
5254 char buf[MSG_SIZ];
\r
5255 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5256 DisplayError(buf, 0);
\r
5258 if (!appData.showThinking) ToggleShowThinking();
\r
5259 AnalyzeFileEvent();
\r
5260 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5261 AnalysisPeriodicEvent(1);
\r
5265 case IDM_IcsClient:
\r
5269 case IDM_EditGame:
\r
5273 case IDM_EditPosition:
\r
5274 EditPositionEvent();
\r
5277 case IDM_Training:
\r
5281 case IDM_ShowGameList:
\r
5282 ShowGameListProc();
\r
5285 case IDM_EditTags:
\r
5289 case IDM_EditComment:
\r
5290 if (commentDialogUp && editComment) {
\r
5293 EditCommentEvent();
\r
5313 case IDM_CallFlag:
\r
5333 case IDM_StopObserving:
\r
5334 StopObservingEvent();
\r
5337 case IDM_StopExamining:
\r
5338 StopExaminingEvent();
\r
5341 case IDM_TypeInMove:
\r
5342 PopUpMoveDialog('\000');
\r
5345 case IDM_Backward:
\r
5347 SetFocus(hwndMain);
\r
5352 SetFocus(hwndMain);
\r
5357 SetFocus(hwndMain);
\r
5362 SetFocus(hwndMain);
\r
5369 case IDM_TruncateGame:
\r
5370 TruncateGameEvent();
\r
5377 case IDM_RetractMove:
\r
5378 RetractMoveEvent();
\r
5381 case IDM_FlipView:
\r
5382 flipView = !flipView;
\r
5383 DrawPosition(FALSE, NULL);
\r
5386 case IDM_FlipClock:
\r
5387 flipClock = !flipClock;
\r
5388 DisplayBothClocks();
\r
5391 case IDM_GeneralOptions:
\r
5392 GeneralOptionsPopup(hwnd);
\r
5393 DrawPosition(TRUE, NULL);
\r
5396 case IDM_BoardOptions:
\r
5397 BoardOptionsPopup(hwnd);
\r
5400 case IDM_EnginePlayOptions:
\r
5401 EnginePlayOptionsPopup(hwnd);
\r
5404 case IDM_OptionsUCI:
\r
5405 UciOptionsPopup(hwnd);
\r
5408 case IDM_IcsOptions:
\r
5409 IcsOptionsPopup(hwnd);
\r
5413 FontsOptionsPopup(hwnd);
\r
5417 SoundOptionsPopup(hwnd);
\r
5420 case IDM_CommPort:
\r
5421 CommPortOptionsPopup(hwnd);
\r
5424 case IDM_LoadOptions:
\r
5425 LoadOptionsPopup(hwnd);
\r
5428 case IDM_SaveOptions:
\r
5429 SaveOptionsPopup(hwnd);
\r
5432 case IDM_TimeControl:
\r
5433 TimeControlOptionsPopup(hwnd);
\r
5436 case IDM_SaveSettings:
\r
5437 SaveSettings(settingsFileName);
\r
5440 case IDM_SaveSettingsOnExit:
\r
5441 saveSettingsOnExit = !saveSettingsOnExit;
\r
5442 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5443 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5444 MF_CHECKED : MF_UNCHECKED));
\r
5455 case IDM_AboutGame:
\r
5460 appData.debugMode = !appData.debugMode;
\r
5461 if (appData.debugMode) {
\r
5462 char dir[MSG_SIZ];
\r
5463 GetCurrentDirectory(MSG_SIZ, dir);
\r
5464 SetCurrentDirectory(installDir);
\r
5465 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5466 SetCurrentDirectory(dir);
\r
5467 setbuf(debugFP, NULL);
\r
5474 case IDM_HELPCONTENTS:
\r
5475 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5476 MessageBox (GetFocus(),
\r
5477 "Unable to activate help",
\r
5478 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5482 case IDM_HELPSEARCH:
\r
5483 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5484 MessageBox (GetFocus(),
\r
5485 "Unable to activate help",
\r
5486 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5490 case IDM_HELPHELP:
\r
5491 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5492 MessageBox (GetFocus(),
\r
5493 "Unable to activate help",
\r
5494 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5499 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5501 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5502 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5503 FreeProcInstance(lpProc);
\r
5506 case IDM_DirectCommand1:
\r
5507 AskQuestionEvent("Direct Command",
\r
5508 "Send to chess program:", "", "1");
\r
5510 case IDM_DirectCommand2:
\r
5511 AskQuestionEvent("Direct Command",
\r
5512 "Send to second chess program:", "", "2");
\r
5515 case EP_WhitePawn:
\r
5516 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5517 fromX = fromY = -1;
\r
5520 case EP_WhiteKnight:
\r
5521 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5522 fromX = fromY = -1;
\r
5525 case EP_WhiteBishop:
\r
5526 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5527 fromX = fromY = -1;
\r
5530 case EP_WhiteRook:
\r
5531 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5532 fromX = fromY = -1;
\r
5535 case EP_WhiteQueen:
\r
5536 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5537 fromX = fromY = -1;
\r
5540 case EP_WhiteFerz:
\r
5541 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5542 fromX = fromY = -1;
\r
5545 case EP_WhiteWazir:
\r
5546 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5547 fromX = fromY = -1;
\r
5550 case EP_WhiteAlfil:
\r
5551 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5552 fromX = fromY = -1;
\r
5555 case EP_WhiteCannon:
\r
5556 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5557 fromX = fromY = -1;
\r
5560 case EP_WhiteCardinal:
\r
5561 EditPositionMenuEvent(WhiteCardinal, fromX, fromY);
\r
5562 fromX = fromY = -1;
\r
5565 case EP_WhiteMarshall:
\r
5566 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5567 fromX = fromY = -1;
\r
5570 case EP_WhiteKing:
\r
5571 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5572 fromX = fromY = -1;
\r
5575 case EP_BlackPawn:
\r
5576 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5577 fromX = fromY = -1;
\r
5580 case EP_BlackKnight:
\r
5581 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5582 fromX = fromY = -1;
\r
5585 case EP_BlackBishop:
\r
5586 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5587 fromX = fromY = -1;
\r
5590 case EP_BlackRook:
\r
5591 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5592 fromX = fromY = -1;
\r
5595 case EP_BlackQueen:
\r
5596 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5597 fromX = fromY = -1;
\r
5600 case EP_BlackFerz:
\r
5601 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5602 fromX = fromY = -1;
\r
5605 case EP_BlackWazir:
\r
5606 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5607 fromX = fromY = -1;
\r
5610 case EP_BlackAlfil:
\r
5611 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5612 fromX = fromY = -1;
\r
5615 case EP_BlackCannon:
\r
5616 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5617 fromX = fromY = -1;
\r
5620 case EP_BlackCardinal:
\r
5621 EditPositionMenuEvent(BlackCardinal, fromX, fromY);
\r
5622 fromX = fromY = -1;
\r
5625 case EP_BlackMarshall:
\r
5626 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5627 fromX = fromY = -1;
\r
5630 case EP_BlackKing:
\r
5631 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5632 fromX = fromY = -1;
\r
5635 case EP_EmptySquare:
\r
5636 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5637 fromX = fromY = -1;
\r
5640 case EP_ClearBoard:
\r
5641 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5642 fromX = fromY = -1;
\r
5646 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5647 fromX = fromY = -1;
\r
5651 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5652 fromX = fromY = -1;
\r
5656 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5657 fromX = fromY = -1;
\r
5661 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5662 fromX = fromY = -1;
\r
5666 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5667 fromX = fromY = -1;
\r
5671 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5672 fromX = fromY = -1;
\r
5676 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5677 fromX = fromY = -1;
\r
5681 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5682 fromX = fromY = -1;
\r
5686 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5687 fromX = fromY = -1;
\r
5691 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5697 case CLOCK_TIMER_ID:
\r
5698 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5699 clockTimerEvent = 0;
\r
5700 DecrementClocks(); /* call into back end */
\r
5702 case LOAD_GAME_TIMER_ID:
\r
5703 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5704 loadGameTimerEvent = 0;
\r
5705 AutoPlayGameLoop(); /* call into back end */
\r
5707 case ANALYSIS_TIMER_ID:
\r
5708 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
5709 appData.periodicUpdates) {
\r
5710 AnalysisPeriodicEvent(0);
\r
5712 KillTimer(hwnd, analysisTimerEvent);
\r
5713 analysisTimerEvent = 0;
\r
5716 case DELAYED_TIMER_ID:
\r
5717 KillTimer(hwnd, delayedTimerEvent);
\r
5718 delayedTimerEvent = 0;
\r
5719 delayedTimerCallback();
\r
5724 case WM_USER_Input:
\r
5725 InputEvent(hwnd, message, wParam, lParam);
\r
5728 /* [AS] Also move "attached" child windows */
\r
5729 case WM_WINDOWPOSCHANGING:
\r
5730 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5731 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5733 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
5734 /* Window is moving */
\r
5737 GetWindowRect( hwnd, &rcMain );
\r
5739 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5740 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5741 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5746 /* [AS] Snapping */
\r
5747 case WM_ENTERSIZEMOVE:
\r
5748 if (hwnd == hwndMain) {
\r
5749 doingSizing = TRUE;
\r
5752 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5756 if (hwnd == hwndMain) {
\r
5757 lastSizing = wParam;
\r
5762 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5764 case WM_EXITSIZEMOVE:
\r
5765 if (hwnd == hwndMain) {
\r
5767 doingSizing = FALSE;
\r
5768 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5769 GetClientRect(hwnd, &client);
\r
5770 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5773 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5776 case WM_DESTROY: /* message: window being destroyed */
\r
5777 PostQuitMessage(0);
\r
5781 if (hwnd == hwndMain) {
\r
5786 default: /* Passes it on if unprocessed */
\r
5787 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5792 /*---------------------------------------------------------------------------*\
\r
5794 * Misc utility routines
\r
5796 \*---------------------------------------------------------------------------*/
\r
5799 * Decent random number generator, at least not as bad as Windows
\r
5800 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5802 unsigned int randstate;
\r
5807 randstate = randstate * 1664525 + 1013904223;
\r
5808 return (int) randstate & 0x7fffffff;
\r
5812 mysrandom(unsigned int seed)
\r
5819 * returns TRUE if user selects a different color, FALSE otherwise
\r
5823 ChangeColor(HWND hwnd, COLORREF *which)
\r
5825 static BOOL firstTime = TRUE;
\r
5826 static DWORD customColors[16];
\r
5828 COLORREF newcolor;
\r
5833 /* Make initial colors in use available as custom colors */
\r
5834 /* Should we put the compiled-in defaults here instead? */
\r
5836 customColors[i++] = lightSquareColor & 0xffffff;
\r
5837 customColors[i++] = darkSquareColor & 0xffffff;
\r
5838 customColors[i++] = whitePieceColor & 0xffffff;
\r
5839 customColors[i++] = blackPieceColor & 0xffffff;
\r
5840 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5841 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5843 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5844 customColors[i++] = textAttribs[ccl].color;
\r
5846 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5847 firstTime = FALSE;
\r
5850 cc.lStructSize = sizeof(cc);
\r
5851 cc.hwndOwner = hwnd;
\r
5852 cc.hInstance = NULL;
\r
5853 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5854 cc.lpCustColors = (LPDWORD) customColors;
\r
5855 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5857 if (!ChooseColor(&cc)) return FALSE;
\r
5859 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5860 if (newcolor == *which) return FALSE;
\r
5861 *which = newcolor;
\r
5865 InitDrawingColors();
\r
5866 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5871 MyLoadSound(MySound *ms)
\r
5877 if (ms->data) free(ms->data);
\r
5880 switch (ms->name[0]) {
\r
5886 /* System sound from Control Panel. Don't preload here. */
\r
5890 if (ms->name[1] == NULLCHAR) {
\r
5891 /* "!" alone = silence */
\r
5894 /* Builtin wave resource. Error if not found. */
\r
5895 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5896 if (h == NULL) break;
\r
5897 ms->data = (void *)LoadResource(hInst, h);
\r
5898 if (h == NULL) break;
\r
5903 /* .wav file. Error if not found. */
\r
5904 f = fopen(ms->name, "rb");
\r
5905 if (f == NULL) break;
\r
5906 if (fstat(fileno(f), &st) < 0) break;
\r
5907 ms->data = malloc(st.st_size);
\r
5908 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5914 char buf[MSG_SIZ];
\r
5915 sprintf(buf, "Error loading sound %s", ms->name);
\r
5916 DisplayError(buf, GetLastError());
\r
5922 MyPlaySound(MySound *ms)
\r
5924 BOOLEAN ok = FALSE;
\r
5925 switch (ms->name[0]) {
\r
5931 /* System sound from Control Panel (deprecated feature).
\r
5932 "$" alone or an unset sound name gets default beep (still in use). */
\r
5933 if (ms->name[1]) {
\r
5934 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5936 if (!ok) ok = MessageBeep(MB_OK);
\r
5939 /* Builtin wave resource, or "!" alone for silence */
\r
5940 if (ms->name[1]) {
\r
5941 if (ms->data == NULL) return FALSE;
\r
5942 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5948 /* .wav file. Error if not found. */
\r
5949 if (ms->data == NULL) return FALSE;
\r
5950 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5953 /* Don't print an error: this can happen innocently if the sound driver
\r
5954 is busy; for instance, if another instance of WinBoard is playing
\r
5955 a sound at about the same time. */
\r
5958 char buf[MSG_SIZ];
\r
5959 sprintf(buf, "Error playing sound %s", ms->name);
\r
5960 DisplayError(buf, GetLastError());
\r
5968 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5971 OPENFILENAME *ofn;
\r
5972 static UINT *number; /* gross that this is static */
\r
5974 switch (message) {
\r
5975 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5976 /* Center the dialog over the application window */
\r
5977 ofn = (OPENFILENAME *) lParam;
\r
5978 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5979 number = (UINT *) ofn->lCustData;
\r
5980 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5984 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5985 return FALSE; /* Allow for further processing */
\r
5988 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5989 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5991 return FALSE; /* Allow for further processing */
\r
5997 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5999 static UINT *number;
\r
6000 OPENFILENAME *ofname;
\r
6003 case WM_INITDIALOG:
\r
6004 ofname = (OPENFILENAME *)lParam;
\r
6005 number = (UINT *)(ofname->lCustData);
\r
6008 ofnot = (OFNOTIFY *)lParam;
\r
6009 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6010 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6019 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
6020 char *nameFilt, char *dlgTitle, UINT *number,
\r
6021 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6023 OPENFILENAME openFileName;
\r
6024 char buf1[MSG_SIZ];
\r
6027 if (fileName == NULL) fileName = buf1;
\r
6028 if (defName == NULL) {
\r
6029 strcpy(fileName, "*.");
\r
6030 strcat(fileName, defExt);
\r
6032 strcpy(fileName, defName);
\r
6034 if (fileTitle) strcpy(fileTitle, "");
\r
6035 if (number) *number = 0;
\r
6037 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6038 openFileName.hwndOwner = hwnd;
\r
6039 openFileName.hInstance = (HANDLE) hInst;
\r
6040 openFileName.lpstrFilter = nameFilt;
\r
6041 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6042 openFileName.nMaxCustFilter = 0L;
\r
6043 openFileName.nFilterIndex = 1L;
\r
6044 openFileName.lpstrFile = fileName;
\r
6045 openFileName.nMaxFile = MSG_SIZ;
\r
6046 openFileName.lpstrFileTitle = fileTitle;
\r
6047 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6048 openFileName.lpstrInitialDir = NULL;
\r
6049 openFileName.lpstrTitle = dlgTitle;
\r
6050 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6051 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
6052 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6053 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6054 openFileName.nFileOffset = 0;
\r
6055 openFileName.nFileExtension = 0;
\r
6056 openFileName.lpstrDefExt = defExt;
\r
6057 openFileName.lCustData = (LONG) number;
\r
6058 openFileName.lpfnHook = oldDialog ?
\r
6059 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6060 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6062 if (write ? GetSaveFileName(&openFileName) :
\r
6063 GetOpenFileName(&openFileName)) {
\r
6064 /* open the file */
\r
6065 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
6067 MessageBox(hwnd, "File open failed", NULL,
\r
6068 MB_OK|MB_ICONEXCLAMATION);
\r
6072 int err = CommDlgExtendedError();
\r
6073 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6082 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6084 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6087 * Get the first pop-up menu in the menu template. This is the
\r
6088 * menu that TrackPopupMenu displays.
\r
6090 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6092 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6095 * TrackPopup uses screen coordinates, so convert the
\r
6096 * coordinates of the mouse click to screen coordinates.
\r
6098 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6100 /* Draw and track the floating pop-up menu. */
\r
6101 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6102 pt.x, pt.y, 0, hwnd, NULL);
\r
6104 /* Destroy the menu.*/
\r
6105 DestroyMenu(hmenu);
\r
6110 int sizeX, sizeY, newSizeX, newSizeY;
\r
6112 } ResizeEditPlusButtonsClosure;
\r
6115 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6117 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6121 if (hChild == cl->hText) return TRUE;
\r
6122 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6123 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6124 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6125 ScreenToClient(cl->hDlg, &pt);
\r
6126 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6127 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6131 /* Resize a dialog that has a (rich) edit field filling most of
\r
6132 the top, with a row of buttons below */
\r
6134 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6137 int newTextHeight, newTextWidth;
\r
6138 ResizeEditPlusButtonsClosure cl;
\r
6140 /*if (IsIconic(hDlg)) return;*/
\r
6141 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6143 cl.hdwp = BeginDeferWindowPos(8);
\r
6145 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6146 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6147 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6148 if (newTextHeight < 0) {
\r
6149 newSizeY += -newTextHeight;
\r
6150 newTextHeight = 0;
\r
6152 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6153 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6159 cl.newSizeX = newSizeX;
\r
6160 cl.newSizeY = newSizeY;
\r
6161 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6163 EndDeferWindowPos(cl.hdwp);
\r
6166 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6168 RECT rChild, rParent;
\r
6169 int wChild, hChild, wParent, hParent;
\r
6170 int wScreen, hScreen, xNew, yNew;
\r
6173 /* Get the Height and Width of the child window */
\r
6174 GetWindowRect (hwndChild, &rChild);
\r
6175 wChild = rChild.right - rChild.left;
\r
6176 hChild = rChild.bottom - rChild.top;
\r
6178 /* Get the Height and Width of the parent window */
\r
6179 GetWindowRect (hwndParent, &rParent);
\r
6180 wParent = rParent.right - rParent.left;
\r
6181 hParent = rParent.bottom - rParent.top;
\r
6183 /* Get the display limits */
\r
6184 hdc = GetDC (hwndChild);
\r
6185 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6186 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6187 ReleaseDC(hwndChild, hdc);
\r
6189 /* Calculate new X position, then adjust for screen */
\r
6190 xNew = rParent.left + ((wParent - wChild) /2);
\r
6193 } else if ((xNew+wChild) > wScreen) {
\r
6194 xNew = wScreen - wChild;
\r
6197 /* Calculate new Y position, then adjust for screen */
\r
6199 yNew = rParent.top + ((hParent - hChild) /2);
\r
6202 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6207 } else if ((yNew+hChild) > hScreen) {
\r
6208 yNew = hScreen - hChild;
\r
6211 /* Set it, and return */
\r
6212 return SetWindowPos (hwndChild, NULL,
\r
6213 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6216 /* Center one window over another */
\r
6217 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6219 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6222 /*---------------------------------------------------------------------------*\
\r
6224 * Startup Dialog functions
\r
6226 \*---------------------------------------------------------------------------*/
\r
6228 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6230 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6232 while (*cd != NULL) {
\r
6233 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6239 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6241 char buf1[ARG_MAX];
\r
6244 if (str[0] == '@') {
\r
6245 FILE* f = fopen(str + 1, "r");
\r
6247 DisplayFatalError(str + 1, errno, 2);
\r
6250 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6252 buf1[len] = NULLCHAR;
\r
6256 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6259 char buf[MSG_SIZ];
\r
6260 char *end = strchr(str, '\n');
\r
6261 if (end == NULL) return;
\r
6262 memcpy(buf, str, end - str);
\r
6263 buf[end - str] = NULLCHAR;
\r
6264 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6270 SetStartupDialogEnables(HWND hDlg)
\r
6272 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6273 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6274 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6275 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6276 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6277 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6278 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6279 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6280 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6281 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6282 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6283 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6284 IsDlgButtonChecked(hDlg, OPT_View));
\r
6288 QuoteForFilename(char *filename)
\r
6290 int dquote, space;
\r
6291 dquote = strchr(filename, '"') != NULL;
\r
6292 space = strchr(filename, ' ') != NULL;
\r
6293 if (dquote || space) {
\r
6305 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6307 char buf[MSG_SIZ];
\r
6310 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6311 q = QuoteForFilename(nthcp);
\r
6312 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6313 if (*nthdir != NULLCHAR) {
\r
6314 q = QuoteForFilename(nthdir);
\r
6315 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6317 if (*nthcp == NULLCHAR) {
\r
6318 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6319 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6320 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6321 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6326 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6328 char buf[MSG_SIZ];
\r
6332 switch (message) {
\r
6333 case WM_INITDIALOG:
\r
6334 /* Center the dialog */
\r
6335 CenterWindow (hDlg, GetDesktopWindow());
\r
6336 /* Initialize the dialog items */
\r
6337 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6338 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6339 firstChessProgramNames);
\r
6340 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6341 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6342 secondChessProgramNames);
\r
6343 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6344 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6345 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6346 if (*appData.icsHelper != NULLCHAR) {
\r
6347 char *q = QuoteForFilename(appData.icsHelper);
\r
6348 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6350 if (*appData.icsHost == NULLCHAR) {
\r
6351 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6352 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6353 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6354 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6355 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6358 if (appData.icsActive) {
\r
6359 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6361 else if (appData.noChessProgram) {
\r
6362 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6365 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6368 SetStartupDialogEnables(hDlg);
\r
6372 switch (LOWORD(wParam)) {
\r
6374 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6375 strcpy(buf, "/fcp=");
\r
6376 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6378 ParseArgs(StringGet, &p);
\r
6379 strcpy(buf, "/scp=");
\r
6380 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6382 ParseArgs(StringGet, &p);
\r
6383 appData.noChessProgram = FALSE;
\r
6384 appData.icsActive = FALSE;
\r
6385 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6386 strcpy(buf, "/ics /icshost=");
\r
6387 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6389 ParseArgs(StringGet, &p);
\r
6390 if (appData.zippyPlay) {
\r
6391 strcpy(buf, "/fcp=");
\r
6392 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6394 ParseArgs(StringGet, &p);
\r
6396 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6397 appData.noChessProgram = TRUE;
\r
6398 appData.icsActive = FALSE;
\r
6400 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6401 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6404 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6405 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6407 ParseArgs(StringGet, &p);
\r
6409 EndDialog(hDlg, TRUE);
\r
6416 case IDM_HELPCONTENTS:
\r
6417 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6418 MessageBox (GetFocus(),
\r
6419 "Unable to activate help",
\r
6420 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6425 SetStartupDialogEnables(hDlg);
\r
6433 /*---------------------------------------------------------------------------*\
\r
6435 * About box dialog functions
\r
6437 \*---------------------------------------------------------------------------*/
\r
6439 /* Process messages for "About" dialog box */
\r
6441 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6443 switch (message) {
\r
6444 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6445 /* Center the dialog over the application window */
\r
6446 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6447 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6450 case WM_COMMAND: /* message: received a command */
\r
6451 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6452 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6453 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6461 /*---------------------------------------------------------------------------*\
\r
6463 * Comment Dialog functions
\r
6465 \*---------------------------------------------------------------------------*/
\r
6468 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6470 static HANDLE hwndText = NULL;
\r
6471 int len, newSizeX, newSizeY, flags;
\r
6472 static int sizeX, sizeY;
\r
6477 switch (message) {
\r
6478 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6479 /* Initialize the dialog items */
\r
6480 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6481 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6482 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6483 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6484 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6485 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6486 SetWindowText(hDlg, commentTitle);
\r
6487 if (editComment) {
\r
6488 SetFocus(hwndText);
\r
6490 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6492 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6493 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6494 MAKELPARAM(FALSE, 0));
\r
6495 /* Size and position the dialog */
\r
6496 if (!commentDialog) {
\r
6497 commentDialog = hDlg;
\r
6498 flags = SWP_NOZORDER;
\r
6499 GetClientRect(hDlg, &rect);
\r
6500 sizeX = rect.right;
\r
6501 sizeY = rect.bottom;
\r
6502 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
6503 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
6504 WINDOWPLACEMENT wp;
\r
6505 EnsureOnScreen(&commentX, &commentY);
\r
6506 wp.length = sizeof(WINDOWPLACEMENT);
\r
6508 wp.showCmd = SW_SHOW;
\r
6509 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6510 wp.rcNormalPosition.left = commentX;
\r
6511 wp.rcNormalPosition.right = commentX + commentW;
\r
6512 wp.rcNormalPosition.top = commentY;
\r
6513 wp.rcNormalPosition.bottom = commentY + commentH;
\r
6514 SetWindowPlacement(hDlg, &wp);
\r
6516 GetClientRect(hDlg, &rect);
\r
6517 newSizeX = rect.right;
\r
6518 newSizeY = rect.bottom;
\r
6519 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6520 newSizeX, newSizeY);
\r
6527 case WM_COMMAND: /* message: received a command */
\r
6528 switch (LOWORD(wParam)) {
\r
6530 if (editComment) {
\r
6532 /* Read changed options from the dialog box */
\r
6533 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6534 len = GetWindowTextLength(hwndText);
\r
6535 str = (char *) malloc(len + 1);
\r
6536 GetWindowText(hwndText, str, len + 1);
\r
6545 ReplaceComment(commentIndex, str);
\r
6552 case OPT_CancelComment:
\r
6556 case OPT_ClearComment:
\r
6557 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6560 case OPT_EditComment:
\r
6561 EditCommentEvent();
\r
6570 newSizeX = LOWORD(lParam);
\r
6571 newSizeY = HIWORD(lParam);
\r
6572 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6577 case WM_GETMINMAXINFO:
\r
6578 /* Prevent resizing window too small */
\r
6579 mmi = (MINMAXINFO *) lParam;
\r
6580 mmi->ptMinTrackSize.x = 100;
\r
6581 mmi->ptMinTrackSize.y = 100;
\r
6588 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6593 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6595 if (str == NULL) str = "";
\r
6596 p = (char *) malloc(2 * strlen(str) + 2);
\r
6599 if (*str == '\n') *q++ = '\r';
\r
6603 if (commentText != NULL) free(commentText);
\r
6605 commentIndex = index;
\r
6606 commentTitle = title;
\r
6608 editComment = edit;
\r
6610 if (commentDialog) {
\r
6611 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6612 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
6614 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6615 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6616 hwndMain, (DLGPROC)lpProc);
\r
6617 FreeProcInstance(lpProc);
\r
6619 commentDialogUp = TRUE;
\r
6623 /*---------------------------------------------------------------------------*\
\r
6625 * Type-in move dialog functions
\r
6627 \*---------------------------------------------------------------------------*/
\r
6630 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6632 char move[MSG_SIZ];
\r
6634 ChessMove moveType;
\r
6635 int fromX, fromY, toX, toY;
\r
6638 switch (message) {
\r
6639 case WM_INITDIALOG:
\r
6640 move[0] = (char) lParam;
\r
6641 move[1] = NULLCHAR;
\r
6642 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6643 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6644 SetWindowText(hInput, move);
\r
6646 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6650 switch (LOWORD(wParam)) {
\r
6652 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
6653 gameMode != Training) {
\r
6654 DisplayMoveError("Displayed move is not current");
\r
6656 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6657 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
6658 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
6659 if (gameMode != Training)
\r
6660 forwardMostMove = currentMove;
\r
6661 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
6663 DisplayMoveError("Could not parse move");
\r
6666 EndDialog(hDlg, TRUE);
\r
6669 EndDialog(hDlg, FALSE);
\r
6680 PopUpMoveDialog(char firstchar)
\r
6684 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
6685 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
6686 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
6687 gameMode == EditPosition || gameMode == IcsExamining ||
\r
6688 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
6689 gameMode == Training) {
\r
6690 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6691 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6692 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6693 FreeProcInstance(lpProc);
\r
6697 /*---------------------------------------------------------------------------*\
\r
6701 \*---------------------------------------------------------------------------*/
\r
6703 /* Nonmodal error box */
\r
6704 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6705 WPARAM wParam, LPARAM lParam);
\r
6708 ErrorPopUp(char *title, char *content)
\r
6712 BOOLEAN modal = hwndMain == NULL;
\r
6730 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6731 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6734 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6736 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6737 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6738 hwndMain, (DLGPROC)lpProc);
\r
6739 FreeProcInstance(lpProc);
\r
6746 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6747 if (errorDialog == NULL) return;
\r
6748 DestroyWindow(errorDialog);
\r
6749 errorDialog = NULL;
\r
6753 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6758 switch (message) {
\r
6759 case WM_INITDIALOG:
\r
6760 GetWindowRect(hDlg, &rChild);
\r
6763 SetWindowPos(hDlg, NULL, rChild.left,
\r
6764 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6765 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6769 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6770 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6771 and it doesn't work when you resize the dialog.
\r
6772 For now, just give it a default position.
\r
6774 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6776 errorDialog = hDlg;
\r
6777 SetWindowText(hDlg, errorTitle);
\r
6778 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6779 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6783 switch (LOWORD(wParam)) {
\r
6786 if (errorDialog == hDlg) errorDialog = NULL;
\r
6787 DestroyWindow(hDlg);
\r
6799 HWND gothicDialog = NULL;
\r
6802 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6806 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6808 switch (message) {
\r
6809 case WM_INITDIALOG:
\r
6810 GetWindowRect(hDlg, &rChild);
\r
6812 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
6816 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6817 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6818 and it doesn't work when you resize the dialog.
\r
6819 For now, just give it a default position.
\r
6821 gothicDialog = hDlg;
\r
6822 SetWindowText(hDlg, errorTitle);
\r
6823 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6824 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6828 switch (LOWORD(wParam)) {
\r
6831 if (errorDialog == hDlg) errorDialog = NULL;
\r
6832 DestroyWindow(hDlg);
\r
6844 GothicPopUp(char *title, char up)
\r
6848 BOOLEAN modal = hwndMain == NULL;
\r
6850 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6851 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6853 if(up && gothicDialog == NULL) {
\r
6854 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6855 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6856 hwndMain, (DLGPROC)lpProc);
\r
6857 FreeProcInstance(lpProc);
\r
6858 } else if(!up && gothicDialog != NULL) {
\r
6859 DestroyWindow(gothicDialog);
\r
6860 gothicDialog = NULL;
\r
6865 /*---------------------------------------------------------------------------*\
\r
6867 * Ics Interaction console functions
\r
6869 \*---------------------------------------------------------------------------*/
\r
6871 #define HISTORY_SIZE 64
\r
6872 static char *history[HISTORY_SIZE];
\r
6873 int histIn = 0, histP = 0;
\r
6876 SaveInHistory(char *cmd)
\r
6878 if (history[histIn] != NULL) {
\r
6879 free(history[histIn]);
\r
6880 history[histIn] = NULL;
\r
6882 if (*cmd == NULLCHAR) return;
\r
6883 history[histIn] = StrSave(cmd);
\r
6884 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6885 if (history[histIn] != NULL) {
\r
6886 free(history[histIn]);
\r
6887 history[histIn] = NULL;
\r
6893 PrevInHistory(char *cmd)
\r
6896 if (histP == histIn) {
\r
6897 if (history[histIn] != NULL) free(history[histIn]);
\r
6898 history[histIn] = StrSave(cmd);
\r
6900 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6901 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6903 return history[histP];
\r
6909 if (histP == histIn) return NULL;
\r
6910 histP = (histP + 1) % HISTORY_SIZE;
\r
6911 return history[histP];
\r
6918 BOOLEAN immediate;
\r
6919 } IcsTextMenuEntry;
\r
6920 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
6921 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
6924 ParseIcsTextMenu(char *icsTextMenuString)
\r
6927 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
6928 char *p = icsTextMenuString;
\r
6929 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6932 if (e->command != NULL) {
\r
6934 e->command = NULL;
\r
6938 e = icsTextMenuEntry;
\r
6939 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6940 if (*p == ';' || *p == '\n') {
\r
6941 e->item = strdup("-");
\r
6942 e->command = NULL;
\r
6944 } else if (*p == '-') {
\r
6945 e->item = strdup("-");
\r
6946 e->command = NULL;
\r
6950 char *q, *r, *s, *t;
\r
6952 q = strchr(p, ',');
\r
6953 if (q == NULL) break;
\r
6955 r = strchr(q + 1, ',');
\r
6956 if (r == NULL) break;
\r
6958 s = strchr(r + 1, ',');
\r
6959 if (s == NULL) break;
\r
6962 t = strchr(s + 1, c);
\r
6965 t = strchr(s + 1, c);
\r
6967 if (t != NULL) *t = NULLCHAR;
\r
6968 e->item = strdup(p);
\r
6969 e->command = strdup(q + 1);
\r
6970 e->getname = *(r + 1) != '0';
\r
6971 e->immediate = *(s + 1) != '0';
\r
6975 if (t == NULL) break;
\r
6984 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6988 hmenu = LoadMenu(hInst, "TextMenu");
\r
6989 h = GetSubMenu(hmenu, 0);
\r
6991 if (strcmp(e->item, "-") == 0) {
\r
6992 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6994 if (e->item[0] == '|') {
\r
6995 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
6996 IDM_CommandX + i, &e->item[1]);
\r
6998 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7007 WNDPROC consoleTextWindowProc;
\r
7010 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7012 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7013 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7017 SetWindowText(hInput, command);
\r
7019 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7021 sel.cpMin = 999999;
\r
7022 sel.cpMax = 999999;
\r
7023 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7028 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7029 if (sel.cpMin == sel.cpMax) {
\r
7030 /* Expand to surrounding word */
\r
7033 tr.chrg.cpMax = sel.cpMin;
\r
7034 tr.chrg.cpMin = --sel.cpMin;
\r
7035 if (sel.cpMin < 0) break;
\r
7036 tr.lpstrText = name;
\r
7037 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7038 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7042 tr.chrg.cpMin = sel.cpMax;
\r
7043 tr.chrg.cpMax = ++sel.cpMax;
\r
7044 tr.lpstrText = name;
\r
7045 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7046 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7049 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7050 MessageBeep(MB_ICONEXCLAMATION);
\r
7054 tr.lpstrText = name;
\r
7055 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7057 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7058 MessageBeep(MB_ICONEXCLAMATION);
\r
7061 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7064 sprintf(buf, "%s %s", command, name);
\r
7065 SetWindowText(hInput, buf);
\r
7066 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7068 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7069 SetWindowText(hInput, buf);
\r
7070 sel.cpMin = 999999;
\r
7071 sel.cpMax = 999999;
\r
7072 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7078 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7083 switch (message) {
\r
7085 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7088 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7091 sel.cpMin = 999999;
\r
7092 sel.cpMax = 999999;
\r
7093 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7094 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7099 if (wParam == '\t') {
\r
7100 if (GetKeyState(VK_SHIFT) < 0) {
\r
7102 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7103 if (buttonDesc[0].hwnd) {
\r
7104 SetFocus(buttonDesc[0].hwnd);
\r
7106 SetFocus(hwndMain);
\r
7110 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7113 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7115 SendMessage(hInput, message, wParam, lParam);
\r
7119 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7121 return SendMessage(hInput, message, wParam, lParam);
\r
7122 case WM_MBUTTONDOWN:
\r
7123 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7124 case WM_RBUTTONDOWN:
\r
7125 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7126 /* Move selection here if it was empty */
\r
7128 pt.x = LOWORD(lParam);
\r
7129 pt.y = HIWORD(lParam);
\r
7130 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7131 if (sel.cpMin == sel.cpMax) {
\r
7132 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7133 sel.cpMax = sel.cpMin;
\r
7134 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7136 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7139 case WM_RBUTTONUP:
\r
7140 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7141 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7142 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7145 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7146 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7147 if (sel.cpMin == sel.cpMax) {
\r
7148 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7149 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7151 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7152 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7154 pt.x = LOWORD(lParam);
\r
7155 pt.y = HIWORD(lParam);
\r
7156 MenuPopup(hwnd, pt, hmenu, -1);
\r
7160 switch (LOWORD(wParam)) {
\r
7161 case IDM_QuickPaste:
\r
7163 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7164 if (sel.cpMin == sel.cpMax) {
\r
7165 MessageBeep(MB_ICONEXCLAMATION);
\r
7168 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7169 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7170 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7175 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7178 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7181 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7185 int i = LOWORD(wParam) - IDM_CommandX;
\r
7186 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7187 icsTextMenuEntry[i].command != NULL) {
\r
7188 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7189 icsTextMenuEntry[i].getname,
\r
7190 icsTextMenuEntry[i].immediate);
\r
7198 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7201 WNDPROC consoleInputWindowProc;
\r
7204 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7206 char buf[MSG_SIZ];
\r
7208 static BOOL sendNextChar = FALSE;
\r
7209 static BOOL quoteNextChar = FALSE;
\r
7210 InputSource *is = consoleInputSource;
\r
7214 switch (message) {
\r
7216 if (!appData.localLineEditing || sendNextChar) {
\r
7217 is->buf[0] = (CHAR) wParam;
\r
7219 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7220 sendNextChar = FALSE;
\r
7223 if (quoteNextChar) {
\r
7224 buf[0] = (char) wParam;
\r
7225 buf[1] = NULLCHAR;
\r
7226 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7227 quoteNextChar = FALSE;
\r
7231 case '\r': /* Enter key */
\r
7232 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7233 if (consoleEcho) SaveInHistory(is->buf);
\r
7234 is->buf[is->count++] = '\n';
\r
7235 is->buf[is->count] = NULLCHAR;
\r
7236 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7237 if (consoleEcho) {
\r
7238 ConsoleOutput(is->buf, is->count, TRUE);
\r
7239 } else if (appData.localLineEditing) {
\r
7240 ConsoleOutput("\n", 1, TRUE);
\r
7243 case '\033': /* Escape key */
\r
7244 SetWindowText(hwnd, "");
\r
7245 cf.cbSize = sizeof(CHARFORMAT);
\r
7246 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7247 if (consoleEcho) {
\r
7248 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7250 cf.crTextColor = COLOR_ECHOOFF;
\r
7252 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7253 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7255 case '\t': /* Tab key */
\r
7256 if (GetKeyState(VK_SHIFT) < 0) {
\r
7258 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7261 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7262 if (buttonDesc[0].hwnd) {
\r
7263 SetFocus(buttonDesc[0].hwnd);
\r
7265 SetFocus(hwndMain);
\r
7269 case '\023': /* Ctrl+S */
\r
7270 sendNextChar = TRUE;
\r
7272 case '\021': /* Ctrl+Q */
\r
7273 quoteNextChar = TRUE;
\r
7282 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7283 p = PrevInHistory(buf);
\r
7285 SetWindowText(hwnd, p);
\r
7286 sel.cpMin = 999999;
\r
7287 sel.cpMax = 999999;
\r
7288 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7293 p = NextInHistory();
\r
7295 SetWindowText(hwnd, p);
\r
7296 sel.cpMin = 999999;
\r
7297 sel.cpMax = 999999;
\r
7298 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7304 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7308 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7312 case WM_MBUTTONDOWN:
\r
7313 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7314 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7316 case WM_RBUTTONUP:
\r
7317 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7318 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7319 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7323 hmenu = LoadMenu(hInst, "InputMenu");
\r
7324 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7325 if (sel.cpMin == sel.cpMax) {
\r
7326 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7327 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7329 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7330 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7332 pt.x = LOWORD(lParam);
\r
7333 pt.y = HIWORD(lParam);
\r
7334 MenuPopup(hwnd, pt, hmenu, -1);
\r
7338 switch (LOWORD(wParam)) {
\r
7340 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7342 case IDM_SelectAll:
\r
7344 sel.cpMax = -1; /*999999?*/
\r
7345 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7348 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7351 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7354 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7359 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7362 #define CO_MAX 100000
\r
7363 #define CO_TRIM 1000
\r
7366 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7368 static SnapData sd;
\r
7369 static HWND hText, hInput, hFocus;
\r
7370 InputSource *is = consoleInputSource;
\r
7372 static int sizeX, sizeY;
\r
7373 int newSizeX, newSizeY;
\r
7376 switch (message) {
\r
7377 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7378 hwndConsole = hDlg;
\r
7379 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7380 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7382 consoleTextWindowProc = (WNDPROC)
\r
7383 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7384 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7385 consoleInputWindowProc = (WNDPROC)
\r
7386 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7387 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7388 Colorize(ColorNormal, TRUE);
\r
7389 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7390 ChangedConsoleFont();
\r
7391 GetClientRect(hDlg, &rect);
\r
7392 sizeX = rect.right;
\r
7393 sizeY = rect.bottom;
\r
7394 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7395 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7396 WINDOWPLACEMENT wp;
\r
7397 EnsureOnScreen(&consoleX, &consoleY);
\r
7398 wp.length = sizeof(WINDOWPLACEMENT);
\r
7400 wp.showCmd = SW_SHOW;
\r
7401 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7402 wp.rcNormalPosition.left = consoleX;
\r
7403 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7404 wp.rcNormalPosition.top = consoleY;
\r
7405 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7406 SetWindowPlacement(hDlg, &wp);
\r
7420 if (IsIconic(hDlg)) break;
\r
7421 newSizeX = LOWORD(lParam);
\r
7422 newSizeY = HIWORD(lParam);
\r
7423 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7424 RECT rectText, rectInput;
\r
7426 int newTextHeight, newTextWidth;
\r
7427 GetWindowRect(hText, &rectText);
\r
7428 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7429 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7430 if (newTextHeight < 0) {
\r
7431 newSizeY += -newTextHeight;
\r
7432 newTextHeight = 0;
\r
7434 SetWindowPos(hText, NULL, 0, 0,
\r
7435 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7436 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7437 pt.x = rectInput.left;
\r
7438 pt.y = rectInput.top + newSizeY - sizeY;
\r
7439 ScreenToClient(hDlg, &pt);
\r
7440 SetWindowPos(hInput, NULL,
\r
7441 pt.x, pt.y, /* needs client coords */
\r
7442 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7443 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7449 case WM_GETMINMAXINFO:
\r
7450 /* Prevent resizing window too small */
\r
7451 mmi = (MINMAXINFO *) lParam;
\r
7452 mmi->ptMinTrackSize.x = 100;
\r
7453 mmi->ptMinTrackSize.y = 100;
\r
7456 /* [AS] Snapping */
\r
7457 case WM_ENTERSIZEMOVE:
\r
7458 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7461 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7464 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7466 case WM_EXITSIZEMOVE:
\r
7467 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7470 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7478 if (hwndConsole) return;
\r
7479 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7480 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7485 ConsoleOutput(char* data, int length, int forceVisible)
\r
7490 char buf[CO_MAX+1];
\r
7493 static int delayLF = 0;
\r
7494 CHARRANGE savesel, sel;
\r
7496 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7504 while (length--) {
\r
7512 } else if (*p == '\007') {
\r
7513 MyPlaySound(&sounds[(int)SoundBell]);
\r
7520 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7521 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7522 /* Save current selection */
\r
7523 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7524 exlen = GetWindowTextLength(hText);
\r
7525 /* Find out whether current end of text is visible */
\r
7526 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7527 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7528 /* Trim existing text if it's too long */
\r
7529 if (exlen + (q - buf) > CO_MAX) {
\r
7530 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7533 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7534 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7536 savesel.cpMin -= trim;
\r
7537 savesel.cpMax -= trim;
\r
7538 if (exlen < 0) exlen = 0;
\r
7539 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7540 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7542 /* Append the new text */
\r
7543 sel.cpMin = exlen;
\r
7544 sel.cpMax = exlen;
\r
7545 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7546 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7547 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7548 if (forceVisible || exlen == 0 ||
\r
7549 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7550 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7551 /* Scroll to make new end of text visible if old end of text
\r
7552 was visible or new text is an echo of user typein */
\r
7553 sel.cpMin = 9999999;
\r
7554 sel.cpMax = 9999999;
\r
7555 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7556 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7557 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7558 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7560 if (savesel.cpMax == exlen || forceVisible) {
\r
7561 /* Move insert point to new end of text if it was at the old
\r
7562 end of text or if the new text is an echo of user typein */
\r
7563 sel.cpMin = 9999999;
\r
7564 sel.cpMax = 9999999;
\r
7565 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7567 /* Restore previous selection */
\r
7568 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7570 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7577 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7581 COLORREF oldFg, oldBg;
\r
7585 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
7587 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7588 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7589 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7592 rect.right = x + squareSize;
\r
7594 rect.bottom = y + squareSize;
\r
7597 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7598 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7599 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7600 &rect, str, strlen(str), NULL);
\r
7602 (void) SetTextColor(hdc, oldFg);
\r
7603 (void) SetBkColor(hdc, oldBg);
\r
7604 (void) SelectObject(hdc, oldFont);
\r
7608 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7609 RECT *rect, char *color, char *flagFell)
\r
7613 COLORREF oldFg, oldBg;
\r
7616 if (appData.clockMode) {
\r
7618 sprintf(buf, "%c %s %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7620 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
7627 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7628 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7630 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7631 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7633 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7635 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7636 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7637 rect, str, strlen(str), NULL);
\r
7639 (void) SetTextColor(hdc, oldFg);
\r
7640 (void) SetBkColor(hdc, oldBg);
\r
7641 (void) SelectObject(hdc, oldFont);
\r
7646 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7652 if( count <= 0 ) {
\r
7653 if (appData.debugMode) {
\r
7654 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7657 return ERROR_INVALID_USER_BUFFER;
\r
7660 ResetEvent(ovl->hEvent);
\r
7661 ovl->Offset = ovl->OffsetHigh = 0;
\r
7662 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7666 err = GetLastError();
\r
7667 if (err == ERROR_IO_PENDING) {
\r
7668 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7672 err = GetLastError();
\r
7679 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7684 ResetEvent(ovl->hEvent);
\r
7685 ovl->Offset = ovl->OffsetHigh = 0;
\r
7686 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7690 err = GetLastError();
\r
7691 if (err == ERROR_IO_PENDING) {
\r
7692 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7696 err = GetLastError();
\r
7702 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7703 void CheckForInputBufferFull( InputSource * is )
\r
7705 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7706 /* Look for end of line */
\r
7707 char * p = is->buf;
\r
7709 while( p < is->next && *p != '\n' ) {
\r
7713 if( p >= is->next ) {
\r
7714 if (appData.debugMode) {
\r
7715 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
\r
7718 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7719 is->count = (DWORD) -1;
\r
7720 is->next = is->buf;
\r
7726 InputThread(LPVOID arg)
\r
7731 is = (InputSource *) arg;
\r
7732 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7733 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7734 while (is->hThread != NULL) {
\r
7735 is->error = DoReadFile(is->hFile, is->next,
\r
7736 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7737 &is->count, &ovl);
\r
7738 if (is->error == NO_ERROR) {
\r
7739 is->next += is->count;
\r
7741 if (is->error == ERROR_BROKEN_PIPE) {
\r
7742 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7745 is->count = (DWORD) -1;
\r
7746 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7751 CheckForInputBufferFull( is );
\r
7753 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7755 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7757 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7760 CloseHandle(ovl.hEvent);
\r
7761 CloseHandle(is->hFile);
\r
7763 if (appData.debugMode) {
\r
7764 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
\r
7771 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7773 NonOvlInputThread(LPVOID arg)
\r
7780 is = (InputSource *) arg;
\r
7781 while (is->hThread != NULL) {
\r
7782 is->error = ReadFile(is->hFile, is->next,
\r
7783 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7784 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7785 if (is->error == NO_ERROR) {
\r
7786 /* Change CRLF to LF */
\r
7787 if (is->next > is->buf) {
\r
7789 i = is->count + 1;
\r
7797 if (prev == '\r' && *p == '\n') {
\r
7809 if (is->error == ERROR_BROKEN_PIPE) {
\r
7810 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7813 is->count = (DWORD) -1;
\r
7817 CheckForInputBufferFull( is );
\r
7819 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7821 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7823 if (is->count < 0) break; /* Quit on error */
\r
7825 CloseHandle(is->hFile);
\r
7830 SocketInputThread(LPVOID arg)
\r
7834 is = (InputSource *) arg;
\r
7835 while (is->hThread != NULL) {
\r
7836 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7837 if ((int)is->count == SOCKET_ERROR) {
\r
7838 is->count = (DWORD) -1;
\r
7839 is->error = WSAGetLastError();
\r
7841 is->error = NO_ERROR;
\r
7842 is->next += is->count;
\r
7843 if (is->count == 0 && is->second == is) {
\r
7844 /* End of file on stderr; quit with no message */
\r
7848 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7850 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7852 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7858 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7862 is = (InputSource *) lParam;
\r
7863 if (is->lineByLine) {
\r
7864 /* Feed in lines one by one */
\r
7865 char *p = is->buf;
\r
7867 while (q < is->next) {
\r
7868 if (*q++ == '\n') {
\r
7869 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7874 /* Move any partial line to the start of the buffer */
\r
7876 while (p < is->next) {
\r
7881 if (is->error != NO_ERROR || is->count == 0) {
\r
7882 /* Notify backend of the error. Note: If there was a partial
\r
7883 line at the end, it is not flushed through. */
\r
7884 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7887 /* Feed in the whole chunk of input at once */
\r
7888 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7889 is->next = is->buf;
\r
7893 /*---------------------------------------------------------------------------*\
\r
7895 * Menu enables. Used when setting various modes.
\r
7897 \*---------------------------------------------------------------------------*/
\r
7905 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7907 while (enab->item > 0) {
\r
7908 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7913 Enables gnuEnables[] = {
\r
7914 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7915 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7916 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7917 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7918 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7919 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7920 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7921 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7922 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7923 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7927 Enables icsEnables[] = {
\r
7928 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7929 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7930 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7931 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7932 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7933 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7934 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7935 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7936 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7937 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7938 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7939 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7944 Enables zippyEnables[] = {
\r
7945 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7946 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7947 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7952 Enables ncpEnables[] = {
\r
7953 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7954 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7955 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7956 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7957 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7958 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7959 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7960 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7961 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7962 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7963 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7964 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7965 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7966 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7967 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7971 Enables trainingOnEnables[] = {
\r
7972 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7973 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7974 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7975 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7976 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7977 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7978 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7979 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7983 Enables trainingOffEnables[] = {
\r
7984 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7985 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7986 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7987 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7988 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7989 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7990 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7991 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7995 /* These modify either ncpEnables or gnuEnables */
\r
7996 Enables cmailEnables[] = {
\r
7997 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7998 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7999 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8000 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8001 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8002 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8003 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8007 Enables machineThinkingEnables[] = {
\r
8008 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8009 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8010 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8011 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8012 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8013 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8014 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8015 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8016 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8017 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8018 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8019 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8020 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8021 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8022 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8026 Enables userThinkingEnables[] = {
\r
8027 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8028 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8029 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8030 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8031 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8032 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8033 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8034 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8035 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8036 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8037 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8038 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8039 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8040 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8041 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8045 /*---------------------------------------------------------------------------*\
\r
8047 * Front-end interface functions exported by XBoard.
\r
8048 * Functions appear in same order as prototypes in frontend.h.
\r
8050 \*---------------------------------------------------------------------------*/
\r
8054 static UINT prevChecked = 0;
\r
8055 static int prevPausing = 0;
\r
8058 if (pausing != prevPausing) {
\r
8059 prevPausing = pausing;
\r
8060 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8061 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8062 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8065 switch (gameMode) {
\r
8066 case BeginningOfGame:
\r
8067 if (appData.icsActive)
\r
8068 nowChecked = IDM_IcsClient;
\r
8069 else if (appData.noChessProgram)
\r
8070 nowChecked = IDM_EditGame;
\r
8072 nowChecked = IDM_MachineBlack;
\r
8074 case MachinePlaysBlack:
\r
8075 nowChecked = IDM_MachineBlack;
\r
8077 case MachinePlaysWhite:
\r
8078 nowChecked = IDM_MachineWhite;
\r
8080 case TwoMachinesPlay:
\r
8081 nowChecked = IDM_TwoMachines;
\r
8084 nowChecked = IDM_AnalysisMode;
\r
8087 nowChecked = IDM_AnalyzeFile;
\r
8090 nowChecked = IDM_EditGame;
\r
8092 case PlayFromGameFile:
\r
8093 nowChecked = IDM_LoadGame;
\r
8095 case EditPosition:
\r
8096 nowChecked = IDM_EditPosition;
\r
8099 nowChecked = IDM_Training;
\r
8101 case IcsPlayingWhite:
\r
8102 case IcsPlayingBlack:
\r
8103 case IcsObserving:
\r
8105 nowChecked = IDM_IcsClient;
\r
8112 if (prevChecked != 0)
\r
8113 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8114 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8115 if (nowChecked != 0)
\r
8116 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8117 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8119 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8120 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8121 MF_BYCOMMAND|MF_ENABLED);
\r
8123 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8124 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8127 prevChecked = nowChecked;
\r
8133 HMENU hmenu = GetMenu(hwndMain);
\r
8134 SetMenuEnables(hmenu, icsEnables);
\r
8135 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8136 MF_BYPOSITION|MF_ENABLED);
\r
8138 if (appData.zippyPlay) {
\r
8139 SetMenuEnables(hmenu, zippyEnables);
\r
8147 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8153 HMENU hmenu = GetMenu(hwndMain);
\r
8154 SetMenuEnables(hmenu, ncpEnables);
\r
8155 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8156 MF_BYPOSITION|MF_GRAYED);
\r
8157 DrawMenuBar(hwndMain);
\r
8163 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8167 SetTrainingModeOn()
\r
8170 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8171 for (i = 0; i < N_BUTTONS; i++) {
\r
8172 if (buttonDesc[i].hwnd != NULL)
\r
8173 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8178 VOID SetTrainingModeOff()
\r
8181 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8182 for (i = 0; i < N_BUTTONS; i++) {
\r
8183 if (buttonDesc[i].hwnd != NULL)
\r
8184 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8190 SetUserThinkingEnables()
\r
8192 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8196 SetMachineThinkingEnables()
\r
8198 HMENU hMenu = GetMenu(hwndMain);
\r
8199 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8201 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8203 if (gameMode == MachinePlaysBlack) {
\r
8204 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8205 } else if (gameMode == MachinePlaysWhite) {
\r
8206 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8207 } else if (gameMode == TwoMachinesPlay) {
\r
8208 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8214 DisplayTitle(char *str)
\r
8216 char title[MSG_SIZ], *host;
\r
8217 if (str[0] != NULLCHAR) {
\r
8218 strcpy(title, str);
\r
8219 } else if (appData.icsActive) {
\r
8220 if (appData.icsCommPort[0] != NULLCHAR)
\r
8223 host = appData.icsHost;
\r
8224 sprintf(title, "%s: %s", szTitle, host);
\r
8225 } else if (appData.noChessProgram) {
\r
8226 strcpy(title, szTitle);
\r
8228 strcpy(title, szTitle);
\r
8229 strcat(title, ": ");
\r
8230 strcat(title, first.tidy);
\r
8232 SetWindowText(hwndMain, title);
\r
8237 DisplayMessage(char *str1, char *str2)
\r
8241 int remain = MESSAGE_TEXT_MAX - 1;
\r
8244 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8245 messageText[0] = NULLCHAR;
\r
8247 len = strlen(str1);
\r
8248 if (len > remain) len = remain;
\r
8249 strncpy(messageText, str1, len);
\r
8250 messageText[len] = NULLCHAR;
\r
8253 if (*str2 && remain >= 2) {
\r
8255 strcat(messageText, " ");
\r
8258 len = strlen(str2);
\r
8259 if (len > remain) len = remain;
\r
8260 strncat(messageText, str2, len);
\r
8262 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8264 if (IsIconic(hwndMain)) return;
\r
8265 hdc = GetDC(hwndMain);
\r
8266 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8267 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8268 &messageRect, messageText, strlen(messageText), NULL);
\r
8269 (void) SelectObject(hdc, oldFont);
\r
8270 (void) ReleaseDC(hwndMain, hdc);
\r
8274 DisplayError(char *str, int error)
\r
8276 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8282 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8283 NULL, error, LANG_NEUTRAL,
\r
8284 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8286 sprintf(buf, "%s:\n%s", str, buf2);
\r
8288 ErrorMap *em = errmap;
\r
8289 while (em->err != 0 && em->err != error) em++;
\r
8290 if (em->err != 0) {
\r
8291 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8293 sprintf(buf, "%s:\nError code %d", str, error);
\r
8298 ErrorPopUp("Error", buf);
\r
8303 DisplayMoveError(char *str)
\r
8305 fromX = fromY = -1;
\r
8306 ClearHighlights();
\r
8307 DrawPosition(FALSE, NULL);
\r
8308 if (appData.popupMoveErrors) {
\r
8309 ErrorPopUp("Error", str);
\r
8311 DisplayMessage(str, "");
\r
8312 moveErrorMessageUp = TRUE;
\r
8317 DisplayFatalError(char *str, int error, int exitStatus)
\r
8319 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8321 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8324 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8325 NULL, error, LANG_NEUTRAL,
\r
8326 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8328 sprintf(buf, "%s:\n%s", str, buf2);
\r
8330 ErrorMap *em = errmap;
\r
8331 while (em->err != 0 && em->err != error) em++;
\r
8332 if (em->err != 0) {
\r
8333 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8335 sprintf(buf, "%s:\nError code %d", str, error);
\r
8340 if (appData.debugMode) {
\r
8341 fprintf(debugFP, "%s: %s\n", label, str);
\r
8343 if (appData.popupExitMessage) {
\r
8344 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8345 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8347 ExitEvent(exitStatus);
\r
8352 DisplayInformation(char *str)
\r
8354 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8359 DisplayNote(char *str)
\r
8361 ErrorPopUp("Note", str);
\r
8366 char *title, *question, *replyPrefix;
\r
8371 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8373 static QuestionParams *qp;
\r
8374 char reply[MSG_SIZ];
\r
8377 switch (message) {
\r
8378 case WM_INITDIALOG:
\r
8379 qp = (QuestionParams *) lParam;
\r
8380 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8381 SetWindowText(hDlg, qp->title);
\r
8382 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8383 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8387 switch (LOWORD(wParam)) {
\r
8389 strcpy(reply, qp->replyPrefix);
\r
8390 if (*reply) strcat(reply, " ");
\r
8391 len = strlen(reply);
\r
8392 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8393 strcat(reply, "\n");
\r
8394 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8395 EndDialog(hDlg, TRUE);
\r
8396 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
8399 EndDialog(hDlg, FALSE);
\r
8410 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8412 QuestionParams qp;
\r
8416 qp.question = question;
\r
8417 qp.replyPrefix = replyPrefix;
\r
8419 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8420 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8421 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8422 FreeProcInstance(lpProc);
\r
8425 /* [AS] Pick FRC position */
\r
8426 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8428 static int * lpIndexFRC;
\r
8434 case WM_INITDIALOG:
\r
8435 lpIndexFRC = (int *) lParam;
\r
8437 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8439 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8440 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8441 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8442 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8447 switch( LOWORD(wParam) ) {
\r
8449 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8450 EndDialog( hDlg, 0 );
\r
8453 EndDialog( hDlg, 1 );
\r
8455 case IDC_NFG_Edit:
\r
8456 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8457 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8459 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8462 case IDC_NFG_Random:
\r
8463 sprintf( buf, "%d", myrandom() % 960 );
\r
8464 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8477 int index = appData.defaultFrcPosition;
\r
8478 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8480 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8482 if( result == 0 ) {
\r
8483 appData.defaultFrcPosition = index;
\r
8489 /* [AS] Game list options */
\r
8495 static GLT_Item GLT_ItemInfo[] = {
\r
8496 { GLT_EVENT, "Event" },
\r
8497 { GLT_SITE, "Site" },
\r
8498 { GLT_DATE, "Date" },
\r
8499 { GLT_ROUND, "Round" },
\r
8500 { GLT_PLAYERS, "Players" },
\r
8501 { GLT_RESULT, "Result" },
\r
8502 { GLT_WHITE_ELO, "White Rating" },
\r
8503 { GLT_BLACK_ELO, "Black Rating" },
\r
8504 { GLT_TIME_CONTROL,"Time Control" },
\r
8505 { GLT_VARIANT, "Variant" },
\r
8506 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
8510 const char * GLT_FindItem( char id )
\r
8512 const char * result = 0;
\r
8514 GLT_Item * list = GLT_ItemInfo;
\r
8516 while( list->id != 0 ) {
\r
8517 if( list->id == id ) {
\r
8518 result = list->name;
\r
8528 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
8530 const char * name = GLT_FindItem( id );
\r
8533 if( index >= 0 ) {
\r
8534 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
8537 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
8542 void GLT_TagsToList( HWND hDlg, char * tags )
\r
8546 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8549 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8553 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
8555 pc = GLT_ALL_TAGS;
\r
8558 if( strchr( tags, *pc ) == 0 ) {
\r
8559 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8564 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8567 char GLT_ListItemToTag( HWND hDlg, int index )
\r
8569 char result = '\0';
\r
8572 GLT_Item * list = GLT_ItemInfo;
\r
8574 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
8575 while( list->id != 0 ) {
\r
8576 if( strcmp( list->name, name ) == 0 ) {
\r
8577 result = list->id;
\r
8588 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8590 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8591 int idx2 = idx1 + delta;
\r
8592 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8594 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8597 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8598 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8599 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8600 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8604 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8606 static char glt[64];
\r
8607 static char * lpUserGLT;
\r
8611 case WM_INITDIALOG:
\r
8612 lpUserGLT = (char *) lParam;
\r
8614 strcpy( glt, lpUserGLT );
\r
8616 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8618 /* Initialize list */
\r
8619 GLT_TagsToList( hDlg, glt );
\r
8621 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8626 switch( LOWORD(wParam) ) {
\r
8629 char * pc = lpUserGLT;
\r
8631 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8635 id = GLT_ListItemToTag( hDlg, idx );
\r
8639 } while( id != '\0' );
\r
8641 EndDialog( hDlg, 0 );
\r
8644 EndDialog( hDlg, 1 );
\r
8647 case IDC_GLT_Default:
\r
8648 strcpy( glt, GLT_DEFAULT_TAGS );
\r
8649 GLT_TagsToList( hDlg, glt );
\r
8652 case IDC_GLT_Restore:
\r
8653 strcpy( glt, lpUserGLT );
\r
8654 GLT_TagsToList( hDlg, glt );
\r
8658 GLT_MoveSelection( hDlg, -1 );
\r
8661 case IDC_GLT_Down:
\r
8662 GLT_MoveSelection( hDlg, +1 );
\r
8672 int GameListOptions()
\r
8676 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8678 strcpy( glt, appData.gameListTags );
\r
8680 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
8682 if( result == 0 ) {
\r
8683 /* [AS] Memory leak here! */
\r
8684 appData.gameListTags = strdup( glt );
\r
8692 DisplayIcsInteractionTitle(char *str)
\r
8694 char consoleTitle[MSG_SIZ];
\r
8696 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8697 SetWindowText(hwndConsole, consoleTitle);
\r
8701 DrawPosition(int fullRedraw, Board board)
\r
8703 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8710 fromX = fromY = -1;
\r
8711 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8712 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8713 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8714 dragInfo.lastpos = dragInfo.pos;
\r
8715 dragInfo.start.x = dragInfo.start.y = -1;
\r
8716 dragInfo.from = dragInfo.start;
\r
8718 DrawPosition(TRUE, NULL);
\r
8724 CommentPopUp(char *title, char *str)
\r
8726 HWND hwnd = GetActiveWindow();
\r
8727 EitherCommentPopUp(0, title, str, FALSE);
\r
8728 SetActiveWindow(hwnd);
\r
8732 CommentPopDown(void)
\r
8734 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8735 if (commentDialog) {
\r
8736 ShowWindow(commentDialog, SW_HIDE);
\r
8738 commentDialogUp = FALSE;
\r
8742 EditCommentPopUp(int index, char *title, char *str)
\r
8744 EitherCommentPopUp(index, title, str, TRUE);
\r
8751 MyPlaySound(&sounds[(int)SoundMove]);
\r
8754 VOID PlayIcsWinSound()
\r
8756 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8759 VOID PlayIcsLossSound()
\r
8761 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8764 VOID PlayIcsDrawSound()
\r
8766 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8769 VOID PlayIcsUnfinishedSound()
\r
8771 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8777 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8785 consoleEcho = TRUE;
\r
8786 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8787 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8788 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8797 consoleEcho = FALSE;
\r
8798 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8799 /* This works OK: set text and background both to the same color */
\r
8801 cf.crTextColor = COLOR_ECHOOFF;
\r
8802 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8803 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8806 /* No Raw()...? */
\r
8808 void Colorize(ColorClass cc, int continuation)
\r
8810 currentColorClass = cc;
\r
8811 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8812 consoleCF.crTextColor = textAttribs[cc].color;
\r
8813 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8814 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8820 static char buf[MSG_SIZ];
\r
8821 DWORD bufsiz = MSG_SIZ;
\r
8823 if (!GetUserName(buf, &bufsiz)) {
\r
8824 /*DisplayError("Error getting user name", GetLastError());*/
\r
8825 strcpy(buf, "User");
\r
8833 static char buf[MSG_SIZ];
\r
8834 DWORD bufsiz = MSG_SIZ;
\r
8836 if (!GetComputerName(buf, &bufsiz)) {
\r
8837 /*DisplayError("Error getting host name", GetLastError());*/
\r
8838 strcpy(buf, "Unknown");
\r
8845 ClockTimerRunning()
\r
8847 return clockTimerEvent != 0;
\r
8853 if (clockTimerEvent == 0) return FALSE;
\r
8854 KillTimer(hwndMain, clockTimerEvent);
\r
8855 clockTimerEvent = 0;
\r
8860 StartClockTimer(long millisec)
\r
8862 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8863 (UINT) millisec, NULL);
\r
8867 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8870 hdc = GetDC(hwndMain);
\r
8871 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8873 if (!IsIconic(hwndMain)) {
\r
8874 DisplayAClock(hdc, timeRemaining, highlight, flipClock ? &blackRect : &whiteRect, "White", flag);
\r
8876 if (highlight && iconCurrent == iconBlack) {
\r
8877 iconCurrent = iconWhite;
\r
8878 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8879 if (IsIconic(hwndMain)) {
\r
8880 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8883 (void) ReleaseDC(hwndMain, hdc);
\r
8885 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8889 DisplayBlackClock(long timeRemaining, int highlight)
\r
8892 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8894 hdc = GetDC(hwndMain);
\r
8895 if (!IsIconic(hwndMain)) {
\r
8896 DisplayAClock(hdc, timeRemaining, highlight, flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
8898 if (highlight && iconCurrent == iconWhite) {
\r
8899 iconCurrent = iconBlack;
\r
8900 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8901 if (IsIconic(hwndMain)) {
\r
8902 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8905 (void) ReleaseDC(hwndMain, hdc);
\r
8907 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8912 LoadGameTimerRunning()
\r
8914 return loadGameTimerEvent != 0;
\r
8918 StopLoadGameTimer()
\r
8920 if (loadGameTimerEvent == 0) return FALSE;
\r
8921 KillTimer(hwndMain, loadGameTimerEvent);
\r
8922 loadGameTimerEvent = 0;
\r
8927 StartLoadGameTimer(long millisec)
\r
8929 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8930 (UINT) millisec, NULL);
\r
8938 char fileTitle[MSG_SIZ];
\r
8940 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8941 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
8942 appData.oldSaveStyle ? "gam" : "pgn",
\r
8944 "Save Game to File", NULL, fileTitle, NULL);
\r
8946 SaveGame(f, 0, "");
\r
8953 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8955 if (delayedTimerEvent != 0) {
\r
8956 if (appData.debugMode) {
\r
8957 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8959 KillTimer(hwndMain, delayedTimerEvent);
\r
8960 delayedTimerEvent = 0;
\r
8961 delayedTimerCallback();
\r
8963 delayedTimerCallback = cb;
\r
8964 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8965 (UINT) millisec, NULL);
\r
8968 DelayedEventCallback
\r
8971 if (delayedTimerEvent) {
\r
8972 return delayedTimerCallback;
\r
8979 CancelDelayedEvent()
\r
8981 if (delayedTimerEvent) {
\r
8982 KillTimer(hwndMain, delayedTimerEvent);
\r
8983 delayedTimerEvent = 0;
\r
8987 /* Start a child process running the given program.
\r
8988 The process's standard output can be read from "from", and its
\r
8989 standard input can be written to "to".
\r
8990 Exit with fatal error if anything goes wrong.
\r
8991 Returns an opaque pointer that can be used to destroy the process
\r
8995 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8997 #define BUFSIZE 4096
\r
8999 HANDLE hChildStdinRd, hChildStdinWr,
\r
9000 hChildStdoutRd, hChildStdoutWr;
\r
9001 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9002 SECURITY_ATTRIBUTES saAttr;
\r
9004 PROCESS_INFORMATION piProcInfo;
\r
9005 STARTUPINFO siStartInfo;
\r
9007 char buf[MSG_SIZ];
\r
9010 if (appData.debugMode) {
\r
9011 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9016 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9017 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9018 saAttr.bInheritHandle = TRUE;
\r
9019 saAttr.lpSecurityDescriptor = NULL;
\r
9022 * The steps for redirecting child's STDOUT:
\r
9023 * 1. Create anonymous pipe to be STDOUT for child.
\r
9024 * 2. Create a noninheritable duplicate of read handle,
\r
9025 * and close the inheritable read handle.
\r
9028 /* Create a pipe for the child's STDOUT. */
\r
9029 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9030 return GetLastError();
\r
9033 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9034 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9035 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9036 FALSE, /* not inherited */
\r
9037 DUPLICATE_SAME_ACCESS);
\r
9039 return GetLastError();
\r
9041 CloseHandle(hChildStdoutRd);
\r
9044 * The steps for redirecting child's STDIN:
\r
9045 * 1. Create anonymous pipe to be STDIN for child.
\r
9046 * 2. Create a noninheritable duplicate of write handle,
\r
9047 * and close the inheritable write handle.
\r
9050 /* Create a pipe for the child's STDIN. */
\r
9051 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9052 return GetLastError();
\r
9055 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9056 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9057 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9058 FALSE, /* not inherited */
\r
9059 DUPLICATE_SAME_ACCESS);
\r
9061 return GetLastError();
\r
9063 CloseHandle(hChildStdinWr);
\r
9065 /* Arrange to (1) look in dir for the child .exe file, and
\r
9066 * (2) have dir be the child's working directory. Interpret
\r
9067 * dir relative to the directory WinBoard loaded from. */
\r
9068 GetCurrentDirectory(MSG_SIZ, buf);
\r
9069 SetCurrentDirectory(installDir);
\r
9070 SetCurrentDirectory(dir);
\r
9072 /* Now create the child process. */
\r
9074 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9075 siStartInfo.lpReserved = NULL;
\r
9076 siStartInfo.lpDesktop = NULL;
\r
9077 siStartInfo.lpTitle = NULL;
\r
9078 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9079 siStartInfo.cbReserved2 = 0;
\r
9080 siStartInfo.lpReserved2 = NULL;
\r
9081 siStartInfo.hStdInput = hChildStdinRd;
\r
9082 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9083 siStartInfo.hStdError = hChildStdoutWr;
\r
9085 fSuccess = CreateProcess(NULL,
\r
9086 cmdLine, /* command line */
\r
9087 NULL, /* process security attributes */
\r
9088 NULL, /* primary thread security attrs */
\r
9089 TRUE, /* handles are inherited */
\r
9090 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9091 NULL, /* use parent's environment */
\r
9093 &siStartInfo, /* STARTUPINFO pointer */
\r
9094 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9096 err = GetLastError();
\r
9097 SetCurrentDirectory(buf); /* return to prev directory */
\r
9102 /* Close the handles we don't need in the parent */
\r
9103 CloseHandle(piProcInfo.hThread);
\r
9104 CloseHandle(hChildStdinRd);
\r
9105 CloseHandle(hChildStdoutWr);
\r
9107 /* Prepare return value */
\r
9108 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9109 cp->kind = CPReal;
\r
9110 cp->hProcess = piProcInfo.hProcess;
\r
9111 cp->pid = piProcInfo.dwProcessId;
\r
9112 cp->hFrom = hChildStdoutRdDup;
\r
9113 cp->hTo = hChildStdinWrDup;
\r
9115 *pr = (void *) cp;
\r
9117 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9118 2000 where engines sometimes don't see the initial command(s)
\r
9119 from WinBoard and hang. I don't understand how that can happen,
\r
9120 but the Sleep is harmless, so I've put it in. Others have also
\r
9121 reported what may be the same problem, so hopefully this will fix
\r
9122 it for them too. */
\r
9130 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9134 cp = (ChildProc *) pr;
\r
9135 if (cp == NULL) return;
\r
9137 switch (cp->kind) {
\r
9139 /* TerminateProcess is considered harmful, so... */
\r
9140 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9141 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9142 /* The following doesn't work because the chess program
\r
9143 doesn't "have the same console" as WinBoard. Maybe
\r
9144 we could arrange for this even though neither WinBoard
\r
9145 nor the chess program uses a console for stdio? */
\r
9146 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9148 /* [AS] Special termination modes for misbehaving programs... */
\r
9149 if( signal == 9 ) {
\r
9150 if ( appData.debugMode) {
\r
9151 fprintf( debugFP, "Terminating process %u\n", cp->pid );
\r
9154 TerminateProcess( cp->hProcess, 0 );
\r
9156 else if( signal == 10 ) {
\r
9157 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9159 if( dw != WAIT_OBJECT_0 ) {
\r
9160 if ( appData.debugMode) {
\r
9161 fprintf( debugFP, "Process %u still alive after timeout, killing...\n", cp->pid );
\r
9164 TerminateProcess( cp->hProcess, 0 );
\r
9168 CloseHandle(cp->hProcess);
\r
9172 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9176 closesocket(cp->sock);
\r
9181 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9182 closesocket(cp->sock);
\r
9183 closesocket(cp->sock2);
\r
9191 InterruptChildProcess(ProcRef pr)
\r
9195 cp = (ChildProc *) pr;
\r
9196 if (cp == NULL) return;
\r
9197 switch (cp->kind) {
\r
9199 /* The following doesn't work because the chess program
\r
9200 doesn't "have the same console" as WinBoard. Maybe
\r
9201 we could arrange for this even though neither WinBoard
\r
9202 nor the chess program uses a console for stdio */
\r
9203 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9208 /* Can't interrupt */
\r
9212 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9219 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9221 char cmdLine[MSG_SIZ];
\r
9223 if (port[0] == NULLCHAR) {
\r
9224 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9226 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9228 return StartChildProcess(cmdLine, "", pr);
\r
9232 /* Code to open TCP sockets */
\r
9235 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9240 struct sockaddr_in sa, mysa;
\r
9241 struct hostent FAR *hp;
\r
9242 unsigned short uport;
\r
9243 WORD wVersionRequested;
\r
9246 /* Initialize socket DLL */
\r
9247 wVersionRequested = MAKEWORD(1, 1);
\r
9248 err = WSAStartup(wVersionRequested, &wsaData);
\r
9249 if (err != 0) return err;
\r
9252 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9253 err = WSAGetLastError();
\r
9258 /* Bind local address using (mostly) don't-care values.
\r
9260 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9261 mysa.sin_family = AF_INET;
\r
9262 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9263 uport = (unsigned short) 0;
\r
9264 mysa.sin_port = htons(uport);
\r
9265 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9266 == SOCKET_ERROR) {
\r
9267 err = WSAGetLastError();
\r
9272 /* Resolve remote host name */
\r
9273 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9274 if (!(hp = gethostbyname(host))) {
\r
9275 unsigned int b0, b1, b2, b3;
\r
9277 err = WSAGetLastError();
\r
9279 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9280 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9281 hp->h_addrtype = AF_INET;
\r
9283 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9284 hp->h_addr_list[0] = (char *) malloc(4);
\r
9285 hp->h_addr_list[0][0] = (char) b0;
\r
9286 hp->h_addr_list[0][1] = (char) b1;
\r
9287 hp->h_addr_list[0][2] = (char) b2;
\r
9288 hp->h_addr_list[0][3] = (char) b3;
\r
9294 sa.sin_family = hp->h_addrtype;
\r
9295 uport = (unsigned short) atoi(port);
\r
9296 sa.sin_port = htons(uport);
\r
9297 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9299 /* Make connection */
\r
9300 if (connect(s, (struct sockaddr *) &sa,
\r
9301 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9302 err = WSAGetLastError();
\r
9307 /* Prepare return value */
\r
9308 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9309 cp->kind = CPSock;
\r
9311 *pr = (ProcRef *) cp;
\r
9317 OpenCommPort(char *name, ProcRef *pr)
\r
9322 char fullname[MSG_SIZ];
\r
9324 if (*name != '\\')
\r
9325 sprintf(fullname, "\\\\.\\%s", name);
\r
9327 strcpy(fullname, name);
\r
9329 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9330 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9331 if (h == (HANDLE) -1) {
\r
9332 return GetLastError();
\r
9336 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9338 /* Accumulate characters until a 100ms pause, then parse */
\r
9339 ct.ReadIntervalTimeout = 100;
\r
9340 ct.ReadTotalTimeoutMultiplier = 0;
\r
9341 ct.ReadTotalTimeoutConstant = 0;
\r
9342 ct.WriteTotalTimeoutMultiplier = 0;
\r
9343 ct.WriteTotalTimeoutConstant = 0;
\r
9344 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9346 /* Prepare return value */
\r
9347 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9348 cp->kind = CPComm;
\r
9351 *pr = (ProcRef *) cp;
\r
9357 OpenLoopback(ProcRef *pr)
\r
9359 DisplayFatalError("Not implemented", 0, 1);
\r
9365 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9370 struct sockaddr_in sa, mysa;
\r
9371 struct hostent FAR *hp;
\r
9372 unsigned short uport;
\r
9373 WORD wVersionRequested;
\r
9376 char stderrPortStr[MSG_SIZ];
\r
9378 /* Initialize socket DLL */
\r
9379 wVersionRequested = MAKEWORD(1, 1);
\r
9380 err = WSAStartup(wVersionRequested, &wsaData);
\r
9381 if (err != 0) return err;
\r
9383 /* Resolve remote host name */
\r
9384 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9385 if (!(hp = gethostbyname(host))) {
\r
9386 unsigned int b0, b1, b2, b3;
\r
9388 err = WSAGetLastError();
\r
9390 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9391 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9392 hp->h_addrtype = AF_INET;
\r
9394 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9395 hp->h_addr_list[0] = (char *) malloc(4);
\r
9396 hp->h_addr_list[0][0] = (char) b0;
\r
9397 hp->h_addr_list[0][1] = (char) b1;
\r
9398 hp->h_addr_list[0][2] = (char) b2;
\r
9399 hp->h_addr_list[0][3] = (char) b3;
\r
9405 sa.sin_family = hp->h_addrtype;
\r
9406 uport = (unsigned short) 514;
\r
9407 sa.sin_port = htons(uport);
\r
9408 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9410 /* Bind local socket to unused "privileged" port address
\r
9412 s = INVALID_SOCKET;
\r
9413 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9414 mysa.sin_family = AF_INET;
\r
9415 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9416 for (fromPort = 1023;; fromPort--) {
\r
9417 if (fromPort < 0) {
\r
9419 return WSAEADDRINUSE;
\r
9421 if (s == INVALID_SOCKET) {
\r
9422 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9423 err = WSAGetLastError();
\r
9428 uport = (unsigned short) fromPort;
\r
9429 mysa.sin_port = htons(uport);
\r
9430 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9431 == SOCKET_ERROR) {
\r
9432 err = WSAGetLastError();
\r
9433 if (err == WSAEADDRINUSE) continue;
\r
9437 if (connect(s, (struct sockaddr *) &sa,
\r
9438 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9439 err = WSAGetLastError();
\r
9440 if (err == WSAEADDRINUSE) {
\r
9451 /* Bind stderr local socket to unused "privileged" port address
\r
9453 s2 = INVALID_SOCKET;
\r
9454 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9455 mysa.sin_family = AF_INET;
\r
9456 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9457 for (fromPort = 1023;; fromPort--) {
\r
9458 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9459 if (fromPort < 0) {
\r
9460 (void) closesocket(s);
\r
9462 return WSAEADDRINUSE;
\r
9464 if (s2 == INVALID_SOCKET) {
\r
9465 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9466 err = WSAGetLastError();
\r
9472 uport = (unsigned short) fromPort;
\r
9473 mysa.sin_port = htons(uport);
\r
9474 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9475 == SOCKET_ERROR) {
\r
9476 err = WSAGetLastError();
\r
9477 if (err == WSAEADDRINUSE) continue;
\r
9478 (void) closesocket(s);
\r
9482 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9483 err = WSAGetLastError();
\r
9484 if (err == WSAEADDRINUSE) {
\r
9486 s2 = INVALID_SOCKET;
\r
9489 (void) closesocket(s);
\r
9490 (void) closesocket(s2);
\r
9496 prevStderrPort = fromPort; // remember port used
\r
9497 sprintf(stderrPortStr, "%d", fromPort);
\r
9499 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9500 err = WSAGetLastError();
\r
9501 (void) closesocket(s);
\r
9502 (void) closesocket(s2);
\r
9507 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9508 err = WSAGetLastError();
\r
9509 (void) closesocket(s);
\r
9510 (void) closesocket(s2);
\r
9514 if (*user == NULLCHAR) user = UserName();
\r
9515 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9516 err = WSAGetLastError();
\r
9517 (void) closesocket(s);
\r
9518 (void) closesocket(s2);
\r
9522 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9523 err = WSAGetLastError();
\r
9524 (void) closesocket(s);
\r
9525 (void) closesocket(s2);
\r
9530 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9531 err = WSAGetLastError();
\r
9532 (void) closesocket(s);
\r
9533 (void) closesocket(s2);
\r
9537 (void) closesocket(s2); /* Stop listening */
\r
9539 /* Prepare return value */
\r
9540 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9541 cp->kind = CPRcmd;
\r
9544 *pr = (ProcRef *) cp;
\r
9551 AddInputSource(ProcRef pr, int lineByLine,
\r
9552 InputCallback func, VOIDSTAR closure)
\r
9554 InputSource *is, *is2 = NULL;
\r
9555 ChildProc *cp = (ChildProc *) pr;
\r
9557 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9558 is->lineByLine = lineByLine;
\r
9560 is->closure = closure;
\r
9561 is->second = NULL;
\r
9562 is->next = is->buf;
\r
9563 if (pr == NoProc) {
\r
9564 is->kind = CPReal;
\r
9565 consoleInputSource = is;
\r
9567 is->kind = cp->kind;
\r
9569 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9570 we create all threads suspended so that the is->hThread variable can be
\r
9571 safely assigned, then let the threads start with ResumeThread.
\r
9573 switch (cp->kind) {
\r
9575 is->hFile = cp->hFrom;
\r
9576 cp->hFrom = NULL; /* now owned by InputThread */
\r
9578 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9579 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9583 is->hFile = cp->hFrom;
\r
9584 cp->hFrom = NULL; /* now owned by InputThread */
\r
9586 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9587 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9591 is->sock = cp->sock;
\r
9593 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9594 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9598 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9600 is->sock = cp->sock;
\r
9602 is2->sock = cp->sock2;
\r
9603 is2->second = is2;
\r
9605 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9606 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9608 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9609 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9613 if( is->hThread != NULL ) {
\r
9614 ResumeThread( is->hThread );
\r
9617 if( is2 != NULL && is2->hThread != NULL ) {
\r
9618 ResumeThread( is2->hThread );
\r
9622 return (InputSourceRef) is;
\r
9626 RemoveInputSource(InputSourceRef isr)
\r
9630 is = (InputSource *) isr;
\r
9631 is->hThread = NULL; /* tell thread to stop */
\r
9632 CloseHandle(is->hThread);
\r
9633 if (is->second != NULL) {
\r
9634 is->second->hThread = NULL;
\r
9635 CloseHandle(is->second->hThread);
\r
9641 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9644 int outCount = SOCKET_ERROR;
\r
9645 ChildProc *cp = (ChildProc *) pr;
\r
9646 static OVERLAPPED ovl;
\r
9648 if (pr == NoProc) {
\r
9649 ConsoleOutput(message, count, FALSE);
\r
9653 if (ovl.hEvent == NULL) {
\r
9654 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9656 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9658 switch (cp->kind) {
\r
9661 outCount = send(cp->sock, message, count, 0);
\r
9662 if (outCount == SOCKET_ERROR) {
\r
9663 *outError = WSAGetLastError();
\r
9665 *outError = NO_ERROR;
\r
9670 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9671 &dOutCount, NULL)) {
\r
9672 *outError = NO_ERROR;
\r
9673 outCount = (int) dOutCount;
\r
9675 *outError = GetLastError();
\r
9680 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9681 &dOutCount, &ovl);
\r
9682 if (*outError == NO_ERROR) {
\r
9683 outCount = (int) dOutCount;
\r
9691 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9694 /* Ignore delay, not implemented for WinBoard */
\r
9695 return OutputToProcess(pr, message, count, outError);
\r
9700 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9701 char *buf, int count, int error)
\r
9703 DisplayFatalError("Not implemented", 0, 1);
\r
9706 /* see wgamelist.c for Game List functions */
\r
9707 /* see wedittags.c for Edit Tags functions */
\r
9714 char buf[MSG_SIZ];
\r
9717 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9718 f = fopen(buf, "r");
\r
9720 ProcessICSInitScript(f);
\r
9728 StartAnalysisClock()
\r
9730 if (analysisTimerEvent) return;
\r
9731 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9732 (UINT) 2000, NULL);
\r
9736 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9738 static HANDLE hwndText;
\r
9740 static int sizeX, sizeY;
\r
9741 int newSizeX, newSizeY, flags;
\r
9744 switch (message) {
\r
9745 case WM_INITDIALOG: /* message: initialize dialog box */
\r
9746 /* Initialize the dialog items */
\r
9747 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
9748 SetWindowText(hDlg, analysisTitle);
\r
9749 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
9750 /* Size and position the dialog */
\r
9751 if (!analysisDialog) {
\r
9752 analysisDialog = hDlg;
\r
9753 flags = SWP_NOZORDER;
\r
9754 GetClientRect(hDlg, &rect);
\r
9755 sizeX = rect.right;
\r
9756 sizeY = rect.bottom;
\r
9757 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
9758 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
9759 WINDOWPLACEMENT wp;
\r
9760 EnsureOnScreen(&analysisX, &analysisY);
\r
9761 wp.length = sizeof(WINDOWPLACEMENT);
\r
9763 wp.showCmd = SW_SHOW;
\r
9764 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
9765 wp.rcNormalPosition.left = analysisX;
\r
9766 wp.rcNormalPosition.right = analysisX + analysisW;
\r
9767 wp.rcNormalPosition.top = analysisY;
\r
9768 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
9769 SetWindowPlacement(hDlg, &wp);
\r
9771 GetClientRect(hDlg, &rect);
\r
9772 newSizeX = rect.right;
\r
9773 newSizeY = rect.bottom;
\r
9774 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
9775 newSizeX, newSizeY);
\r
9782 case WM_COMMAND: /* message: received a command */
\r
9783 switch (LOWORD(wParam)) {
\r
9793 newSizeX = LOWORD(lParam);
\r
9794 newSizeY = HIWORD(lParam);
\r
9795 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
9800 case WM_GETMINMAXINFO:
\r
9801 /* Prevent resizing window too small */
\r
9802 mmi = (MINMAXINFO *) lParam;
\r
9803 mmi->ptMinTrackSize.x = 100;
\r
9804 mmi->ptMinTrackSize.y = 100;
\r
9811 AnalysisPopUp(char* title, char* str)
\r
9817 EngineOutputPopUp();
\r
9820 if (str == NULL) str = "";
\r
9821 p = (char *) malloc(2 * strlen(str) + 2);
\r
9824 if (*str == '\n') *q++ = '\r';
\r
9828 if (analysisText != NULL) free(analysisText);
\r
9831 if (analysisDialog) {
\r
9832 SetWindowText(analysisDialog, title);
\r
9833 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
9834 ShowWindow(analysisDialog, SW_SHOW);
\r
9836 analysisTitle = title;
\r
9837 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
9838 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
9839 hwndMain, (DLGPROC)lpProc);
\r
9840 FreeProcInstance(lpProc);
\r
9842 analysisDialogUp = TRUE;
\r
9848 if (analysisDialog) {
\r
9849 ShowWindow(analysisDialog, SW_HIDE);
\r
9851 analysisDialogUp = FALSE;
\r
9856 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9858 highlightInfo.sq[0].x = fromX;
\r
9859 highlightInfo.sq[0].y = fromY;
\r
9860 highlightInfo.sq[1].x = toX;
\r
9861 highlightInfo.sq[1].y = toY;
\r
9867 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9868 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9872 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9874 premoveHighlightInfo.sq[0].x = fromX;
\r
9875 premoveHighlightInfo.sq[0].y = fromY;
\r
9876 premoveHighlightInfo.sq[1].x = toX;
\r
9877 premoveHighlightInfo.sq[1].y = toY;
\r
9881 ClearPremoveHighlights()
\r
9883 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9884 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9888 ShutDownFrontEnd()
\r
9890 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9891 DeleteClipboardTempFiles();
\r
9897 if (IsIconic(hwndMain))
\r
9898 ShowWindow(hwndMain, SW_RESTORE);
\r
9900 SetActiveWindow(hwndMain);
\r
9904 * Prototypes for animation support routines
\r
9906 static void ScreenSquare(int column, int row, POINT * pt);
\r
9907 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9908 POINT frames[], int * nFrames);
\r
9914 AnimateMove(board, fromX, fromY, toX, toY)
\r
9921 ChessSquare piece;
\r
9922 POINT start, finish, mid;
\r
9923 POINT frames[kFactor * 2 + 1];
\r
9926 if (!appData.animate) return;
\r
9927 if (doingSizing) return;
\r
9928 if (fromY < 0 || fromX < 0) return;
\r
9929 piece = board[fromY][fromX];
\r
9930 if (piece >= EmptySquare) return;
\r
9932 ScreenSquare(fromX, fromY, &start);
\r
9933 ScreenSquare(toX, toY, &finish);
\r
9935 /* All pieces except knights move in straight line */
\r
9936 if (piece != WhiteKnight && piece != BlackKnight) {
\r
9937 mid.x = start.x + (finish.x - start.x) / 2;
\r
9938 mid.y = start.y + (finish.y - start.y) / 2;
\r
9940 /* Knight: make diagonal movement then straight */
\r
9941 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9942 mid.x = start.x + (finish.x - start.x) / 2;
\r
9946 mid.y = start.y + (finish.y - start.y) / 2;
\r
9950 /* Don't use as many frames for very short moves */
\r
9951 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9952 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9954 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9956 animInfo.from.x = fromX;
\r
9957 animInfo.from.y = fromY;
\r
9958 animInfo.to.x = toX;
\r
9959 animInfo.to.y = toY;
\r
9960 animInfo.lastpos = start;
\r
9961 animInfo.piece = piece;
\r
9962 for (n = 0; n < nFrames; n++) {
\r
9963 animInfo.pos = frames[n];
\r
9964 DrawPosition(FALSE, NULL);
\r
9965 animInfo.lastpos = animInfo.pos;
\r
9966 Sleep(appData.animSpeed);
\r
9968 animInfo.pos = finish;
\r
9969 DrawPosition(FALSE, NULL);
\r
9970 animInfo.piece = EmptySquare;
\r
9973 /* Convert board position to corner of screen rect and color */
\r
9976 ScreenSquare(column, row, pt)
\r
9977 int column; int row; POINT * pt;
\r
9980 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
9981 pt->y = lineGap + row * (squareSize + lineGap);
\r
9983 pt->x = lineGap + column * (squareSize + lineGap);
\r
9984 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
9988 /* Generate a series of frame coords from start->mid->finish.
\r
9989 The movement rate doubles until the half way point is
\r
9990 reached, then halves back down to the final destination,
\r
9991 which gives a nice slow in/out effect. The algorithmn
\r
9992 may seem to generate too many intermediates for short
\r
9993 moves, but remember that the purpose is to attract the
\r
9994 viewers attention to the piece about to be moved and
\r
9995 then to where it ends up. Too few frames would be less
\r
9999 Tween(start, mid, finish, factor, frames, nFrames)
\r
10000 POINT * start; POINT * mid;
\r
10001 POINT * finish; int factor;
\r
10002 POINT frames[]; int * nFrames;
\r
10004 int n, fraction = 1, count = 0;
\r
10006 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10007 for (n = 0; n < factor; n++)
\r
10009 for (n = 0; n < factor; n++) {
\r
10010 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10011 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10013 fraction = fraction / 2;
\r
10017 frames[count] = *mid;
\r
10020 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10022 for (n = 0; n < factor; n++) {
\r
10023 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10024 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10026 fraction = fraction * 2;
\r
10028 *nFrames = count;
\r
10032 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10037 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10038 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10040 OutputDebugString( buf );
\r
10043 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10045 EvalGraphSet( first, last, current, pvInfoList );
\r
10048 void SetProgramStats( FrontEndProgramStats * stats )
\r
10053 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10054 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10056 OutputDebugString( buf );
\r
10059 EngineOutputUpdate( stats );
\r