2 * WinBoard.c -- Windows NT front end to XBoard
\r
3 * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
\r
5 * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
\r
6 * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.
\r
8 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
9 * which was written and is copyrighted by Wayne Christopher.
\r
11 * The following terms apply to Digital Equipment Corporation's copyright
\r
12 * interest in XBoard:
\r
13 * ------------------------------------------------------------------------
\r
14 * All Rights Reserved
\r
16 * Permission to use, copy, modify, and distribute this software and its
\r
17 * documentation for any purpose and without fee is hereby granted,
\r
18 * provided that the above copyright notice appear in all copies and that
\r
19 * both that copyright notice and this permission notice appear in
\r
20 * supporting documentation, and that the name of Digital not be
\r
21 * used in advertising or publicity pertaining to distribution of the
\r
22 * software without specific, written prior permission.
\r
24 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
25 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
26 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
27 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
28 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
29 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
31 * ------------------------------------------------------------------------
\r
33 * The following terms apply to the enhanced version of XBoard distributed
\r
34 * by the Free Software Foundation:
\r
35 * ------------------------------------------------------------------------
\r
36 * This program is free software; you can redistribute it and/or modify
\r
37 * it under the terms of the GNU General Public License as published by
\r
38 * the Free Software Foundation; either version 2 of the License, or
\r
39 * (at your option) any later version.
\r
41 * This program is distributed in the hope that it will be useful,
\r
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
44 * GNU General Public License for more details.
\r
46 * You should have received a copy of the GNU General Public License
\r
47 * along with this program; if not, write to the Free Software
\r
48 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
\r
49 * ------------------------------------------------------------------------
\r
54 #include <windows.h>
\r
55 #include <winuser.h>
\r
56 #include <winsock.h>
\r
62 #include <sys/stat.h>
\r
65 #include <commdlg.h>
\r
67 #include <richedit.h>
\r
68 #include <mmsystem.h>
\r
76 #include "winboard.h"
\r
77 #include "frontend.h"
\r
78 #include "backend.h"
\r
80 #include "wclipbrd.h"
\r
81 #include "wgamelist.h"
\r
82 #include "wedittags.h"
\r
83 #include "woptions.h"
\r
84 #include "wsockerr.h"
\r
85 #include "defaults.h"
\r
89 //void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
92 void mysrandom(unsigned int seed);
\r
94 extern int whiteFlag, blackFlag;
\r
95 Boolean flipClock = FALSE;
\r
97 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
100 ChessSquare piece;
\r
101 POINT pos; /* window coordinates of current pos */
\r
102 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
103 POINT from; /* board coordinates of the piece's orig pos */
\r
104 POINT to; /* board coordinates of the piece's new pos */
\r
107 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
110 POINT start; /* window coordinates of start pos */
\r
111 POINT pos; /* window coordinates of current pos */
\r
112 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
113 POINT from; /* board coordinates of the piece's orig pos */
\r
116 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
119 POINT sq[2]; /* board coordinates of from, to squares */
\r
122 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
123 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
125 /* Window class names */
\r
126 char szAppName[] = "WinBoard";
\r
127 char szConsoleName[] = "WBConsole";
\r
129 /* Title bar text */
\r
130 char szTitle[] = "WinBoard";
\r
131 char szConsoleTitle[] = "ICS Interaction";
\r
134 char *settingsFileName;
\r
135 BOOLEAN saveSettingsOnExit;
\r
136 char installDir[MSG_SIZ];
\r
138 BoardSize boardSize;
\r
139 BOOLEAN chessProgram;
\r
140 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
141 static int squareSize, lineGap, minorSize;
\r
142 static int winWidth, winHeight;
\r
143 static RECT messageRect, whiteRect, blackRect;
\r
144 static char messageText[MESSAGE_TEXT_MAX];
\r
145 static int clockTimerEvent = 0;
\r
146 static int loadGameTimerEvent = 0;
\r
147 static int analysisTimerEvent = 0;
\r
148 static DelayedEventCallback delayedTimerCallback;
\r
149 static int delayedTimerEvent = 0;
\r
150 static int buttonCount = 2;
\r
151 char *icsTextMenuString;
\r
153 char *firstChessProgramNames;
\r
154 char *secondChessProgramNames;
\r
156 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
158 #define PALETTESIZE 256
\r
160 HINSTANCE hInst; /* current instance */
\r
161 HWND hwndMain = NULL; /* root window*/
\r
162 HWND hwndConsole = NULL;
\r
163 BOOLEAN alwaysOnTop = FALSE;
\r
165 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
166 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
168 ColorClass currentColorClass;
\r
170 HWND hCommPort = NULL; /* currently open comm port */
\r
171 static HWND hwndPause; /* pause button */
\r
172 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
173 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
174 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
175 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
176 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
177 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
178 static HPEN gridPen = NULL;
\r
179 static HPEN highlightPen = NULL;
\r
180 static HPEN premovePen = NULL;
\r
181 static NPLOGPALETTE pLogPal;
\r
182 static BOOL paletteChanged = FALSE;
\r
183 static HICON iconWhite, iconBlack, iconCurrent;
\r
184 static int doingSizing = FALSE;
\r
185 static int lastSizing = 0;
\r
186 static int prevStderrPort;
\r
188 /* [AS] Support for background textures */
\r
189 #define BACK_TEXTURE_MODE_DISABLED 0
\r
190 #define BACK_TEXTURE_MODE_PLAIN 1
\r
191 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
193 static HBITMAP liteBackTexture = NULL;
\r
194 static HBITMAP darkBackTexture = NULL;
\r
195 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
196 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
197 static int backTextureSquareSize = 0;
\r
198 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
200 #if __GNUC__ && !defined(_winmajor)
\r
201 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
203 #define oldDialog (_winmajor < 4)
\r
206 char *defaultTextAttribs[] =
\r
208 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
209 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
219 int cliWidth, cliHeight;
\r
222 SizeInfo sizeInfo[] =
\r
224 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
225 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
226 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
227 { "petite", 33, 1, 1, 1, 0, 0 },
\r
228 { "slim", 37, 2, 1, 0, 0, 0 },
\r
229 { "small", 40, 2, 1, 0, 0, 0 },
\r
230 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
231 { "middling", 49, 2, 0, 0, 0, 0 },
\r
232 { "average", 54, 2, 0, 0, 0, 0 },
\r
233 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
234 { "medium", 64, 3, 0, 0, 0, 0 },
\r
235 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
236 { "large", 80, 3, 0, 0, 0, 0 },
\r
237 { "big", 87, 3, 0, 0, 0, 0 },
\r
238 { "huge", 95, 3, 0, 0, 0, 0 },
\r
239 { "giant", 108, 3, 0, 0, 0, 0 },
\r
240 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
241 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
242 { NULL, 0, 0, 0, 0, 0, 0 }
\r
245 #define MF(x) {x, {0, }, {0, }, 0}
\r
246 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
248 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
249 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
250 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
251 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
252 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
253 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
254 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
255 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
256 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
257 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
258 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
259 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
260 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
261 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
262 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
263 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
264 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
265 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
268 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
277 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
278 #define N_BUTTONS 5
\r
280 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
282 {"<<", IDM_ToStart, NULL, NULL},
\r
283 {"<", IDM_Backward, NULL, NULL},
\r
284 {"P", IDM_Pause, NULL, NULL},
\r
285 {">", IDM_Forward, NULL, NULL},
\r
286 {">>", IDM_ToEnd, NULL, NULL},
\r
289 int tinyLayout = 0, smallLayout = 0;
\r
290 #define MENU_BAR_ITEMS 6
\r
291 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
292 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
293 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
297 MySound sounds[(int)NSoundClasses];
\r
298 MyTextAttribs textAttribs[(int)NColorClasses];
\r
300 MyColorizeAttribs colorizeAttribs[] = {
\r
301 { (COLORREF)0, 0, "Shout Text" },
\r
302 { (COLORREF)0, 0, "SShout/CShout" },
\r
303 { (COLORREF)0, 0, "Channel 1 Text" },
\r
304 { (COLORREF)0, 0, "Channel Text" },
\r
305 { (COLORREF)0, 0, "Kibitz Text" },
\r
306 { (COLORREF)0, 0, "Tell Text" },
\r
307 { (COLORREF)0, 0, "Challenge Text" },
\r
308 { (COLORREF)0, 0, "Request Text" },
\r
309 { (COLORREF)0, 0, "Seek Text" },
\r
310 { (COLORREF)0, 0, "Normal Text" },
\r
311 { (COLORREF)0, 0, "None" }
\r
316 static char *commentTitle;
\r
317 static char *commentText;
\r
318 static int commentIndex;
\r
319 static Boolean editComment = FALSE;
\r
320 HWND commentDialog = NULL;
\r
321 BOOLEAN commentDialogUp = FALSE;
\r
322 static int commentX, commentY, commentH, commentW;
\r
324 static char *analysisTitle;
\r
325 static char *analysisText;
\r
326 HWND analysisDialog = NULL;
\r
327 BOOLEAN analysisDialogUp = FALSE;
\r
328 static int analysisX, analysisY, analysisH, analysisW;
\r
330 char errorTitle[MSG_SIZ];
\r
331 char errorMessage[2*MSG_SIZ];
\r
332 HWND errorDialog = NULL;
\r
333 BOOLEAN moveErrorMessageUp = FALSE;
\r
334 BOOLEAN consoleEcho = TRUE;
\r
335 CHARFORMAT consoleCF;
\r
336 COLORREF consoleBackgroundColor;
\r
338 char *programVersion;
\r
344 typedef int CPKind;
\r
353 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
356 #define INPUT_SOURCE_BUF_SIZE 4096
\r
358 typedef struct _InputSource {
\r
365 char buf[INPUT_SOURCE_BUF_SIZE];
\r
369 InputCallback func;
\r
370 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
374 InputSource *consoleInputSource;
\r
379 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
380 VOID ConsoleCreate();
\r
382 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
383 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
384 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
385 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
387 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
388 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
389 void ParseIcsTextMenu(char *icsTextMenuString);
\r
390 VOID PopUpMoveDialog(char firstchar);
\r
391 VOID PopUpNameDialog(char firstchar);
\r
392 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
396 int GameListOptions();
\r
398 HWND moveHistoryDialog = NULL;
\r
399 BOOLEAN moveHistoryDialogUp = FALSE;
\r
401 WindowPlacement wpMoveHistory;
\r
403 HWND evalGraphDialog = NULL;
\r
404 BOOLEAN evalGraphDialogUp = FALSE;
\r
406 WindowPlacement wpEvalGraph;
\r
408 HWND engineOutputDialog = NULL;
\r
409 BOOLEAN engineOutputDialogUp = FALSE;
\r
411 WindowPlacement wpEngineOutput;
\r
413 VOID MoveHistoryPopUp();
\r
414 VOID MoveHistoryPopDown();
\r
415 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
416 BOOL MoveHistoryIsUp();
\r
418 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
419 VOID EvalGraphPopUp();
\r
420 VOID EvalGraphPopDown();
\r
421 BOOL EvalGraphIsUp();
\r
423 VOID EngineOutputPopUp();
\r
424 VOID EngineOutputPopDown();
\r
425 BOOL EngineOutputIsUp();
\r
426 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
428 VOID GothicPopUp(char *title, VariantClass variant);
\r
430 * Setting "frozen" should disable all user input other than deleting
\r
431 * the window. We do this while engines are initializing themselves.
\r
433 static int frozen = 0;
\r
434 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
440 if (frozen) return;
\r
442 hmenu = GetMenu(hwndMain);
\r
443 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
444 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
446 DrawMenuBar(hwndMain);
\r
449 /* Undo a FreezeUI */
\r
455 if (!frozen) return;
\r
457 hmenu = GetMenu(hwndMain);
\r
458 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
459 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
461 DrawMenuBar(hwndMain);
\r
464 /*---------------------------------------------------------------------------*\
\r
468 \*---------------------------------------------------------------------------*/
\r
471 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
472 LPSTR lpCmdLine, int nCmdShow)
\r
475 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
479 LoadLibrary("RICHED32.DLL");
\r
480 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
482 if (!InitApplication(hInstance)) {
\r
485 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
489 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
490 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
491 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
493 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
495 while (GetMessage(&msg, /* message structure */
\r
496 NULL, /* handle of window receiving the message */
\r
497 0, /* lowest message to examine */
\r
498 0)) /* highest message to examine */
\r
500 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
501 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
502 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
503 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
504 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
505 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
506 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
507 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
508 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
509 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
510 TranslateMessage(&msg); /* Translates virtual key codes */
\r
511 DispatchMessage(&msg); /* Dispatches message to window */
\r
516 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
519 /*---------------------------------------------------------------------------*\
\r
521 * Initialization functions
\r
523 \*---------------------------------------------------------------------------*/
\r
526 InitApplication(HINSTANCE hInstance)
\r
530 /* Fill in window class structure with parameters that describe the */
\r
533 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
534 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
535 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
536 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
537 wc.hInstance = hInstance; /* Owner of this class */
\r
538 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
539 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
540 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
541 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
542 wc.lpszClassName = szAppName; /* Name to register as */
\r
544 /* Register the window class and return success/failure code. */
\r
545 if (!RegisterClass(&wc)) return FALSE;
\r
547 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
548 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
550 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
551 wc.hInstance = hInstance;
\r
552 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
553 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
554 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
555 wc.lpszMenuName = NULL;
\r
556 wc.lpszClassName = szConsoleName;
\r
558 if (!RegisterClass(&wc)) return FALSE;
\r
563 /* Set by InitInstance, used by EnsureOnScreen */
\r
564 int screenHeight, screenWidth;
\r
567 EnsureOnScreen(int *x, int *y)
\r
569 int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
570 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
571 if (*x > screenWidth - 32) *x = 0;
\r
572 if (*y > screenHeight - 32) *y = 0;
\r
573 if (*x < 10) *x = 10;
\r
574 if (*y < gap) *y = gap;
\r
578 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
580 HWND hwnd; /* Main window handle. */
\r
582 WINDOWPLACEMENT wp;
\r
585 hInst = hInstance; /* Store instance handle in our global variable */
\r
587 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
588 *filepart = NULLCHAR;
\r
590 GetCurrentDirectory(MSG_SIZ, installDir);
\r
592 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
593 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
594 if (appData.debugMode) {
\r
595 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
596 setbuf(debugFP, NULL);
\r
601 // InitEngineUCI( installDir, &first ); // [HGM] incorporated in InitBackEnd1()
\r
602 // InitEngineUCI( installDir, &second );
\r
604 /* Create a main window for this application instance. */
\r
605 hwnd = CreateWindow(szAppName, szTitle,
\r
606 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
607 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
608 NULL, NULL, hInstance, NULL);
\r
611 /* If window could not be created, return "failure" */
\r
616 iconWhite = LoadIcon(hInstance, "icon_white");
\r
617 iconBlack = LoadIcon(hInstance, "icon_black");
\r
618 iconCurrent = iconWhite;
\r
619 InitDrawingColors();
\r
620 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
621 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
622 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
623 /* Compute window size for each board size, and use the largest
\r
624 size that fits on this screen as the default. */
\r
625 InitDrawingSizes((BoardSize)ibs, 0);
\r
626 if (boardSize == (BoardSize)-1 &&
\r
627 winHeight <= screenHeight
\r
628 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
629 && winWidth <= screenWidth) {
\r
630 boardSize = (BoardSize)ibs;
\r
633 InitDrawingSizes(boardSize, 0);
\r
635 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
637 /* [AS] Load textures if specified */
\r
638 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
640 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
641 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
642 liteBackTextureMode = appData.liteBackTextureMode;
\r
644 if (liteBackTexture == NULL && appData.debugMode) {
\r
645 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
649 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
650 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
651 darkBackTextureMode = appData.darkBackTextureMode;
\r
653 if (darkBackTexture == NULL && appData.debugMode) {
\r
654 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
658 mysrandom( (unsigned) time(NULL) );
\r
660 /* Make a console window if needed */
\r
661 if (appData.icsActive) {
\r
665 /* [AS] Restore layout */
\r
666 if( wpMoveHistory.visible ) {
\r
667 MoveHistoryPopUp();
\r
670 if( wpEvalGraph.visible ) {
\r
674 if( wpEngineOutput.visible ) {
\r
675 EngineOutputPopUp();
\r
680 /* Make the window visible; update its client area; and return "success" */
\r
681 EnsureOnScreen(&boardX, &boardY);
\r
682 wp.length = sizeof(WINDOWPLACEMENT);
\r
684 wp.showCmd = nCmdShow;
\r
685 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
686 wp.rcNormalPosition.left = boardX;
\r
687 wp.rcNormalPosition.right = boardX + winWidth;
\r
688 wp.rcNormalPosition.top = boardY;
\r
689 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
690 SetWindowPlacement(hwndMain, &wp);
\r
692 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
693 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
696 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
697 if( gameInfo.variant != VariantFischeRandom ) {
\r
698 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
703 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
704 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
706 ShowWindow(hwndConsole, nCmdShow);
\r
708 UpdateWindow(hwnd);
\r
716 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
717 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
718 ArgSettingsFilename
\r
726 String *pString; // ArgString
\r
727 int *pInt; // ArgInt
\r
728 float *pFloat; // ArgFloat
\r
729 Boolean *pBoolean; // ArgBoolean
\r
730 COLORREF *pColor; // ArgColor
\r
731 ColorClass cc; // ArgAttribs
\r
732 String *pFilename; // ArgFilename
\r
733 BoardSize *pBoardSize; // ArgBoardSize
\r
734 int whichFont; // ArgFont
\r
735 DCB *pDCB; // ArgCommSettings
\r
736 String *pFilename; // ArgSettingsFilename
\r
744 ArgDescriptor argDescriptors[] = {
\r
745 /* positional arguments */
\r
746 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
747 { "", ArgNone, NULL },
\r
748 /* keyword arguments */
\r
749 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
750 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
751 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
752 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
753 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
754 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
755 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
756 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
757 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
758 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
759 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
760 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
761 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
762 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
763 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
764 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
765 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
766 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
768 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
770 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
772 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
773 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
775 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
776 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
777 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
778 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
779 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
780 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
781 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
782 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
783 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
784 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
785 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
786 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
787 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
788 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
789 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
790 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
791 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
792 /*!!bitmapDirectory?*/
\r
793 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
794 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
795 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
796 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
797 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
798 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
799 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
800 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
801 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
802 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
803 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
804 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
805 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
806 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
807 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
808 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
809 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
810 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
811 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
812 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
813 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
814 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
815 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
816 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
817 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
818 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
819 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
820 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
821 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
822 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
823 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
824 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
825 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
826 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
827 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
828 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
829 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
830 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
831 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
832 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
833 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
834 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
835 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
836 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
837 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
838 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
839 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
840 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
841 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
842 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
843 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
844 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
845 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
846 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
847 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
848 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
849 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
850 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
851 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
852 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
853 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
854 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
855 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
856 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
857 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
858 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
859 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
860 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
861 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
862 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
863 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
864 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
865 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
866 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
867 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
868 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
869 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
870 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
871 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
872 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
873 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
874 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
875 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
876 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
877 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
878 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
879 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
880 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
881 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
882 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
883 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
884 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
885 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
886 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
887 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
888 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
889 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
890 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
891 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
892 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
893 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
894 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
895 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
896 TRUE }, /* must come after all fonts */
\r
897 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
898 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
899 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
900 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
901 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
902 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
903 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
904 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
905 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
906 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
907 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
908 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
909 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
910 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
911 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
912 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
913 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
914 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
915 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
916 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
917 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
918 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
919 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
920 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
921 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
922 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
923 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
924 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
925 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
926 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
927 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
929 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
930 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
932 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
933 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
934 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
935 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
936 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
937 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
938 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
939 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
940 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
941 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
942 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
943 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
944 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
945 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
946 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
947 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
948 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
949 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
950 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
951 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
952 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
953 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
954 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
955 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
956 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
957 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
958 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
959 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
960 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
961 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
962 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
963 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
964 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
965 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
966 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
967 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
968 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
969 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
970 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
971 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
972 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
973 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
974 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
975 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
976 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
977 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
978 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
979 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
980 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
981 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
982 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
983 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
984 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
985 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
986 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
987 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
988 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
989 { "highlightLastMove", ArgBoolean,
\r
990 (LPVOID) &appData.highlightLastMove, TRUE },
\r
991 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
992 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
993 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
994 { "highlightDragging", ArgBoolean,
\r
995 (LPVOID) &appData.highlightDragging, TRUE },
\r
996 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
997 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
998 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
999 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
1000 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
1001 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1002 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1003 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1004 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1005 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1006 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1007 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1008 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1009 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1010 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1011 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1012 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1013 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1014 { "soundShout", ArgFilename,
\r
1015 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1016 { "soundSShout", ArgFilename,
\r
1017 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1018 { "soundChannel1", ArgFilename,
\r
1019 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1020 { "soundChannel", ArgFilename,
\r
1021 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1022 { "soundKibitz", ArgFilename,
\r
1023 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1024 { "soundTell", ArgFilename,
\r
1025 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1026 { "soundChallenge", ArgFilename,
\r
1027 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1028 { "soundRequest", ArgFilename,
\r
1029 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1030 { "soundSeek", ArgFilename,
\r
1031 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1032 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1033 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1034 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1035 { "soundIcsLoss", ArgFilename,
\r
1036 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1037 { "soundIcsDraw", ArgFilename,
\r
1038 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1039 { "soundIcsUnfinished", ArgFilename,
\r
1040 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1041 { "soundIcsAlarm", ArgFilename,
\r
1042 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1043 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1044 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1045 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1046 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1047 { "reuseChessPrograms", ArgBoolean,
\r
1048 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1049 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1050 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1051 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1052 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1053 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1054 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1055 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1056 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1057 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1058 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1059 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1060 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1061 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1062 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1063 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1064 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1065 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1066 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1067 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1068 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1069 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1070 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1071 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1072 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1073 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1074 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1075 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1076 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1077 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1078 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1079 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1080 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1081 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1082 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1083 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1084 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1085 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1087 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1089 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1090 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1091 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1092 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1093 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1094 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1095 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1096 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1097 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1098 /* [AS] New features */
\r
1099 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1100 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1101 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1102 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1103 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1104 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1105 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1106 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1107 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1108 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1109 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1110 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1111 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1112 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1113 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1114 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1115 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1116 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1117 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1118 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1119 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1120 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1121 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1122 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1123 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1124 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1125 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1126 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1127 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1128 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1129 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1130 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1131 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1132 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1133 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1134 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1135 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1136 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1137 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1138 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1139 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1140 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1141 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1142 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1143 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1144 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1145 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1146 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1148 /* [AS] Layout stuff */
\r
1149 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1150 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1151 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1152 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1153 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1155 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1156 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1157 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1158 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1159 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1161 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1162 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1163 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1164 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1165 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1167 /* [HGM] board-size, adjudication and misc. options */
\r
1168 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1169 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1170 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1171 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1172 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1173 { "flipBlack", ArgBoolean, (LPVOID) &appData.upsideDown, TRUE },
\r
1174 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1175 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1176 { "firstAlphaRank", ArgBoolean, (LPVOID) &first.alphaRank, FALSE },
\r
1177 { "secondAlphaRank", ArgBoolean, (LPVOID) &second.alphaRank, FALSE },
\r
1178 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1179 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1180 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1181 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1182 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1183 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1184 { "autoKibitz", ArgTrue, (LPVOID) &appData.autoKibitz, FALSE },
\r
1185 { "engineDebugOutput", ArgInt, (LPVOID) &appData.engineComments, FALSE },
\r
1186 { "userName", ArgString, (LPVOID) &appData.userName, FALSE },
\r
1187 { "rewindIndex", ArgInt, (LPVOID) &appData.rewindIndex, FALSE },
\r
1188 { "sameColorGames", ArgInt, (LPVOID) &appData.sameColorGames, FALSE },
\r
1189 { "smpCores", ArgInt, (LPVOID) &appData.smpCores, TRUE },
\r
1190 { "egtFormats", ArgString, (LPVOID) &appData.egtFormats, TRUE },
\r
1193 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1194 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1195 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1196 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1197 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1198 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1199 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1200 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1201 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1202 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1203 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1204 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1205 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1207 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1208 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1209 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1210 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1211 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1212 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1213 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1215 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1216 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1217 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1218 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1219 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1220 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1221 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1222 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1223 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1224 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1225 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1226 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1227 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1228 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1229 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1230 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1231 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1232 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1234 /* [HGM] options for broadcasting and time odds */
\r
1235 { "serverMoves", ArgString, (LPVOID) &appData.serverMovesName, FALSE },
\r
1236 { "suppressLoadMoves", ArgBoolean, (LPVOID) &appData.suppressLoadMoves, FALSE },
\r
1237 { "serverPause", ArgInt, (LPVOID) &appData.serverPause, FALSE },
\r
1238 { "firstTimeOdds", ArgInt, (LPVOID) &appData.firstTimeOdds, FALSE },
\r
1239 { "secondTimeOdds", ArgInt, (LPVOID) &appData.secondTimeOdds, FALSE },
\r
1240 { "timeOddsMode", ArgInt, (LPVOID) &appData.timeOddsMode, TRUE },
\r
1241 { "firstAccumulateTC", ArgInt, (LPVOID) &appData.firstAccumulateTC, FALSE },
\r
1242 { "secondAccumulateTC", ArgInt, (LPVOID) &appData.secondAccumulateTC, FALSE },
\r
1243 { "firstNPS", ArgInt, (LPVOID) &appData.firstNPS, FALSE },
\r
1244 { "secondNPS", ArgInt, (LPVOID) &appData.secondNPS, FALSE },
\r
1245 { NULL, ArgNone, NULL, FALSE }
\r
1249 /* Kludge for indirection files on command line */
\r
1250 char* lastIndirectionFilename;
\r
1251 ArgDescriptor argDescriptorIndirection =
\r
1252 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1256 ExitArgError(char *msg, char *badArg)
\r
1258 char buf[MSG_SIZ];
\r
1260 sprintf(buf, "%s %s", msg, badArg);
\r
1261 DisplayFatalError(buf, 0, 2);
\r
1265 /* Command line font name parser. NULL name means do nothing.
\r
1266 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1267 For backward compatibility, syntax without the colon is also
\r
1268 accepted, but font names with digits in them won't work in that case.
\r
1271 ParseFontName(char *name, MyFontParams *mfp)
\r
1274 if (name == NULL) return;
\r
1276 q = strchr(p, ':');
\r
1278 if (q - p >= sizeof(mfp->faceName))
\r
1279 ExitArgError("Font name too long:", name);
\r
1280 memcpy(mfp->faceName, p, q - p);
\r
1281 mfp->faceName[q - p] = NULLCHAR;
\r
1284 q = mfp->faceName;
\r
1285 while (*p && !isdigit(*p)) {
\r
1287 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1288 ExitArgError("Font name too long:", name);
\r
1290 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1293 if (!*p) ExitArgError("Font point size missing:", name);
\r
1294 mfp->pointSize = (float) atof(p);
\r
1295 mfp->bold = (strchr(p, 'b') != NULL);
\r
1296 mfp->italic = (strchr(p, 'i') != NULL);
\r
1297 mfp->underline = (strchr(p, 'u') != NULL);
\r
1298 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1301 /* Color name parser.
\r
1302 X version accepts X color names, but this one
\r
1303 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1305 ParseColorName(char *name)
\r
1307 int red, green, blue, count;
\r
1308 char buf[MSG_SIZ];
\r
1310 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1312 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1313 &red, &green, &blue);
\r
1316 sprintf(buf, "Can't parse color name %s", name);
\r
1317 DisplayError(buf, 0);
\r
1318 return RGB(0, 0, 0);
\r
1320 return PALETTERGB(red, green, blue);
\r
1324 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1326 char *e = argValue;
\r
1330 if (*e == 'b') eff |= CFE_BOLD;
\r
1331 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1332 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1333 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1334 else if (*e == '#' || isdigit(*e)) break;
\r
1338 *color = ParseColorName(e);
\r
1343 ParseBoardSize(char *name)
\r
1345 BoardSize bs = SizeTiny;
\r
1346 while (sizeInfo[bs].name != NULL) {
\r
1347 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1350 ExitArgError("Unrecognized board size value", name);
\r
1351 return bs; /* not reached */
\r
1356 StringGet(void *getClosure)
\r
1358 char **p = (char **) getClosure;
\r
1363 FileGet(void *getClosure)
\r
1366 FILE* f = (FILE*) getClosure;
\r
1375 /* Parse settings file named "name". If file found, return the
\r
1376 full name in fullname and return TRUE; else return FALSE */
\r
1378 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1383 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1384 f = fopen(fullname, "r");
\r
1386 ParseArgs(FileGet, f);
\r
1395 ParseArgs(GetFunc get, void *cl)
\r
1397 char argName[ARG_MAX];
\r
1398 char argValue[ARG_MAX];
\r
1399 ArgDescriptor *ad;
\r
1408 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1409 if (ch == NULLCHAR) break;
\r
1411 /* Comment to end of line */
\r
1413 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1415 } else if (ch == '/' || ch == '-') {
\r
1418 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1419 ch != '\n' && ch != '\t') {
\r
1425 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1426 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1428 if (ad->argName == NULL)
\r
1429 ExitArgError("Unrecognized argument", argName);
\r
1431 } else if (ch == '@') {
\r
1432 /* Indirection file */
\r
1433 ad = &argDescriptorIndirection;
\r
1436 /* Positional argument */
\r
1437 ad = &argDescriptors[posarg++];
\r
1438 strcpy(argName, ad->argName);
\r
1441 if (ad->argType == ArgTrue) {
\r
1442 *(Boolean *) ad->argLoc = TRUE;
\r
1445 if (ad->argType == ArgFalse) {
\r
1446 *(Boolean *) ad->argLoc = FALSE;
\r
1450 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1451 if (ch == NULLCHAR || ch == '\n') {
\r
1452 ExitArgError("No value provided for argument", argName);
\r
1456 // Quoting with { }. No characters have to (or can) be escaped.
\r
1457 // Thus the string cannot contain a '}' character.
\r
1477 } else if (ch == '\'' || ch == '"') {
\r
1478 // Quoting with ' ' or " ", with \ as escape character.
\r
1479 // Inconvenient for long strings that may contain Windows filenames.
\r
1496 if (ch == start) {
\r
1505 if (ad->argType == ArgFilename
\r
1506 || ad->argType == ArgSettingsFilename) {
\r
1512 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1536 for (i = 0; i < 3; i++) {
\r
1537 if (ch >= '0' && ch <= '7') {
\r
1538 octval = octval*8 + (ch - '0');
\r
1545 *q++ = (char) octval;
\r
1556 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1563 switch (ad->argType) {
\r
1565 *(int *) ad->argLoc = atoi(argValue);
\r
1569 *(float *) ad->argLoc = (float) atof(argValue);
\r
1574 *(char **) ad->argLoc = strdup(argValue);
\r
1577 case ArgSettingsFilename:
\r
1579 char fullname[MSG_SIZ];
\r
1580 if (ParseSettingsFile(argValue, fullname)) {
\r
1581 if (ad->argLoc != NULL) {
\r
1582 *(char **) ad->argLoc = strdup(fullname);
\r
1585 if (ad->argLoc != NULL) {
\r
1587 ExitArgError("Failed to open indirection file", argValue);
\r
1594 switch (argValue[0]) {
\r
1597 *(Boolean *) ad->argLoc = TRUE;
\r
1601 *(Boolean *) ad->argLoc = FALSE;
\r
1604 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1610 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1613 case ArgAttribs: {
\r
1614 ColorClass cc = (ColorClass)ad->argLoc;
\r
1615 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1619 case ArgBoardSize:
\r
1620 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1624 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1627 case ArgCommSettings:
\r
1628 ParseCommSettings(argValue, &dcb);
\r
1632 ExitArgError("Unrecognized argument", argValue);
\r
1639 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1641 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1642 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1645 lf->lfEscapement = 0;
\r
1646 lf->lfOrientation = 0;
\r
1647 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1648 lf->lfItalic = mfp->italic;
\r
1649 lf->lfUnderline = mfp->underline;
\r
1650 lf->lfStrikeOut = mfp->strikeout;
\r
1651 lf->lfCharSet = DEFAULT_CHARSET;
\r
1652 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1653 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1654 lf->lfQuality = DEFAULT_QUALITY;
\r
1655 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1656 strcpy(lf->lfFaceName, mfp->faceName);
\r
1660 CreateFontInMF(MyFont *mf)
\r
1662 LFfromMFP(&mf->lf, &mf->mfp);
\r
1663 if (mf->hf) DeleteObject(mf->hf);
\r
1664 mf->hf = CreateFontIndirect(&mf->lf);
\r
1668 SetDefaultTextAttribs()
\r
1671 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1672 ParseAttribs(&textAttribs[cc].color,
\r
1673 &textAttribs[cc].effects,
\r
1674 defaultTextAttribs[cc]);
\r
1679 SetDefaultSounds()
\r
1683 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1684 textAttribs[cc].sound.name = strdup("");
\r
1685 textAttribs[cc].sound.data = NULL;
\r
1687 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1688 sounds[sc].name = strdup("");
\r
1689 sounds[sc].data = NULL;
\r
1691 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1699 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1700 MyLoadSound(&textAttribs[cc].sound);
\r
1702 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1703 MyLoadSound(&sounds[sc]);
\r
1708 InitAppData(LPSTR lpCmdLine)
\r
1711 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1714 programName = szAppName;
\r
1716 /* Initialize to defaults */
\r
1717 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1718 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1719 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1720 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1721 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1722 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1723 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1724 SetDefaultTextAttribs();
\r
1725 SetDefaultSounds();
\r
1726 appData.movesPerSession = MOVES_PER_SESSION;
\r
1727 appData.initString = INIT_STRING;
\r
1728 appData.secondInitString = INIT_STRING;
\r
1729 appData.firstComputerString = COMPUTER_STRING;
\r
1730 appData.secondComputerString = COMPUTER_STRING;
\r
1731 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1732 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1733 appData.firstPlaysBlack = FALSE;
\r
1734 appData.noChessProgram = FALSE;
\r
1735 chessProgram = FALSE;
\r
1736 appData.firstHost = FIRST_HOST;
\r
1737 appData.secondHost = SECOND_HOST;
\r
1738 appData.firstDirectory = FIRST_DIRECTORY;
\r
1739 appData.secondDirectory = SECOND_DIRECTORY;
\r
1740 appData.bitmapDirectory = "";
\r
1741 appData.remoteShell = REMOTE_SHELL;
\r
1742 appData.remoteUser = "";
\r
1743 appData.timeDelay = TIME_DELAY;
\r
1744 appData.timeControl = TIME_CONTROL;
\r
1745 appData.timeIncrement = TIME_INCREMENT;
\r
1746 appData.icsActive = FALSE;
\r
1747 appData.icsHost = "";
\r
1748 appData.icsPort = ICS_PORT;
\r
1749 appData.icsCommPort = ICS_COMM_PORT;
\r
1750 appData.icsLogon = ICS_LOGON;
\r
1751 appData.icsHelper = "";
\r
1752 appData.useTelnet = FALSE;
\r
1753 appData.telnetProgram = TELNET_PROGRAM;
\r
1754 appData.gateway = "";
\r
1755 appData.loadGameFile = "";
\r
1756 appData.loadGameIndex = 0;
\r
1757 appData.saveGameFile = "";
\r
1758 appData.autoSaveGames = FALSE;
\r
1759 appData.loadPositionFile = "";
\r
1760 appData.loadPositionIndex = 1;
\r
1761 appData.savePositionFile = "";
\r
1762 appData.matchMode = FALSE;
\r
1763 appData.matchGames = 0;
\r
1764 appData.monoMode = FALSE;
\r
1765 appData.debugMode = FALSE;
\r
1766 appData.clockMode = TRUE;
\r
1767 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1768 appData.Iconic = FALSE; /*unused*/
\r
1769 appData.searchTime = "";
\r
1770 appData.searchDepth = 0;
\r
1771 appData.showCoords = FALSE;
\r
1772 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1773 appData.autoCallFlag = FALSE;
\r
1774 appData.flipView = FALSE;
\r
1775 appData.autoFlipView = TRUE;
\r
1776 appData.cmailGameName = "";
\r
1777 appData.alwaysPromoteToQueen = FALSE;
\r
1778 appData.oldSaveStyle = FALSE;
\r
1779 appData.quietPlay = FALSE;
\r
1780 appData.showThinking = FALSE;
\r
1781 appData.ponderNextMove = TRUE;
\r
1782 appData.periodicUpdates = TRUE;
\r
1783 appData.popupExitMessage = TRUE;
\r
1784 appData.popupMoveErrors = FALSE;
\r
1785 appData.autoObserve = FALSE;
\r
1786 appData.autoComment = FALSE;
\r
1787 appData.animate = TRUE;
\r
1788 appData.animSpeed = 10;
\r
1789 appData.animateDragging = TRUE;
\r
1790 appData.highlightLastMove = TRUE;
\r
1791 appData.getMoveList = TRUE;
\r
1792 appData.testLegality = TRUE;
\r
1793 appData.premove = TRUE;
\r
1794 appData.premoveWhite = FALSE;
\r
1795 appData.premoveWhiteText = "";
\r
1796 appData.premoveBlack = FALSE;
\r
1797 appData.premoveBlackText = "";
\r
1798 appData.icsAlarm = TRUE;
\r
1799 appData.icsAlarmTime = 5000;
\r
1800 appData.autoRaiseBoard = TRUE;
\r
1801 appData.localLineEditing = TRUE;
\r
1802 appData.colorize = TRUE;
\r
1803 appData.reuseFirst = TRUE;
\r
1804 appData.reuseSecond = TRUE;
\r
1805 appData.blindfold = FALSE;
\r
1806 dcb.DCBlength = sizeof(DCB);
\r
1807 dcb.BaudRate = 9600;
\r
1808 dcb.fBinary = TRUE;
\r
1809 dcb.fParity = FALSE;
\r
1810 dcb.fOutxCtsFlow = FALSE;
\r
1811 dcb.fOutxDsrFlow = FALSE;
\r
1812 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1813 dcb.fDsrSensitivity = FALSE;
\r
1814 dcb.fTXContinueOnXoff = TRUE;
\r
1815 dcb.fOutX = FALSE;
\r
1817 dcb.fNull = FALSE;
\r
1818 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1819 dcb.fAbortOnError = FALSE;
\r
1820 dcb.wReserved = 0;
\r
1822 dcb.Parity = SPACEPARITY;
\r
1823 dcb.StopBits = ONESTOPBIT;
\r
1824 settingsFileName = SETTINGS_FILE;
\r
1825 saveSettingsOnExit = TRUE;
\r
1826 boardX = CW_USEDEFAULT;
\r
1827 boardY = CW_USEDEFAULT;
\r
1828 consoleX = CW_USEDEFAULT;
\r
1829 consoleY = CW_USEDEFAULT;
\r
1830 consoleW = CW_USEDEFAULT;
\r
1831 consoleH = CW_USEDEFAULT;
\r
1832 analysisX = CW_USEDEFAULT;
\r
1833 analysisY = CW_USEDEFAULT;
\r
1834 analysisW = CW_USEDEFAULT;
\r
1835 analysisH = CW_USEDEFAULT;
\r
1836 commentX = CW_USEDEFAULT;
\r
1837 commentY = CW_USEDEFAULT;
\r
1838 commentW = CW_USEDEFAULT;
\r
1839 commentH = CW_USEDEFAULT;
\r
1840 editTagsX = CW_USEDEFAULT;
\r
1841 editTagsY = CW_USEDEFAULT;
\r
1842 editTagsW = CW_USEDEFAULT;
\r
1843 editTagsH = CW_USEDEFAULT;
\r
1844 gameListX = CW_USEDEFAULT;
\r
1845 gameListY = CW_USEDEFAULT;
\r
1846 gameListW = CW_USEDEFAULT;
\r
1847 gameListH = CW_USEDEFAULT;
\r
1848 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1849 icsNames = ICS_NAMES;
\r
1850 firstChessProgramNames = FCP_NAMES;
\r
1851 secondChessProgramNames = SCP_NAMES;
\r
1852 appData.initialMode = "";
\r
1853 appData.variant = "normal";
\r
1854 appData.firstProtocolVersion = PROTOVER;
\r
1855 appData.secondProtocolVersion = PROTOVER;
\r
1856 appData.showButtonBar = TRUE;
\r
1858 /* [AS] New properties (see comments in header file) */
\r
1859 appData.firstScoreIsAbsolute = FALSE;
\r
1860 appData.secondScoreIsAbsolute = FALSE;
\r
1861 appData.saveExtendedInfoInPGN = FALSE;
\r
1862 appData.hideThinkingFromHuman = FALSE;
\r
1863 appData.liteBackTextureFile = "";
\r
1864 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1865 appData.darkBackTextureFile = "";
\r
1866 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1867 appData.renderPiecesWithFont = "";
\r
1868 appData.fontToPieceTable = "";
\r
1869 appData.fontBackColorWhite = 0;
\r
1870 appData.fontForeColorWhite = 0;
\r
1871 appData.fontBackColorBlack = 0;
\r
1872 appData.fontForeColorBlack = 0;
\r
1873 appData.fontPieceSize = 80;
\r
1874 appData.overrideLineGap = 1;
\r
1875 appData.adjudicateLossThreshold = 0;
\r
1876 appData.delayBeforeQuit = 0;
\r
1877 appData.delayAfterQuit = 0;
\r
1878 appData.nameOfDebugFile = "winboard.debug";
\r
1879 appData.pgnEventHeader = "Computer Chess Game";
\r
1880 appData.defaultFrcPosition = -1;
\r
1881 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1882 appData.saveOutOfBookInfo = TRUE;
\r
1883 appData.showEvalInMoveHistory = TRUE;
\r
1884 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1885 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1886 appData.highlightMoveWithArrow = FALSE;
\r
1887 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1888 appData.useStickyWindows = TRUE;
\r
1889 appData.adjudicateDrawMoves = 0;
\r
1890 appData.autoDisplayComment = TRUE;
\r
1891 appData.autoDisplayTags = TRUE;
\r
1892 appData.firstIsUCI = FALSE;
\r
1893 appData.secondIsUCI = FALSE;
\r
1894 appData.firstHasOwnBookUCI = TRUE;
\r
1895 appData.secondHasOwnBookUCI = TRUE;
\r
1896 appData.polyglotDir = "";
\r
1897 appData.usePolyglotBook = FALSE;
\r
1898 appData.polyglotBook = "";
\r
1899 appData.defaultHashSize = 64;
\r
1900 appData.defaultCacheSizeEGTB = 4;
\r
1901 appData.defaultPathEGTB = "c:\\egtb";
\r
1903 InitWindowPlacement( &wpMoveHistory );
\r
1904 InitWindowPlacement( &wpEvalGraph );
\r
1905 InitWindowPlacement( &wpEngineOutput );
\r
1907 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1908 appData.NrFiles = -1;
\r
1909 appData.NrRanks = -1;
\r
1910 appData.holdingsSize = -1;
\r
1911 appData.testClaims = FALSE;
\r
1912 appData.checkMates = FALSE;
\r
1913 appData.materialDraws= FALSE;
\r
1914 appData.trivialDraws = FALSE;
\r
1915 appData.ruleMoves = 51;
\r
1916 appData.drawRepeats = 6;
\r
1917 appData.matchPause = 10000;
\r
1918 appData.alphaRank = FALSE;
\r
1919 appData.allWhite = FALSE;
\r
1920 appData.upsideDown = FALSE;
\r
1921 appData.serverPause = 15;
\r
1922 appData.serverMovesName = NULL;
\r
1923 appData.suppressLoadMoves = FALSE;
\r
1924 appData.firstTimeOdds = 1;
\r
1925 appData.secondTimeOdds = 1;
\r
1926 appData.firstAccumulateTC = 1; // combine previous and current sessions
\r
1927 appData.secondAccumulateTC = 1;
\r
1928 appData.firstNPS = -1; // [HGM] nps: use wall-clock time
\r
1929 appData.secondNPS = -1;
\r
1930 appData.engineComments = 1;
\r
1931 appData.smpCores = 1; // [HGM] SMP: max nr of cores
\r
1932 appData.egtFormats = "";
\r
1935 appData.zippyTalk = ZIPPY_TALK;
\r
1936 appData.zippyPlay = ZIPPY_PLAY;
\r
1937 appData.zippyLines = ZIPPY_LINES;
\r
1938 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1939 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1940 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1941 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1942 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1943 appData.zippyUseI = ZIPPY_USE_I;
\r
1944 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1945 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1946 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1947 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1948 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1949 appData.zippyAbort = ZIPPY_ABORT;
\r
1950 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1951 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1952 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1955 /* Point font array elements to structures and
\r
1956 parse default font names */
\r
1957 for (i=0; i<NUM_FONTS; i++) {
\r
1958 for (j=0; j<NUM_SIZES; j++) {
\r
1959 font[j][i] = &fontRec[j][i];
\r
1960 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1964 /* Parse default settings file if any */
\r
1965 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1966 settingsFileName = strdup(buf);
\r
1969 /* Parse command line */
\r
1970 ParseArgs(StringGet, &lpCmdLine);
\r
1972 /* [HGM] make sure board size is acceptable */
\r
1973 if(appData.NrFiles > BOARD_SIZE ||
\r
1974 appData.NrRanks > BOARD_SIZE )
\r
1975 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
1977 /* [HGM] After parsing the options from the .ini file, and overruling them
\r
1978 * with options from the command line, we now make an even higher priority
\r
1979 * overrule by WB options attached to the engine command line. This so that
\r
1980 * tournament managers can use WB options (such as /timeOdds) that follow
\r
1983 if(appData.firstChessProgram != NULL) {
\r
1984 char *p = StrStr(appData.firstChessProgram, "WBopt");
\r
1985 static char *f = "first";
\r
1986 char buf[MSG_SIZ], *q = buf;
\r
1987 if(p != NULL) { // engine command line contains WinBoard options
\r
1988 sprintf(buf, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
\r
1989 ParseArgs(StringGet, &q);
\r
1990 p[-1] = 0; // cut them offengine command line
\r
1993 // now do same for second chess program
\r
1994 if(appData.secondChessProgram != NULL) {
\r
1995 char *p = StrStr(appData.secondChessProgram, "WBopt");
\r
1996 static char *s = "second";
\r
1997 char buf[MSG_SIZ], *q = buf;
\r
1998 if(p != NULL) { // engine command line contains WinBoard options
\r
1999 sprintf(buf, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
\r
2000 ParseArgs(StringGet, &q);
\r
2001 p[-1] = 0; // cut them offengine command line
\r
2006 /* Propagate options that affect others */
\r
2007 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
2008 if (appData.icsActive || appData.noChessProgram) {
\r
2009 chessProgram = FALSE; /* not local chess program mode */
\r
2012 /* Open startup dialog if needed */
\r
2013 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
2014 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
2015 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
2016 *appData.secondChessProgram == NULLCHAR))) {
\r
2019 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
2020 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
2021 FreeProcInstance(lpProc);
\r
2024 /* Make sure save files land in the right (?) directory */
\r
2025 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
2026 appData.saveGameFile = strdup(buf);
\r
2028 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
2029 appData.savePositionFile = strdup(buf);
\r
2032 /* Finish initialization for fonts and sounds */
\r
2033 for (i=0; i<NUM_FONTS; i++) {
\r
2034 for (j=0; j<NUM_SIZES; j++) {
\r
2035 CreateFontInMF(font[j][i]);
\r
2038 /* xboard, and older WinBoards, controlled the move sound with the
\r
2039 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
2040 always turn the option on (so that the backend will call us),
\r
2041 then let the user turn the sound off by setting it to silence if
\r
2042 desired. To accommodate old winboard.ini files saved by old
\r
2043 versions of WinBoard, we also turn off the sound if the option
\r
2044 was initially set to false. */
\r
2045 if (!appData.ringBellAfterMoves) {
\r
2046 sounds[(int)SoundMove].name = strdup("");
\r
2047 appData.ringBellAfterMoves = TRUE;
\r
2049 GetCurrentDirectory(MSG_SIZ, currDir);
\r
2050 SetCurrentDirectory(installDir);
\r
2052 SetCurrentDirectory(currDir);
\r
2054 p = icsTextMenuString;
\r
2055 if (p[0] == '@') {
\r
2056 FILE* f = fopen(p + 1, "r");
\r
2058 DisplayFatalError(p + 1, errno, 2);
\r
2061 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2063 buf[i] = NULLCHAR;
\r
2066 ParseIcsTextMenu(strdup(p));
\r
2073 HMENU hmenu = GetMenu(hwndMain);
\r
2075 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2076 MF_BYCOMMAND|((appData.icsActive &&
\r
2077 *appData.icsCommPort != NULLCHAR) ?
\r
2078 MF_ENABLED : MF_GRAYED));
\r
2079 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2080 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2081 MF_CHECKED : MF_UNCHECKED));
\r
2086 SaveSettings(char* name)
\r
2089 ArgDescriptor *ad;
\r
2090 WINDOWPLACEMENT wp;
\r
2091 char dir[MSG_SIZ];
\r
2093 if (!hwndMain) return;
\r
2095 GetCurrentDirectory(MSG_SIZ, dir);
\r
2096 SetCurrentDirectory(installDir);
\r
2097 f = fopen(name, "w");
\r
2098 SetCurrentDirectory(dir);
\r
2100 DisplayError(name, errno);
\r
2103 fprintf(f, ";\n");
\r
2104 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2105 fprintf(f, ";\n");
\r
2106 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2107 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2108 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2109 fprintf(f, ";\n");
\r
2111 wp.length = sizeof(WINDOWPLACEMENT);
\r
2112 GetWindowPlacement(hwndMain, &wp);
\r
2113 boardX = wp.rcNormalPosition.left;
\r
2114 boardY = wp.rcNormalPosition.top;
\r
2116 if (hwndConsole) {
\r
2117 GetWindowPlacement(hwndConsole, &wp);
\r
2118 consoleX = wp.rcNormalPosition.left;
\r
2119 consoleY = wp.rcNormalPosition.top;
\r
2120 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2121 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2124 if (analysisDialog) {
\r
2125 GetWindowPlacement(analysisDialog, &wp);
\r
2126 analysisX = wp.rcNormalPosition.left;
\r
2127 analysisY = wp.rcNormalPosition.top;
\r
2128 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2129 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2132 if (commentDialog) {
\r
2133 GetWindowPlacement(commentDialog, &wp);
\r
2134 commentX = wp.rcNormalPosition.left;
\r
2135 commentY = wp.rcNormalPosition.top;
\r
2136 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2137 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2140 if (editTagsDialog) {
\r
2141 GetWindowPlacement(editTagsDialog, &wp);
\r
2142 editTagsX = wp.rcNormalPosition.left;
\r
2143 editTagsY = wp.rcNormalPosition.top;
\r
2144 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2145 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2148 if (gameListDialog) {
\r
2149 GetWindowPlacement(gameListDialog, &wp);
\r
2150 gameListX = wp.rcNormalPosition.left;
\r
2151 gameListY = wp.rcNormalPosition.top;
\r
2152 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2153 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2156 /* [AS] Move history */
\r
2157 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2159 if( moveHistoryDialog ) {
\r
2160 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2161 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2162 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2163 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2164 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2167 /* [AS] Eval graph */
\r
2168 wpEvalGraph.visible = EvalGraphIsUp();
\r
2170 if( evalGraphDialog ) {
\r
2171 GetWindowPlacement(evalGraphDialog, &wp);
\r
2172 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2173 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2174 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2175 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2178 /* [AS] Engine output */
\r
2179 wpEngineOutput.visible = EngineOutputIsUp();
\r
2181 if( engineOutputDialog ) {
\r
2182 GetWindowPlacement(engineOutputDialog, &wp);
\r
2183 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2184 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2185 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2186 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2189 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2190 if (!ad->save) continue;
\r
2191 switch (ad->argType) {
\r
2194 char *p = *(char **)ad->argLoc;
\r
2195 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2196 /* Quote multiline values or \-containing values
\r
2197 with { } if possible */
\r
2198 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2200 /* Else quote with " " */
\r
2201 fprintf(f, "/%s=\"", ad->argName);
\r
2203 if (*p == '\n') fprintf(f, "\n");
\r
2204 else if (*p == '\r') fprintf(f, "\\r");
\r
2205 else if (*p == '\t') fprintf(f, "\\t");
\r
2206 else if (*p == '\b') fprintf(f, "\\b");
\r
2207 else if (*p == '\f') fprintf(f, "\\f");
\r
2208 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2209 else if (*p == '\"') fprintf(f, "\\\"");
\r
2210 else if (*p == '\\') fprintf(f, "\\\\");
\r
2214 fprintf(f, "\"\n");
\r
2219 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2222 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2225 fprintf(f, "/%s=%s\n", ad->argName,
\r
2226 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2229 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2232 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2236 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2237 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2238 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2243 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2244 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2245 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2246 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2247 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2248 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2249 (ta->effects) ? " " : "",
\r
2250 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2254 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2255 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2257 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2260 case ArgBoardSize:
\r
2261 fprintf(f, "/%s=%s\n", ad->argName,
\r
2262 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2267 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2268 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2269 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2270 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2271 ad->argName, mfp->faceName, mfp->pointSize,
\r
2272 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2273 mfp->bold ? "b" : "",
\r
2274 mfp->italic ? "i" : "",
\r
2275 mfp->underline ? "u" : "",
\r
2276 mfp->strikeout ? "s" : "");
\r
2280 case ArgCommSettings:
\r
2281 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2289 /*---------------------------------------------------------------------------*\
\r
2291 * GDI board drawing routines
\r
2293 \*---------------------------------------------------------------------------*/
\r
2295 /* [AS] Draw square using background texture */
\r
2296 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2301 return; /* Should never happen! */
\r
2304 SetGraphicsMode( dst, GM_ADVANCED );
\r
2311 /* X reflection */
\r
2316 x.eDx = (FLOAT) dw + dx - 1;
\r
2319 SetWorldTransform( dst, &x );
\r
2322 /* Y reflection */
\r
2328 x.eDy = (FLOAT) dh + dy - 1;
\r
2330 SetWorldTransform( dst, &x );
\r
2338 x.eDx = (FLOAT) dx;
\r
2339 x.eDy = (FLOAT) dy;
\r
2342 SetWorldTransform( dst, &x );
\r
2346 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2354 SetWorldTransform( dst, &x );
\r
2356 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2359 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2361 PM_WP = (int) WhitePawn,
\r
2362 PM_WN = (int) WhiteKnight,
\r
2363 PM_WB = (int) WhiteBishop,
\r
2364 PM_WR = (int) WhiteRook,
\r
2365 PM_WQ = (int) WhiteQueen,
\r
2366 PM_WF = (int) WhiteFerz,
\r
2367 PM_WW = (int) WhiteWazir,
\r
2368 PM_WE = (int) WhiteAlfil,
\r
2369 PM_WM = (int) WhiteMan,
\r
2370 PM_WO = (int) WhiteCannon,
\r
2371 PM_WU = (int) WhiteUnicorn,
\r
2372 PM_WH = (int) WhiteNightrider,
\r
2373 PM_WA = (int) WhiteAngel,
\r
2374 PM_WC = (int) WhiteMarshall,
\r
2375 PM_WAB = (int) WhiteCardinal,
\r
2376 PM_WD = (int) WhiteDragon,
\r
2377 PM_WL = (int) WhiteLance,
\r
2378 PM_WS = (int) WhiteCobra,
\r
2379 PM_WV = (int) WhiteFalcon,
\r
2380 PM_WSG = (int) WhiteSilver,
\r
2381 PM_WG = (int) WhiteGrasshopper,
\r
2382 PM_WK = (int) WhiteKing,
\r
2383 PM_BP = (int) BlackPawn,
\r
2384 PM_BN = (int) BlackKnight,
\r
2385 PM_BB = (int) BlackBishop,
\r
2386 PM_BR = (int) BlackRook,
\r
2387 PM_BQ = (int) BlackQueen,
\r
2388 PM_BF = (int) BlackFerz,
\r
2389 PM_BW = (int) BlackWazir,
\r
2390 PM_BE = (int) BlackAlfil,
\r
2391 PM_BM = (int) BlackMan,
\r
2392 PM_BO = (int) BlackCannon,
\r
2393 PM_BU = (int) BlackUnicorn,
\r
2394 PM_BH = (int) BlackNightrider,
\r
2395 PM_BA = (int) BlackAngel,
\r
2396 PM_BC = (int) BlackMarshall,
\r
2397 PM_BG = (int) BlackGrasshopper,
\r
2398 PM_BAB = (int) BlackCardinal,
\r
2399 PM_BD = (int) BlackDragon,
\r
2400 PM_BL = (int) BlackLance,
\r
2401 PM_BS = (int) BlackCobra,
\r
2402 PM_BV = (int) BlackFalcon,
\r
2403 PM_BSG = (int) BlackSilver,
\r
2404 PM_BK = (int) BlackKing
\r
2407 static HFONT hPieceFont = NULL;
\r
2408 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2409 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2410 static int fontBitmapSquareSize = 0;
\r
2411 static char pieceToFontChar[(int) EmptySquare] =
\r
2412 { 'p', 'n', 'b', 'r', 'q',
\r
2413 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2414 'k', 'o', 'm', 'v', 't', 'w',
\r
2415 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2418 extern BOOL SetCharTable( char *table, const char * map );
\r
2419 /* [HGM] moved to backend.c */
\r
2421 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2424 BYTE r1 = GetRValue( color );
\r
2425 BYTE g1 = GetGValue( color );
\r
2426 BYTE b1 = GetBValue( color );
\r
2432 /* Create a uniform background first */
\r
2433 hbrush = CreateSolidBrush( color );
\r
2434 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2435 FillRect( hdc, &rc, hbrush );
\r
2436 DeleteObject( hbrush );
\r
2439 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2440 int steps = squareSize / 2;
\r
2443 for( i=0; i<steps; i++ ) {
\r
2444 BYTE r = r1 - (r1-r2) * i / steps;
\r
2445 BYTE g = g1 - (g1-g2) * i / steps;
\r
2446 BYTE b = b1 - (b1-b2) * i / steps;
\r
2448 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2449 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2450 FillRect( hdc, &rc, hbrush );
\r
2451 DeleteObject(hbrush);
\r
2454 else if( mode == 2 ) {
\r
2455 /* Diagonal gradient, good more or less for every piece */
\r
2456 POINT triangle[3];
\r
2457 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2458 HBRUSH hbrush_old;
\r
2459 int steps = squareSize;
\r
2462 triangle[0].x = squareSize - steps;
\r
2463 triangle[0].y = squareSize;
\r
2464 triangle[1].x = squareSize;
\r
2465 triangle[1].y = squareSize;
\r
2466 triangle[2].x = squareSize;
\r
2467 triangle[2].y = squareSize - steps;
\r
2469 for( i=0; i<steps; i++ ) {
\r
2470 BYTE r = r1 - (r1-r2) * i / steps;
\r
2471 BYTE g = g1 - (g1-g2) * i / steps;
\r
2472 BYTE b = b1 - (b1-b2) * i / steps;
\r
2474 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2475 hbrush_old = SelectObject( hdc, hbrush );
\r
2476 Polygon( hdc, triangle, 3 );
\r
2477 SelectObject( hdc, hbrush_old );
\r
2478 DeleteObject(hbrush);
\r
2483 SelectObject( hdc, hpen );
\r
2488 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2489 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2490 piece: follow the steps as explained below.
\r
2492 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2496 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2500 int backColor = whitePieceColor;
\r
2501 int foreColor = blackPieceColor;
\r
2503 if( index < (int)BlackPawn && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2504 backColor = appData.fontBackColorWhite;
\r
2505 foreColor = appData.fontForeColorWhite;
\r
2507 else if( index >= (int)BlackPawn && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2508 backColor = appData.fontBackColorBlack;
\r
2509 foreColor = appData.fontForeColorBlack;
\r
2513 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2515 hbm_old = SelectObject( hdc, hbm );
\r
2519 rc.right = squareSize;
\r
2520 rc.bottom = squareSize;
\r
2522 /* Step 1: background is now black */
\r
2523 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2525 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2527 pt.x = (squareSize - sz.cx) / 2;
\r
2528 pt.y = (squareSize - sz.cy) / 2;
\r
2530 SetBkMode( hdc, TRANSPARENT );
\r
2531 SetTextColor( hdc, chroma );
\r
2532 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2533 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2535 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2536 /* Step 3: the area outside the piece is filled with white */
\r
2537 // FloodFill( hdc, 0, 0, chroma );
\r
2538 ExtFloodFill( hdc, 0, 0, 0, FLOODFILLSURFACE );
\r
2539 ExtFloodFill( hdc, 0, squareSize-1, 0, FLOODFILLSURFACE ); // [HGM] fill from all 4 corners, for if piece too big
\r
2540 ExtFloodFill( hdc, squareSize-1, 0, 0, FLOODFILLSURFACE );
\r
2541 ExtFloodFill( hdc, squareSize-1, squareSize-1, 0, FLOODFILLSURFACE );
\r
2542 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2544 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2545 but if the start point is not inside the piece we're lost!
\r
2546 There should be a better way to do this... if we could create a region or path
\r
2547 from the fill operation we would be fine for example.
\r
2549 // FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2550 ExtFloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF), FLOODFILLBORDER );
\r
2552 { /* [HGM] shave off edges of mask, in an attempt to correct for the fact that FloodFill does not work correctly under Win XP */
\r
2553 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2554 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2556 SelectObject( dc2, bm2 );
\r
2557 BitBlt( dc2, 0, 0, squareSize, squareSize, hdc, 0, 0, SRCCOPY ); // make copy
\r
2558 BitBlt( hdc, 0, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2559 BitBlt( hdc, 2, 1, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2560 BitBlt( hdc, 1, 0, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2561 BitBlt( hdc, 1, 2, squareSize-2, squareSize-2, dc2, 1, 1, SRCPAINT );
\r
2564 DeleteObject( bm2 );
\r
2567 SetTextColor( hdc, 0 );
\r
2569 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2570 draw the piece again in black for safety.
\r
2572 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2574 SelectObject( hdc, hbm_old );
\r
2576 if( hPieceMask[index] != NULL ) {
\r
2577 DeleteObject( hPieceMask[index] );
\r
2580 hPieceMask[index] = hbm;
\r
2583 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2585 SelectObject( hdc, hbm );
\r
2588 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2589 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2590 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2592 SelectObject( dc1, hPieceMask[index] );
\r
2593 SelectObject( dc2, bm2 );
\r
2594 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2595 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2598 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2599 the piece background and deletes (makes transparent) the rest.
\r
2600 Thanks to that mask, we are free to paint the background with the greates
\r
2601 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2602 We use this, to make gradients and give the pieces a "roundish" look.
\r
2604 SetPieceBackground( hdc, backColor, 2 );
\r
2605 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2609 DeleteObject( bm2 );
\r
2612 SetTextColor( hdc, foreColor );
\r
2613 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2615 SelectObject( hdc, hbm_old );
\r
2617 if( hPieceFace[index] != NULL ) {
\r
2618 DeleteObject( hPieceFace[index] );
\r
2621 hPieceFace[index] = hbm;
\r
2624 static int TranslatePieceToFontPiece( int piece )
\r
2654 case BlackMarshall:
\r
2658 case BlackNightrider:
\r
2664 case BlackUnicorn:
\r
2668 case BlackGrasshopper:
\r
2680 case BlackCardinal:
\r
2687 case WhiteMarshall:
\r
2691 case WhiteNightrider:
\r
2697 case WhiteUnicorn:
\r
2701 case WhiteGrasshopper:
\r
2713 case WhiteCardinal:
\r
2722 void CreatePiecesFromFont()
\r
2725 HDC hdc_window = NULL;
\r
2731 if( fontBitmapSquareSize < 0 ) {
\r
2732 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2736 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2737 fontBitmapSquareSize = -1;
\r
2741 if( fontBitmapSquareSize != squareSize ) {
\r
2742 hdc_window = GetDC( hwndMain );
\r
2743 hdc = CreateCompatibleDC( hdc_window );
\r
2745 if( hPieceFont != NULL ) {
\r
2746 DeleteObject( hPieceFont );
\r
2749 for( i=0; i<=(int)BlackKing; i++ ) {
\r
2750 hPieceMask[i] = NULL;
\r
2751 hPieceFace[i] = NULL;
\r
2757 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2758 fontHeight = appData.fontPieceSize;
\r
2761 fontHeight = (fontHeight * squareSize) / 100;
\r
2763 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2765 lf.lfEscapement = 0;
\r
2766 lf.lfOrientation = 0;
\r
2767 lf.lfWeight = FW_NORMAL;
\r
2769 lf.lfUnderline = 0;
\r
2770 lf.lfStrikeOut = 0;
\r
2771 lf.lfCharSet = DEFAULT_CHARSET;
\r
2772 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2773 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2774 lf.lfQuality = PROOF_QUALITY;
\r
2775 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2776 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2777 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2779 hPieceFont = CreateFontIndirect( &lf );
\r
2781 if( hPieceFont == NULL ) {
\r
2782 fontBitmapSquareSize = -2;
\r
2785 /* Setup font-to-piece character table */
\r
2786 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2787 /* No (or wrong) global settings, try to detect the font */
\r
2788 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2790 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2792 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2793 /* DiagramTT* family */
\r
2794 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2796 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2797 /* Fairy symbols */
\r
2798 SetCharTable(pieceToFontChar, "PNBRQFEACWMOHIJGDVSLUKpnbrqfeacwmohijgdvsluk");
\r
2800 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2801 /* Good Companion (Some characters get warped as literal :-( */
\r
2802 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2803 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2804 SetCharTable(pieceToFontChar, s);
\r
2807 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2808 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2812 /* Create bitmaps */
\r
2813 hfont_old = SelectObject( hdc, hPieceFont );
\r
2815 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2816 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2817 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2818 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2819 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2820 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2821 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2822 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2823 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2824 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2825 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2826 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2828 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2829 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2830 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2831 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2832 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2833 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2834 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2835 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2836 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2837 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2838 CreatePieceMaskFromFont( hdc_window, hdc, PM_WSG );
\r
2839 CreatePieceMaskFromFont( hdc_window, hdc, PM_WV );
\r
2840 CreatePieceMaskFromFont( hdc_window, hdc, PM_WAB );
\r
2841 CreatePieceMaskFromFont( hdc_window, hdc, PM_WD );
\r
2842 CreatePieceMaskFromFont( hdc_window, hdc, PM_WL );
\r
2843 CreatePieceMaskFromFont( hdc_window, hdc, PM_WS );
\r
2844 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2845 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2846 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2847 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2848 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2849 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2850 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2851 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2852 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2853 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2854 CreatePieceMaskFromFont( hdc_window, hdc, PM_BSG );
\r
2855 CreatePieceMaskFromFont( hdc_window, hdc, PM_BV );
\r
2856 CreatePieceMaskFromFont( hdc_window, hdc, PM_BAB );
\r
2857 CreatePieceMaskFromFont( hdc_window, hdc, PM_BD );
\r
2858 CreatePieceMaskFromFont( hdc_window, hdc, PM_BL );
\r
2859 CreatePieceMaskFromFont( hdc_window, hdc, PM_BS );
\r
2861 for(i=(int)WhitePawn; i<(int)EmptySquare; i++) /* [HGM] made a loop for this */
\r
2862 if(PieceToChar((ChessSquare)i) != '.') /* skip unused pieces */
\r
2863 CreatePieceMaskFromFont( hdc_window, hdc, i );
\r
2865 SelectObject( hdc, hfont_old );
\r
2867 fontBitmapSquareSize = squareSize;
\r
2871 if( hdc != NULL ) {
\r
2875 if( hdc_window != NULL ) {
\r
2876 ReleaseDC( hwndMain, hdc_window );
\r
2881 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2885 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2886 if (gameInfo.event &&
\r
2887 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2888 strcmp(name, "k80s") == 0) {
\r
2889 strcpy(name, "tim");
\r
2891 return LoadBitmap(hinst, name);
\r
2895 /* Insert a color into the program's logical palette
\r
2896 structure. This code assumes the given color is
\r
2897 the result of the RGB or PALETTERGB macro, and it
\r
2898 knows how those macros work (which is documented).
\r
2901 InsertInPalette(COLORREF color)
\r
2903 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2905 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2906 DisplayFatalError("Too many colors", 0, 1);
\r
2907 pLogPal->palNumEntries--;
\r
2911 pe->peFlags = (char) 0;
\r
2912 pe->peRed = (char) (0xFF & color);
\r
2913 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2914 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2920 InitDrawingColors()
\r
2922 if (pLogPal == NULL) {
\r
2923 /* Allocate enough memory for a logical palette with
\r
2924 * PALETTESIZE entries and set the size and version fields
\r
2925 * of the logical palette structure.
\r
2927 pLogPal = (NPLOGPALETTE)
\r
2928 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2929 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2930 pLogPal->palVersion = 0x300;
\r
2932 pLogPal->palNumEntries = 0;
\r
2934 InsertInPalette(lightSquareColor);
\r
2935 InsertInPalette(darkSquareColor);
\r
2936 InsertInPalette(whitePieceColor);
\r
2937 InsertInPalette(blackPieceColor);
\r
2938 InsertInPalette(highlightSquareColor);
\r
2939 InsertInPalette(premoveHighlightColor);
\r
2941 /* create a logical color palette according the information
\r
2942 * in the LOGPALETTE structure.
\r
2944 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2946 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2947 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2948 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2949 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2950 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2951 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2953 /* [AS] Force rendering of the font-based pieces */
\r
2954 if( fontBitmapSquareSize > 0 ) {
\r
2955 fontBitmapSquareSize = 0;
\r
2961 BoardWidth(int boardSize, int n)
\r
2962 { /* [HGM] argument n added to allow different width and height */
\r
2963 int lineGap = sizeInfo[boardSize].lineGap;
\r
2965 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2966 lineGap = appData.overrideLineGap;
\r
2969 return (n + 1) * lineGap +
\r
2970 n * sizeInfo[boardSize].squareSize;
\r
2973 /* Respond to board resize by dragging edge */
\r
2975 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2977 BoardSize newSize = NUM_SIZES - 1;
\r
2978 static int recurse = 0;
\r
2979 if (IsIconic(hwndMain)) return;
\r
2980 if (recurse > 0) return;
\r
2982 while (newSize > 0) {
\r
2983 InitDrawingSizes(newSize, 0);
\r
2984 if(newSizeX >= sizeInfo[newSize].cliWidth ||
\r
2985 newSizeY >= sizeInfo[newSize].cliHeight) break;
\r
2988 boardSize = newSize;
\r
2989 InitDrawingSizes(boardSize, flags);
\r
2996 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2998 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2999 ChessSquare piece;
\r
3000 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
3002 SIZE clockSize, messageSize;
\r
3004 char buf[MSG_SIZ];
\r
3006 HMENU hmenu = GetMenu(hwndMain);
\r
3007 RECT crect, wrect;
\r
3009 LOGBRUSH logbrush;
\r
3011 /* [HGM] call with -1 uses old size (for if nr of files, ranks changes) */
\r
3012 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
3014 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
3015 smallLayout = sizeInfo[boardSize].smallLayout;
\r
3016 squareSize = sizeInfo[boardSize].squareSize;
\r
3017 lineGap = sizeInfo[boardSize].lineGap;
\r
3018 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
3020 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
3021 lineGap = appData.overrideLineGap;
\r
3024 if (tinyLayout != oldTinyLayout) {
\r
3025 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
3027 style &= ~WS_SYSMENU;
\r
3028 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
3029 "&Minimize\tCtrl+F4");
\r
3031 style |= WS_SYSMENU;
\r
3032 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
3034 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
3036 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
3037 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
3038 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
3040 DrawMenuBar(hwndMain);
\r
3043 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
3044 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
3046 /* Get text area sizes */
\r
3047 hdc = GetDC(hwndMain);
\r
3048 if (appData.clockMode) {
\r
3049 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
3051 sprintf(buf, "White");
\r
3053 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
3054 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
3055 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
3056 str = "We only care about the height here";
\r
3057 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
3058 SelectObject(hdc, oldFont);
\r
3059 ReleaseDC(hwndMain, hdc);
\r
3061 /* Compute where everything goes */
\r
3062 whiteRect.left = OUTER_MARGIN;
\r
3063 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
3064 whiteRect.top = OUTER_MARGIN;
\r
3065 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
3067 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
3068 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
3069 blackRect.top = whiteRect.top;
\r
3070 blackRect.bottom = whiteRect.bottom;
\r
3072 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
3073 if (appData.showButtonBar) {
\r
3074 messageRect.right = blackRect.right
\r
3075 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
3077 messageRect.right = blackRect.right;
\r
3079 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
3080 messageRect.bottom = messageRect.top + messageSize.cy;
\r
3082 boardRect.left = whiteRect.left;
\r
3083 boardRect.right = boardRect.left + boardWidth;
\r
3084 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
3085 boardRect.bottom = boardRect.top + boardHeight;
\r
3087 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
3088 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
3089 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
3090 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
3091 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
3092 GetWindowRect(hwndMain, &wrect);
\r
3093 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3094 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3095 /* compensate if menu bar wrapped */
\r
3096 GetClientRect(hwndMain, &crect);
\r
3097 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
3098 winHeight += offby;
\r
3100 case WMSZ_TOPLEFT:
\r
3101 SetWindowPos(hwndMain, NULL,
\r
3102 wrect.right - winWidth, wrect.bottom - winHeight,
\r
3103 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3106 case WMSZ_TOPRIGHT:
\r
3108 SetWindowPos(hwndMain, NULL,
\r
3109 wrect.left, wrect.bottom - winHeight,
\r
3110 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3113 case WMSZ_BOTTOMLEFT:
\r
3115 SetWindowPos(hwndMain, NULL,
\r
3116 wrect.right - winWidth, wrect.top,
\r
3117 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
3120 case WMSZ_BOTTOMRIGHT:
\r
3124 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
3125 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
3130 for (i = 0; i < N_BUTTONS; i++) {
\r
3131 if (buttonDesc[i].hwnd != NULL) {
\r
3132 DestroyWindow(buttonDesc[i].hwnd);
\r
3133 buttonDesc[i].hwnd = NULL;
\r
3135 if (appData.showButtonBar) {
\r
3136 buttonDesc[i].hwnd =
\r
3137 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3138 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3139 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3140 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3141 (HMENU) buttonDesc[i].id,
\r
3142 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3144 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3145 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3146 MAKELPARAM(FALSE, 0));
\r
3148 if (buttonDesc[i].id == IDM_Pause)
\r
3149 hwndPause = buttonDesc[i].hwnd;
\r
3150 buttonDesc[i].wndproc = (WNDPROC)
\r
3151 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3154 if (gridPen != NULL) DeleteObject(gridPen);
\r
3155 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3156 if (premovePen != NULL) DeleteObject(premovePen);
\r
3157 if (lineGap != 0) {
\r
3158 logbrush.lbStyle = BS_SOLID;
\r
3159 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3161 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3162 lineGap, &logbrush, 0, NULL);
\r
3163 logbrush.lbColor = highlightSquareColor;
\r
3165 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3166 lineGap, &logbrush, 0, NULL);
\r
3168 logbrush.lbColor = premoveHighlightColor;
\r
3170 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3171 lineGap, &logbrush, 0, NULL);
\r
3173 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3174 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3175 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3176 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3177 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3178 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3179 BOARD_WIDTH * (squareSize + lineGap);
\r
3180 lineGap / 2 + (i * (squareSize + lineGap));
\r
3181 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3183 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3184 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3185 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3186 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3187 lineGap / 2 + (i * (squareSize + lineGap));
\r
3188 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3189 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3190 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3194 /* [HGM] Licensing requirement */
\r
3196 if(gameInfo.variant == VariantGothic) GothicPopUp( GOTHIC, VariantGothic); else
\r
3199 if(gameInfo.variant == VariantFalcon) GothicPopUp( FALCON, VariantFalcon); else
\r
3201 GothicPopUp( "", VariantNormal);
\r
3204 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3205 oldBoardSize = boardSize;
\r
3206 oldTinyLayout = tinyLayout;
\r
3208 /* Load piece bitmaps for this board size */
\r
3209 for (i=0; i<=2; i++) {
\r
3210 for (piece = WhitePawn;
\r
3211 (int) piece < (int) BlackPawn;
\r
3212 piece = (ChessSquare) ((int) piece + 1)) {
\r
3213 if (pieceBitmap[i][piece] != NULL)
\r
3214 DeleteObject(pieceBitmap[i][piece]);
\r
3218 fontBitmapSquareSize = 0; /* [HGM] render: make sure pieces will be recreated, as we might need others now */
\r
3219 // Orthodox Chess pieces
\r
3220 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3221 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3222 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3223 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3224 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3225 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3226 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3227 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3228 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3229 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3230 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3231 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3232 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3233 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3234 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3235 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3236 // in Shogi, Hijack the unused Queen for Lance
\r
3237 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3238 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3239 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3241 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3242 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3243 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3246 if(squareSize <= 72 && squareSize >= 33) {
\r
3247 /* A & C are available in most sizes now */
\r
3248 if(squareSize != 49 && squareSize != 72 && squareSize != 33) { // Vortex-like
\r
3249 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3250 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3251 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3252 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3253 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3254 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3255 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3256 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3257 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3258 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3259 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3260 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3261 } else { // Smirf-like
\r
3262 pieceBitmap[0][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "s");
\r
3263 pieceBitmap[1][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "o");
\r
3264 pieceBitmap[2][WhiteAngel] = DoLoadBitmap(hInst, "aa", squareSize, "w");
\r
3266 if(gameInfo.variant == VariantGothic) { // Vortex-like
\r
3267 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3268 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3269 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3270 } else { // WinBoard standard
\r
3271 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3272 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3273 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3278 if(squareSize==72 || squareSize==49 || squareSize==33) { /* experiment with some home-made bitmaps */
\r
3279 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3280 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3281 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3282 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3283 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3284 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3285 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3286 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3287 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3288 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3289 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3290 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3291 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3292 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3293 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3294 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3295 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3296 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3297 pieceBitmap[0][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "s");
\r
3298 pieceBitmap[1][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "o");
\r
3299 pieceBitmap[2][WhiteFalcon] = DoLoadBitmap(hInst, "v", squareSize, "w");
\r
3300 pieceBitmap[0][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "s");
\r
3301 pieceBitmap[1][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "o");
\r
3302 pieceBitmap[2][WhiteCobra] = DoLoadBitmap(hInst, "s", squareSize, "w");
\r
3303 pieceBitmap[0][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3304 pieceBitmap[1][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3305 pieceBitmap[2][WhiteLance] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3306 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3307 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3308 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3310 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3311 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3312 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3313 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3314 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3315 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3316 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3317 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3318 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3319 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3320 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3321 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3322 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3324 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3325 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3326 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3327 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3328 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3329 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3330 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "s");
\r
3331 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "o");
\r
3332 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "cv", squareSize, "w");
\r
3333 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3334 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3335 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3338 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3339 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3340 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3341 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3342 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3343 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3344 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3345 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3346 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3347 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3348 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3349 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3350 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3351 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3352 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3356 if(gameInfo.variant == VariantShogi && squareSize == 58)
\r
3357 /* special Shogi support in this size */
\r
3358 { for (i=0; i<=2; i++) { /* replace all bitmaps */
\r
3359 for (piece = WhitePawn;
\r
3360 (int) piece < (int) BlackPawn;
\r
3361 piece = (ChessSquare) ((int) piece + 1)) {
\r
3362 if (pieceBitmap[i][piece] != NULL)
\r
3363 DeleteObject(pieceBitmap[i][piece]);
\r
3366 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3367 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3368 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3369 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3370 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3371 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3372 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3373 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3374 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3375 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3376 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3377 pieceBitmap[0][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3378 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3379 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3380 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "o");
\r
3381 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "o");
\r
3382 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "sb", squareSize, "o");
\r
3383 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "o");
\r
3384 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "o");
\r
3385 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "o");
\r
3386 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "sf", squareSize, "o");
\r
3387 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "o");
\r
3388 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "su", squareSize, "o");
\r
3389 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "sh", squareSize, "o");
\r
3390 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "sa", squareSize, "o");
\r
3391 pieceBitmap[1][WhiteDragon] = DoLoadBitmap(hInst, "sc", squareSize, "o");
\r
3392 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "sg", squareSize, "o");
\r
3393 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ss", squareSize, "o");
\r
3394 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3395 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3396 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3397 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3398 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3399 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "sk", squareSize, "w");
\r
3400 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3401 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3402 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "sp", squareSize, "w");
\r
3403 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "sn", squareSize, "w");
\r
3404 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3405 pieceBitmap[2][WhiteDragon] = DoLoadBitmap(hInst, "sr", squareSize, "w");
\r
3406 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "sl", squareSize, "w");
\r
3407 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "sw", squareSize, "w");
\r
3413 PieceBitmap(ChessSquare p, int kind)
\r
3415 if ((int) p >= (int) BlackPawn)
\r
3416 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3418 return pieceBitmap[kind][(int) p];
\r
3421 /***************************************************************/
\r
3423 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3424 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3426 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3427 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3431 SquareToPos(int row, int column, int * x, int * y)
\r
3434 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3435 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3437 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3438 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3443 DrawCoordsOnDC(HDC hdc)
\r
3445 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
3446 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
3447 char str[2] = { NULLCHAR, NULLCHAR };
\r
3448 int oldMode, oldAlign, x, y, start, i;
\r
3452 if (!appData.showCoords)
\r
3455 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3457 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3458 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3459 oldAlign = GetTextAlign(hdc);
\r
3460 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3462 y = boardRect.top + lineGap;
\r
3463 x = boardRect.left + lineGap + gameInfo.holdingsWidth*(squareSize + lineGap);
\r
3465 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3466 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3467 str[0] = files[start + i];
\r
3468 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3469 y += squareSize + lineGap;
\r
3472 start = flipView ? 12-(BOARD_RGHT-BOARD_LEFT) : 12;
\r
3474 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3475 for (i = 0; i < BOARD_RGHT - BOARD_LEFT; i++) {
\r
3476 str[0] = ranks[start + i];
\r
3477 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3478 x += squareSize + lineGap;
\r
3481 SelectObject(hdc, oldBrush);
\r
3482 SetBkMode(hdc, oldMode);
\r
3483 SetTextAlign(hdc, oldAlign);
\r
3484 SelectObject(hdc, oldFont);
\r
3488 DrawGridOnDC(HDC hdc)
\r
3492 if (lineGap != 0) {
\r
3493 oldPen = SelectObject(hdc, gridPen);
\r
3494 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3495 SelectObject(hdc, oldPen);
\r
3499 #define HIGHLIGHT_PEN 0
\r
3500 #define PREMOVE_PEN 1
\r
3503 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3506 HPEN oldPen, hPen;
\r
3507 if (lineGap == 0) return;
\r
3509 x1 = boardRect.left +
\r
3510 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3511 y1 = boardRect.top +
\r
3512 lineGap/2 + y * (squareSize + lineGap);
\r
3514 x1 = boardRect.left +
\r
3515 lineGap/2 + x * (squareSize + lineGap);
\r
3516 y1 = boardRect.top +
\r
3517 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3519 hPen = pen ? premovePen : highlightPen;
\r
3520 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3521 MoveToEx(hdc, x1, y1, NULL);
\r
3522 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3523 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3524 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3525 LineTo(hdc, x1, y1);
\r
3526 SelectObject(hdc, oldPen);
\r
3530 DrawHighlightsOnDC(HDC hdc)
\r
3533 for (i=0; i<2; i++) {
\r
3534 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3535 DrawHighlightOnDC(hdc, TRUE,
\r
3536 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3539 for (i=0; i<2; i++) {
\r
3540 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3541 premoveHighlightInfo.sq[i].y >= 0) {
\r
3542 DrawHighlightOnDC(hdc, TRUE,
\r
3543 premoveHighlightInfo.sq[i].x,
\r
3544 premoveHighlightInfo.sq[i].y,
\r
3550 /* Note: sqcolor is used only in monoMode */
\r
3551 /* Note that this code is largely duplicated in woptions.c,
\r
3552 function DrawSampleSquare, so that needs to be updated too */
\r
3554 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3556 HBITMAP oldBitmap;
\r
3560 if (appData.blindfold) return;
\r
3562 /* [AS] Use font-based pieces if needed */
\r
3563 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3564 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3565 CreatePiecesFromFont();
\r
3567 if( fontBitmapSquareSize == squareSize ) {
\r
3568 int index = TranslatePieceToFontPiece( piece );
\r
3570 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3574 squareSize, squareSize,
\r
3579 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3583 squareSize, squareSize,
\r
3592 if (appData.monoMode) {
\r
3593 SelectObject(tmphdc, PieceBitmap(piece,
\r
3594 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3595 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3596 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3598 tmpSize = squareSize;
\r
3600 (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||
\r
3601 piece >= (int)BlackNightrider && piece <= BlackGrasshopper) ) {
\r
3602 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3603 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3604 x += (squareSize - minorSize)>>1;
\r
3605 y += squareSize - minorSize - 2;
\r
3606 tmpSize = minorSize;
\r
3608 if (color || appData.allWhite ) {
\r
3609 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3611 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3612 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3613 if(appData.upsideDown && color==flipView)
\r
3614 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3616 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3618 /* Use black piece color for outline of white pieces */
\r
3619 /* Not sure this looks really good (though xboard does it).
\r
3620 Maybe better to have another selectable color, default black */
\r
3621 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3622 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3623 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3625 /* Use black for outline of white pieces */
\r
3626 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3627 if(appData.upsideDown && color==flipView)
\r
3628 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3630 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3634 /* Use white piece color for details of black pieces */
\r
3635 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3636 WHITE_PIECE ones aren't always the right shape. */
\r
3637 /* Not sure this looks really good (though xboard does it).
\r
3638 Maybe better to have another selectable color, default medium gray? */
\r
3639 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3640 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3641 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3642 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3643 SelectObject(hdc, blackPieceBrush);
\r
3644 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3646 /* Use square color for details of black pieces */
\r
3647 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3648 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3649 if(appData.upsideDown && !flipView)
\r
3650 StretchBlt(hdc, x+tmpSize, y+tmpSize, -tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3652 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3655 SelectObject(hdc, oldBrush);
\r
3656 SelectObject(tmphdc, oldBitmap);
\r
3660 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3661 int GetBackTextureMode( int algo )
\r
3663 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3667 case BACK_TEXTURE_MODE_PLAIN:
\r
3668 result = 1; /* Always use identity map */
\r
3670 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3671 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3679 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3680 to handle redraws cleanly (as random numbers would always be different).
\r
3682 VOID RebuildTextureSquareInfo()
\r
3692 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3694 if( liteBackTexture != NULL ) {
\r
3695 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3696 lite_w = bi.bmWidth;
\r
3697 lite_h = bi.bmHeight;
\r
3701 if( darkBackTexture != NULL ) {
\r
3702 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3703 dark_w = bi.bmWidth;
\r
3704 dark_h = bi.bmHeight;
\r
3708 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3709 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3710 if( (col + row) & 1 ) {
\r
3712 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3713 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_WIDTH;
\r
3714 backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_HEIGHT;
\r
3715 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3720 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3721 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_WIDTH;
\r
3722 backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_HEIGHT;
\r
3723 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3730 /* [AS] Arrow highlighting support */
\r
3732 static int A_WIDTH = 5; /* Width of arrow body */
\r
3734 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3735 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3737 static double Sqr( double x )
\r
3742 static int Round( double x )
\r
3744 return (int) (x + 0.5);
\r
3747 /* Draw an arrow between two points using current settings */
\r
3748 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3751 double dx, dy, j, k, x, y;
\r
3753 if( d_x == s_x ) {
\r
3754 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3756 arrow[0].x = s_x + A_WIDTH;
\r
3759 arrow[1].x = s_x + A_WIDTH;
\r
3760 arrow[1].y = d_y - h;
\r
3762 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3763 arrow[2].y = d_y - h;
\r
3768 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3769 arrow[4].y = d_y - h;
\r
3771 arrow[5].x = s_x - A_WIDTH;
\r
3772 arrow[5].y = d_y - h;
\r
3774 arrow[6].x = s_x - A_WIDTH;
\r
3777 else if( d_y == s_y ) {
\r
3778 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3781 arrow[0].y = s_y + A_WIDTH;
\r
3783 arrow[1].x = d_x - w;
\r
3784 arrow[1].y = s_y + A_WIDTH;
\r
3786 arrow[2].x = d_x - w;
\r
3787 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3792 arrow[4].x = d_x - w;
\r
3793 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3795 arrow[5].x = d_x - w;
\r
3796 arrow[5].y = s_y - A_WIDTH;
\r
3799 arrow[6].y = s_y - A_WIDTH;
\r
3802 /* [AS] Needed a lot of paper for this! :-) */
\r
3803 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3804 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3806 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3808 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3813 arrow[0].x = Round(x - j);
\r
3814 arrow[0].y = Round(y + j*dx);
\r
3816 arrow[1].x = Round(x + j);
\r
3817 arrow[1].y = Round(y - j*dx);
\r
3820 x = (double) d_x - k;
\r
3821 y = (double) d_y - k*dy;
\r
3824 x = (double) d_x + k;
\r
3825 y = (double) d_y + k*dy;
\r
3828 arrow[2].x = Round(x + j);
\r
3829 arrow[2].y = Round(y - j*dx);
\r
3831 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3832 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3837 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3838 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3840 arrow[6].x = Round(x - j);
\r
3841 arrow[6].y = Round(y + j*dx);
\r
3844 Polygon( hdc, arrow, 7 );
\r
3847 /* [AS] Draw an arrow between two squares */
\r
3848 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3850 int s_x, s_y, d_x, d_y;
\r
3857 if( s_col == d_col && s_row == d_row ) {
\r
3861 /* Get source and destination points */
\r
3862 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3863 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3866 d_y += squareSize / 4;
\r
3868 else if( d_y < s_y ) {
\r
3869 d_y += 3 * squareSize / 4;
\r
3872 d_y += squareSize / 2;
\r
3876 d_x += squareSize / 4;
\r
3878 else if( d_x < s_x ) {
\r
3879 d_x += 3 * squareSize / 4;
\r
3882 d_x += squareSize / 2;
\r
3885 s_x += squareSize / 2;
\r
3886 s_y += squareSize / 2;
\r
3888 /* Adjust width */
\r
3889 A_WIDTH = squareSize / 14;
\r
3892 stLB.lbStyle = BS_SOLID;
\r
3893 stLB.lbColor = appData.highlightArrowColor;
\r
3896 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3897 holdpen = SelectObject( hdc, hpen );
\r
3898 hbrush = CreateBrushIndirect( &stLB );
\r
3899 holdbrush = SelectObject( hdc, hbrush );
\r
3901 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3903 SelectObject( hdc, holdpen );
\r
3904 SelectObject( hdc, holdbrush );
\r
3905 DeleteObject( hpen );
\r
3906 DeleteObject( hbrush );
\r
3909 BOOL HasHighlightInfo()
\r
3911 BOOL result = FALSE;
\r
3913 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3914 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3922 BOOL IsDrawArrowEnabled()
\r
3924 BOOL result = FALSE;
\r
3926 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3933 VOID DrawArrowHighlight( HDC hdc )
\r
3935 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3936 DrawArrowBetweenSquares( hdc,
\r
3937 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3938 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3942 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3944 HRGN result = NULL;
\r
3946 if( HasHighlightInfo() ) {
\r
3947 int x1, y1, x2, y2;
\r
3948 int sx, sy, dx, dy;
\r
3950 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3951 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3953 sx = MIN( x1, x2 );
\r
3954 sy = MIN( y1, y2 );
\r
3955 dx = MAX( x1, x2 ) + squareSize;
\r
3956 dy = MAX( y1, y2 ) + squareSize;
\r
3958 result = CreateRectRgn( sx, sy, dx, dy );
\r
3965 Warning: this function modifies the behavior of several other functions.
\r
3967 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3968 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3969 repaint is scattered all over the place, which is not good for features such as
\r
3970 "arrow highlighting" that require a full repaint of the board.
\r
3972 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3973 user interaction, when speed is not so important) but especially to avoid errors
\r
3974 in the displayed graphics.
\r
3976 In such patched places, I always try refer to this function so there is a single
\r
3977 place to maintain knowledge.
\r
3979 To restore the original behavior, just return FALSE unconditionally.
\r
3981 BOOL IsFullRepaintPreferrable()
\r
3983 BOOL result = FALSE;
\r
3985 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3986 /* Arrow may appear on the board */
\r
3994 This function is called by DrawPosition to know whether a full repaint must
\r
3997 Only DrawPosition may directly call this function, which makes use of
\r
3998 some state information. Other function should call DrawPosition specifying
\r
3999 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
4001 BOOL DrawPositionNeedsFullRepaint()
\r
4003 BOOL result = FALSE;
\r
4006 Probably a slightly better policy would be to trigger a full repaint
\r
4007 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
4008 but animation is fast enough that it's difficult to notice.
\r
4010 if( animInfo.piece == EmptySquare ) {
\r
4011 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
4020 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
4022 int row, column, x, y, square_color, piece_color;
\r
4023 ChessSquare piece;
\r
4025 HDC texture_hdc = NULL;
\r
4027 /* [AS] Initialize background textures if needed */
\r
4028 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
4029 static int backTextureBoardSize; /* [HGM] boardsize: also new texture if board format changed */
\r
4030 if( backTextureSquareSize != squareSize
\r
4031 || backTextureBoardSize != BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT) {
\r
4032 backTextureBoardSize = BOARD_WIDTH+BOARD_SIZE*BOARD_HEIGHT;
\r
4033 backTextureSquareSize = squareSize;
\r
4034 RebuildTextureSquareInfo();
\r
4037 texture_hdc = CreateCompatibleDC( hdc );
\r
4040 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4041 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4043 SquareToPos(row, column, &x, &y);
\r
4045 piece = board[row][column];
\r
4047 square_color = ((column + row) % 2) == 1;
\r
4048 if(!strcmp(appData.variant, "xiangqi") ) {
\r
4049 square_color = !InPalace(row, column);
\r
4050 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
4051 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
4053 piece_color = (int) piece < (int) BlackPawn;
\r
4056 /* [HGM] holdings file: light square or black */
\r
4057 if(column == BOARD_LEFT-2) {
\r
4058 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
4061 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
4065 if(column == BOARD_RGHT + 1 ) {
\r
4066 if( row < gameInfo.holdingsSize )
\r
4069 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
4073 if(column == BOARD_LEFT-1 ) /* left align */
\r
4074 DisplayHoldingsCount(hdc, x, y, flipView, (int) board[row][column]);
\r
4075 else if( column == BOARD_RGHT) /* right align */
\r
4076 DisplayHoldingsCount(hdc, x, y, !flipView, (int) board[row][column]);
\r
4078 if (appData.monoMode) {
\r
4079 if (piece == EmptySquare) {
\r
4080 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
4081 square_color ? WHITENESS : BLACKNESS);
\r
4083 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
4086 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
4087 /* [AS] Draw the square using a texture bitmap */
\r
4088 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
4091 squareSize, squareSize,
\r
4094 backTextureSquareInfo[row][column].mode,
\r
4095 backTextureSquareInfo[row][column].x,
\r
4096 backTextureSquareInfo[row][column].y );
\r
4098 SelectObject( texture_hdc, hbm );
\r
4100 if (piece != EmptySquare) {
\r
4101 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4105 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
4107 oldBrush = SelectObject(hdc, brush );
\r
4108 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
4109 SelectObject(hdc, oldBrush);
\r
4110 if (piece != EmptySquare)
\r
4111 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
4116 if( texture_hdc != NULL ) {
\r
4117 DeleteDC( texture_hdc );
\r
4121 int saveDiagFlag = 0; FILE *diagFile; // [HGM] diag
\r
4122 void fputDW(FILE *f, int x)
\r
4124 fputc(x & 255, f);
\r
4125 fputc(x>>8 & 255, f);
\r
4126 fputc(x>>16 & 255, f);
\r
4127 fputc(x>>24 & 255, f);
\r
4130 #define MAX_CLIPS 200 /* more than enough */
\r
4133 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
4135 static Board lastReq, lastDrawn;
\r
4136 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
4137 static int lastDrawnFlipView = 0;
\r
4138 static int lastReqValid = 0, lastDrawnValid = 0;
\r
4139 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
4142 HBITMAP bufferBitmap;
\r
4143 HBITMAP oldBitmap;
\r
4145 HRGN clips[MAX_CLIPS];
\r
4146 ChessSquare dragged_piece = EmptySquare;
\r
4148 /* I'm undecided on this - this function figures out whether a full
\r
4149 * repaint is necessary on its own, so there's no real reason to have the
\r
4150 * caller tell it that. I think this can safely be set to FALSE - but
\r
4151 * if we trust the callers not to request full repaints unnessesarily, then
\r
4152 * we could skip some clipping work. In other words, only request a full
\r
4153 * redraw when the majority of pieces have changed positions (ie. flip,
\r
4154 * gamestart and similar) --Hawk
\r
4156 Boolean fullrepaint = repaint;
\r
4158 if( DrawPositionNeedsFullRepaint() ) {
\r
4159 fullrepaint = TRUE;
\r
4163 if( fullrepaint ) {
\r
4164 static int repaint_count = 0;
\r
4168 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
4169 OutputDebugString( buf );
\r
4173 if (board == NULL) {
\r
4174 if (!lastReqValid) {
\r
4179 CopyBoard(lastReq, board);
\r
4183 if (doingSizing) {
\r
4187 if (IsIconic(hwndMain)) {
\r
4191 if (hdc == NULL) {
\r
4192 hdc = GetDC(hwndMain);
\r
4193 if (!appData.monoMode) {
\r
4194 SelectPalette(hdc, hPal, FALSE);
\r
4195 RealizePalette(hdc);
\r
4199 releaseDC = FALSE;
\r
4203 fprintf(debugFP, "*******************************\n"
\r
4205 "dragInfo.from (%d,%d)\n"
\r
4206 "dragInfo.start (%d,%d)\n"
\r
4207 "dragInfo.pos (%d,%d)\n"
\r
4208 "dragInfo.lastpos (%d,%d)\n",
\r
4209 repaint ? "TRUE" : "FALSE",
\r
4210 dragInfo.from.x, dragInfo.from.y,
\r
4211 dragInfo.start.x, dragInfo.start.y,
\r
4212 dragInfo.pos.x, dragInfo.pos.y,
\r
4213 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
4214 fprintf(debugFP, "prev: ");
\r
4215 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4216 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4217 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
4220 fprintf(debugFP, "\n");
\r
4221 fprintf(debugFP, "board: ");
\r
4222 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
4223 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4224 fprintf(debugFP, "%d ", board[row][column]);
\r
4227 fprintf(debugFP, "\n");
\r
4231 /* Create some work-DCs */
\r
4232 hdcmem = CreateCompatibleDC(hdc);
\r
4233 tmphdc = CreateCompatibleDC(hdc);
\r
4235 /* If dragging is in progress, we temporarely remove the piece */
\r
4236 /* [HGM] or temporarily decrease count if stacked */
\r
4237 /* !! Moved to before board compare !! */
\r
4238 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
4239 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
4240 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
4241 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
4242 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4244 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
4245 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4246 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4248 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4251 /* Figure out which squares need updating by comparing the
\r
4252 * newest board with the last drawn board and checking if
\r
4253 * flipping has changed.
\r
4255 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4256 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4257 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4258 if (lastDrawn[row][column] != board[row][column]) {
\r
4259 SquareToPos(row, column, &x, &y);
\r
4260 clips[num_clips++] =
\r
4261 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4265 for (i=0; i<2; i++) {
\r
4266 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4267 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4268 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4269 lastDrawnHighlight.sq[i].y >= 0) {
\r
4270 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4271 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4272 clips[num_clips++] =
\r
4273 CreateRectRgn(x - lineGap, y - lineGap,
\r
4274 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4276 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4277 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4278 clips[num_clips++] =
\r
4279 CreateRectRgn(x - lineGap, y - lineGap,
\r
4280 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4284 for (i=0; i<2; i++) {
\r
4285 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4286 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4287 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4288 lastDrawnPremove.sq[i].y >= 0) {
\r
4289 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4290 lastDrawnPremove.sq[i].x, &x, &y);
\r
4291 clips[num_clips++] =
\r
4292 CreateRectRgn(x - lineGap, y - lineGap,
\r
4293 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4295 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4296 premoveHighlightInfo.sq[i].y >= 0) {
\r
4297 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4298 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4299 clips[num_clips++] =
\r
4300 CreateRectRgn(x - lineGap, y - lineGap,
\r
4301 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4306 fullrepaint = TRUE;
\r
4309 /* Create a buffer bitmap - this is the actual bitmap
\r
4310 * being written to. When all the work is done, we can
\r
4311 * copy it to the real DC (the screen). This avoids
\r
4312 * the problems with flickering.
\r
4314 GetClientRect(hwndMain, &Rect);
\r
4315 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4316 Rect.bottom-Rect.top+1);
\r
4317 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4318 if (!appData.monoMode) {
\r
4319 SelectPalette(hdcmem, hPal, FALSE);
\r
4322 /* Create clips for dragging */
\r
4323 if (!fullrepaint) {
\r
4324 if (dragInfo.from.x >= 0) {
\r
4325 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4326 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4328 if (dragInfo.start.x >= 0) {
\r
4329 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4330 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4332 if (dragInfo.pos.x >= 0) {
\r
4333 x = dragInfo.pos.x - squareSize / 2;
\r
4334 y = dragInfo.pos.y - squareSize / 2;
\r
4335 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4337 if (dragInfo.lastpos.x >= 0) {
\r
4338 x = dragInfo.lastpos.x - squareSize / 2;
\r
4339 y = dragInfo.lastpos.y - squareSize / 2;
\r
4340 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4344 /* Are we animating a move?
\r
4346 * - remove the piece from the board (temporarely)
\r
4347 * - calculate the clipping region
\r
4349 if (!fullrepaint) {
\r
4350 if (animInfo.piece != EmptySquare) {
\r
4351 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4352 x = boardRect.left + animInfo.lastpos.x;
\r
4353 y = boardRect.top + animInfo.lastpos.y;
\r
4354 x2 = boardRect.left + animInfo.pos.x;
\r
4355 y2 = boardRect.top + animInfo.pos.y;
\r
4356 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4357 /* Slight kludge. The real problem is that after AnimateMove is
\r
4358 done, the position on the screen does not match lastDrawn.
\r
4359 This currently causes trouble only on e.p. captures in
\r
4360 atomic, where the piece moves to an empty square and then
\r
4361 explodes. The old and new positions both had an empty square
\r
4362 at the destination, but animation has drawn a piece there and
\r
4363 we have to remember to erase it. */
\r
4364 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4368 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4369 if (num_clips == 0)
\r
4370 fullrepaint = TRUE;
\r
4372 /* Set clipping on the memory DC */
\r
4373 if (!fullrepaint) {
\r
4374 SelectClipRgn(hdcmem, clips[0]);
\r
4375 for (x = 1; x < num_clips; x++) {
\r
4376 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4377 abort(); // this should never ever happen!
\r
4381 /* Do all the drawing to the memory DC */
\r
4382 DrawGridOnDC(hdcmem);
\r
4383 DrawHighlightsOnDC(hdcmem);
\r
4384 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4386 if( appData.highlightMoveWithArrow ) {
\r
4387 DrawArrowHighlight(hdcmem);
\r
4390 DrawCoordsOnDC(hdcmem);
\r
4392 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4393 /* to make sure lastDrawn contains what is actually drawn */
\r
4395 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4396 if (dragged_piece != EmptySquare) {
\r
4397 /* [HGM] or restack */
\r
4398 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4399 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4401 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4402 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4403 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4404 x = dragInfo.pos.x - squareSize / 2;
\r
4405 y = dragInfo.pos.y - squareSize / 2;
\r
4406 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4407 ((int) dragged_piece < (int) BlackPawn),
\r
4408 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4411 /* Put the animated piece back into place and draw it */
\r
4412 if (animInfo.piece != EmptySquare) {
\r
4413 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4414 x = boardRect.left + animInfo.pos.x;
\r
4415 y = boardRect.top + animInfo.pos.y;
\r
4416 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4417 ((int) animInfo.piece < (int) BlackPawn),
\r
4418 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4421 /* Release the bufferBitmap by selecting in the old bitmap
\r
4422 * and delete the memory DC
\r
4424 SelectObject(hdcmem, oldBitmap);
\r
4427 /* Set clipping on the target DC */
\r
4428 if (!fullrepaint) {
\r
4429 SelectClipRgn(hdc, clips[0]);
\r
4430 for (x = 1; x < num_clips; x++) {
\r
4431 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4432 abort(); // this should never ever happen!
\r
4436 /* Copy the new bitmap onto the screen in one go.
\r
4437 * This way we avoid any flickering
\r
4439 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4440 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4441 boardRect.right - boardRect.left,
\r
4442 boardRect.bottom - boardRect.top,
\r
4443 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4444 if(saveDiagFlag) {
\r
4445 BITMAP b; int i, j, m, w, wb, fac=0; char pData[1000000];
\r
4446 BITMAPINFOHEADER bih; int color[16], nrColors=0;
\r
4448 GetObject(bufferBitmap, sizeof(b), &b);
\r
4449 if(b.bmWidthBytes*b.bmHeight <= 990000) {
\r
4450 bih.biSize = sizeof(BITMAPINFOHEADER);
\r
4451 bih.biWidth = b.bmWidth;
\r
4452 bih.biHeight = b.bmHeight;
\r
4454 bih.biBitCount = b.bmBitsPixel;
\r
4455 bih.biCompression = 0;
\r
4456 bih.biSizeImage = b.bmWidthBytes*b.bmHeight;
\r
4457 bih.biXPelsPerMeter = 0;
\r
4458 bih.biYPelsPerMeter = 0;
\r
4459 bih.biClrUsed = 0;
\r
4460 bih.biClrImportant = 0;
\r
4461 // fprintf(diagFile, "t=%d\nw=%d\nh=%d\nB=%d\nP=%d\nX=%d\n",
\r
4462 // b.bmType, b.bmWidth, b.bmHeight, b.bmWidthBytes, b.bmPlanes, b.bmBitsPixel);
\r
4463 GetDIBits(tmphdc,bufferBitmap,0,b.bmHeight,pData,(BITMAPINFO*)&bih,DIB_RGB_COLORS);
\r
4464 // fprintf(diagFile, "%8x\n", (int) pData);
\r
4467 wb = b.bmWidthBytes;
\r
4469 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)>>2; i++) {
\r
4470 int k = ((int*) pData)[i];
\r
4471 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4472 if(j >= 16) break;
\r
4474 if(j >= nrColors) nrColors = j+1;
\r
4476 if(j<16) { // 16 colors is enough. Compress to 4 bits per pixel
\r
4478 for(i=0; i<b.bmHeight - boardRect.top + OUTER_MARGIN; i++) {
\r
4479 for(w=0; w<(wb>>2); w+=2) {
\r
4480 int k = ((int*) pData)[(wb*i>>2) + w];
\r
4481 for(j=0; j<nrColors; j++) if(color[j] == k) break;
\r
4482 k = ((int*) pData)[(wb*i>>2) + w + 1];
\r
4483 for(m=0; m<nrColors; m++) if(color[m] == k) break;
\r
4484 pData[p++] = m | j<<4;
\r
4486 while(p&3) pData[p++] = 0;
\r
4489 wb = (wb+31>>5)<<2;
\r
4491 // write BITMAPFILEHEADER
\r
4492 fprintf(diagFile, "BM");
\r
4493 fputDW(diagFile, wb*(b.bmHeight - boardRect.top + OUTER_MARGIN)+0x36 + (fac?64:0));
\r
4494 fputDW(diagFile, 0);
\r
4495 fputDW(diagFile, 0x36 + (fac?64:0));
\r
4496 // write BITMAPINFOHEADER
\r
4497 fputDW(diagFile, 40);
\r
4498 fputDW(diagFile, b.bmWidth);
\r
4499 fputDW(diagFile, b.bmHeight - boardRect.top + OUTER_MARGIN);
\r
4500 if(fac) fputDW(diagFile, 0x040001); // planes and bits/pixel
\r
4501 else fputDW(diagFile, 0x200001); // planes and bits/pixel
\r
4502 fputDW(diagFile, 0);
\r
4503 fputDW(diagFile, 0);
\r
4504 fputDW(diagFile, 0);
\r
4505 fputDW(diagFile, 0);
\r
4506 fputDW(diagFile, 0);
\r
4507 fputDW(diagFile, 0);
\r
4508 // write color table
\r
4510 for(i=0; i<16; i++) fputDW(diagFile, color[i]);
\r
4511 // write bitmap data
\r
4512 for(i=0; i<wb*(b.bmHeight - boardRect.top + OUTER_MARGIN); i++)
\r
4513 fputc(pData[i], diagFile);
\r
4518 SelectObject(tmphdc, oldBitmap);
\r
4520 /* Massive cleanup */
\r
4521 for (x = 0; x < num_clips; x++)
\r
4522 DeleteObject(clips[x]);
\r
4525 DeleteObject(bufferBitmap);
\r
4528 ReleaseDC(hwndMain, hdc);
\r
4530 if (lastDrawnFlipView != flipView) {
\r
4532 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4534 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4537 /* CopyBoard(lastDrawn, board);*/
\r
4538 lastDrawnHighlight = highlightInfo;
\r
4539 lastDrawnPremove = premoveHighlightInfo;
\r
4540 lastDrawnFlipView = flipView;
\r
4541 lastDrawnValid = 1;
\r
4544 /* [HGM] diag: Save the current board display to the given open file and close the file */
\r
4552 saveDiagFlag = 1; diagFile = f;
\r
4553 HDCDrawPosition(NULL, TRUE, NULL);
\r
4557 // if(f != NULL) fprintf(f, "Sorry, but this feature is still in preparation\n");
\r
4564 /*---------------------------------------------------------------------------*\
\r
4565 | CLIENT PAINT PROCEDURE
\r
4566 | This is the main event-handler for the WM_PAINT message.
\r
4568 \*---------------------------------------------------------------------------*/
\r
4570 PaintProc(HWND hwnd)
\r
4576 if(hdc = BeginPaint(hwnd, &ps)) {
\r
4577 if (IsIconic(hwnd)) {
\r
4578 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4580 if (!appData.monoMode) {
\r
4581 SelectPalette(hdc, hPal, FALSE);
\r
4582 RealizePalette(hdc);
\r
4584 HDCDrawPosition(hdc, 1, NULL);
\r
4586 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4587 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4588 ETO_CLIPPED|ETO_OPAQUE,
\r
4589 &messageRect, messageText, strlen(messageText), NULL);
\r
4590 SelectObject(hdc, oldFont);
\r
4591 DisplayBothClocks();
\r
4593 EndPaint(hwnd,&ps);
\r
4601 * If the user selects on a border boundary, return -1; if off the board,
\r
4602 * return -2. Otherwise map the event coordinate to the square.
\r
4603 * The offset boardRect.left or boardRect.top must already have been
\r
4604 * subtracted from x.
\r
4607 EventToSquare(int x)
\r
4614 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4616 x /= (squareSize + lineGap);
\r
4617 if (x >= BOARD_SIZE)
\r
4628 DropEnable dropEnables[] = {
\r
4629 { 'P', DP_Pawn, "Pawn" },
\r
4630 { 'N', DP_Knight, "Knight" },
\r
4631 { 'B', DP_Bishop, "Bishop" },
\r
4632 { 'R', DP_Rook, "Rook" },
\r
4633 { 'Q', DP_Queen, "Queen" },
\r
4637 SetupDropMenu(HMENU hmenu)
\r
4639 int i, count, enable;
\r
4641 extern char white_holding[], black_holding[];
\r
4642 char item[MSG_SIZ];
\r
4644 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4645 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4646 dropEnables[i].piece);
\r
4648 while (p && *p++ == dropEnables[i].piece) count++;
\r
4649 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4650 enable = count > 0 || !appData.testLegality
\r
4651 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4652 && !appData.icsActive);
\r
4653 ModifyMenu(hmenu, dropEnables[i].command,
\r
4654 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4655 dropEnables[i].command, item);
\r
4659 static int fromX = -1, fromY = -1, toX, toY;
\r
4661 /* Event handler for mouse messages */
\r
4663 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4667 static int recursive = 0;
\r
4669 BOOLEAN needsRedraw = FALSE;
\r
4670 BOOLEAN saveAnimate;
\r
4671 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4672 static BOOLEAN sameAgain = FALSE, promotionChoice = FALSE;
\r
4673 ChessMove moveType;
\r
4676 if (message == WM_MBUTTONUP) {
\r
4677 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4678 to the middle button: we simulate pressing the left button too!
\r
4680 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4681 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4687 pt.x = LOWORD(lParam);
\r
4688 pt.y = HIWORD(lParam);
\r
4689 x = EventToSquare(pt.x - boardRect.left);
\r
4690 y = EventToSquare(pt.y - boardRect.top);
\r
4691 if (!flipView && y >= 0) {
\r
4692 y = BOARD_HEIGHT - 1 - y;
\r
4694 if (flipView && x >= 0) {
\r
4695 x = BOARD_WIDTH - 1 - x;
\r
4698 switch (message) {
\r
4699 case WM_LBUTTONDOWN:
\r
4700 if(promotionChoice) { // we are waiting for a click to indicate promotion piece
\r
4701 promotionChoice = FALSE; // only one chance: if click not OK it is interpreted as cancel
\r
4702 if(appData.debugMode) fprintf(debugFP, "promotion click, x=%d, y=%d\n", x, y);
\r
4703 if(gameInfo.holdingsWidth &&
\r
4704 (WhiteOnMove(currentMove)
\r
4705 ? x == BOARD_WIDTH-1 && y < gameInfo.holdingsSize && y > 0
\r
4706 : x == 0 && y >= BOARD_HEIGHT - gameInfo.holdingsSize && y < BOARD_HEIGHT-1) ) {
\r
4707 // click in right holdings, for determining promotion piece
\r
4708 ChessSquare p = boards[currentMove][y][x];
\r
4709 if(appData.debugMode) fprintf(debugFP, "square contains %d\n", (int)p);
\r
4710 if(p != EmptySquare) {
\r
4711 FinishMove(WhitePromotionQueen, fromX, fromY, toX, toY, ToLower(PieceToChar(p)));
\r
4712 fromX = fromY = -1;
\r
4716 DrawPosition(FALSE, boards[currentMove]);
\r
4720 sameAgain = FALSE;
\r
4722 /* Downclick vertically off board; check if on clock */
\r
4723 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4724 if (gameMode == EditPosition) {
\r
4725 SetWhiteToPlayEvent();
\r
4726 } else if (gameMode == IcsPlayingBlack ||
\r
4727 gameMode == MachinePlaysWhite) {
\r
4729 } else if (gameMode == EditGame) {
\r
4730 AdjustClock(flipClock, -1);
\r
4732 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4733 if (gameMode == EditPosition) {
\r
4734 SetBlackToPlayEvent();
\r
4735 } else if (gameMode == IcsPlayingWhite ||
\r
4736 gameMode == MachinePlaysBlack) {
\r
4738 } else if (gameMode == EditGame) {
\r
4739 AdjustClock(!flipClock, -1);
\r
4742 if (!appData.highlightLastMove) {
\r
4743 ClearHighlights();
\r
4744 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4746 fromX = fromY = -1;
\r
4747 dragInfo.start.x = dragInfo.start.y = -1;
\r
4748 dragInfo.from = dragInfo.start;
\r
4750 } else if (x < 0 || y < 0
\r
4751 /* [HGM] block clicks between board and holdings */
\r
4752 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4753 || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
\r
4754 || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize
\r
4755 /* EditPosition, empty square, or different color piece;
\r
4756 click-click move is possible */
\r
4759 } else if (fromX == x && fromY == y) {
\r
4760 /* Downclick on same square again */
\r
4761 ClearHighlights();
\r
4762 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4763 sameAgain = TRUE;
\r
4764 } else if (fromX != -1 &&
\r
4765 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4767 /* Downclick on different square. */
\r
4768 /* [HGM] if on holdings file, should count as new first click ! */
\r
4769 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4772 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4773 to make sure move is legal before showing promotion popup */
\r
4774 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4775 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4776 fromX = fromY = -1;
\r
4777 ClearHighlights();
\r
4778 DrawPosition(FALSE, boards[currentMove]);
\r
4781 if(moveType != ImpossibleMove) {
\r
4782 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4783 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4784 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4785 appData.alwaysPromoteToQueen) {
\r
4786 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4787 if (!appData.highlightLastMove) {
\r
4788 ClearHighlights();
\r
4789 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4792 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4793 SetHighlights(fromX, fromY, toX, toY);
\r
4794 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4795 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4796 If promotion to Q is legal, all are legal! */
\r
4797 if(gameInfo.variant == VariantSuper)
\r
4798 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4799 // kludge to temporarily execute move on display, wthout promotng yet
\r
4800 promotionChoice = TRUE;
\r
4801 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4802 boards[currentMove][toY][toX] = p;
\r
4803 DrawPosition(FALSE, boards[currentMove]);
\r
4804 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4805 boards[currentMove][toY][toX] = q;
\r
4807 PromotionPopup(hwnd);
\r
4808 } else { /* not a promotion */
\r
4809 if (appData.animate || appData.highlightLastMove) {
\r
4810 SetHighlights(fromX, fromY, toX, toY);
\r
4812 ClearHighlights();
\r
4814 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4815 fromX = fromY = -1;
\r
4816 if (appData.animate && !appData.highlightLastMove) {
\r
4817 ClearHighlights();
\r
4818 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4824 /* [HGM] it seemed that braces were missing here */
\r
4825 SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4826 fromX = fromY = -1;
\r
4830 ClearHighlights();
\r
4831 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4833 /* First downclick, or restart on a square with same color piece */
\r
4834 if (!frozen && OKToStartUserMove(x, y)) {
\r
4837 dragInfo.lastpos = pt;
\r
4838 dragInfo.from.x = fromX;
\r
4839 dragInfo.from.y = fromY;
\r
4840 dragInfo.start = dragInfo.from;
\r
4841 SetCapture(hwndMain);
\r
4843 fromX = fromY = -1;
\r
4844 dragInfo.start.x = dragInfo.start.y = -1;
\r
4845 dragInfo.from = dragInfo.start;
\r
4846 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4850 case WM_LBUTTONUP:
\r
4852 if (fromX == -1) break;
\r
4853 if (x == fromX && y == fromY) {
\r
4854 dragInfo.from.x = dragInfo.from.y = -1;
\r
4855 /* Upclick on same square */
\r
4857 /* Clicked same square twice: abort click-click move */
\r
4858 fromX = fromY = -1;
\r
4860 ClearPremoveHighlights();
\r
4862 /* First square clicked: start click-click move */
\r
4863 SetHighlights(fromX, fromY, -1, -1);
\r
4865 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4866 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4867 /* Errant click; ignore */
\r
4870 /* Finish drag move. */
\r
4871 if (appData.debugMode) {
\r
4872 fprintf(debugFP, "release\n");
\r
4874 dragInfo.from.x = dragInfo.from.y = -1;
\r
4877 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4878 appData.animate = appData.animate && !appData.animateDragging;
\r
4879 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4880 if(moveType == AmbiguousMove) { /* [HGM] Edit-Position move executed */
\r
4881 fromX = fromY = -1;
\r
4882 ClearHighlights();
\r
4883 DrawPosition(FALSE, boards[currentMove]);
\r
4886 if(moveType != ImpossibleMove) {
\r
4887 /* [HGM] use move type to determine if move is promotion.
\r
4888 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
4889 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4890 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4891 appData.alwaysPromoteToQueen)
\r
4892 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4894 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4895 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4896 if(gameInfo.variant == VariantSuper)
\r
4897 { ChessSquare p = boards[currentMove][fromY][fromX], q = boards[currentMove][toY][toX];
\r
4898 // kludge to temporarily execute move on display, wthout promotng yet
\r
4899 promotionChoice = TRUE;
\r
4900 boards[currentMove][fromY][fromX] = EmptySquare; // move Pawn to 8th rank
\r
4901 boards[currentMove][toY][toX] = p;
\r
4902 DrawPosition(FALSE, boards[currentMove]);
\r
4903 boards[currentMove][fromY][fromX] = p; // take back, but display stays
\r
4904 boards[currentMove][toY][toX] = q;
\r
4907 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
4908 } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4910 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4911 appData.animate = saveAnimate;
\r
4912 fromX = fromY = -1;
\r
4913 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
4914 ClearHighlights();
\r
4916 if (appData.animate || appData.animateDragging ||
\r
4917 appData.highlightDragging || gotPremove) {
\r
4918 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4921 dragInfo.start.x = dragInfo.start.y = -1;
\r
4922 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4925 case WM_MOUSEMOVE:
\r
4926 if ((appData.animateDragging || appData.highlightDragging)
\r
4927 && (wParam & MK_LBUTTON)
\r
4928 && dragInfo.from.x >= 0)
\r
4930 BOOL full_repaint = FALSE;
\r
4932 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
4933 if (appData.animateDragging) {
\r
4934 dragInfo.pos = pt;
\r
4936 if (appData.highlightDragging) {
\r
4937 SetHighlights(fromX, fromY, x, y);
\r
4938 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4939 full_repaint = TRUE;
\r
4943 DrawPosition( full_repaint, NULL);
\r
4945 dragInfo.lastpos = dragInfo.pos;
\r
4949 case WM_MBUTTONDOWN:
\r
4950 case WM_RBUTTONDOWN:
\r
4953 fromX = fromY = -1;
\r
4954 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4955 dragInfo.start.x = dragInfo.start.y = -1;
\r
4956 dragInfo.from = dragInfo.start;
\r
4957 dragInfo.lastpos = dragInfo.pos;
\r
4958 if (appData.highlightDragging) {
\r
4959 ClearHighlights();
\r
4962 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4963 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4964 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
4965 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4966 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
4969 DrawPosition(TRUE, NULL);
\r
4971 switch (gameMode) {
\r
4972 case EditPosition:
\r
4973 case IcsExamining:
\r
4974 if (x < 0 || y < 0) break;
\r
4977 if (message == WM_MBUTTONDOWN) {
\r
4978 buttonCount = 3; /* even if system didn't think so */
\r
4979 if (wParam & MK_SHIFT)
\r
4980 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4982 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4983 } else { /* message == WM_RBUTTONDOWN */
\r
4985 if (buttonCount == 3) {
\r
4986 if (wParam & MK_SHIFT)
\r
4987 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4989 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4991 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4994 /* Just have one menu, on the right button. Windows users don't
\r
4995 think to try the middle one, and sometimes other software steals
\r
4996 it, or it doesn't really exist. */
\r
4997 if(gameInfo.variant != VariantShogi)
\r
4998 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
5000 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
5004 case IcsPlayingWhite:
\r
5005 case IcsPlayingBlack:
\r
5007 case MachinePlaysWhite:
\r
5008 case MachinePlaysBlack:
\r
5009 if (appData.testLegality &&
\r
5010 gameInfo.variant != VariantBughouse &&
\r
5011 gameInfo.variant != VariantCrazyhouse) break;
\r
5012 if (x < 0 || y < 0) break;
\r
5015 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
5016 SetupDropMenu(hmenu);
\r
5017 MenuPopup(hwnd, pt, hmenu, -1);
\r
5028 /* Preprocess messages for buttons in main window */
\r
5030 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5032 int id = GetWindowLong(hwnd, GWL_ID);
\r
5035 for (i=0; i<N_BUTTONS; i++) {
\r
5036 if (buttonDesc[i].id == id) break;
\r
5038 if (i == N_BUTTONS) return 0;
\r
5039 switch (message) {
\r
5044 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
5045 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
5052 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
5055 if (appData.icsActive) {
\r
5056 if (GetKeyState(VK_SHIFT) < 0) {
\r
5058 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5059 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5063 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5064 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5071 if (appData.icsActive) {
\r
5072 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5073 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5075 SendMessage(h, WM_CHAR, wParam, lParam);
\r
5077 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
5078 PopUpMoveDialog((char)wParam);
\r
5084 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
5087 /* Process messages for Promotion dialog box */
\r
5089 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5093 switch (message) {
\r
5094 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5095 /* Center the dialog over the application window */
\r
5096 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
5097 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
5098 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
5099 gameInfo.variant == VariantGiveaway || gameInfo.variant == VariantSuper ) ?
\r
5100 SW_SHOW : SW_HIDE);
\r
5101 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
5102 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
5103 (PieceToChar(WhiteAngel) >= 'A' &&
\r
5104 PieceToChar(WhiteAngel) != '~' ||
\r
5105 PieceToChar(BlackAngel) >= 'A' &&
\r
5106 PieceToChar(BlackAngel) != '~' ) ?
\r
5107 SW_SHOW : SW_HIDE);
\r
5108 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
5109 (PieceToChar(WhiteMarshall) >= 'A' &&
\r
5110 PieceToChar(WhiteMarshall) != '~' ||
\r
5111 PieceToChar(BlackMarshall) >= 'A' &&
\r
5112 PieceToChar(BlackMarshall) != '~' ) ?
\r
5113 SW_SHOW : SW_HIDE);
\r
5114 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
5115 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
5116 gameInfo.variant != VariantShogi ?
\r
5117 SW_SHOW : SW_HIDE);
\r
5118 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
5119 gameInfo.variant != VariantShogi ?
\r
5120 SW_SHOW : SW_HIDE);
\r
5121 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
5122 gameInfo.variant == VariantShogi ?
\r
5123 SW_SHOW : SW_HIDE);
\r
5124 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
5125 gameInfo.variant == VariantShogi ?
\r
5126 SW_SHOW : SW_HIDE);
\r
5127 ShowWindow(GetDlgItem(hDlg, IDC_Centaur),
\r
5128 gameInfo.variant == VariantSuper ?
\r
5129 SW_SHOW : SW_HIDE);
\r
5132 case WM_COMMAND: /* message: received a command */
\r
5133 switch (LOWORD(wParam)) {
\r
5135 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5136 ClearHighlights();
\r
5137 DrawPosition(FALSE, NULL);
\r
5140 promoChar = gameInfo.variant == VariantSuper ? PieceToChar(BlackSilver) : PieceToChar(BlackKing);
\r
5143 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
5146 promoChar = PieceToChar(BlackRook);
\r
5149 promoChar = PieceToChar(BlackBishop);
\r
5151 case PB_Chancellor:
\r
5152 promoChar = PieceToChar(BlackMarshall);
\r
5154 case PB_Archbishop:
\r
5155 promoChar = PieceToChar(BlackAngel);
\r
5158 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
5163 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
5164 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
5165 only show the popup when we are already sure the move is valid or
\r
5166 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
5167 will figure out it is a promotion from the promoChar. */
\r
5168 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
5169 if (!appData.highlightLastMove) {
\r
5170 ClearHighlights();
\r
5171 DrawPosition(FALSE, NULL);
\r
5178 /* Pop up promotion dialog */
\r
5180 PromotionPopup(HWND hwnd)
\r
5184 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
5185 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
5186 hwnd, (DLGPROC)lpProc);
\r
5187 FreeProcInstance(lpProc);
\r
5190 /* Toggle ShowThinking */
\r
5192 ToggleShowThinking()
\r
5194 appData.showThinking = !appData.showThinking;
\r
5195 ShowThinkingEvent();
5199 LoadGameDialog(HWND hwnd, char* title)
\r
5203 char fileTitle[MSG_SIZ];
\r
5204 f = OpenFileDialog(hwnd, "rb", "",
\r
5205 appData.oldSaveStyle ? "gam" : "pgn",
\r
5207 title, &number, fileTitle, NULL);
\r
5209 cmailMsgLoaded = FALSE;
\r
5210 if (number == 0) {
\r
5211 int error = GameListBuild(f);
\r
5213 DisplayError("Cannot build game list", error);
\r
5214 } else if (!ListEmpty(&gameList) &&
\r
5215 ((ListGame *) gameList.tailPred)->number > 1) {
\r
5216 GameListPopUp(f, fileTitle);
\r
5219 GameListDestroy();
\r
5222 LoadGame(f, number, fileTitle, FALSE);
\r
5227 ChangedConsoleFont()
\r
5230 CHARRANGE tmpsel, sel;
\r
5231 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
5232 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5233 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5236 cfmt.cbSize = sizeof(CHARFORMAT);
\r
5237 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
5238 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
5239 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
5240 * size. This was undocumented in the version of MSVC++ that I had
\r
5241 * when I wrote the code, but is apparently documented now.
\r
5243 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
5244 cfmt.bCharSet = f->lf.lfCharSet;
\r
5245 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
5246 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5247 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
5248 /* Why are the following seemingly needed too? */
\r
5249 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5250 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
5251 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
5253 tmpsel.cpMax = -1; /*999999?*/
\r
5254 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
5255 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
5256 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
5257 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
5259 paraf.cbSize = sizeof(paraf);
\r
5260 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
5261 paraf.dxStartIndent = 0;
\r
5262 paraf.dxOffset = WRAP_INDENT;
\r
5263 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
5264 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
5267 /*---------------------------------------------------------------------------*\
\r
5269 * Window Proc for main window
\r
5271 \*---------------------------------------------------------------------------*/
\r
5273 /* Process messages for main window, etc. */
\r
5275 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
5278 int wmId, wmEvent;
\r
5282 char fileTitle[MSG_SIZ];
\r
5283 static SnapData sd;
\r
5285 switch (message) {
\r
5287 case WM_PAINT: /* message: repaint portion of window */
\r
5291 case WM_ERASEBKGND:
\r
5292 if (IsIconic(hwnd)) {
\r
5293 /* Cheat; change the message */
\r
5294 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
5296 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5300 case WM_LBUTTONDOWN:
\r
5301 case WM_MBUTTONDOWN:
\r
5302 case WM_RBUTTONDOWN:
\r
5303 case WM_LBUTTONUP:
\r
5304 case WM_MBUTTONUP:
\r
5305 case WM_RBUTTONUP:
\r
5306 case WM_MOUSEMOVE:
\r
5307 MouseEvent(hwnd, message, wParam, lParam);
\r
5312 if (appData.icsActive) {
\r
5313 if (wParam == '\t') {
\r
5314 if (GetKeyState(VK_SHIFT) < 0) {
\r
5316 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5317 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5321 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
5322 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5326 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
5327 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
5329 SendMessage(h, message, wParam, lParam);
\r
5331 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
5332 PopUpMoveDialog((char)wParam);
\r
5336 case WM_PALETTECHANGED:
\r
5337 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
5339 HDC hdc = GetDC(hwndMain);
\r
5340 SelectPalette(hdc, hPal, TRUE);
\r
5341 nnew = RealizePalette(hdc);
\r
5343 paletteChanged = TRUE;
\r
5345 UpdateColors(hdc);
\r
5347 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
5350 ReleaseDC(hwnd, hdc);
\r
5354 case WM_QUERYNEWPALETTE:
\r
5355 if (!appData.monoMode /*&& paletteChanged*/) {
\r
5357 HDC hdc = GetDC(hwndMain);
\r
5358 paletteChanged = FALSE;
\r
5359 SelectPalette(hdc, hPal, FALSE);
\r
5360 nnew = RealizePalette(hdc);
\r
5362 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5364 ReleaseDC(hwnd, hdc);
\r
5369 case WM_COMMAND: /* message: command from application menu */
\r
5370 wmId = LOWORD(wParam);
\r
5371 wmEvent = HIWORD(wParam);
\r
5376 AnalysisPopDown();
\r
5379 case IDM_NewGameFRC:
\r
5380 if( NewGameFRC() == 0 ) {
\r
5382 AnalysisPopDown();
\r
5386 case IDM_NewVariant:
\r
5387 NewVariantPopup(hwnd);
\r
5390 case IDM_LoadGame:
\r
5391 LoadGameDialog(hwnd, "Load Game from File");
\r
5394 case IDM_LoadNextGame:
\r
5398 case IDM_LoadPrevGame:
\r
5402 case IDM_ReloadGame:
\r
5406 case IDM_LoadPosition:
\r
5407 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5408 Reset(FALSE, TRUE);
\r
5411 f = OpenFileDialog(hwnd, "rb", "",
\r
5412 appData.oldSaveStyle ? "pos" : "fen",
\r
5414 "Load Position from File", &number, fileTitle, NULL);
\r
5416 LoadPosition(f, number, fileTitle);
\r
5420 case IDM_LoadNextPosition:
\r
5421 ReloadPosition(1);
\r
5424 case IDM_LoadPrevPosition:
\r
5425 ReloadPosition(-1);
\r
5428 case IDM_ReloadPosition:
\r
5429 ReloadPosition(0);
\r
5432 case IDM_SaveGame:
\r
5433 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5434 f = OpenFileDialog(hwnd, "a", defName,
\r
5435 appData.oldSaveStyle ? "gam" : "pgn",
\r
5437 "Save Game to File", NULL, fileTitle, NULL);
\r
5439 SaveGame(f, 0, "");
\r
5443 case IDM_SavePosition:
\r
5444 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5445 f = OpenFileDialog(hwnd, "a", defName,
\r
5446 appData.oldSaveStyle ? "pos" : "fen",
\r
5448 "Save Position to File", NULL, fileTitle, NULL);
\r
5450 SavePosition(f, 0, "");
\r
5454 case IDM_SaveDiagram:
\r
5455 defName = "diagram";
\r
5456 f = OpenFileDialog(hwnd, "wb", defName,
\r
5459 "Save Diagram to File", NULL, fileTitle, NULL);
\r
5465 case IDM_CopyGame:
\r
5466 CopyGameToClipboard();
\r
5469 case IDM_PasteGame:
\r
5470 PasteGameFromClipboard();
\r
5473 case IDM_CopyGameListToClipboard:
\r
5474 CopyGameListToClipboard();
\r
5477 /* [AS] Autodetect FEN or PGN data */
\r
5478 case IDM_PasteAny:
\r
5479 PasteGameOrFENFromClipboard();
\r
5482 /* [AS] Move history */
\r
5483 case IDM_ShowMoveHistory:
\r
5484 if( MoveHistoryIsUp() ) {
\r
5485 MoveHistoryPopDown();
\r
5488 MoveHistoryPopUp();
\r
5492 /* [AS] Eval graph */
\r
5493 case IDM_ShowEvalGraph:
\r
5494 if( EvalGraphIsUp() ) {
\r
5495 EvalGraphPopDown();
\r
5502 /* [AS] Engine output */
\r
5503 case IDM_ShowEngineOutput:
\r
5504 if( EngineOutputIsUp() ) {
\r
5505 EngineOutputPopDown();
\r
5508 EngineOutputPopUp();
\r
5512 /* [AS] User adjudication */
\r
5513 case IDM_UserAdjudication_White:
\r
5514 UserAdjudicationEvent( +1 );
\r
5517 case IDM_UserAdjudication_Black:
\r
5518 UserAdjudicationEvent( -1 );
\r
5521 case IDM_UserAdjudication_Draw:
\r
5522 UserAdjudicationEvent( 0 );
\r
5525 /* [AS] Game list options dialog */
\r
5526 case IDM_GameListOptions:
\r
5527 GameListOptions();
\r
5530 case IDM_CopyPosition:
\r
5531 CopyFENToClipboard();
\r
5534 case IDM_PastePosition:
\r
5535 PasteFENFromClipboard();
\r
5538 case IDM_MailMove:
\r
5542 case IDM_ReloadCMailMsg:
\r
5543 Reset(TRUE, TRUE);
\r
5544 ReloadCmailMsgEvent(FALSE);
\r
5547 case IDM_Minimize:
\r
5548 ShowWindow(hwnd, SW_MINIMIZE);
\r
5555 case IDM_MachineWhite:
\r
5556 MachineWhiteEvent();
\r
5558 * refresh the tags dialog only if it's visible
\r
5560 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5562 tags = PGNTags(&gameInfo);
\r
5563 TagsPopUp(tags, CmailMsg());
\r
5568 case IDM_MachineBlack:
\r
5569 MachineBlackEvent();
\r
5571 * refresh the tags dialog only if it's visible
\r
5573 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5575 tags = PGNTags(&gameInfo);
\r
5576 TagsPopUp(tags, CmailMsg());
\r
5581 case IDM_TwoMachines:
\r
5582 TwoMachinesEvent();
\r
5584 * refresh the tags dialog only if it's visible
\r
5586 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5588 tags = PGNTags(&gameInfo);
\r
5589 TagsPopUp(tags, CmailMsg());
\r
5594 case IDM_AnalysisMode:
\r
5595 if (!first.analysisSupport) {
\r
5596 char buf[MSG_SIZ];
\r
5597 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5598 DisplayError(buf, 0);
\r
5600 if (!appData.showThinking) ToggleShowThinking();
\r
5601 AnalyzeModeEvent();
\r
5605 case IDM_AnalyzeFile:
\r
5606 if (!first.analysisSupport) {
\r
5607 char buf[MSG_SIZ];
\r
5608 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5609 DisplayError(buf, 0);
\r
5611 if (!appData.showThinking) ToggleShowThinking();
\r
5612 AnalyzeFileEvent();
\r
5613 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5614 AnalysisPeriodicEvent(1);
\r
5618 case IDM_IcsClient:
\r
5622 case IDM_EditGame:
\r
5626 case IDM_EditPosition:
\r
5627 EditPositionEvent();
\r
5630 case IDM_Training:
\r
5634 case IDM_ShowGameList:
\r
5635 ShowGameListProc();
\r
5638 case IDM_EditTags:
\r
5642 case IDM_EditComment:
\r
5643 if (commentDialogUp && editComment) {
\r
5646 EditCommentEvent();
\r
5666 case IDM_CallFlag:
\r
5686 case IDM_StopObserving:
\r
5687 StopObservingEvent();
\r
5690 case IDM_StopExamining:
\r
5691 StopExaminingEvent();
\r
5694 case IDM_TypeInMove:
\r
5695 PopUpMoveDialog('\000');
\r
5698 case IDM_TypeInName:
\r
5699 PopUpNameDialog('\000');
\r
5702 case IDM_Backward:
\r
5704 SetFocus(hwndMain);
\r
5709 SetFocus(hwndMain);
\r
5714 SetFocus(hwndMain);
\r
5719 SetFocus(hwndMain);
\r
5726 case IDM_TruncateGame:
\r
5727 TruncateGameEvent();
\r
5734 case IDM_RetractMove:
\r
5735 RetractMoveEvent();
\r
5738 case IDM_FlipView:
\r
5739 flipView = !flipView;
\r
5740 DrawPosition(FALSE, NULL);
\r
5743 case IDM_FlipClock:
\r
5744 flipClock = !flipClock;
\r
5745 DisplayBothClocks();
\r
5748 case IDM_GeneralOptions:
\r
5749 GeneralOptionsPopup(hwnd);
\r
5750 DrawPosition(TRUE, NULL);
\r
5753 case IDM_BoardOptions:
\r
5754 BoardOptionsPopup(hwnd);
\r
5757 case IDM_EnginePlayOptions:
\r
5758 EnginePlayOptionsPopup(hwnd);
\r
5761 case IDM_OptionsUCI:
\r
5762 UciOptionsPopup(hwnd);
\r
5765 case IDM_IcsOptions:
\r
5766 IcsOptionsPopup(hwnd);
\r
5770 FontsOptionsPopup(hwnd);
\r
5774 SoundOptionsPopup(hwnd);
\r
5777 case IDM_CommPort:
\r
5778 CommPortOptionsPopup(hwnd);
\r
5781 case IDM_LoadOptions:
\r
5782 LoadOptionsPopup(hwnd);
\r
5785 case IDM_SaveOptions:
\r
5786 SaveOptionsPopup(hwnd);
\r
5789 case IDM_TimeControl:
\r
5790 TimeControlOptionsPopup(hwnd);
\r
5793 case IDM_SaveSettings:
\r
5794 SaveSettings(settingsFileName);
\r
5797 case IDM_SaveSettingsOnExit:
\r
5798 saveSettingsOnExit = !saveSettingsOnExit;
\r
5799 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5800 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5801 MF_CHECKED : MF_UNCHECKED));
\r
5812 case IDM_AboutGame:
\r
5817 appData.debugMode = !appData.debugMode;
\r
5818 if (appData.debugMode) {
\r
5819 char dir[MSG_SIZ];
\r
5820 GetCurrentDirectory(MSG_SIZ, dir);
\r
5821 SetCurrentDirectory(installDir);
\r
5822 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5823 SetCurrentDirectory(dir);
\r
5824 setbuf(debugFP, NULL);
\r
5831 case IDM_HELPCONTENTS:
\r
5832 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5833 MessageBox (GetFocus(),
\r
5834 "Unable to activate help",
\r
5835 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5839 case IDM_HELPSEARCH:
\r
5840 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5841 MessageBox (GetFocus(),
\r
5842 "Unable to activate help",
\r
5843 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5847 case IDM_HELPHELP:
\r
5848 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5849 MessageBox (GetFocus(),
\r
5850 "Unable to activate help",
\r
5851 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5856 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5858 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5859 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5860 FreeProcInstance(lpProc);
\r
5863 case IDM_DirectCommand1:
\r
5864 AskQuestionEvent("Direct Command",
\r
5865 "Send to chess program:", "", "1");
\r
5867 case IDM_DirectCommand2:
\r
5868 AskQuestionEvent("Direct Command",
\r
5869 "Send to second chess program:", "", "2");
\r
5872 case EP_WhitePawn:
\r
5873 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5874 fromX = fromY = -1;
\r
5877 case EP_WhiteKnight:
\r
5878 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5879 fromX = fromY = -1;
\r
5882 case EP_WhiteBishop:
\r
5883 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5884 fromX = fromY = -1;
\r
5887 case EP_WhiteRook:
\r
5888 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5889 fromX = fromY = -1;
\r
5892 case EP_WhiteQueen:
\r
5893 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5894 fromX = fromY = -1;
\r
5897 case EP_WhiteFerz:
\r
5898 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5899 fromX = fromY = -1;
\r
5902 case EP_WhiteWazir:
\r
5903 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5904 fromX = fromY = -1;
\r
5907 case EP_WhiteAlfil:
\r
5908 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5909 fromX = fromY = -1;
\r
5912 case EP_WhiteCannon:
\r
5913 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5914 fromX = fromY = -1;
\r
5917 case EP_WhiteCardinal:
\r
5918 EditPositionMenuEvent(WhiteAngel, fromX, fromY);
\r
5919 fromX = fromY = -1;
\r
5922 case EP_WhiteMarshall:
\r
5923 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5924 fromX = fromY = -1;
\r
5927 case EP_WhiteKing:
\r
5928 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5929 fromX = fromY = -1;
\r
5932 case EP_BlackPawn:
\r
5933 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5934 fromX = fromY = -1;
\r
5937 case EP_BlackKnight:
\r
5938 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5939 fromX = fromY = -1;
\r
5942 case EP_BlackBishop:
\r
5943 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5944 fromX = fromY = -1;
\r
5947 case EP_BlackRook:
\r
5948 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5949 fromX = fromY = -1;
\r
5952 case EP_BlackQueen:
\r
5953 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5954 fromX = fromY = -1;
\r
5957 case EP_BlackFerz:
\r
5958 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5959 fromX = fromY = -1;
\r
5962 case EP_BlackWazir:
\r
5963 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5964 fromX = fromY = -1;
\r
5967 case EP_BlackAlfil:
\r
5968 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5969 fromX = fromY = -1;
\r
5972 case EP_BlackCannon:
\r
5973 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5974 fromX = fromY = -1;
\r
5977 case EP_BlackCardinal:
\r
5978 EditPositionMenuEvent(BlackAngel, fromX, fromY);
\r
5979 fromX = fromY = -1;
\r
5982 case EP_BlackMarshall:
\r
5983 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5984 fromX = fromY = -1;
\r
5987 case EP_BlackKing:
\r
5988 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5989 fromX = fromY = -1;
\r
5992 case EP_EmptySquare:
\r
5993 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5994 fromX = fromY = -1;
\r
5997 case EP_ClearBoard:
\r
5998 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5999 fromX = fromY = -1;
\r
6003 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
6004 fromX = fromY = -1;
\r
6008 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
6009 fromX = fromY = -1;
\r
6013 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
6014 fromX = fromY = -1;
\r
6018 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
6019 fromX = fromY = -1;
\r
6023 DropMenuEvent(WhitePawn, fromX, fromY);
\r
6024 fromX = fromY = -1;
\r
6028 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
6029 fromX = fromY = -1;
\r
6033 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
6034 fromX = fromY = -1;
\r
6038 DropMenuEvent(WhiteRook, fromX, fromY);
\r
6039 fromX = fromY = -1;
\r
6043 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
6044 fromX = fromY = -1;
\r
6048 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6054 case CLOCK_TIMER_ID:
\r
6055 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
6056 clockTimerEvent = 0;
\r
6057 DecrementClocks(); /* call into back end */
\r
6059 case LOAD_GAME_TIMER_ID:
\r
6060 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
6061 loadGameTimerEvent = 0;
\r
6062 AutoPlayGameLoop(); /* call into back end */
\r
6064 case ANALYSIS_TIMER_ID:
\r
6065 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
6066 appData.periodicUpdates) {
\r
6067 AnalysisPeriodicEvent(0);
\r
6069 KillTimer(hwnd, analysisTimerEvent);
\r
6070 analysisTimerEvent = 0;
\r
6073 case DELAYED_TIMER_ID:
\r
6074 KillTimer(hwnd, delayedTimerEvent);
\r
6075 delayedTimerEvent = 0;
\r
6076 delayedTimerCallback();
\r
6081 case WM_USER_Input:
\r
6082 InputEvent(hwnd, message, wParam, lParam);
\r
6085 /* [AS] Also move "attached" child windows */
\r
6086 case WM_WINDOWPOSCHANGING:
\r
6087 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
6088 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
6090 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
6091 /* Window is moving */
\r
6094 GetWindowRect( hwnd, &rcMain );
\r
6096 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
6097 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
6098 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
6103 /* [AS] Snapping */
\r
6104 case WM_ENTERSIZEMOVE:
\r
6105 if(appData.debugMode) { fprintf(debugFP, "size-move\n"); }
\r
6106 if (hwnd == hwndMain) {
\r
6107 doingSizing = TRUE;
\r
6110 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
6114 if(appData.debugMode) { fprintf(debugFP, "sizing\n"); }
\r
6115 if (hwnd == hwndMain) {
\r
6116 lastSizing = wParam;
\r
6121 if(appData.debugMode) { fprintf(debugFP, "moving\n"); }
\r
6122 return OnMoving( &sd, hwnd, wParam, lParam );
\r
6124 case WM_EXITSIZEMOVE:
\r
6125 if(appData.debugMode) { fprintf(debugFP, "exit size-move, size = %d\n", squareSize); }
\r
6126 if (hwnd == hwndMain) {
\r
6128 doingSizing = FALSE;
\r
6129 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6130 GetClientRect(hwnd, &client);
\r
6131 ResizeBoard(client.right, client.bottom, lastSizing);
\r
6133 if(appData.debugMode) { fprintf(debugFP, "square size = %d\n", squareSize); }
\r
6135 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
6138 case WM_DESTROY: /* message: window being destroyed */
\r
6139 PostQuitMessage(0);
\r
6143 if (hwnd == hwndMain) {
\r
6148 default: /* Passes it on if unprocessed */
\r
6149 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
6154 /*---------------------------------------------------------------------------*\
\r
6156 * Misc utility routines
\r
6158 \*---------------------------------------------------------------------------*/
\r
6161 * Decent random number generator, at least not as bad as Windows
\r
6162 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
6164 unsigned int randstate;
\r
6169 randstate = randstate * 1664525 + 1013904223;
\r
6170 return (int) randstate & 0x7fffffff;
\r
6174 mysrandom(unsigned int seed)
\r
6181 * returns TRUE if user selects a different color, FALSE otherwise
\r
6185 ChangeColor(HWND hwnd, COLORREF *which)
\r
6187 static BOOL firstTime = TRUE;
\r
6188 static DWORD customColors[16];
\r
6190 COLORREF newcolor;
\r
6195 /* Make initial colors in use available as custom colors */
\r
6196 /* Should we put the compiled-in defaults here instead? */
\r
6198 customColors[i++] = lightSquareColor & 0xffffff;
\r
6199 customColors[i++] = darkSquareColor & 0xffffff;
\r
6200 customColors[i++] = whitePieceColor & 0xffffff;
\r
6201 customColors[i++] = blackPieceColor & 0xffffff;
\r
6202 customColors[i++] = highlightSquareColor & 0xffffff;
\r
6203 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
6205 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
6206 customColors[i++] = textAttribs[ccl].color;
\r
6208 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
6209 firstTime = FALSE;
\r
6212 cc.lStructSize = sizeof(cc);
\r
6213 cc.hwndOwner = hwnd;
\r
6214 cc.hInstance = NULL;
\r
6215 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
6216 cc.lpCustColors = (LPDWORD) customColors;
\r
6217 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
6219 if (!ChooseColor(&cc)) return FALSE;
\r
6221 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
6222 if (newcolor == *which) return FALSE;
\r
6223 *which = newcolor;
\r
6227 InitDrawingColors();
\r
6228 InvalidateRect(hwnd, &boardRect, FALSE);
\r
6233 MyLoadSound(MySound *ms)
\r
6239 if (ms->data) free(ms->data);
\r
6242 switch (ms->name[0]) {
\r
6248 /* System sound from Control Panel. Don't preload here. */
\r
6252 if (ms->name[1] == NULLCHAR) {
\r
6253 /* "!" alone = silence */
\r
6256 /* Builtin wave resource. Error if not found. */
\r
6257 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
6258 if (h == NULL) break;
\r
6259 ms->data = (void *)LoadResource(hInst, h);
\r
6260 if (h == NULL) break;
\r
6265 /* .wav file. Error if not found. */
\r
6266 f = fopen(ms->name, "rb");
\r
6267 if (f == NULL) break;
\r
6268 if (fstat(fileno(f), &st) < 0) break;
\r
6269 ms->data = malloc(st.st_size);
\r
6270 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
6276 char buf[MSG_SIZ];
\r
6277 sprintf(buf, "Error loading sound %s", ms->name);
\r
6278 DisplayError(buf, GetLastError());
\r
6284 MyPlaySound(MySound *ms)
\r
6286 BOOLEAN ok = FALSE;
\r
6287 switch (ms->name[0]) {
\r
6293 /* System sound from Control Panel (deprecated feature).
\r
6294 "$" alone or an unset sound name gets default beep (still in use). */
\r
6295 if (ms->name[1]) {
\r
6296 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
6298 if (!ok) ok = MessageBeep(MB_OK);
\r
6301 /* Builtin wave resource, or "!" alone for silence */
\r
6302 if (ms->name[1]) {
\r
6303 if (ms->data == NULL) return FALSE;
\r
6304 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6310 /* .wav file. Error if not found. */
\r
6311 if (ms->data == NULL) return FALSE;
\r
6312 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
6315 /* Don't print an error: this can happen innocently if the sound driver
\r
6316 is busy; for instance, if another instance of WinBoard is playing
\r
6317 a sound at about the same time. */
\r
6320 char buf[MSG_SIZ];
\r
6321 sprintf(buf, "Error playing sound %s", ms->name);
\r
6322 DisplayError(buf, GetLastError());
\r
6330 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6333 OPENFILENAME *ofn;
\r
6334 static UINT *number; /* gross that this is static */
\r
6336 switch (message) {
\r
6337 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6338 /* Center the dialog over the application window */
\r
6339 ofn = (OPENFILENAME *) lParam;
\r
6340 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
6341 number = (UINT *) ofn->lCustData;
\r
6342 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
6346 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6347 return FALSE; /* Allow for further processing */
\r
6350 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
6351 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
6353 return FALSE; /* Allow for further processing */
\r
6359 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
6361 static UINT *number;
\r
6362 OPENFILENAME *ofname;
\r
6365 case WM_INITDIALOG:
\r
6366 ofname = (OPENFILENAME *)lParam;
\r
6367 number = (UINT *)(ofname->lCustData);
\r
6370 ofnot = (OFNOTIFY *)lParam;
\r
6371 if (ofnot->hdr.code == CDN_FILEOK) {
\r
6372 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
6381 OpenFileDialog(HWND hwnd, char *write, char *defName, char *defExt, // [HGM] diag: type of 'write' now string
\r
6382 char *nameFilt, char *dlgTitle, UINT *number,
\r
6383 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
6385 OPENFILENAME openFileName;
\r
6386 char buf1[MSG_SIZ];
\r
6389 if (fileName == NULL) fileName = buf1;
\r
6390 if (defName == NULL) {
\r
6391 strcpy(fileName, "*.");
\r
6392 strcat(fileName, defExt);
\r
6394 strcpy(fileName, defName);
\r
6396 if (fileTitle) strcpy(fileTitle, "");
\r
6397 if (number) *number = 0;
\r
6399 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
6400 openFileName.hwndOwner = hwnd;
\r
6401 openFileName.hInstance = (HANDLE) hInst;
\r
6402 openFileName.lpstrFilter = nameFilt;
\r
6403 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
6404 openFileName.nMaxCustFilter = 0L;
\r
6405 openFileName.nFilterIndex = 1L;
\r
6406 openFileName.lpstrFile = fileName;
\r
6407 openFileName.nMaxFile = MSG_SIZ;
\r
6408 openFileName.lpstrFileTitle = fileTitle;
\r
6409 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
6410 openFileName.lpstrInitialDir = NULL;
\r
6411 openFileName.lpstrTitle = dlgTitle;
\r
6412 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
6413 | (write[0] != 'r' ? 0 : OFN_FILEMUSTEXIST)
\r
6414 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
6415 | (oldDialog ? 0 : OFN_EXPLORER);
\r
6416 openFileName.nFileOffset = 0;
\r
6417 openFileName.nFileExtension = 0;
\r
6418 openFileName.lpstrDefExt = defExt;
\r
6419 openFileName.lCustData = (LONG) number;
\r
6420 openFileName.lpfnHook = oldDialog ?
\r
6421 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
6422 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6424 if (write[0] != 'r' ? GetSaveFileName(&openFileName) :
\r
6425 GetOpenFileName(&openFileName)) {
\r
6426 /* open the file */
\r
6427 f = fopen(openFileName.lpstrFile, write);
\r
6429 MessageBox(hwnd, "File open failed", NULL,
\r
6430 MB_OK|MB_ICONEXCLAMATION);
\r
6434 int err = CommDlgExtendedError();
\r
6435 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6444 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6446 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6449 * Get the first pop-up menu in the menu template. This is the
\r
6450 * menu that TrackPopupMenu displays.
\r
6452 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6454 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6457 * TrackPopup uses screen coordinates, so convert the
\r
6458 * coordinates of the mouse click to screen coordinates.
\r
6460 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6462 /* Draw and track the floating pop-up menu. */
\r
6463 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6464 pt.x, pt.y, 0, hwnd, NULL);
\r
6466 /* Destroy the menu.*/
\r
6467 DestroyMenu(hmenu);
\r
6472 int sizeX, sizeY, newSizeX, newSizeY;
\r
6474 } ResizeEditPlusButtonsClosure;
\r
6477 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6479 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6483 if (hChild == cl->hText) return TRUE;
\r
6484 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6485 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6486 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6487 ScreenToClient(cl->hDlg, &pt);
\r
6488 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6489 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6493 /* Resize a dialog that has a (rich) edit field filling most of
\r
6494 the top, with a row of buttons below */
\r
6496 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6499 int newTextHeight, newTextWidth;
\r
6500 ResizeEditPlusButtonsClosure cl;
\r
6502 /*if (IsIconic(hDlg)) return;*/
\r
6503 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6505 cl.hdwp = BeginDeferWindowPos(8);
\r
6507 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6508 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6509 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6510 if (newTextHeight < 0) {
\r
6511 newSizeY += -newTextHeight;
\r
6512 newTextHeight = 0;
\r
6514 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6515 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6521 cl.newSizeX = newSizeX;
\r
6522 cl.newSizeY = newSizeY;
\r
6523 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6525 EndDeferWindowPos(cl.hdwp);
\r
6528 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6530 RECT rChild, rParent;
\r
6531 int wChild, hChild, wParent, hParent;
\r
6532 int wScreen, hScreen, xNew, yNew;
\r
6535 /* Get the Height and Width of the child window */
\r
6536 GetWindowRect (hwndChild, &rChild);
\r
6537 wChild = rChild.right - rChild.left;
\r
6538 hChild = rChild.bottom - rChild.top;
\r
6540 /* Get the Height and Width of the parent window */
\r
6541 GetWindowRect (hwndParent, &rParent);
\r
6542 wParent = rParent.right - rParent.left;
\r
6543 hParent = rParent.bottom - rParent.top;
\r
6545 /* Get the display limits */
\r
6546 hdc = GetDC (hwndChild);
\r
6547 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6548 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6549 ReleaseDC(hwndChild, hdc);
\r
6551 /* Calculate new X position, then adjust for screen */
\r
6552 xNew = rParent.left + ((wParent - wChild) /2);
\r
6555 } else if ((xNew+wChild) > wScreen) {
\r
6556 xNew = wScreen - wChild;
\r
6559 /* Calculate new Y position, then adjust for screen */
\r
6561 yNew = rParent.top + ((hParent - hChild) /2);
\r
6564 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6569 } else if ((yNew+hChild) > hScreen) {
\r
6570 yNew = hScreen - hChild;
\r
6573 /* Set it, and return */
\r
6574 return SetWindowPos (hwndChild, NULL,
\r
6575 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6578 /* Center one window over another */
\r
6579 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6581 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6584 /*---------------------------------------------------------------------------*\
\r
6586 * Startup Dialog functions
\r
6588 \*---------------------------------------------------------------------------*/
\r
6590 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6592 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6594 while (*cd != NULL) {
\r
6595 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6601 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6603 char buf1[ARG_MAX];
\r
6606 if (str[0] == '@') {
\r
6607 FILE* f = fopen(str + 1, "r");
\r
6609 DisplayFatalError(str + 1, errno, 2);
\r
6612 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6614 buf1[len] = NULLCHAR;
\r
6618 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6621 char buf[MSG_SIZ];
\r
6622 char *end = strchr(str, '\n');
\r
6623 if (end == NULL) return;
\r
6624 memcpy(buf, str, end - str);
\r
6625 buf[end - str] = NULLCHAR;
\r
6626 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6632 SetStartupDialogEnables(HWND hDlg)
\r
6634 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6635 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6636 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6637 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6638 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6639 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6640 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6641 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6642 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6643 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6644 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6645 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6646 IsDlgButtonChecked(hDlg, OPT_View));
\r
6650 QuoteForFilename(char *filename)
\r
6652 int dquote, space;
\r
6653 dquote = strchr(filename, '"') != NULL;
\r
6654 space = strchr(filename, ' ') != NULL;
\r
6655 if (dquote || space) {
\r
6667 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6669 char buf[MSG_SIZ];
\r
6672 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6673 q = QuoteForFilename(nthcp);
\r
6674 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6675 if (*nthdir != NULLCHAR) {
\r
6676 q = QuoteForFilename(nthdir);
\r
6677 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6679 if (*nthcp == NULLCHAR) {
\r
6680 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6681 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6682 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6683 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6688 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6690 char buf[MSG_SIZ];
\r
6694 switch (message) {
\r
6695 case WM_INITDIALOG:
\r
6696 /* Center the dialog */
\r
6697 CenterWindow (hDlg, GetDesktopWindow());
\r
6698 /* Initialize the dialog items */
\r
6699 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6700 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6701 firstChessProgramNames);
\r
6702 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6703 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6704 secondChessProgramNames);
\r
6705 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6706 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6707 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6708 if (*appData.icsHelper != NULLCHAR) {
\r
6709 char *q = QuoteForFilename(appData.icsHelper);
\r
6710 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6712 if (*appData.icsHost == NULLCHAR) {
\r
6713 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6714 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6715 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6716 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6717 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6720 if (appData.icsActive) {
\r
6721 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6723 else if (appData.noChessProgram) {
\r
6724 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6727 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6730 SetStartupDialogEnables(hDlg);
\r
6734 switch (LOWORD(wParam)) {
\r
6736 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6737 strcpy(buf, "/fcp=");
\r
6738 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6740 ParseArgs(StringGet, &p);
\r
6741 strcpy(buf, "/scp=");
\r
6742 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6744 ParseArgs(StringGet, &p);
\r
6745 appData.noChessProgram = FALSE;
\r
6746 appData.icsActive = FALSE;
\r
6747 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6748 strcpy(buf, "/ics /icshost=");
\r
6749 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6751 ParseArgs(StringGet, &p);
\r
6752 if (appData.zippyPlay) {
\r
6753 strcpy(buf, "/fcp=");
\r
6754 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6756 ParseArgs(StringGet, &p);
\r
6758 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6759 appData.noChessProgram = TRUE;
\r
6760 appData.icsActive = FALSE;
\r
6762 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6763 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6766 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6767 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6769 ParseArgs(StringGet, &p);
\r
6771 EndDialog(hDlg, TRUE);
\r
6778 case IDM_HELPCONTENTS:
\r
6779 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6780 MessageBox (GetFocus(),
\r
6781 "Unable to activate help",
\r
6782 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6787 SetStartupDialogEnables(hDlg);
\r
6795 /*---------------------------------------------------------------------------*\
\r
6797 * About box dialog functions
\r
6799 \*---------------------------------------------------------------------------*/
\r
6801 /* Process messages for "About" dialog box */
\r
6803 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6805 switch (message) {
\r
6806 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6807 /* Center the dialog over the application window */
\r
6808 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6809 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6812 case WM_COMMAND: /* message: received a command */
\r
6813 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6814 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6815 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6823 /*---------------------------------------------------------------------------*\
\r
6825 * Comment Dialog functions
\r
6827 \*---------------------------------------------------------------------------*/
\r
6830 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6832 static HANDLE hwndText = NULL;
\r
6833 int len, newSizeX, newSizeY, flags;
\r
6834 static int sizeX, sizeY;
\r
6839 switch (message) {
\r
6840 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6841 /* Initialize the dialog items */
\r
6842 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6843 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6844 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6845 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6846 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6847 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6848 SetWindowText(hDlg, commentTitle);
\r
6849 if (editComment) {
\r
6850 SetFocus(hwndText);
\r
6852 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6854 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6855 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6856 MAKELPARAM(FALSE, 0));
\r
6857 /* Size and position the dialog */
\r
6858 if (!commentDialog) {
\r
6859 commentDialog = hDlg;
\r
6860 flags = SWP_NOZORDER;
\r
6861 GetClientRect(hDlg, &rect);
\r
6862 sizeX = rect.right;
\r
6863 sizeY = rect.bottom;
\r
6864 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
6865 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
6866 WINDOWPLACEMENT wp;
\r
6867 EnsureOnScreen(&commentX, &commentY);
\r
6868 wp.length = sizeof(WINDOWPLACEMENT);
\r
6870 wp.showCmd = SW_SHOW;
\r
6871 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6872 wp.rcNormalPosition.left = commentX;
\r
6873 wp.rcNormalPosition.right = commentX + commentW;
\r
6874 wp.rcNormalPosition.top = commentY;
\r
6875 wp.rcNormalPosition.bottom = commentY + commentH;
\r
6876 SetWindowPlacement(hDlg, &wp);
\r
6878 GetClientRect(hDlg, &rect);
\r
6879 newSizeX = rect.right;
\r
6880 newSizeY = rect.bottom;
\r
6881 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6882 newSizeX, newSizeY);
\r
6889 case WM_COMMAND: /* message: received a command */
\r
6890 switch (LOWORD(wParam)) {
\r
6892 if (editComment) {
\r
6894 /* Read changed options from the dialog box */
\r
6895 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6896 len = GetWindowTextLength(hwndText);
\r
6897 str = (char *) malloc(len + 1);
\r
6898 GetWindowText(hwndText, str, len + 1);
\r
6907 ReplaceComment(commentIndex, str);
\r
6914 case OPT_CancelComment:
\r
6918 case OPT_ClearComment:
\r
6919 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6922 case OPT_EditComment:
\r
6923 EditCommentEvent();
\r
6932 newSizeX = LOWORD(lParam);
\r
6933 newSizeY = HIWORD(lParam);
\r
6934 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6939 case WM_GETMINMAXINFO:
\r
6940 /* Prevent resizing window too small */
\r
6941 mmi = (MINMAXINFO *) lParam;
\r
6942 mmi->ptMinTrackSize.x = 100;
\r
6943 mmi->ptMinTrackSize.y = 100;
\r
6950 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6955 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6957 if (str == NULL) str = "";
\r
6958 p = (char *) malloc(2 * strlen(str) + 2);
\r
6961 if (*str == '\n') *q++ = '\r';
\r
6965 if (commentText != NULL) free(commentText);
\r
6967 commentIndex = index;
\r
6968 commentTitle = title;
\r
6970 editComment = edit;
\r
6972 if (commentDialog) {
\r
6973 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6974 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
6976 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6977 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6978 hwndMain, (DLGPROC)lpProc);
\r
6979 FreeProcInstance(lpProc);
\r
6981 commentDialogUp = TRUE;
\r
6985 /*---------------------------------------------------------------------------*\
\r
6987 * Type-in move dialog functions
\r
6989 \*---------------------------------------------------------------------------*/
\r
6992 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6994 char move[MSG_SIZ];
\r
6996 ChessMove moveType;
\r
6997 int fromX, fromY, toX, toY;
\r
7000 switch (message) {
\r
7001 case WM_INITDIALOG:
\r
7002 move[0] = (char) lParam;
\r
7003 move[1] = NULLCHAR;
\r
7004 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7005 hInput = GetDlgItem(hDlg, OPT_Move);
\r
7006 SetWindowText(hInput, move);
\r
7008 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7012 switch (LOWORD(wParam)) {
\r
7014 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
7015 gameMode != Training) {
\r
7016 DisplayMoveError("Displayed move is not current");
\r
7018 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
7019 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
7020 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
7021 if (gameMode != Training)
\r
7022 forwardMostMove = currentMove;
\r
7023 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
7025 DisplayMoveError("Could not parse move");
\r
7028 EndDialog(hDlg, TRUE);
\r
7031 EndDialog(hDlg, FALSE);
\r
7042 PopUpMoveDialog(char firstchar)
\r
7046 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
7047 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
7048 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
7049 gameMode == EditPosition || gameMode == IcsExamining ||
\r
7050 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
7051 gameMode == Training) {
\r
7052 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
7053 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
7054 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7055 FreeProcInstance(lpProc);
\r
7059 /*---------------------------------------------------------------------------*\
\r
7061 * Type-in name dialog functions
\r
7063 \*---------------------------------------------------------------------------*/
\r
7066 TypeInNameDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7068 char move[MSG_SIZ];
\r
7071 switch (message) {
\r
7072 case WM_INITDIALOG:
\r
7073 move[0] = (char) lParam;
\r
7074 move[1] = NULLCHAR;
\r
7075 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
7076 hInput = GetDlgItem(hDlg, OPT_Name);
\r
7077 SetWindowText(hInput, move);
\r
7079 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
7083 switch (LOWORD(wParam)) {
\r
7085 GetDlgItemText(hDlg, OPT_Name, move, sizeof(move));
\r
7086 appData.userName = strdup(move);
\r
7088 EndDialog(hDlg, TRUE);
\r
7091 EndDialog(hDlg, FALSE);
\r
7102 PopUpNameDialog(char firstchar)
\r
7106 lpProc = MakeProcInstance((FARPROC)TypeInNameDialog, hInst);
\r
7107 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInName),
\r
7108 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
7109 FreeProcInstance(lpProc);
\r
7112 /*---------------------------------------------------------------------------*\
\r
7116 \*---------------------------------------------------------------------------*/
\r
7118 /* Nonmodal error box */
\r
7119 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
7120 WPARAM wParam, LPARAM lParam);
\r
7123 ErrorPopUp(char *title, char *content)
\r
7127 BOOLEAN modal = hwndMain == NULL;
\r
7145 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7146 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7149 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
7151 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
7152 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7153 hwndMain, (DLGPROC)lpProc);
\r
7154 FreeProcInstance(lpProc);
\r
7161 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
7162 if (errorDialog == NULL) return;
\r
7163 DestroyWindow(errorDialog);
\r
7164 errorDialog = NULL;
\r
7168 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7173 switch (message) {
\r
7174 case WM_INITDIALOG:
\r
7175 GetWindowRect(hDlg, &rChild);
\r
7178 SetWindowPos(hDlg, NULL, rChild.left,
\r
7179 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
7180 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7184 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7185 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7186 and it doesn't work when you resize the dialog.
\r
7187 For now, just give it a default position.
\r
7189 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
7191 errorDialog = hDlg;
\r
7192 SetWindowText(hDlg, errorTitle);
\r
7193 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7194 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7198 switch (LOWORD(wParam)) {
\r
7201 if (errorDialog == hDlg) errorDialog = NULL;
\r
7202 DestroyWindow(hDlg);
\r
7214 HWND gothicDialog = NULL;
\r
7217 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7221 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
7223 switch (message) {
\r
7224 case WM_INITDIALOG:
\r
7225 GetWindowRect(hDlg, &rChild);
\r
7227 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
7231 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
7232 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
7233 and it doesn't work when you resize the dialog.
\r
7234 For now, just give it a default position.
\r
7236 gothicDialog = hDlg;
\r
7237 SetWindowText(hDlg, errorTitle);
\r
7238 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
7239 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
7243 switch (LOWORD(wParam)) {
\r
7246 if (errorDialog == hDlg) errorDialog = NULL;
\r
7247 DestroyWindow(hDlg);
\r
7259 GothicPopUp(char *title, VariantClass variant)
\r
7263 BOOLEAN modal = hwndMain == NULL;
\r
7264 static char *lastTitle;
\r
7266 strncpy(errorTitle, title, sizeof(errorTitle));
\r
7267 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
7269 if(lastTitle != title && gothicDialog != NULL) {
\r
7270 DestroyWindow(gothicDialog);
\r
7271 gothicDialog = NULL;
\r
7273 if(variant != VariantNormal && gothicDialog == NULL) {
\r
7274 title = lastTitle;
\r
7275 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
7276 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
7277 hwndMain, (DLGPROC)lpProc);
\r
7278 FreeProcInstance(lpProc);
\r
7283 /*---------------------------------------------------------------------------*\
\r
7285 * Ics Interaction console functions
\r
7287 \*---------------------------------------------------------------------------*/
\r
7289 #define HISTORY_SIZE 64
\r
7290 static char *history[HISTORY_SIZE];
\r
7291 int histIn = 0, histP = 0;
\r
7294 SaveInHistory(char *cmd)
\r
7296 if (history[histIn] != NULL) {
\r
7297 free(history[histIn]);
\r
7298 history[histIn] = NULL;
\r
7300 if (*cmd == NULLCHAR) return;
\r
7301 history[histIn] = StrSave(cmd);
\r
7302 histIn = (histIn + 1) % HISTORY_SIZE;
\r
7303 if (history[histIn] != NULL) {
\r
7304 free(history[histIn]);
\r
7305 history[histIn] = NULL;
\r
7311 PrevInHistory(char *cmd)
\r
7314 if (histP == histIn) {
\r
7315 if (history[histIn] != NULL) free(history[histIn]);
\r
7316 history[histIn] = StrSave(cmd);
\r
7318 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
7319 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
7321 return history[histP];
\r
7327 if (histP == histIn) return NULL;
\r
7328 histP = (histP + 1) % HISTORY_SIZE;
\r
7329 return history[histP];
\r
7336 BOOLEAN immediate;
\r
7337 } IcsTextMenuEntry;
\r
7338 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
7339 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
7342 ParseIcsTextMenu(char *icsTextMenuString)
\r
7345 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
7346 char *p = icsTextMenuString;
\r
7347 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7350 if (e->command != NULL) {
\r
7352 e->command = NULL;
\r
7356 e = icsTextMenuEntry;
\r
7357 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
7358 if (*p == ';' || *p == '\n') {
\r
7359 e->item = strdup("-");
\r
7360 e->command = NULL;
\r
7362 } else if (*p == '-') {
\r
7363 e->item = strdup("-");
\r
7364 e->command = NULL;
\r
7368 char *q, *r, *s, *t;
\r
7370 q = strchr(p, ',');
\r
7371 if (q == NULL) break;
\r
7373 r = strchr(q + 1, ',');
\r
7374 if (r == NULL) break;
\r
7376 s = strchr(r + 1, ',');
\r
7377 if (s == NULL) break;
\r
7380 t = strchr(s + 1, c);
\r
7383 t = strchr(s + 1, c);
\r
7385 if (t != NULL) *t = NULLCHAR;
\r
7386 e->item = strdup(p);
\r
7387 e->command = strdup(q + 1);
\r
7388 e->getname = *(r + 1) != '0';
\r
7389 e->immediate = *(s + 1) != '0';
\r
7393 if (t == NULL) break;
\r
7402 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
7406 hmenu = LoadMenu(hInst, "TextMenu");
\r
7407 h = GetSubMenu(hmenu, 0);
\r
7409 if (strcmp(e->item, "-") == 0) {
\r
7410 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
7412 if (e->item[0] == '|') {
\r
7413 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
7414 IDM_CommandX + i, &e->item[1]);
\r
7416 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
7425 WNDPROC consoleTextWindowProc;
\r
7428 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
7430 char buf[MSG_SIZ], name[MSG_SIZ];
\r
7431 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7435 SetWindowText(hInput, command);
\r
7437 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7439 sel.cpMin = 999999;
\r
7440 sel.cpMax = 999999;
\r
7441 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7446 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7447 if (sel.cpMin == sel.cpMax) {
\r
7448 /* Expand to surrounding word */
\r
7451 tr.chrg.cpMax = sel.cpMin;
\r
7452 tr.chrg.cpMin = --sel.cpMin;
\r
7453 if (sel.cpMin < 0) break;
\r
7454 tr.lpstrText = name;
\r
7455 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7456 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7460 tr.chrg.cpMin = sel.cpMax;
\r
7461 tr.chrg.cpMax = ++sel.cpMax;
\r
7462 tr.lpstrText = name;
\r
7463 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
7464 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
7467 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7468 MessageBeep(MB_ICONEXCLAMATION);
\r
7472 tr.lpstrText = name;
\r
7473 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
7475 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
7476 MessageBeep(MB_ICONEXCLAMATION);
\r
7479 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7482 sprintf(buf, "%s %s", command, name);
\r
7483 SetWindowText(hInput, buf);
\r
7484 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7486 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7487 SetWindowText(hInput, buf);
\r
7488 sel.cpMin = 999999;
\r
7489 sel.cpMax = 999999;
\r
7490 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7496 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7501 switch (message) {
\r
7503 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7506 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7509 sel.cpMin = 999999;
\r
7510 sel.cpMax = 999999;
\r
7511 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7512 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7517 if (wParam == '\t') {
\r
7518 if (GetKeyState(VK_SHIFT) < 0) {
\r
7520 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7521 if (buttonDesc[0].hwnd) {
\r
7522 SetFocus(buttonDesc[0].hwnd);
\r
7524 SetFocus(hwndMain);
\r
7528 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7531 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7533 SendMessage(hInput, message, wParam, lParam);
\r
7537 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7539 return SendMessage(hInput, message, wParam, lParam);
\r
7540 case WM_MBUTTONDOWN:
\r
7541 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7542 case WM_RBUTTONDOWN:
\r
7543 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7544 /* Move selection here if it was empty */
\r
7546 pt.x = LOWORD(lParam);
\r
7547 pt.y = HIWORD(lParam);
\r
7548 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7549 if (sel.cpMin == sel.cpMax) {
\r
7550 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7551 sel.cpMax = sel.cpMin;
\r
7552 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7554 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7557 case WM_RBUTTONUP:
\r
7558 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7559 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7560 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7563 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7564 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7565 if (sel.cpMin == sel.cpMax) {
\r
7566 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7567 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7569 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7570 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7572 pt.x = LOWORD(lParam);
\r
7573 pt.y = HIWORD(lParam);
\r
7574 MenuPopup(hwnd, pt, hmenu, -1);
\r
7578 switch (LOWORD(wParam)) {
\r
7579 case IDM_QuickPaste:
\r
7581 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7582 if (sel.cpMin == sel.cpMax) {
\r
7583 MessageBeep(MB_ICONEXCLAMATION);
\r
7586 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7587 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7588 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7593 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7596 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7599 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7603 int i = LOWORD(wParam) - IDM_CommandX;
\r
7604 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7605 icsTextMenuEntry[i].command != NULL) {
\r
7606 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7607 icsTextMenuEntry[i].getname,
\r
7608 icsTextMenuEntry[i].immediate);
\r
7616 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7619 WNDPROC consoleInputWindowProc;
\r
7622 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7624 char buf[MSG_SIZ];
\r
7626 static BOOL sendNextChar = FALSE;
\r
7627 static BOOL quoteNextChar = FALSE;
\r
7628 InputSource *is = consoleInputSource;
\r
7632 switch (message) {
\r
7634 if (!appData.localLineEditing || sendNextChar) {
\r
7635 is->buf[0] = (CHAR) wParam;
\r
7637 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7638 sendNextChar = FALSE;
\r
7641 if (quoteNextChar) {
\r
7642 buf[0] = (char) wParam;
\r
7643 buf[1] = NULLCHAR;
\r
7644 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7645 quoteNextChar = FALSE;
\r
7649 case '\r': /* Enter key */
\r
7650 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7651 if (consoleEcho) SaveInHistory(is->buf);
\r
7652 is->buf[is->count++] = '\n';
\r
7653 is->buf[is->count] = NULLCHAR;
\r
7654 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7655 if (consoleEcho) {
\r
7656 ConsoleOutput(is->buf, is->count, TRUE);
\r
7657 } else if (appData.localLineEditing) {
\r
7658 ConsoleOutput("\n", 1, TRUE);
\r
7661 case '\033': /* Escape key */
\r
7662 SetWindowText(hwnd, "");
\r
7663 cf.cbSize = sizeof(CHARFORMAT);
\r
7664 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7665 if (consoleEcho) {
\r
7666 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7668 cf.crTextColor = COLOR_ECHOOFF;
\r
7670 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7671 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7673 case '\t': /* Tab key */
\r
7674 if (GetKeyState(VK_SHIFT) < 0) {
\r
7676 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7679 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7680 if (buttonDesc[0].hwnd) {
\r
7681 SetFocus(buttonDesc[0].hwnd);
\r
7683 SetFocus(hwndMain);
\r
7687 case '\023': /* Ctrl+S */
\r
7688 sendNextChar = TRUE;
\r
7690 case '\021': /* Ctrl+Q */
\r
7691 quoteNextChar = TRUE;
\r
7700 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7701 p = PrevInHistory(buf);
\r
7703 SetWindowText(hwnd, p);
\r
7704 sel.cpMin = 999999;
\r
7705 sel.cpMax = 999999;
\r
7706 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7711 p = NextInHistory();
\r
7713 SetWindowText(hwnd, p);
\r
7714 sel.cpMin = 999999;
\r
7715 sel.cpMax = 999999;
\r
7716 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7722 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7726 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7730 case WM_MBUTTONDOWN:
\r
7731 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7732 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7734 case WM_RBUTTONUP:
\r
7735 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7736 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7737 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7741 hmenu = LoadMenu(hInst, "InputMenu");
\r
7742 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7743 if (sel.cpMin == sel.cpMax) {
\r
7744 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7745 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7747 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7748 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7750 pt.x = LOWORD(lParam);
\r
7751 pt.y = HIWORD(lParam);
\r
7752 MenuPopup(hwnd, pt, hmenu, -1);
\r
7756 switch (LOWORD(wParam)) {
\r
7758 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7760 case IDM_SelectAll:
\r
7762 sel.cpMax = -1; /*999999?*/
\r
7763 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7766 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7769 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7772 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7777 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7780 #define CO_MAX 100000
\r
7781 #define CO_TRIM 1000
\r
7784 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7786 static SnapData sd;
\r
7787 static HWND hText, hInput, hFocus;
\r
7788 InputSource *is = consoleInputSource;
\r
7790 static int sizeX, sizeY;
\r
7791 int newSizeX, newSizeY;
\r
7794 switch (message) {
\r
7795 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7796 hwndConsole = hDlg;
\r
7797 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7798 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7800 consoleTextWindowProc = (WNDPROC)
\r
7801 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7802 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7803 consoleInputWindowProc = (WNDPROC)
\r
7804 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7805 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7806 Colorize(ColorNormal, TRUE);
\r
7807 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7808 ChangedConsoleFont();
\r
7809 GetClientRect(hDlg, &rect);
\r
7810 sizeX = rect.right;
\r
7811 sizeY = rect.bottom;
\r
7812 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7813 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7814 WINDOWPLACEMENT wp;
\r
7815 EnsureOnScreen(&consoleX, &consoleY);
\r
7816 wp.length = sizeof(WINDOWPLACEMENT);
\r
7818 wp.showCmd = SW_SHOW;
\r
7819 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7820 wp.rcNormalPosition.left = consoleX;
\r
7821 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7822 wp.rcNormalPosition.top = consoleY;
\r
7823 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7824 SetWindowPlacement(hDlg, &wp);
\r
7838 if (IsIconic(hDlg)) break;
\r
7839 newSizeX = LOWORD(lParam);
\r
7840 newSizeY = HIWORD(lParam);
\r
7841 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7842 RECT rectText, rectInput;
\r
7844 int newTextHeight, newTextWidth;
\r
7845 GetWindowRect(hText, &rectText);
\r
7846 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7847 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7848 if (newTextHeight < 0) {
\r
7849 newSizeY += -newTextHeight;
\r
7850 newTextHeight = 0;
\r
7852 SetWindowPos(hText, NULL, 0, 0,
\r
7853 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7854 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7855 pt.x = rectInput.left;
\r
7856 pt.y = rectInput.top + newSizeY - sizeY;
\r
7857 ScreenToClient(hDlg, &pt);
\r
7858 SetWindowPos(hInput, NULL,
\r
7859 pt.x, pt.y, /* needs client coords */
\r
7860 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7861 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7867 case WM_GETMINMAXINFO:
\r
7868 /* Prevent resizing window too small */
\r
7869 mmi = (MINMAXINFO *) lParam;
\r
7870 mmi->ptMinTrackSize.x = 100;
\r
7871 mmi->ptMinTrackSize.y = 100;
\r
7874 /* [AS] Snapping */
\r
7875 case WM_ENTERSIZEMOVE:
\r
7876 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7879 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7882 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7884 case WM_EXITSIZEMOVE:
\r
7885 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7888 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7896 if (hwndConsole) return;
\r
7897 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7898 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7903 ConsoleOutput(char* data, int length, int forceVisible)
\r
7908 char buf[CO_MAX+1];
\r
7911 static int delayLF = 0;
\r
7912 CHARRANGE savesel, sel;
\r
7914 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7922 while (length--) {
\r
7930 } else if (*p == '\007') {
\r
7931 MyPlaySound(&sounds[(int)SoundBell]);
\r
7938 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7939 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7940 /* Save current selection */
\r
7941 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7942 exlen = GetWindowTextLength(hText);
\r
7943 /* Find out whether current end of text is visible */
\r
7944 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7945 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7946 /* Trim existing text if it's too long */
\r
7947 if (exlen + (q - buf) > CO_MAX) {
\r
7948 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7951 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7952 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7954 savesel.cpMin -= trim;
\r
7955 savesel.cpMax -= trim;
\r
7956 if (exlen < 0) exlen = 0;
\r
7957 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7958 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7960 /* Append the new text */
\r
7961 sel.cpMin = exlen;
\r
7962 sel.cpMax = exlen;
\r
7963 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7964 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7965 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7966 if (forceVisible || exlen == 0 ||
\r
7967 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7968 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7969 /* Scroll to make new end of text visible if old end of text
\r
7970 was visible or new text is an echo of user typein */
\r
7971 sel.cpMin = 9999999;
\r
7972 sel.cpMax = 9999999;
\r
7973 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7974 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7975 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7976 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7978 if (savesel.cpMax == exlen || forceVisible) {
\r
7979 /* Move insert point to new end of text if it was at the old
\r
7980 end of text or if the new text is an echo of user typein */
\r
7981 sel.cpMin = 9999999;
\r
7982 sel.cpMax = 9999999;
\r
7983 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7985 /* Restore previous selection */
\r
7986 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7988 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7995 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7999 COLORREF oldFg, oldBg;
\r
8003 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
8005 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8006 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8007 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8010 rect.right = x + squareSize;
\r
8012 rect.bottom = y + squareSize;
\r
8015 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
8016 + (rightAlign ? (squareSize*2)/3 : 0),
\r
8017 y, ETO_CLIPPED|ETO_OPAQUE,
\r
8018 &rect, str, strlen(str), NULL);
\r
8020 (void) SetTextColor(hdc, oldFg);
\r
8021 (void) SetBkColor(hdc, oldBg);
\r
8022 (void) SelectObject(hdc, oldFont);
\r
8026 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
8027 RECT *rect, char *color, char *flagFell)
\r
8031 COLORREF oldFg, oldBg;
\r
8034 if (appData.clockMode) {
\r
8036 sprintf(buf, "%c %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
8038 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
8045 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
8046 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
8048 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
8049 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
8051 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
8053 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
8054 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
8055 rect, str, strlen(str), NULL);
\r
8057 (void) SetTextColor(hdc, oldFg);
\r
8058 (void) SetBkColor(hdc, oldBg);
\r
8059 (void) SelectObject(hdc, oldFont);
\r
8064 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8070 if( count <= 0 ) {
\r
8071 if (appData.debugMode) {
\r
8072 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
8075 return ERROR_INVALID_USER_BUFFER;
\r
8078 ResetEvent(ovl->hEvent);
\r
8079 ovl->Offset = ovl->OffsetHigh = 0;
\r
8080 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
8084 err = GetLastError();
\r
8085 if (err == ERROR_IO_PENDING) {
\r
8086 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8090 err = GetLastError();
\r
8097 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
8102 ResetEvent(ovl->hEvent);
\r
8103 ovl->Offset = ovl->OffsetHigh = 0;
\r
8104 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
8108 err = GetLastError();
\r
8109 if (err == ERROR_IO_PENDING) {
\r
8110 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
8114 err = GetLastError();
\r
8120 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
8121 void CheckForInputBufferFull( InputSource * is )
\r
8123 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
8124 /* Look for end of line */
\r
8125 char * p = is->buf;
\r
8127 while( p < is->next && *p != '\n' ) {
\r
8131 if( p >= is->next ) {
\r
8132 if (appData.debugMode) {
\r
8133 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
\r
8136 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
8137 is->count = (DWORD) -1;
\r
8138 is->next = is->buf;
\r
8144 InputThread(LPVOID arg)
\r
8149 is = (InputSource *) arg;
\r
8150 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
8151 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
8152 while (is->hThread != NULL) {
\r
8153 is->error = DoReadFile(is->hFile, is->next,
\r
8154 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8155 &is->count, &ovl);
\r
8156 if (is->error == NO_ERROR) {
\r
8157 is->next += is->count;
\r
8159 if (is->error == ERROR_BROKEN_PIPE) {
\r
8160 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8163 is->count = (DWORD) -1;
\r
8164 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
8169 CheckForInputBufferFull( is );
\r
8171 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8173 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8175 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8178 CloseHandle(ovl.hEvent);
\r
8179 CloseHandle(is->hFile);
\r
8181 if (appData.debugMode) {
\r
8182 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
\r
8189 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
8191 NonOvlInputThread(LPVOID arg)
\r
8198 is = (InputSource *) arg;
\r
8199 while (is->hThread != NULL) {
\r
8200 is->error = ReadFile(is->hFile, is->next,
\r
8201 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
8202 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
8203 if (is->error == NO_ERROR) {
\r
8204 /* Change CRLF to LF */
\r
8205 if (is->next > is->buf) {
\r
8207 i = is->count + 1;
\r
8215 if (prev == '\r' && *p == '\n') {
\r
8227 if (is->error == ERROR_BROKEN_PIPE) {
\r
8228 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
8231 is->count = (DWORD) -1;
\r
8235 CheckForInputBufferFull( is );
\r
8237 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8239 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8241 if (is->count < 0) break; /* Quit on error */
\r
8243 CloseHandle(is->hFile);
\r
8248 SocketInputThread(LPVOID arg)
\r
8252 is = (InputSource *) arg;
\r
8253 while (is->hThread != NULL) {
\r
8254 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
8255 if ((int)is->count == SOCKET_ERROR) {
\r
8256 is->count = (DWORD) -1;
\r
8257 is->error = WSAGetLastError();
\r
8259 is->error = NO_ERROR;
\r
8260 is->next += is->count;
\r
8261 if (is->count == 0 && is->second == is) {
\r
8262 /* End of file on stderr; quit with no message */
\r
8266 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
8268 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
8270 if (is->count <= 0) break; /* Quit on EOF or error */
\r
8276 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
8280 is = (InputSource *) lParam;
\r
8281 if (is->lineByLine) {
\r
8282 /* Feed in lines one by one */
\r
8283 char *p = is->buf;
\r
8285 while (q < is->next) {
\r
8286 if (*q++ == '\n') {
\r
8287 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
8292 /* Move any partial line to the start of the buffer */
\r
8294 while (p < is->next) {
\r
8299 if (is->error != NO_ERROR || is->count == 0) {
\r
8300 /* Notify backend of the error. Note: If there was a partial
\r
8301 line at the end, it is not flushed through. */
\r
8302 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8305 /* Feed in the whole chunk of input at once */
\r
8306 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
8307 is->next = is->buf;
\r
8311 /*---------------------------------------------------------------------------*\
\r
8313 * Menu enables. Used when setting various modes.
\r
8315 \*---------------------------------------------------------------------------*/
\r
8323 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
8325 while (enab->item > 0) {
\r
8326 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
8331 Enables gnuEnables[] = {
\r
8332 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8333 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8334 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8335 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
8336 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
8337 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
8338 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8339 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
8340 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
8341 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8345 Enables icsEnables[] = {
\r
8346 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8347 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8348 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8349 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8350 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8351 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8352 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8353 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8354 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8355 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8356 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8357 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
8362 Enables zippyEnables[] = {
\r
8363 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8364 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
8365 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
8370 Enables ncpEnables[] = {
\r
8371 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
8372 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
8373 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8374 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8375 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8376 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
8377 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
8378 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
8379 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
8380 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
8381 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8382 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8383 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
8384 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
8385 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
8389 Enables trainingOnEnables[] = {
\r
8390 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
8391 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
8392 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
8393 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
8394 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
8395 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
8396 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
8397 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
8401 Enables trainingOffEnables[] = {
\r
8402 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
8403 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
8404 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
8405 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
8406 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
8407 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
8408 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
8409 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
8413 /* These modify either ncpEnables or gnuEnables */
\r
8414 Enables cmailEnables[] = {
\r
8415 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
8416 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
8417 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
8418 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
8419 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
8420 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
8421 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
8425 Enables machineThinkingEnables[] = {
\r
8426 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8427 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
8428 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
8429 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
8430 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
8431 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8432 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8433 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8434 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
8435 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
8436 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
8437 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
8438 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
8439 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
8440 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
8444 Enables userThinkingEnables[] = {
\r
8445 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8446 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
8447 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
8448 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
8449 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
8450 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8451 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8452 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8453 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
8454 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
8455 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
8456 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
8457 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
8458 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
8459 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
8463 /*---------------------------------------------------------------------------*\
\r
8465 * Front-end interface functions exported by XBoard.
\r
8466 * Functions appear in same order as prototypes in frontend.h.
\r
8468 \*---------------------------------------------------------------------------*/
\r
8472 static UINT prevChecked = 0;
\r
8473 static int prevPausing = 0;
\r
8476 if (pausing != prevPausing) {
\r
8477 prevPausing = pausing;
\r
8478 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
8479 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8480 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8483 switch (gameMode) {
\r
8484 case BeginningOfGame:
\r
8485 if (appData.icsActive)
\r
8486 nowChecked = IDM_IcsClient;
\r
8487 else if (appData.noChessProgram)
\r
8488 nowChecked = IDM_EditGame;
\r
8490 nowChecked = IDM_MachineBlack;
\r
8492 case MachinePlaysBlack:
\r
8493 nowChecked = IDM_MachineBlack;
\r
8495 case MachinePlaysWhite:
\r
8496 nowChecked = IDM_MachineWhite;
\r
8498 case TwoMachinesPlay:
\r
8499 nowChecked = IDM_TwoMachines;
\r
8502 nowChecked = IDM_AnalysisMode;
\r
8505 nowChecked = IDM_AnalyzeFile;
\r
8508 nowChecked = IDM_EditGame;
\r
8510 case PlayFromGameFile:
\r
8511 nowChecked = IDM_LoadGame;
\r
8513 case EditPosition:
\r
8514 nowChecked = IDM_EditPosition;
\r
8517 nowChecked = IDM_Training;
\r
8519 case IcsPlayingWhite:
\r
8520 case IcsPlayingBlack:
\r
8521 case IcsObserving:
\r
8523 nowChecked = IDM_IcsClient;
\r
8530 if (prevChecked != 0)
\r
8531 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8532 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8533 if (nowChecked != 0)
\r
8534 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8535 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8537 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8538 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8539 MF_BYCOMMAND|MF_ENABLED);
\r
8541 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8542 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8545 prevChecked = nowChecked;
\r
8551 HMENU hmenu = GetMenu(hwndMain);
\r
8552 SetMenuEnables(hmenu, icsEnables);
\r
8553 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8554 MF_BYPOSITION|MF_ENABLED);
\r
8556 if (appData.zippyPlay) {
\r
8557 SetMenuEnables(hmenu, zippyEnables);
\r
8565 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8571 HMENU hmenu = GetMenu(hwndMain);
\r
8572 SetMenuEnables(hmenu, ncpEnables);
\r
8573 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8574 MF_BYPOSITION|MF_GRAYED);
\r
8575 DrawMenuBar(hwndMain);
\r
8581 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8585 SetTrainingModeOn()
\r
8588 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8589 for (i = 0; i < N_BUTTONS; i++) {
\r
8590 if (buttonDesc[i].hwnd != NULL)
\r
8591 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8596 VOID SetTrainingModeOff()
\r
8599 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8600 for (i = 0; i < N_BUTTONS; i++) {
\r
8601 if (buttonDesc[i].hwnd != NULL)
\r
8602 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8608 SetUserThinkingEnables()
\r
8610 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8614 SetMachineThinkingEnables()
\r
8616 HMENU hMenu = GetMenu(hwndMain);
\r
8617 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8619 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8621 if (gameMode == MachinePlaysBlack) {
\r
8622 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8623 } else if (gameMode == MachinePlaysWhite) {
\r
8624 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8625 } else if (gameMode == TwoMachinesPlay) {
\r
8626 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8632 DisplayTitle(char *str)
\r
8634 char title[MSG_SIZ], *host;
\r
8635 if (str[0] != NULLCHAR) {
\r
8636 strcpy(title, str);
\r
8637 } else if (appData.icsActive) {
\r
8638 if (appData.icsCommPort[0] != NULLCHAR)
\r
8641 host = appData.icsHost;
\r
8642 sprintf(title, "%s: %s", szTitle, host);
\r
8643 } else if (appData.noChessProgram) {
\r
8644 strcpy(title, szTitle);
\r
8646 strcpy(title, szTitle);
\r
8647 strcat(title, ": ");
\r
8648 strcat(title, first.tidy);
\r
8650 SetWindowText(hwndMain, title);
\r
8655 DisplayMessage(char *str1, char *str2)
\r
8659 int remain = MESSAGE_TEXT_MAX - 1;
\r
8662 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8663 messageText[0] = NULLCHAR;
\r
8665 len = strlen(str1);
\r
8666 if (len > remain) len = remain;
\r
8667 strncpy(messageText, str1, len);
\r
8668 messageText[len] = NULLCHAR;
\r
8671 if (*str2 && remain >= 2) {
\r
8673 strcat(messageText, " ");
\r
8676 len = strlen(str2);
\r
8677 if (len > remain) len = remain;
\r
8678 strncat(messageText, str2, len);
\r
8680 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8682 if (IsIconic(hwndMain)) return;
\r
8683 hdc = GetDC(hwndMain);
\r
8684 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8685 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8686 &messageRect, messageText, strlen(messageText), NULL);
\r
8687 (void) SelectObject(hdc, oldFont);
\r
8688 (void) ReleaseDC(hwndMain, hdc);
\r
8692 DisplayError(char *str, int error)
\r
8694 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8700 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8701 NULL, error, LANG_NEUTRAL,
\r
8702 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8704 sprintf(buf, "%s:\n%s", str, buf2);
\r
8706 ErrorMap *em = errmap;
\r
8707 while (em->err != 0 && em->err != error) em++;
\r
8708 if (em->err != 0) {
\r
8709 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8711 sprintf(buf, "%s:\nError code %d", str, error);
\r
8716 ErrorPopUp("Error", buf);
\r
8721 DisplayMoveError(char *str)
\r
8723 fromX = fromY = -1;
\r
8724 ClearHighlights();
\r
8725 DrawPosition(FALSE, NULL);
\r
8726 if (appData.popupMoveErrors) {
\r
8727 ErrorPopUp("Error", str);
\r
8729 DisplayMessage(str, "");
\r
8730 moveErrorMessageUp = TRUE;
\r
8735 DisplayFatalError(char *str, int error, int exitStatus)
\r
8737 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8739 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8742 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8743 NULL, error, LANG_NEUTRAL,
\r
8744 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8746 sprintf(buf, "%s:\n%s", str, buf2);
\r
8748 ErrorMap *em = errmap;
\r
8749 while (em->err != 0 && em->err != error) em++;
\r
8750 if (em->err != 0) {
\r
8751 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8753 sprintf(buf, "%s:\nError code %d", str, error);
\r
8758 if (appData.debugMode) {
\r
8759 fprintf(debugFP, "%s: %s\n", label, str);
\r
8761 if (appData.popupExitMessage) {
\r
8762 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8763 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8765 ExitEvent(exitStatus);
\r
8770 DisplayInformation(char *str)
\r
8772 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8777 DisplayNote(char *str)
\r
8779 ErrorPopUp("Note", str);
\r
8784 char *title, *question, *replyPrefix;
\r
8789 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8791 static QuestionParams *qp;
\r
8792 char reply[MSG_SIZ];
\r
8795 switch (message) {
\r
8796 case WM_INITDIALOG:
\r
8797 qp = (QuestionParams *) lParam;
\r
8798 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8799 SetWindowText(hDlg, qp->title);
\r
8800 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8801 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8805 switch (LOWORD(wParam)) {
\r
8807 strcpy(reply, qp->replyPrefix);
\r
8808 if (*reply) strcat(reply, " ");
\r
8809 len = strlen(reply);
\r
8810 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8811 strcat(reply, "\n");
\r
8812 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8813 EndDialog(hDlg, TRUE);
\r
8814 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
8817 EndDialog(hDlg, FALSE);
\r
8828 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8830 QuestionParams qp;
\r
8834 qp.question = question;
\r
8835 qp.replyPrefix = replyPrefix;
\r
8837 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8838 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8839 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8840 FreeProcInstance(lpProc);
\r
8843 /* [AS] Pick FRC position */
\r
8844 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8846 static int * lpIndexFRC;
\r
8852 case WM_INITDIALOG:
\r
8853 lpIndexFRC = (int *) lParam;
\r
8855 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8857 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8858 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8859 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8860 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8865 switch( LOWORD(wParam) ) {
\r
8867 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8868 EndDialog( hDlg, 0 );
\r
8869 shuffleOpenings = TRUE; /* [HGM] shuffle: switch shuffling on for as long as we stay in current variant */
\r
8872 EndDialog( hDlg, 1 );
\r
8874 case IDC_NFG_Edit:
\r
8875 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8876 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8878 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8881 case IDC_NFG_Random:
\r
8882 sprintf( buf, "%d", myrandom() ); /* [HGM] shuffle: no longer limit to 960 */
\r
8883 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8896 int index = appData.defaultFrcPosition;
\r
8897 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8899 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8901 if( result == 0 ) {
\r
8902 appData.defaultFrcPosition = index;
\r
8908 /* [AS] Game list options */
\r
8914 static GLT_Item GLT_ItemInfo[] = {
\r
8915 { GLT_EVENT, "Event" },
\r
8916 { GLT_SITE, "Site" },
\r
8917 { GLT_DATE, "Date" },
\r
8918 { GLT_ROUND, "Round" },
\r
8919 { GLT_PLAYERS, "Players" },
\r
8920 { GLT_RESULT, "Result" },
\r
8921 { GLT_WHITE_ELO, "White Rating" },
\r
8922 { GLT_BLACK_ELO, "Black Rating" },
\r
8923 { GLT_TIME_CONTROL,"Time Control" },
\r
8924 { GLT_VARIANT, "Variant" },
\r
8925 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
8929 const char * GLT_FindItem( char id )
\r
8931 const char * result = 0;
\r
8933 GLT_Item * list = GLT_ItemInfo;
\r
8935 while( list->id != 0 ) {
\r
8936 if( list->id == id ) {
\r
8937 result = list->name;
\r
8947 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
8949 const char * name = GLT_FindItem( id );
\r
8952 if( index >= 0 ) {
\r
8953 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
8956 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
8961 void GLT_TagsToList( HWND hDlg, char * tags )
\r
8965 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8968 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8972 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
8974 pc = GLT_ALL_TAGS;
\r
8977 if( strchr( tags, *pc ) == 0 ) {
\r
8978 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8983 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8986 char GLT_ListItemToTag( HWND hDlg, int index )
\r
8988 char result = '\0';
\r
8991 GLT_Item * list = GLT_ItemInfo;
\r
8993 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
8994 while( list->id != 0 ) {
\r
8995 if( strcmp( list->name, name ) == 0 ) {
\r
8996 result = list->id;
\r
9007 void GLT_MoveSelection( HWND hDlg, int delta )
\r
9009 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
9010 int idx2 = idx1 + delta;
\r
9011 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9013 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
9016 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
9017 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
9018 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
9019 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
9023 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9025 static char glt[64];
\r
9026 static char * lpUserGLT;
\r
9030 case WM_INITDIALOG:
\r
9031 lpUserGLT = (char *) lParam;
\r
9033 strcpy( glt, lpUserGLT );
\r
9035 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
9037 /* Initialize list */
\r
9038 GLT_TagsToList( hDlg, glt );
\r
9040 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
9045 switch( LOWORD(wParam) ) {
\r
9048 char * pc = lpUserGLT;
\r
9050 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
9054 id = GLT_ListItemToTag( hDlg, idx );
\r
9058 } while( id != '\0' );
\r
9060 EndDialog( hDlg, 0 );
\r
9063 EndDialog( hDlg, 1 );
\r
9066 case IDC_GLT_Default:
\r
9067 strcpy( glt, GLT_DEFAULT_TAGS );
\r
9068 GLT_TagsToList( hDlg, glt );
\r
9071 case IDC_GLT_Restore:
\r
9072 strcpy( glt, lpUserGLT );
\r
9073 GLT_TagsToList( hDlg, glt );
\r
9077 GLT_MoveSelection( hDlg, -1 );
\r
9080 case IDC_GLT_Down:
\r
9081 GLT_MoveSelection( hDlg, +1 );
\r
9091 int GameListOptions()
\r
9095 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
9097 strcpy( glt, appData.gameListTags );
\r
9099 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
9101 if( result == 0 ) {
\r
9102 /* [AS] Memory leak here! */
\r
9103 appData.gameListTags = strdup( glt );
\r
9111 DisplayIcsInteractionTitle(char *str)
\r
9113 char consoleTitle[MSG_SIZ];
\r
9115 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
9116 SetWindowText(hwndConsole, consoleTitle);
\r
9120 DrawPosition(int fullRedraw, Board board)
\r
9122 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
9129 fromX = fromY = -1;
\r
9130 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
9131 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9132 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
9133 dragInfo.lastpos = dragInfo.pos;
\r
9134 dragInfo.start.x = dragInfo.start.y = -1;
\r
9135 dragInfo.from = dragInfo.start;
\r
9137 DrawPosition(TRUE, NULL);
\r
9143 CommentPopUp(char *title, char *str)
\r
9145 HWND hwnd = GetActiveWindow();
\r
9146 EitherCommentPopUp(0, title, str, FALSE);
\r
9147 SetActiveWindow(hwnd);
\r
9151 CommentPopDown(void)
\r
9153 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
9154 if (commentDialog) {
\r
9155 ShowWindow(commentDialog, SW_HIDE);
\r
9157 commentDialogUp = FALSE;
\r
9161 EditCommentPopUp(int index, char *title, char *str)
\r
9163 EitherCommentPopUp(index, title, str, TRUE);
\r
9170 MyPlaySound(&sounds[(int)SoundMove]);
\r
9173 VOID PlayIcsWinSound()
\r
9175 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
9178 VOID PlayIcsLossSound()
\r
9180 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
9183 VOID PlayIcsDrawSound()
\r
9185 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
9188 VOID PlayIcsUnfinishedSound()
\r
9190 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
9196 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
9204 consoleEcho = TRUE;
\r
9205 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9206 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
9207 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
9216 consoleEcho = FALSE;
\r
9217 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
9218 /* This works OK: set text and background both to the same color */
\r
9220 cf.crTextColor = COLOR_ECHOOFF;
\r
9221 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
9222 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
9225 /* No Raw()...? */
\r
9227 void Colorize(ColorClass cc, int continuation)
\r
9229 currentColorClass = cc;
\r
9230 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
9231 consoleCF.crTextColor = textAttribs[cc].color;
\r
9232 consoleCF.dwEffects = textAttribs[cc].effects;
\r
9233 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
9239 static char buf[MSG_SIZ];
\r
9240 DWORD bufsiz = MSG_SIZ;
\r
9242 if(appData.userName != NULL && appData.userName[0] != 0) {
\r
9243 return appData.userName; /* [HGM] username: prefer name selected by user over his system login */
\r
9245 if (!GetUserName(buf, &bufsiz)) {
\r
9246 /*DisplayError("Error getting user name", GetLastError());*/
\r
9247 strcpy(buf, "User");
\r
9255 static char buf[MSG_SIZ];
\r
9256 DWORD bufsiz = MSG_SIZ;
\r
9258 if (!GetComputerName(buf, &bufsiz)) {
\r
9259 /*DisplayError("Error getting host name", GetLastError());*/
\r
9260 strcpy(buf, "Unknown");
\r
9267 ClockTimerRunning()
\r
9269 return clockTimerEvent != 0;
\r
9275 if (clockTimerEvent == 0) return FALSE;
\r
9276 KillTimer(hwndMain, clockTimerEvent);
\r
9277 clockTimerEvent = 0;
\r
9282 StartClockTimer(long millisec)
\r
9284 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
9285 (UINT) millisec, NULL);
\r
9289 DisplayWhiteClock(long timeRemaining, int highlight)
\r
9292 hdc = GetDC(hwndMain);
\r
9293 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9295 if (!IsIconic(hwndMain)) {
\r
9296 DisplayAClock(hdc, timeRemaining, highlight, flipClock ? &blackRect : &whiteRect, "White", flag);
\r
9298 if (highlight && iconCurrent == iconBlack) {
\r
9299 iconCurrent = iconWhite;
\r
9300 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9301 if (IsIconic(hwndMain)) {
\r
9302 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9305 (void) ReleaseDC(hwndMain, hdc);
\r
9307 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9311 DisplayBlackClock(long timeRemaining, int highlight)
\r
9314 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
9316 hdc = GetDC(hwndMain);
\r
9317 if (!IsIconic(hwndMain)) {
\r
9318 DisplayAClock(hdc, timeRemaining, highlight, flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
9320 if (highlight && iconCurrent == iconWhite) {
\r
9321 iconCurrent = iconBlack;
\r
9322 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9323 if (IsIconic(hwndMain)) {
\r
9324 DrawIcon(hdc, 2, 2, iconCurrent);
\r
9327 (void) ReleaseDC(hwndMain, hdc);
\r
9329 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
9334 LoadGameTimerRunning()
\r
9336 return loadGameTimerEvent != 0;
\r
9340 StopLoadGameTimer()
\r
9342 if (loadGameTimerEvent == 0) return FALSE;
\r
9343 KillTimer(hwndMain, loadGameTimerEvent);
\r
9344 loadGameTimerEvent = 0;
\r
9349 StartLoadGameTimer(long millisec)
\r
9351 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
9352 (UINT) millisec, NULL);
\r
9360 char fileTitle[MSG_SIZ];
\r
9362 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
9363 f = OpenFileDialog(hwndMain, "a", defName,
\r
9364 appData.oldSaveStyle ? "gam" : "pgn",
\r
9366 "Save Game to File", NULL, fileTitle, NULL);
\r
9368 SaveGame(f, 0, "");
\r
9375 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
9377 if (delayedTimerEvent != 0) {
\r
9378 if (appData.debugMode) {
\r
9379 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
9381 KillTimer(hwndMain, delayedTimerEvent);
\r
9382 delayedTimerEvent = 0;
\r
9383 delayedTimerCallback();
\r
9385 delayedTimerCallback = cb;
\r
9386 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
9387 (UINT) millisec, NULL);
\r
9390 DelayedEventCallback
\r
9393 if (delayedTimerEvent) {
\r
9394 return delayedTimerCallback;
\r
9401 CancelDelayedEvent()
\r
9403 if (delayedTimerEvent) {
\r
9404 KillTimer(hwndMain, delayedTimerEvent);
\r
9405 delayedTimerEvent = 0;
\r
9409 /* Start a child process running the given program.
\r
9410 The process's standard output can be read from "from", and its
\r
9411 standard input can be written to "to".
\r
9412 Exit with fatal error if anything goes wrong.
\r
9413 Returns an opaque pointer that can be used to destroy the process
\r
9417 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
9419 #define BUFSIZE 4096
\r
9421 HANDLE hChildStdinRd, hChildStdinWr,
\r
9422 hChildStdoutRd, hChildStdoutWr;
\r
9423 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
9424 SECURITY_ATTRIBUTES saAttr;
\r
9426 PROCESS_INFORMATION piProcInfo;
\r
9427 STARTUPINFO siStartInfo;
\r
9429 char buf[MSG_SIZ];
\r
9432 if (appData.debugMode) {
\r
9433 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
9438 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
9439 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
9440 saAttr.bInheritHandle = TRUE;
\r
9441 saAttr.lpSecurityDescriptor = NULL;
\r
9444 * The steps for redirecting child's STDOUT:
\r
9445 * 1. Create anonymous pipe to be STDOUT for child.
\r
9446 * 2. Create a noninheritable duplicate of read handle,
\r
9447 * and close the inheritable read handle.
\r
9450 /* Create a pipe for the child's STDOUT. */
\r
9451 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
9452 return GetLastError();
\r
9455 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
9456 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
9457 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
9458 FALSE, /* not inherited */
\r
9459 DUPLICATE_SAME_ACCESS);
\r
9461 return GetLastError();
\r
9463 CloseHandle(hChildStdoutRd);
\r
9466 * The steps for redirecting child's STDIN:
\r
9467 * 1. Create anonymous pipe to be STDIN for child.
\r
9468 * 2. Create a noninheritable duplicate of write handle,
\r
9469 * and close the inheritable write handle.
\r
9472 /* Create a pipe for the child's STDIN. */
\r
9473 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
9474 return GetLastError();
\r
9477 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
9478 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
9479 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
9480 FALSE, /* not inherited */
\r
9481 DUPLICATE_SAME_ACCESS);
\r
9483 return GetLastError();
\r
9485 CloseHandle(hChildStdinWr);
\r
9487 /* Arrange to (1) look in dir for the child .exe file, and
\r
9488 * (2) have dir be the child's working directory. Interpret
\r
9489 * dir relative to the directory WinBoard loaded from. */
\r
9490 GetCurrentDirectory(MSG_SIZ, buf);
\r
9491 SetCurrentDirectory(installDir);
\r
9492 SetCurrentDirectory(dir);
\r
9494 /* Now create the child process. */
\r
9496 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9497 siStartInfo.lpReserved = NULL;
\r
9498 siStartInfo.lpDesktop = NULL;
\r
9499 siStartInfo.lpTitle = NULL;
\r
9500 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9501 siStartInfo.cbReserved2 = 0;
\r
9502 siStartInfo.lpReserved2 = NULL;
\r
9503 siStartInfo.hStdInput = hChildStdinRd;
\r
9504 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9505 siStartInfo.hStdError = hChildStdoutWr;
\r
9507 fSuccess = CreateProcess(NULL,
\r
9508 cmdLine, /* command line */
\r
9509 NULL, /* process security attributes */
\r
9510 NULL, /* primary thread security attrs */
\r
9511 TRUE, /* handles are inherited */
\r
9512 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9513 NULL, /* use parent's environment */
\r
9515 &siStartInfo, /* STARTUPINFO pointer */
\r
9516 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9518 err = GetLastError();
\r
9519 SetCurrentDirectory(buf); /* return to prev directory */
\r
9524 /* Close the handles we don't need in the parent */
\r
9525 CloseHandle(piProcInfo.hThread);
\r
9526 CloseHandle(hChildStdinRd);
\r
9527 CloseHandle(hChildStdoutWr);
\r
9529 /* Prepare return value */
\r
9530 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9531 cp->kind = CPReal;
\r
9532 cp->hProcess = piProcInfo.hProcess;
\r
9533 cp->pid = piProcInfo.dwProcessId;
\r
9534 cp->hFrom = hChildStdoutRdDup;
\r
9535 cp->hTo = hChildStdinWrDup;
\r
9537 *pr = (void *) cp;
\r
9539 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9540 2000 where engines sometimes don't see the initial command(s)
\r
9541 from WinBoard and hang. I don't understand how that can happen,
\r
9542 but the Sleep is harmless, so I've put it in. Others have also
\r
9543 reported what may be the same problem, so hopefully this will fix
\r
9544 it for them too. */
\r
9552 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9554 ChildProc *cp; int result;
\r
9556 cp = (ChildProc *) pr;
\r
9557 if (cp == NULL) return;
\r
9559 switch (cp->kind) {
\r
9561 /* TerminateProcess is considered harmful, so... */
\r
9562 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9563 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9564 /* The following doesn't work because the chess program
\r
9565 doesn't "have the same console" as WinBoard. Maybe
\r
9566 we could arrange for this even though neither WinBoard
\r
9567 nor the chess program uses a console for stdio? */
\r
9568 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9570 /* [AS] Special termination modes for misbehaving programs... */
\r
9571 if( signal == 9 ) {
\r
9572 result = TerminateProcess( cp->hProcess, 0 );
\r
9574 if ( appData.debugMode) {
\r
9575 fprintf( debugFP, "Terminating process %u, result=%d\n", cp->pid, result );
\r
9578 else if( signal == 10 ) {
\r
9579 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9581 if( dw != WAIT_OBJECT_0 ) {
\r
9582 result = TerminateProcess( cp->hProcess, 0 );
\r
9584 if ( appData.debugMode) {
\r
9585 fprintf( debugFP, "Process %u still alive after timeout, killing... result=%d\n", cp->pid, result );
\r
9591 CloseHandle(cp->hProcess);
\r
9595 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9599 closesocket(cp->sock);
\r
9604 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9605 closesocket(cp->sock);
\r
9606 closesocket(cp->sock2);
\r
9614 InterruptChildProcess(ProcRef pr)
\r
9618 cp = (ChildProc *) pr;
\r
9619 if (cp == NULL) return;
\r
9620 switch (cp->kind) {
\r
9622 /* The following doesn't work because the chess program
\r
9623 doesn't "have the same console" as WinBoard. Maybe
\r
9624 we could arrange for this even though neither WinBoard
\r
9625 nor the chess program uses a console for stdio */
\r
9626 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9631 /* Can't interrupt */
\r
9635 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9642 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9644 char cmdLine[MSG_SIZ];
\r
9646 if (port[0] == NULLCHAR) {
\r
9647 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9649 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9651 return StartChildProcess(cmdLine, "", pr);
\r
9655 /* Code to open TCP sockets */
\r
9658 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9663 struct sockaddr_in sa, mysa;
\r
9664 struct hostent FAR *hp;
\r
9665 unsigned short uport;
\r
9666 WORD wVersionRequested;
\r
9669 /* Initialize socket DLL */
\r
9670 wVersionRequested = MAKEWORD(1, 1);
\r
9671 err = WSAStartup(wVersionRequested, &wsaData);
\r
9672 if (err != 0) return err;
\r
9675 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9676 err = WSAGetLastError();
\r
9681 /* Bind local address using (mostly) don't-care values.
\r
9683 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9684 mysa.sin_family = AF_INET;
\r
9685 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9686 uport = (unsigned short) 0;
\r
9687 mysa.sin_port = htons(uport);
\r
9688 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9689 == SOCKET_ERROR) {
\r
9690 err = WSAGetLastError();
\r
9695 /* Resolve remote host name */
\r
9696 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9697 if (!(hp = gethostbyname(host))) {
\r
9698 unsigned int b0, b1, b2, b3;
\r
9700 err = WSAGetLastError();
\r
9702 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9703 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9704 hp->h_addrtype = AF_INET;
\r
9706 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9707 hp->h_addr_list[0] = (char *) malloc(4);
\r
9708 hp->h_addr_list[0][0] = (char) b0;
\r
9709 hp->h_addr_list[0][1] = (char) b1;
\r
9710 hp->h_addr_list[0][2] = (char) b2;
\r
9711 hp->h_addr_list[0][3] = (char) b3;
\r
9717 sa.sin_family = hp->h_addrtype;
\r
9718 uport = (unsigned short) atoi(port);
\r
9719 sa.sin_port = htons(uport);
\r
9720 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9722 /* Make connection */
\r
9723 if (connect(s, (struct sockaddr *) &sa,
\r
9724 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9725 err = WSAGetLastError();
\r
9730 /* Prepare return value */
\r
9731 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9732 cp->kind = CPSock;
\r
9734 *pr = (ProcRef *) cp;
\r
9740 OpenCommPort(char *name, ProcRef *pr)
\r
9745 char fullname[MSG_SIZ];
\r
9747 if (*name != '\\')
\r
9748 sprintf(fullname, "\\\\.\\%s", name);
\r
9750 strcpy(fullname, name);
\r
9752 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9753 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9754 if (h == (HANDLE) -1) {
\r
9755 return GetLastError();
\r
9759 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9761 /* Accumulate characters until a 100ms pause, then parse */
\r
9762 ct.ReadIntervalTimeout = 100;
\r
9763 ct.ReadTotalTimeoutMultiplier = 0;
\r
9764 ct.ReadTotalTimeoutConstant = 0;
\r
9765 ct.WriteTotalTimeoutMultiplier = 0;
\r
9766 ct.WriteTotalTimeoutConstant = 0;
\r
9767 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9769 /* Prepare return value */
\r
9770 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9771 cp->kind = CPComm;
\r
9774 *pr = (ProcRef *) cp;
\r
9780 OpenLoopback(ProcRef *pr)
\r
9782 DisplayFatalError("Not implemented", 0, 1);
\r
9788 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9793 struct sockaddr_in sa, mysa;
\r
9794 struct hostent FAR *hp;
\r
9795 unsigned short uport;
\r
9796 WORD wVersionRequested;
\r
9799 char stderrPortStr[MSG_SIZ];
\r
9801 /* Initialize socket DLL */
\r
9802 wVersionRequested = MAKEWORD(1, 1);
\r
9803 err = WSAStartup(wVersionRequested, &wsaData);
\r
9804 if (err != 0) return err;
\r
9806 /* Resolve remote host name */
\r
9807 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9808 if (!(hp = gethostbyname(host))) {
\r
9809 unsigned int b0, b1, b2, b3;
\r
9811 err = WSAGetLastError();
\r
9813 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9814 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9815 hp->h_addrtype = AF_INET;
\r
9817 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9818 hp->h_addr_list[0] = (char *) malloc(4);
\r
9819 hp->h_addr_list[0][0] = (char) b0;
\r
9820 hp->h_addr_list[0][1] = (char) b1;
\r
9821 hp->h_addr_list[0][2] = (char) b2;
\r
9822 hp->h_addr_list[0][3] = (char) b3;
\r
9828 sa.sin_family = hp->h_addrtype;
\r
9829 uport = (unsigned short) 514;
\r
9830 sa.sin_port = htons(uport);
\r
9831 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9833 /* Bind local socket to unused "privileged" port address
\r
9835 s = INVALID_SOCKET;
\r
9836 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9837 mysa.sin_family = AF_INET;
\r
9838 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9839 for (fromPort = 1023;; fromPort--) {
\r
9840 if (fromPort < 0) {
\r
9842 return WSAEADDRINUSE;
\r
9844 if (s == INVALID_SOCKET) {
\r
9845 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9846 err = WSAGetLastError();
\r
9851 uport = (unsigned short) fromPort;
\r
9852 mysa.sin_port = htons(uport);
\r
9853 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9854 == SOCKET_ERROR) {
\r
9855 err = WSAGetLastError();
\r
9856 if (err == WSAEADDRINUSE) continue;
\r
9860 if (connect(s, (struct sockaddr *) &sa,
\r
9861 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9862 err = WSAGetLastError();
\r
9863 if (err == WSAEADDRINUSE) {
\r
9874 /* Bind stderr local socket to unused "privileged" port address
\r
9876 s2 = INVALID_SOCKET;
\r
9877 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9878 mysa.sin_family = AF_INET;
\r
9879 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9880 for (fromPort = 1023;; fromPort--) {
\r
9881 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9882 if (fromPort < 0) {
\r
9883 (void) closesocket(s);
\r
9885 return WSAEADDRINUSE;
\r
9887 if (s2 == INVALID_SOCKET) {
\r
9888 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9889 err = WSAGetLastError();
\r
9895 uport = (unsigned short) fromPort;
\r
9896 mysa.sin_port = htons(uport);
\r
9897 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9898 == SOCKET_ERROR) {
\r
9899 err = WSAGetLastError();
\r
9900 if (err == WSAEADDRINUSE) continue;
\r
9901 (void) closesocket(s);
\r
9905 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9906 err = WSAGetLastError();
\r
9907 if (err == WSAEADDRINUSE) {
\r
9909 s2 = INVALID_SOCKET;
\r
9912 (void) closesocket(s);
\r
9913 (void) closesocket(s2);
\r
9919 prevStderrPort = fromPort; // remember port used
\r
9920 sprintf(stderrPortStr, "%d", fromPort);
\r
9922 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9923 err = WSAGetLastError();
\r
9924 (void) closesocket(s);
\r
9925 (void) closesocket(s2);
\r
9930 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9931 err = WSAGetLastError();
\r
9932 (void) closesocket(s);
\r
9933 (void) closesocket(s2);
\r
9937 if (*user == NULLCHAR) user = UserName();
\r
9938 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9939 err = WSAGetLastError();
\r
9940 (void) closesocket(s);
\r
9941 (void) closesocket(s2);
\r
9945 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9946 err = WSAGetLastError();
\r
9947 (void) closesocket(s);
\r
9948 (void) closesocket(s2);
\r
9953 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9954 err = WSAGetLastError();
\r
9955 (void) closesocket(s);
\r
9956 (void) closesocket(s2);
\r
9960 (void) closesocket(s2); /* Stop listening */
\r
9962 /* Prepare return value */
\r
9963 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9964 cp->kind = CPRcmd;
\r
9967 *pr = (ProcRef *) cp;
\r
9974 AddInputSource(ProcRef pr, int lineByLine,
\r
9975 InputCallback func, VOIDSTAR closure)
\r
9977 InputSource *is, *is2 = NULL;
\r
9978 ChildProc *cp = (ChildProc *) pr;
\r
9980 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9981 is->lineByLine = lineByLine;
\r
9983 is->closure = closure;
\r
9984 is->second = NULL;
\r
9985 is->next = is->buf;
\r
9986 if (pr == NoProc) {
\r
9987 is->kind = CPReal;
\r
9988 consoleInputSource = is;
\r
9990 is->kind = cp->kind;
\r
9992 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9993 we create all threads suspended so that the is->hThread variable can be
\r
9994 safely assigned, then let the threads start with ResumeThread.
\r
9996 switch (cp->kind) {
\r
9998 is->hFile = cp->hFrom;
\r
9999 cp->hFrom = NULL; /* now owned by InputThread */
\r
10001 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
10002 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10006 is->hFile = cp->hFrom;
\r
10007 cp->hFrom = NULL; /* now owned by InputThread */
\r
10009 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
10010 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10014 is->sock = cp->sock;
\r
10016 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10017 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10021 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
10023 is->sock = cp->sock;
\r
10024 is->second = is2;
\r
10025 is2->sock = cp->sock2;
\r
10026 is2->second = is2;
\r
10028 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10029 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
10031 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
10032 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
10036 if( is->hThread != NULL ) {
\r
10037 ResumeThread( is->hThread );
\r
10040 if( is2 != NULL && is2->hThread != NULL ) {
\r
10041 ResumeThread( is2->hThread );
\r
10045 return (InputSourceRef) is;
\r
10049 RemoveInputSource(InputSourceRef isr)
\r
10053 is = (InputSource *) isr;
\r
10054 is->hThread = NULL; /* tell thread to stop */
\r
10055 CloseHandle(is->hThread);
\r
10056 if (is->second != NULL) {
\r
10057 is->second->hThread = NULL;
\r
10058 CloseHandle(is->second->hThread);
\r
10064 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
10067 int outCount = SOCKET_ERROR;
\r
10068 ChildProc *cp = (ChildProc *) pr;
\r
10069 static OVERLAPPED ovl;
\r
10071 if (pr == NoProc) {
\r
10072 ConsoleOutput(message, count, FALSE);
\r
10076 if (ovl.hEvent == NULL) {
\r
10077 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
10079 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
10081 switch (cp->kind) {
\r
10084 outCount = send(cp->sock, message, count, 0);
\r
10085 if (outCount == SOCKET_ERROR) {
\r
10086 *outError = WSAGetLastError();
\r
10088 *outError = NO_ERROR;
\r
10093 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10094 &dOutCount, NULL)) {
\r
10095 *outError = NO_ERROR;
\r
10096 outCount = (int) dOutCount;
\r
10098 *outError = GetLastError();
\r
10103 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
10104 &dOutCount, &ovl);
\r
10105 if (*outError == NO_ERROR) {
\r
10106 outCount = (int) dOutCount;
\r
10114 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
10117 /* Ignore delay, not implemented for WinBoard */
\r
10118 return OutputToProcess(pr, message, count, outError);
\r
10123 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
10124 char *buf, int count, int error)
\r
10126 DisplayFatalError("Not implemented", 0, 1);
\r
10129 /* see wgamelist.c for Game List functions */
\r
10130 /* see wedittags.c for Edit Tags functions */
\r
10137 char buf[MSG_SIZ];
\r
10140 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
10141 f = fopen(buf, "r");
\r
10143 ProcessICSInitScript(f);
\r
10151 StartAnalysisClock()
\r
10153 if (analysisTimerEvent) return;
\r
10154 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
10155 (UINT) 2000, NULL);
\r
10159 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
10161 static HANDLE hwndText;
\r
10163 static int sizeX, sizeY;
\r
10164 int newSizeX, newSizeY, flags;
\r
10167 switch (message) {
\r
10168 case WM_INITDIALOG: /* message: initialize dialog box */
\r
10169 /* Initialize the dialog items */
\r
10170 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
10171 SetWindowText(hDlg, analysisTitle);
\r
10172 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
10173 /* Size and position the dialog */
\r
10174 if (!analysisDialog) {
\r
10175 analysisDialog = hDlg;
\r
10176 flags = SWP_NOZORDER;
\r
10177 GetClientRect(hDlg, &rect);
\r
10178 sizeX = rect.right;
\r
10179 sizeY = rect.bottom;
\r
10180 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
10181 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
10182 WINDOWPLACEMENT wp;
\r
10183 EnsureOnScreen(&analysisX, &analysisY);
\r
10184 wp.length = sizeof(WINDOWPLACEMENT);
\r
10186 wp.showCmd = SW_SHOW;
\r
10187 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
10188 wp.rcNormalPosition.left = analysisX;
\r
10189 wp.rcNormalPosition.right = analysisX + analysisW;
\r
10190 wp.rcNormalPosition.top = analysisY;
\r
10191 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
10192 SetWindowPlacement(hDlg, &wp);
\r
10194 GetClientRect(hDlg, &rect);
\r
10195 newSizeX = rect.right;
\r
10196 newSizeY = rect.bottom;
\r
10197 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
10198 newSizeX, newSizeY);
\r
10199 sizeX = newSizeX;
\r
10200 sizeY = newSizeY;
\r
10205 case WM_COMMAND: /* message: received a command */
\r
10206 switch (LOWORD(wParam)) {
\r
10216 newSizeX = LOWORD(lParam);
\r
10217 newSizeY = HIWORD(lParam);
\r
10218 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
10219 sizeX = newSizeX;
\r
10220 sizeY = newSizeY;
\r
10223 case WM_GETMINMAXINFO:
\r
10224 /* Prevent resizing window too small */
\r
10225 mmi = (MINMAXINFO *) lParam;
\r
10226 mmi->ptMinTrackSize.x = 100;
\r
10227 mmi->ptMinTrackSize.y = 100;
\r
10234 AnalysisPopUp(char* title, char* str)
\r
10240 EngineOutputPopUp();
\r
10243 if (str == NULL) str = "";
\r
10244 p = (char *) malloc(2 * strlen(str) + 2);
\r
10247 if (*str == '\n') *q++ = '\r';
\r
10251 if (analysisText != NULL) free(analysisText);
\r
10252 analysisText = p;
\r
10254 if (analysisDialog) {
\r
10255 SetWindowText(analysisDialog, title);
\r
10256 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
10257 ShowWindow(analysisDialog, SW_SHOW);
\r
10259 analysisTitle = title;
\r
10260 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
10261 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
10262 hwndMain, (DLGPROC)lpProc);
\r
10263 FreeProcInstance(lpProc);
\r
10265 analysisDialogUp = TRUE;
\r
10269 AnalysisPopDown()
\r
10271 if (analysisDialog) {
\r
10272 ShowWindow(analysisDialog, SW_HIDE);
\r
10274 analysisDialogUp = FALSE;
\r
10279 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
10281 highlightInfo.sq[0].x = fromX;
\r
10282 highlightInfo.sq[0].y = fromY;
\r
10283 highlightInfo.sq[1].x = toX;
\r
10284 highlightInfo.sq[1].y = toY;
\r
10288 ClearHighlights()
\r
10290 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
10291 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
10295 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
10297 premoveHighlightInfo.sq[0].x = fromX;
\r
10298 premoveHighlightInfo.sq[0].y = fromY;
\r
10299 premoveHighlightInfo.sq[1].x = toX;
\r
10300 premoveHighlightInfo.sq[1].y = toY;
\r
10304 ClearPremoveHighlights()
\r
10306 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
10307 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
10311 ShutDownFrontEnd()
\r
10313 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
10314 DeleteClipboardTempFiles();
\r
10320 if (IsIconic(hwndMain))
\r
10321 ShowWindow(hwndMain, SW_RESTORE);
\r
10323 SetActiveWindow(hwndMain);
\r
10327 * Prototypes for animation support routines
\r
10329 static void ScreenSquare(int column, int row, POINT * pt);
\r
10330 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
10331 POINT frames[], int * nFrames);
\r
10334 #define kFactor 4
\r
10337 AnimateMove(board, fromX, fromY, toX, toY)
\r
10344 ChessSquare piece;
\r
10345 POINT start, finish, mid;
\r
10346 POINT frames[kFactor * 2 + 1];
\r
10349 if (!appData.animate) return;
\r
10350 if (doingSizing) return;
\r
10351 if (fromY < 0 || fromX < 0) return;
\r
10352 piece = board[fromY][fromX];
\r
10353 if (piece >= EmptySquare) return;
\r
10355 ScreenSquare(fromX, fromY, &start);
\r
10356 ScreenSquare(toX, toY, &finish);
\r
10358 /* All pieces except knights move in straight line */
\r
10359 if (piece != WhiteKnight && piece != BlackKnight) {
\r
10360 mid.x = start.x + (finish.x - start.x) / 2;
\r
10361 mid.y = start.y + (finish.y - start.y) / 2;
\r
10363 /* Knight: make diagonal movement then straight */
\r
10364 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
10365 mid.x = start.x + (finish.x - start.x) / 2;
\r
10366 mid.y = finish.y;
\r
10368 mid.x = finish.x;
\r
10369 mid.y = start.y + (finish.y - start.y) / 2;
\r
10373 /* Don't use as many frames for very short moves */
\r
10374 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
10375 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
10377 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
10379 animInfo.from.x = fromX;
\r
10380 animInfo.from.y = fromY;
\r
10381 animInfo.to.x = toX;
\r
10382 animInfo.to.y = toY;
\r
10383 animInfo.lastpos = start;
\r
10384 animInfo.piece = piece;
\r
10385 for (n = 0; n < nFrames; n++) {
\r
10386 animInfo.pos = frames[n];
\r
10387 DrawPosition(FALSE, NULL);
\r
10388 animInfo.lastpos = animInfo.pos;
\r
10389 Sleep(appData.animSpeed);
\r
10391 animInfo.pos = finish;
\r
10392 DrawPosition(FALSE, NULL);
\r
10393 animInfo.piece = EmptySquare;
\r
10396 /* Convert board position to corner of screen rect and color */
\r
10399 ScreenSquare(column, row, pt)
\r
10400 int column; int row; POINT * pt;
\r
10403 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
10404 pt->y = lineGap + row * (squareSize + lineGap);
\r
10406 pt->x = lineGap + column * (squareSize + lineGap);
\r
10407 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
10411 /* Generate a series of frame coords from start->mid->finish.
\r
10412 The movement rate doubles until the half way point is
\r
10413 reached, then halves back down to the final destination,
\r
10414 which gives a nice slow in/out effect. The algorithmn
\r
10415 may seem to generate too many intermediates for short
\r
10416 moves, but remember that the purpose is to attract the
\r
10417 viewers attention to the piece about to be moved and
\r
10418 then to where it ends up. Too few frames would be less
\r
10422 Tween(start, mid, finish, factor, frames, nFrames)
\r
10423 POINT * start; POINT * mid;
\r
10424 POINT * finish; int factor;
\r
10425 POINT frames[]; int * nFrames;
\r
10427 int n, fraction = 1, count = 0;
\r
10429 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
10430 for (n = 0; n < factor; n++)
\r
10432 for (n = 0; n < factor; n++) {
\r
10433 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
10434 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
10436 fraction = fraction / 2;
\r
10440 frames[count] = *mid;
\r
10443 /* Slow out, stepping 1/2, then 1/4, ... */
\r
10445 for (n = 0; n < factor; n++) {
\r
10446 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
10447 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
10449 fraction = fraction * 2;
\r
10451 *nFrames = count;
\r
10455 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
10460 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
10461 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
10463 OutputDebugString( buf );
\r
10466 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
10468 EvalGraphSet( first, last, current, pvInfoList );
\r
10471 void SetProgramStats( FrontEndProgramStats * stats )
\r
10476 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
10477 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
10479 OutputDebugString( buf );
\r
10482 EngineOutputUpdate( stats );
\r