2 * WinBoard.c -- Windows NT front end to XBoard
\r
3 * $Id: winboard.c,v 2.3 2003/11/25 05:25:20 mann Exp $
\r
5 * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
\r
6 * Enhancements Copyright 1992-2001 Free Software Foundation, Inc.
\r
8 * XBoard borrows its colors and the bitmaps.xchess bitmap set from XChess,
\r
9 * which was written and is copyrighted by Wayne Christopher.
\r
11 * The following terms apply to Digital Equipment Corporation's copyright
\r
12 * interest in XBoard:
\r
13 * ------------------------------------------------------------------------
\r
14 * All Rights Reserved
\r
16 * Permission to use, copy, modify, and distribute this software and its
\r
17 * documentation for any purpose and without fee is hereby granted,
\r
18 * provided that the above copyright notice appear in all copies and that
\r
19 * both that copyright notice and this permission notice appear in
\r
20 * supporting documentation, and that the name of Digital not be
\r
21 * used in advertising or publicity pertaining to distribution of the
\r
22 * software without specific, written prior permission.
\r
24 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
\r
25 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
\r
26 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
\r
27 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
\r
28 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
\r
29 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
\r
31 * ------------------------------------------------------------------------
\r
33 * The following terms apply to the enhanced version of XBoard distributed
\r
34 * by the Free Software Foundation:
\r
35 * ------------------------------------------------------------------------
\r
36 * This program is free software; you can redistribute it and/or modify
\r
37 * it under the terms of the GNU General Public License as published by
\r
38 * the Free Software Foundation; either version 2 of the License, or
\r
39 * (at your option) any later version.
\r
41 * This program is distributed in the hope that it will be useful,
\r
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
44 * GNU General Public License for more details.
\r
46 * You should have received a copy of the GNU General Public License
\r
47 * along with this program; if not, write to the Free Software
\r
48 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
\r
49 * ------------------------------------------------------------------------
\r
54 #include <windows.h>
\r
55 #include <winuser.h>
\r
56 #include <winsock.h>
\r
62 #include <sys/stat.h>
\r
65 #include <commdlg.h>
\r
67 #include <richedit.h>
\r
68 #include <mmsystem.h>
\r
76 #include "winboard.h"
\r
77 #include "frontend.h"
\r
78 #include "backend.h"
\r
80 #include "wclipbrd.h"
\r
81 #include "wgamelist.h"
\r
82 #include "wedittags.h"
\r
83 #include "woptions.h"
\r
84 #include "wsockerr.h"
\r
85 #include "defaults.h"
\r
89 void InitEngineUCI( const char * iniDir, ChessProgramState * cps );
\r
92 void mysrandom(unsigned int seed);
\r
94 extern int whiteFlag, blackFlag;
\r
95 Boolean flipClock = FALSE;
\r
97 void DisplayHoldingsCount(HDC hdc, int x, int y, int align, int copyNumber);
\r
100 ChessSquare piece;
\r
101 POINT pos; /* window coordinates of current pos */
\r
102 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
103 POINT from; /* board coordinates of the piece's orig pos */
\r
104 POINT to; /* board coordinates of the piece's new pos */
\r
107 static AnimInfo animInfo = { EmptySquare, {-1,-1}, {-1,-1}, {-1,-1} };
\r
110 POINT start; /* window coordinates of start pos */
\r
111 POINT pos; /* window coordinates of current pos */
\r
112 POINT lastpos; /* window coordinates of last pos - used for clipping */
\r
113 POINT from; /* board coordinates of the piece's orig pos */
\r
116 static DragInfo dragInfo = { {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1} };
\r
119 POINT sq[2]; /* board coordinates of from, to squares */
\r
122 static HighlightInfo highlightInfo = { {{-1, -1}, {-1, -1}} };
\r
123 static HighlightInfo premoveHighlightInfo = { {{-1, -1}, {-1, -1}} };
\r
125 /* Window class names */
\r
126 char szAppName[] = "WinBoard";
\r
127 char szConsoleName[] = "WBConsole";
\r
129 /* Title bar text */
\r
130 char szTitle[] = "WinBoard";
\r
131 char szConsoleTitle[] = "ICS Interaction";
\r
134 char *settingsFileName;
\r
135 BOOLEAN saveSettingsOnExit;
\r
136 char installDir[MSG_SIZ];
\r
138 BoardSize boardSize;
\r
139 BOOLEAN chessProgram;
\r
140 static int boardX, boardY, consoleX, consoleY, consoleW, consoleH;
\r
141 static int squareSize, lineGap, minorSize;
\r
142 static int winWidth, winHeight;
\r
143 static RECT messageRect, whiteRect, blackRect;
\r
144 static char messageText[MESSAGE_TEXT_MAX];
\r
145 static int clockTimerEvent = 0;
\r
146 static int loadGameTimerEvent = 0;
\r
147 static int analysisTimerEvent = 0;
\r
148 static DelayedEventCallback delayedTimerCallback;
\r
149 static int delayedTimerEvent = 0;
\r
150 static int buttonCount = 2;
\r
151 char *icsTextMenuString;
\r
153 char *firstChessProgramNames;
\r
154 char *secondChessProgramNames;
\r
156 #define ARG_MAX 128*1024 /* [AS] For Roger Brown's very long list! */
\r
158 #define PALETTESIZE 256
\r
160 HINSTANCE hInst; /* current instance */
\r
161 HWND hwndMain = NULL; /* root window*/
\r
162 HWND hwndConsole = NULL;
\r
163 BOOLEAN alwaysOnTop = FALSE;
\r
165 COLORREF lightSquareColor, darkSquareColor, whitePieceColor,
\r
166 blackPieceColor, highlightSquareColor, premoveHighlightColor;
\r
168 ColorClass currentColorClass;
\r
170 HWND hCommPort = NULL; /* currently open comm port */
\r
171 static HWND hwndPause; /* pause button */
\r
172 static HBITMAP pieceBitmap[3][(int) BlackPawn]; /* [HGM] nr of bitmaps referred to bP in stead of wK */
\r
173 static HBRUSH lightSquareBrush, darkSquareBrush,
\r
174 blackSquareBrush, /* [HGM] for band between board and holdings */
\r
175 whitePieceBrush, blackPieceBrush, iconBkgndBrush, outlineBrush;
\r
176 static POINT gridEndpoints[(BOARD_SIZE + 1) * 4];
\r
177 static DWORD gridVertexCounts[(BOARD_SIZE + 1) * 2];
\r
178 static HPEN gridPen = NULL;
\r
179 static HPEN highlightPen = NULL;
\r
180 static HPEN premovePen = NULL;
\r
181 static NPLOGPALETTE pLogPal;
\r
182 static BOOL paletteChanged = FALSE;
\r
183 static HICON iconWhite, iconBlack, iconCurrent;
\r
184 static int doingSizing = FALSE;
\r
185 static int lastSizing = 0;
\r
186 static int prevStderrPort;
\r
188 /* [AS] Support for background textures */
\r
189 #define BACK_TEXTURE_MODE_DISABLED 0
\r
190 #define BACK_TEXTURE_MODE_PLAIN 1
\r
191 #define BACK_TEXTURE_MODE_FULL_RANDOM 2
\r
193 static HBITMAP liteBackTexture = NULL;
\r
194 static HBITMAP darkBackTexture = NULL;
\r
195 static int liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
196 static int darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
197 static int backTextureSquareSize = 0;
\r
198 static struct { int x; int y; int mode; } backTextureSquareInfo[BOARD_SIZE][BOARD_SIZE];
\r
200 #if __GNUC__ && !defined(_winmajor)
\r
201 #define oldDialog 0 /* cygwin doesn't define _winmajor; mingw does */
\r
203 #define oldDialog (_winmajor < 4)
\r
206 char *defaultTextAttribs[] =
\r
208 COLOR_SHOUT, COLOR_SSHOUT, COLOR_CHANNEL1, COLOR_CHANNEL, COLOR_KIBITZ,
\r
209 COLOR_TELL, COLOR_CHALLENGE, COLOR_REQUEST, COLOR_SEEK, COLOR_NORMAL,
\r
219 int cliWidth, cliHeight;
\r
222 SizeInfo sizeInfo[] =
\r
224 { "tiny", 21, 0, 1, 1, 0, 0 },
\r
225 { "teeny", 25, 1, 1, 1, 0, 0 },
\r
226 { "dinky", 29, 1, 1, 1, 0, 0 },
\r
227 { "petite", 33, 1, 1, 1, 0, 0 },
\r
228 { "slim", 37, 2, 1, 0, 0, 0 },
\r
229 { "small", 40, 2, 1, 0, 0, 0 },
\r
230 { "mediocre", 45, 2, 1, 0, 0, 0 },
\r
231 { "middling", 49, 2, 0, 0, 0, 0 },
\r
232 { "average", 54, 2, 0, 0, 0, 0 },
\r
233 { "moderate", 58, 3, 0, 0, 0, 0 },
\r
234 { "medium", 64, 3, 0, 0, 0, 0 },
\r
235 { "bulky", 72, 3, 0, 0, 0, 0 },
\r
236 { "large", 80, 3, 0, 0, 0, 0 },
\r
237 { "big", 87, 3, 0, 0, 0, 0 },
\r
238 { "huge", 95, 3, 0, 0, 0, 0 },
\r
239 { "giant", 108, 3, 0, 0, 0, 0 },
\r
240 { "colossal", 116, 4, 0, 0, 0, 0 },
\r
241 { "titanic", 129, 4, 0, 0, 0, 0 },
\r
242 { NULL, 0, 0, 0, 0, 0, 0 }
\r
245 #define MF(x) {x, {0, }, {0, }, 0}
\r
246 MyFont fontRec[NUM_SIZES][NUM_FONTS] =
\r
248 { MF(CLOCK_FONT_TINY), MF(MESSAGE_FONT_TINY), MF(COORD_FONT_TINY), MF(CONSOLE_FONT_TINY), MF(COMMENT_FONT_TINY), MF(EDITTAGS_FONT_TINY), MF(MOVEHISTORY_FONT_ALL) },
\r
249 { MF(CLOCK_FONT_TEENY), MF(MESSAGE_FONT_TEENY), MF(COORD_FONT_TEENY), MF(CONSOLE_FONT_TEENY), MF(COMMENT_FONT_TEENY), MF(EDITTAGS_FONT_TEENY), MF(MOVEHISTORY_FONT_ALL) },
\r
250 { MF(CLOCK_FONT_DINKY), MF(MESSAGE_FONT_DINKY), MF(COORD_FONT_DINKY), MF(CONSOLE_FONT_DINKY), MF(COMMENT_FONT_DINKY), MF(EDITTAGS_FONT_DINKY), MF(MOVEHISTORY_FONT_ALL) },
\r
251 { MF(CLOCK_FONT_PETITE), MF(MESSAGE_FONT_PETITE), MF(COORD_FONT_PETITE), MF(CONSOLE_FONT_PETITE), MF(COMMENT_FONT_PETITE), MF(EDITTAGS_FONT_PETITE), MF(MOVEHISTORY_FONT_ALL) },
\r
252 { MF(CLOCK_FONT_SLIM), MF(MESSAGE_FONT_SLIM), MF(COORD_FONT_SLIM), MF(CONSOLE_FONT_SLIM), MF(COMMENT_FONT_SLIM), MF(EDITTAGS_FONT_SLIM), MF(MOVEHISTORY_FONT_ALL) },
\r
253 { MF(CLOCK_FONT_SMALL), MF(MESSAGE_FONT_SMALL), MF(COORD_FONT_SMALL), MF(CONSOLE_FONT_SMALL), MF(COMMENT_FONT_SMALL), MF(EDITTAGS_FONT_SMALL), MF(MOVEHISTORY_FONT_ALL) },
\r
254 { MF(CLOCK_FONT_MEDIOCRE), MF(MESSAGE_FONT_MEDIOCRE), MF(COORD_FONT_MEDIOCRE), MF(CONSOLE_FONT_MEDIOCRE), MF(COMMENT_FONT_MEDIOCRE), MF(EDITTAGS_FONT_MEDIOCRE), MF(MOVEHISTORY_FONT_ALL) },
\r
255 { MF(CLOCK_FONT_MIDDLING), MF(MESSAGE_FONT_MIDDLING), MF(COORD_FONT_MIDDLING), MF(CONSOLE_FONT_MIDDLING), MF(COMMENT_FONT_MIDDLING), MF(EDITTAGS_FONT_MIDDLING), MF(MOVEHISTORY_FONT_ALL) },
\r
256 { MF(CLOCK_FONT_AVERAGE), MF(MESSAGE_FONT_AVERAGE), MF(COORD_FONT_AVERAGE), MF(CONSOLE_FONT_AVERAGE), MF(COMMENT_FONT_AVERAGE), MF(EDITTAGS_FONT_AVERAGE), MF(MOVEHISTORY_FONT_ALL) },
\r
257 { MF(CLOCK_FONT_MODERATE), MF(MESSAGE_FONT_MODERATE), MF(COORD_FONT_MODERATE), MF(CONSOLE_FONT_MODERATE), MF(COMMENT_FONT_MODERATE), MF(EDITTAGS_FONT_MODERATE), MF(MOVEHISTORY_FONT_ALL) },
\r
258 { MF(CLOCK_FONT_MEDIUM), MF(MESSAGE_FONT_MEDIUM), MF(COORD_FONT_MEDIUM), MF(CONSOLE_FONT_MEDIUM), MF(COMMENT_FONT_MEDIUM), MF(EDITTAGS_FONT_MEDIUM), MF(MOVEHISTORY_FONT_ALL) },
\r
259 { MF(CLOCK_FONT_BULKY), MF(MESSAGE_FONT_BULKY), MF(COORD_FONT_BULKY), MF(CONSOLE_FONT_BULKY), MF(COMMENT_FONT_BULKY), MF(EDITTAGS_FONT_BULKY), MF(MOVEHISTORY_FONT_ALL) },
\r
260 { MF(CLOCK_FONT_LARGE), MF(MESSAGE_FONT_LARGE), MF(COORD_FONT_LARGE), MF(CONSOLE_FONT_LARGE), MF(COMMENT_FONT_LARGE), MF(EDITTAGS_FONT_LARGE), MF(MOVEHISTORY_FONT_ALL) },
\r
261 { MF(CLOCK_FONT_BIG), MF(MESSAGE_FONT_BIG), MF(COORD_FONT_BIG), MF(CONSOLE_FONT_BIG), MF(COMMENT_FONT_BIG), MF(EDITTAGS_FONT_BIG), MF(MOVEHISTORY_FONT_ALL) },
\r
262 { MF(CLOCK_FONT_HUGE), MF(MESSAGE_FONT_HUGE), MF(COORD_FONT_HUGE), MF(CONSOLE_FONT_HUGE), MF(COMMENT_FONT_HUGE), MF(EDITTAGS_FONT_HUGE), MF(MOVEHISTORY_FONT_ALL) },
\r
263 { MF(CLOCK_FONT_GIANT), MF(MESSAGE_FONT_GIANT), MF(COORD_FONT_GIANT), MF(CONSOLE_FONT_GIANT), MF(COMMENT_FONT_GIANT), MF(EDITTAGS_FONT_GIANT), MF(MOVEHISTORY_FONT_ALL) },
\r
264 { MF(CLOCK_FONT_COLOSSAL), MF(MESSAGE_FONT_COLOSSAL), MF(COORD_FONT_COLOSSAL), MF(CONSOLE_FONT_COLOSSAL), MF(COMMENT_FONT_COLOSSAL), MF(EDITTAGS_FONT_COLOSSAL), MF(MOVEHISTORY_FONT_ALL) },
\r
265 { MF(CLOCK_FONT_TITANIC), MF(MESSAGE_FONT_TITANIC), MF(COORD_FONT_TITANIC), MF(CONSOLE_FONT_TITANIC), MF(COMMENT_FONT_TITANIC), MF(EDITTAGS_FONT_TITANIC), MF(MOVEHISTORY_FONT_ALL) },
\r
268 MyFont *font[NUM_SIZES][NUM_FONTS];
\r
277 #define BUTTON_WIDTH (tinyLayout ? 16 : 32)
\r
278 #define N_BUTTONS 5
\r
280 MyButtonDesc buttonDesc[N_BUTTONS] =
\r
282 {"<<", IDM_ToStart, NULL, NULL},
\r
283 {"<", IDM_Backward, NULL, NULL},
\r
284 {"P", IDM_Pause, NULL, NULL},
\r
285 {">", IDM_Forward, NULL, NULL},
\r
286 {">>", IDM_ToEnd, NULL, NULL},
\r
289 int tinyLayout = 0, smallLayout = 0;
\r
290 #define MENU_BAR_ITEMS 6
\r
291 char *menuBarText[2][MENU_BAR_ITEMS+1] = {
\r
292 { "&File", "&Mode", "&Action", "&Step", "&Options", "&Help", NULL },
\r
293 { "&F", "&M", "&A", "&S", "&O", "&H", NULL },
\r
297 MySound sounds[(int)NSoundClasses];
\r
298 MyTextAttribs textAttribs[(int)NColorClasses];
\r
300 MyColorizeAttribs colorizeAttribs[] = {
\r
301 { (COLORREF)0, 0, "Shout Text" },
\r
302 { (COLORREF)0, 0, "SShout/CShout" },
\r
303 { (COLORREF)0, 0, "Channel 1 Text" },
\r
304 { (COLORREF)0, 0, "Channel Text" },
\r
305 { (COLORREF)0, 0, "Kibitz Text" },
\r
306 { (COLORREF)0, 0, "Tell Text" },
\r
307 { (COLORREF)0, 0, "Challenge Text" },
\r
308 { (COLORREF)0, 0, "Request Text" },
\r
309 { (COLORREF)0, 0, "Seek Text" },
\r
310 { (COLORREF)0, 0, "Normal Text" },
\r
311 { (COLORREF)0, 0, "None" }
\r
316 static char *commentTitle;
\r
317 static char *commentText;
\r
318 static int commentIndex;
\r
319 static Boolean editComment = FALSE;
\r
320 HWND commentDialog = NULL;
\r
321 BOOLEAN commentDialogUp = FALSE;
\r
322 static int commentX, commentY, commentH, commentW;
\r
324 static char *analysisTitle;
\r
325 static char *analysisText;
\r
326 HWND analysisDialog = NULL;
\r
327 BOOLEAN analysisDialogUp = FALSE;
\r
328 static int analysisX, analysisY, analysisH, analysisW;
\r
330 char errorTitle[MSG_SIZ];
\r
331 char errorMessage[2*MSG_SIZ];
\r
332 HWND errorDialog = NULL;
\r
333 BOOLEAN moveErrorMessageUp = FALSE;
\r
334 BOOLEAN consoleEcho = TRUE;
\r
335 CHARFORMAT consoleCF;
\r
336 COLORREF consoleBackgroundColor;
\r
338 char *programVersion;
\r
344 typedef int CPKind;
\r
353 SOCKET sock2; /* stderr socket for OpenRcmd */
\r
356 #define INPUT_SOURCE_BUF_SIZE 4096
\r
358 typedef struct _InputSource {
\r
365 char buf[INPUT_SOURCE_BUF_SIZE];
\r
369 InputCallback func;
\r
370 struct _InputSource *second; /* for stderr thread on CPRcmd */
\r
374 InputSource *consoleInputSource;
\r
379 VOID ConsoleOutput(char* data, int length, int forceVisible);
\r
380 VOID ConsoleCreate();
\r
382 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
383 VOID ColorizeTextPopup(HWND hwnd, ColorClass cc);
\r
384 VOID PrintCommSettings(FILE *f, char *name, DCB *dcb);
\r
385 VOID ParseCommSettings(char *arg, DCB *dcb);
\r
387 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
\r
388 VOID APIENTRY MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def);
\r
389 void ParseIcsTextMenu(char *icsTextMenuString);
\r
390 VOID PopUpMoveDialog(char firstchar);
\r
391 VOID UpdateSampleText(HWND hDlg, int id, MyColorizeAttribs *mca);
\r
395 int GameListOptions();
\r
397 HWND moveHistoryDialog = NULL;
\r
398 BOOLEAN moveHistoryDialogUp = FALSE;
\r
400 WindowPlacement wpMoveHistory;
\r
402 HWND evalGraphDialog = NULL;
\r
403 BOOLEAN evalGraphDialogUp = FALSE;
\r
405 WindowPlacement wpEvalGraph;
\r
407 HWND engineOutputDialog = NULL;
\r
408 BOOLEAN engineOutputDialogUp = FALSE;
\r
410 WindowPlacement wpEngineOutput;
\r
412 VOID MoveHistoryPopUp();
\r
413 VOID MoveHistoryPopDown();
\r
414 VOID MoveHistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
415 BOOL MoveHistoryIsUp();
\r
417 VOID EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo );
\r
418 VOID EvalGraphPopUp();
\r
419 VOID EvalGraphPopDown();
\r
420 BOOL EvalGraphIsUp();
\r
422 VOID EngineOutputPopUp();
\r
423 VOID EngineOutputPopDown();
\r
424 BOOL EngineOutputIsUp();
\r
425 VOID EngineOutputUpdate( FrontEndProgramStats * stats );
\r
427 VOID GothicPopUp(char *title, char up);
\r
429 * Setting "frozen" should disable all user input other than deleting
\r
430 * the window. We do this while engines are initializing themselves.
\r
432 static int frozen = 0;
\r
433 static int oldMenuItemState[MENU_BAR_ITEMS];
\r
439 if (frozen) return;
\r
441 hmenu = GetMenu(hwndMain);
\r
442 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
443 oldMenuItemState[i] = EnableMenuItem(hmenu, i, MF_BYPOSITION|MF_GRAYED);
\r
445 DrawMenuBar(hwndMain);
\r
448 /* Undo a FreezeUI */
\r
454 if (!frozen) return;
\r
456 hmenu = GetMenu(hwndMain);
\r
457 for (i=0; i<MENU_BAR_ITEMS; i++) {
\r
458 EnableMenuItem(hmenu, i, MF_BYPOSITION|oldMenuItemState[i]);
\r
460 DrawMenuBar(hwndMain);
\r
463 /*---------------------------------------------------------------------------*\
\r
467 \*---------------------------------------------------------------------------*/
\r
470 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
\r
471 LPSTR lpCmdLine, int nCmdShow)
\r
474 HANDLE hAccelMain, hAccelNoAlt, hAccelNoICS;
\r
478 LoadLibrary("RICHED32.DLL");
\r
479 consoleCF.cbSize = sizeof(CHARFORMAT);
\r
481 if (!InitApplication(hInstance)) {
\r
484 if (!InitInstance(hInstance, nCmdShow, lpCmdLine)) {
\r
488 hAccelMain = LoadAccelerators (hInstance, szAppName);
\r
489 hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");
\r
490 hAccelNoICS = LoadAccelerators( hInstance, "NO_ICS"); /* [AS] No Ctrl-V on ICS!!! */
\r
492 /* Acquire and dispatch messages until a WM_QUIT message is received. */
\r
494 while (GetMessage(&msg, /* message structure */
\r
495 NULL, /* handle of window receiving the message */
\r
496 0, /* lowest message to examine */
\r
497 0)) /* highest message to examine */
\r
499 if (!(commentDialog && IsDialogMessage(commentDialog, &msg)) &&
\r
500 !(moveHistoryDialog && IsDialogMessage(moveHistoryDialog, &msg)) &&
\r
501 !(evalGraphDialog && IsDialogMessage(evalGraphDialog, &msg)) &&
\r
502 !(engineOutputDialog && IsDialogMessage(engineOutputDialog, &msg)) &&
\r
503 !(editTagsDialog && IsDialogMessage(editTagsDialog, &msg)) &&
\r
504 !(gameListDialog && IsDialogMessage(gameListDialog, &msg)) &&
\r
505 !(errorDialog && IsDialogMessage(errorDialog, &msg)) &&
\r
506 !(!frozen && TranslateAccelerator(hwndMain, hAccelMain, &msg)) &&
\r
507 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoICS, &msg)) &&
\r
508 !(!hwndConsole && TranslateAccelerator(hwndMain, hAccelNoAlt, &msg))) {
\r
509 TranslateMessage(&msg); /* Translates virtual key codes */
\r
510 DispatchMessage(&msg); /* Dispatches message to window */
\r
515 return (msg.wParam); /* Returns the value from PostQuitMessage */
\r
518 /*---------------------------------------------------------------------------*\
\r
520 * Initialization functions
\r
522 \*---------------------------------------------------------------------------*/
\r
525 InitApplication(HINSTANCE hInstance)
\r
529 /* Fill in window class structure with parameters that describe the */
\r
532 wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s). */
\r
533 wc.lpfnWndProc = (WNDPROC)WndProc; /* Window Procedure */
\r
534 wc.cbClsExtra = 0; /* No per-class extra data. */
\r
535 wc.cbWndExtra = 0; /* No per-window extra data. */
\r
536 wc.hInstance = hInstance; /* Owner of this class */
\r
537 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
538 wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* Cursor */
\r
539 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); /* Default color */
\r
540 wc.lpszMenuName = szAppName; /* Menu name from .RC */
\r
541 wc.lpszClassName = szAppName; /* Name to register as */
\r
543 /* Register the window class and return success/failure code. */
\r
544 if (!RegisterClass(&wc)) return FALSE;
\r
546 wc.style = CS_HREDRAW | CS_VREDRAW;
\r
547 wc.lpfnWndProc = (WNDPROC)ConsoleWndProc;
\r
549 wc.cbWndExtra = DLGWINDOWEXTRA;
\r
550 wc.hInstance = hInstance;
\r
551 wc.hIcon = LoadIcon(hInstance, "icon_white");
\r
552 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
\r
553 wc.hbrBackground = (HBRUSH)(COLOR_MENU+1);
\r
554 wc.lpszMenuName = NULL;
\r
555 wc.lpszClassName = szConsoleName;
\r
557 if (!RegisterClass(&wc)) return FALSE;
\r
562 /* Set by InitInstance, used by EnsureOnScreen */
\r
563 int screenHeight, screenWidth;
\r
566 EnsureOnScreen(int *x, int *y)
\r
568 int gap = GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
\r
569 /* Be sure window at (x,y) is not off screen (or even mostly off screen) */
\r
570 if (*x > screenWidth - 32) *x = 0;
\r
571 if (*y > screenHeight - 32) *y = 0;
\r
572 if (*x < 10) *x = 10;
\r
573 if (*y < gap) *y = gap;
\r
577 InitInstance(HINSTANCE hInstance, int nCmdShow, LPSTR lpCmdLine)
\r
579 HWND hwnd; /* Main window handle. */
\r
581 WINDOWPLACEMENT wp;
\r
584 hInst = hInstance; /* Store instance handle in our global variable */
\r
586 if (SearchPath(NULL, "WinBoard.exe", NULL, MSG_SIZ, installDir, &filepart)) {
\r
587 *filepart = NULLCHAR;
\r
589 GetCurrentDirectory(MSG_SIZ, installDir);
\r
591 gameInfo.boardWidth = gameInfo.boardHeight = 8; // [HGM] won't have open window otherwise
\r
592 InitAppData(lpCmdLine); /* Get run-time parameters */
\r
593 if (appData.debugMode) {
\r
594 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
595 setbuf(debugFP, NULL);
\r
600 InitEngineUCI( installDir, &first );
\r
601 InitEngineUCI( installDir, &second );
\r
603 /* Create a main window for this application instance. */
\r
604 hwnd = CreateWindow(szAppName, szTitle,
\r
605 (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
\r
606 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
\r
607 NULL, NULL, hInstance, NULL);
\r
610 /* If window could not be created, return "failure" */
\r
615 iconWhite = LoadIcon(hInstance, "icon_white");
\r
616 iconBlack = LoadIcon(hInstance, "icon_black");
\r
617 iconCurrent = iconWhite;
\r
618 InitDrawingColors();
\r
619 screenHeight = GetSystemMetrics(SM_CYSCREEN);
\r
620 screenWidth = GetSystemMetrics(SM_CXSCREEN);
\r
621 for (ibs = (int) NUM_SIZES - 1; ibs >= 0; ibs--) {
\r
622 /* Compute window size for each board size, and use the largest
\r
623 size that fits on this screen as the default. */
\r
624 InitDrawingSizes((BoardSize)ibs, 0);
\r
625 if (boardSize == (BoardSize)-1 &&
\r
626 winHeight <= screenHeight
\r
627 - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYCAPTION) - 10
\r
628 && winWidth <= screenWidth) {
\r
629 boardSize = (BoardSize)ibs;
\r
632 InitDrawingSizes(boardSize, 0);
\r
634 buttonCount = GetSystemMetrics(SM_CMOUSEBUTTONS);
\r
636 /* [AS] Load textures if specified */
\r
637 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
639 if( appData.liteBackTextureFile && appData.liteBackTextureFile[0] != NULLCHAR && appData.liteBackTextureFile[0] != '*' ) {
\r
640 liteBackTexture = LoadImage( 0, appData.liteBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
641 liteBackTextureMode = appData.liteBackTextureMode;
\r
643 if (liteBackTexture == NULL && appData.debugMode) {
\r
644 fprintf( debugFP, "Unable to load lite texture bitmap '%s'\n", appData.liteBackTextureFile );
\r
648 if( appData.darkBackTextureFile && appData.darkBackTextureFile[0] != NULLCHAR && appData.darkBackTextureFile[0] != '*' ) {
\r
649 darkBackTexture = LoadImage( 0, appData.darkBackTextureFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
\r
650 darkBackTextureMode = appData.darkBackTextureMode;
\r
652 if (darkBackTexture == NULL && appData.debugMode) {
\r
653 fprintf( debugFP, "Unable to load dark texture bitmap '%s'\n", appData.darkBackTextureFile );
\r
657 mysrandom( (unsigned) time(NULL) );
\r
659 /* Make a console window if needed */
\r
660 if (appData.icsActive) {
\r
664 /* [AS] Restore layout */
\r
665 if( wpMoveHistory.visible ) {
\r
666 MoveHistoryPopUp();
\r
669 if( wpEvalGraph.visible ) {
\r
673 if( wpEngineOutput.visible ) {
\r
674 EngineOutputPopUp();
\r
679 /* Make the window visible; update its client area; and return "success" */
\r
680 EnsureOnScreen(&boardX, &boardY);
\r
681 wp.length = sizeof(WINDOWPLACEMENT);
\r
683 wp.showCmd = nCmdShow;
\r
684 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
685 wp.rcNormalPosition.left = boardX;
\r
686 wp.rcNormalPosition.right = boardX + winWidth;
\r
687 wp.rcNormalPosition.top = boardY;
\r
688 wp.rcNormalPosition.bottom = boardY + winHeight;
\r
689 SetWindowPlacement(hwndMain, &wp);
\r
691 SetWindowPos(hwndMain, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
692 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
694 /* [AS] Disable the FRC stuff if not playing the proper variant */
\r
695 if( gameInfo.variant != VariantFischeRandom ) {
\r
696 EnableMenuItem( GetMenu(hwndMain), IDM_NewGameFRC, MF_GRAYED );
\r
701 SetWindowPos(hwndConsole, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
\r
702 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
\r
704 ShowWindow(hwndConsole, nCmdShow);
\r
706 UpdateWindow(hwnd);
\r
714 ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
\r
715 ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
\r
716 ArgSettingsFilename
\r
724 String *pString; // ArgString
\r
725 int *pInt; // ArgInt
\r
726 float *pFloat; // ArgFloat
\r
727 Boolean *pBoolean; // ArgBoolean
\r
728 COLORREF *pColor; // ArgColor
\r
729 ColorClass cc; // ArgAttribs
\r
730 String *pFilename; // ArgFilename
\r
731 BoardSize *pBoardSize; // ArgBoardSize
\r
732 int whichFont; // ArgFont
\r
733 DCB *pDCB; // ArgCommSettings
\r
734 String *pFilename; // ArgSettingsFilename
\r
742 ArgDescriptor argDescriptors[] = {
\r
743 /* positional arguments */
\r
744 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
745 { "", ArgNone, NULL },
\r
746 /* keyword arguments */
\r
747 { "whitePieceColor", ArgColor, (LPVOID) &whitePieceColor, TRUE },
\r
748 { "wpc", ArgColor, (LPVOID) &whitePieceColor, FALSE },
\r
749 { "blackPieceColor", ArgColor, (LPVOID) &blackPieceColor, TRUE },
\r
750 { "bpc", ArgColor, (LPVOID) &blackPieceColor, FALSE },
\r
751 { "lightSquareColor", ArgColor, (LPVOID) &lightSquareColor, TRUE },
\r
752 { "lsc", ArgColor, (LPVOID) &lightSquareColor, FALSE },
\r
753 { "darkSquareColor", ArgColor, (LPVOID) &darkSquareColor, TRUE },
\r
754 { "dsc", ArgColor, (LPVOID) &darkSquareColor, FALSE },
\r
755 { "highlightSquareColor", ArgColor, (LPVOID) &highlightSquareColor, TRUE },
\r
756 { "hsc", ArgColor, (LPVOID) &highlightSquareColor, FALSE },
\r
757 { "premoveHighlightColor", ArgColor, (LPVOID) &premoveHighlightColor, TRUE },
\r
758 { "phc", ArgColor, (LPVOID) &premoveHighlightColor, FALSE },
\r
759 { "movesPerSession", ArgInt, (LPVOID) &appData.movesPerSession, TRUE },
\r
760 { "mps", ArgInt, (LPVOID) &appData.movesPerSession, FALSE },
\r
761 { "initString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
762 { "firstInitString", ArgString, (LPVOID) &appData.initString, FALSE },
\r
763 { "secondInitString", ArgString, (LPVOID) &appData.secondInitString, FALSE },
\r
764 { "firstComputerString", ArgString, (LPVOID) &appData.firstComputerString,
\r
766 { "secondComputerString", ArgString, (LPVOID) &appData.secondComputerString,
\r
768 { "firstChessProgram", ArgFilename, (LPVOID) &appData.firstChessProgram,
\r
770 { "fcp", ArgFilename, (LPVOID) &appData.firstChessProgram, FALSE },
\r
771 { "secondChessProgram", ArgFilename, (LPVOID) &appData.secondChessProgram,
\r
773 { "scp", ArgFilename, (LPVOID) &appData.secondChessProgram, FALSE },
\r
774 { "firstPlaysBlack", ArgBoolean, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
775 { "fb", ArgTrue, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
776 { "xfb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
777 { "-fb", ArgFalse, (LPVOID) &appData.firstPlaysBlack, FALSE },
\r
778 { "noChessProgram", ArgBoolean, (LPVOID) &appData.noChessProgram, FALSE },
\r
779 { "ncp", ArgTrue, (LPVOID) &appData.noChessProgram, FALSE },
\r
780 { "xncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
781 { "-ncp", ArgFalse, (LPVOID) &appData.noChessProgram, FALSE },
\r
782 { "firstHost", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
783 { "fh", ArgString, (LPVOID) &appData.firstHost, FALSE },
\r
784 { "secondHost", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
785 { "sh", ArgString, (LPVOID) &appData.secondHost, FALSE },
\r
786 { "firstDirectory", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
787 { "fd", ArgFilename, (LPVOID) &appData.firstDirectory, FALSE },
\r
788 { "secondDirectory", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
789 { "sd", ArgFilename, (LPVOID) &appData.secondDirectory, FALSE },
\r
790 /*!!bitmapDirectory?*/
\r
791 { "remoteShell", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
792 { "rsh", ArgFilename, (LPVOID) &appData.remoteShell, FALSE },
\r
793 { "remoteUser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
794 { "ruser", ArgString, (LPVOID) &appData.remoteUser, FALSE },
\r
795 { "timeDelay", ArgFloat, (LPVOID) &appData.timeDelay, TRUE },
\r
796 { "td", ArgFloat, (LPVOID) &appData.timeDelay, FALSE },
\r
797 { "timeControl", ArgString, (LPVOID) &appData.timeControl, TRUE },
\r
798 { "tc", ArgString, (LPVOID) &appData.timeControl, FALSE },
\r
799 { "timeIncrement", ArgInt, (LPVOID) &appData.timeIncrement, TRUE },
\r
800 { "inc", ArgInt, (LPVOID) &appData.timeIncrement, FALSE },
\r
801 { "internetChessServerMode", ArgBoolean, (LPVOID) &appData.icsActive, FALSE },
\r
802 { "ics", ArgTrue, (LPVOID) &appData.icsActive, FALSE },
\r
803 { "xics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
804 { "-ics", ArgFalse, (LPVOID) &appData.icsActive, FALSE },
\r
805 { "internetChessServerHost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
806 { "icshost", ArgString, (LPVOID) &appData.icsHost, FALSE },
\r
807 { "internetChessServerPort", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
808 { "icsport", ArgString, (LPVOID) &appData.icsPort, FALSE },
\r
809 { "internetChessServerCommPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
810 { "icscomm", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
811 { "internetChessServerComPort", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
812 { "icscom", ArgString, (LPVOID) &appData.icsCommPort, FALSE },
\r
813 { "internetChessServerLogonScript", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
814 { "icslogon", ArgFilename, (LPVOID) &appData.icsLogon, FALSE },
\r
815 { "useTelnet", ArgBoolean, (LPVOID) &appData.useTelnet, FALSE },
\r
816 { "telnet", ArgTrue, (LPVOID) &appData.useTelnet, FALSE },
\r
817 { "xtelnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
818 { "-telnet", ArgFalse, (LPVOID) &appData.useTelnet, FALSE },
\r
819 { "telnetProgram", ArgFilename, (LPVOID) &appData.telnetProgram, FALSE },
\r
820 { "icshelper", ArgFilename, (LPVOID) &appData.icsHelper, FALSE },
\r
821 { "gateway", ArgString, (LPVOID) &appData.gateway, FALSE },
\r
822 { "loadGameFile", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
823 { "lgf", ArgFilename, (LPVOID) &appData.loadGameFile, FALSE },
\r
824 { "loadGameIndex", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
825 { "lgi", ArgInt, (LPVOID) &appData.loadGameIndex, FALSE },
\r
826 { "saveGameFile", ArgFilename, (LPVOID) &appData.saveGameFile, TRUE },
\r
827 { "sgf", ArgFilename, (LPVOID) &appData.saveGameFile, FALSE },
\r
828 { "autoSaveGames", ArgBoolean, (LPVOID) &appData.autoSaveGames, TRUE },
\r
829 { "autosave", ArgTrue, (LPVOID) &appData.autoSaveGames, FALSE },
\r
830 { "xautosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
831 { "-autosave", ArgFalse, (LPVOID) &appData.autoSaveGames, FALSE },
\r
832 { "loadPositionFile", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
833 { "lpf", ArgFilename, (LPVOID) &appData.loadPositionFile, FALSE },
\r
834 { "loadPositionIndex", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
835 { "lpi", ArgInt, (LPVOID) &appData.loadPositionIndex, FALSE },
\r
836 { "savePositionFile", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
837 { "spf", ArgFilename, (LPVOID) &appData.savePositionFile, FALSE },
\r
838 { "matchMode", ArgBoolean, (LPVOID) &appData.matchMode, FALSE },
\r
839 { "mm", ArgTrue, (LPVOID) &appData.matchMode, FALSE },
\r
840 { "xmm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
841 { "-mm", ArgFalse, (LPVOID) &appData.matchMode, FALSE },
\r
842 { "matchGames", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
843 { "mg", ArgInt, (LPVOID) &appData.matchGames, FALSE },
\r
844 { "monoMode", ArgBoolean, (LPVOID) &appData.monoMode, TRUE },
\r
845 { "mono", ArgTrue, (LPVOID) &appData.monoMode, FALSE },
\r
846 { "xmono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
847 { "-mono", ArgFalse, (LPVOID) &appData.monoMode, FALSE },
\r
848 { "debugMode", ArgBoolean, (LPVOID) &appData.debugMode, FALSE },
\r
849 { "debug", ArgTrue, (LPVOID) &appData.debugMode, FALSE },
\r
850 { "xdebug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
851 { "-debug", ArgFalse, (LPVOID) &appData.debugMode, FALSE },
\r
852 { "clockMode", ArgBoolean, (LPVOID) &appData.clockMode, FALSE },
\r
853 { "clock", ArgTrue, (LPVOID) &appData.clockMode, FALSE },
\r
854 { "xclock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
855 { "-clock", ArgFalse, (LPVOID) &appData.clockMode, FALSE },
\r
856 { "searchTime", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
857 { "st", ArgString, (LPVOID) &appData.searchTime, FALSE },
\r
858 { "searchDepth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
859 { "depth", ArgInt, (LPVOID) &appData.searchDepth, FALSE },
\r
860 { "showCoords", ArgBoolean, (LPVOID) &appData.showCoords, TRUE },
\r
861 { "coords", ArgTrue, (LPVOID) &appData.showCoords, FALSE },
\r
862 { "xcoords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
863 { "-coords", ArgFalse, (LPVOID) &appData.showCoords, FALSE },
\r
864 { "showThinking", ArgBoolean, (LPVOID) &appData.showThinking, TRUE },
\r
865 { "thinking", ArgTrue, (LPVOID) &appData.showThinking, FALSE },
\r
866 { "xthinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
867 { "-thinking", ArgFalse, (LPVOID) &appData.showThinking, FALSE },
\r
868 { "ponderNextMove", ArgBoolean, (LPVOID) &appData.ponderNextMove, TRUE },
\r
869 { "ponder", ArgTrue, (LPVOID) &appData.ponderNextMove, FALSE },
\r
870 { "xponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
871 { "-ponder", ArgFalse, (LPVOID) &appData.ponderNextMove, FALSE },
\r
872 { "periodicUpdates", ArgBoolean, (LPVOID) &appData.periodicUpdates, TRUE },
\r
873 { "periodic", ArgTrue, (LPVOID) &appData.periodicUpdates, FALSE },
\r
874 { "xperiodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
875 { "-periodic", ArgFalse, (LPVOID) &appData.periodicUpdates, FALSE },
\r
876 { "popupExitMessage", ArgBoolean, (LPVOID) &appData.popupExitMessage, TRUE },
\r
877 { "exit", ArgTrue, (LPVOID) &appData.popupExitMessage, FALSE },
\r
878 { "xexit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
879 { "-exit", ArgFalse, (LPVOID) &appData.popupExitMessage, FALSE },
\r
880 { "popupMoveErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors, TRUE },
\r
881 { "popup", ArgTrue, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
882 { "xpopup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
883 { "-popup", ArgFalse, (LPVOID) &appData.popupMoveErrors, FALSE },
\r
884 { "popUpErrors", ArgBoolean, (LPVOID) &appData.popupMoveErrors,
\r
885 FALSE }, /* only so that old WinBoard.ini files from betas can be read */
\r
886 { "clockFont", ArgFont, (LPVOID) CLOCK_FONT, TRUE },
\r
887 { "messageFont", ArgFont, (LPVOID) MESSAGE_FONT, TRUE },
\r
888 { "coordFont", ArgFont, (LPVOID) COORD_FONT, TRUE },
\r
889 { "tagsFont", ArgFont, (LPVOID) EDITTAGS_FONT, TRUE },
\r
890 { "commentFont", ArgFont, (LPVOID) COMMENT_FONT, TRUE },
\r
891 { "icsFont", ArgFont, (LPVOID) CONSOLE_FONT, TRUE },
\r
892 { "moveHistoryFont", ArgFont, (LPVOID) MOVEHISTORY_FONT, TRUE }, /* [AS] */
\r
893 { "boardSize", ArgBoardSize, (LPVOID) &boardSize,
\r
894 TRUE }, /* must come after all fonts */
\r
895 { "size", ArgBoardSize, (LPVOID) &boardSize, FALSE },
\r
896 { "ringBellAfterMoves", ArgBoolean, (LPVOID) &appData.ringBellAfterMoves,
\r
897 FALSE }, /* historical; kept only so old winboard.ini files will parse */
\r
898 { "alwaysOnTop", ArgBoolean, (LPVOID) &alwaysOnTop, TRUE },
\r
899 { "top", ArgTrue, (LPVOID) &alwaysOnTop, FALSE },
\r
900 { "xtop", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
901 { "-top", ArgFalse, (LPVOID) &alwaysOnTop, FALSE },
\r
902 { "autoCallFlag", ArgBoolean, (LPVOID) &appData.autoCallFlag, TRUE },
\r
903 { "autoflag", ArgTrue, (LPVOID) &appData.autoCallFlag, FALSE },
\r
904 { "xautoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
905 { "-autoflag", ArgFalse, (LPVOID) &appData.autoCallFlag, FALSE },
\r
906 { "autoComment", ArgBoolean, (LPVOID) &appData.autoComment, TRUE },
\r
907 { "autocomm", ArgTrue, (LPVOID) &appData.autoComment, FALSE },
\r
908 { "xautocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
909 { "-autocomm", ArgFalse, (LPVOID) &appData.autoComment, FALSE },
\r
910 { "autoObserve", ArgBoolean, (LPVOID) &appData.autoObserve, TRUE },
\r
911 { "autobs", ArgTrue, (LPVOID) &appData.autoObserve, FALSE },
\r
912 { "xautobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
913 { "-autobs", ArgFalse, (LPVOID) &appData.autoObserve, FALSE },
\r
914 { "flipView", ArgBoolean, (LPVOID) &appData.flipView, FALSE },
\r
915 { "flip", ArgTrue, (LPVOID) &appData.flipView, FALSE },
\r
916 { "xflip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
917 { "-flip", ArgFalse, (LPVOID) &appData.flipView, FALSE },
\r
918 { "autoFlipView", ArgBoolean, (LPVOID) &appData.autoFlipView, TRUE },
\r
919 { "autoflip", ArgTrue, (LPVOID) &appData.autoFlipView, FALSE },
\r
920 { "xautoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
921 { "-autoflip", ArgFalse, (LPVOID) &appData.autoFlipView, FALSE },
\r
922 { "autoRaiseBoard", ArgBoolean, (LPVOID) &appData.autoRaiseBoard, TRUE },
\r
923 { "autoraise", ArgTrue, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
924 { "xautoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
925 { "-autoraise", ArgFalse, (LPVOID) &appData.autoRaiseBoard, FALSE },
\r
927 { "cmailGameName", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
928 { "cmail", ArgString, (LPVOID) &appData.cmailGameName, FALSE },
\r
930 { "alwaysPromoteToQueen", ArgBoolean, (LPVOID) &appData.alwaysPromoteToQueen, TRUE },
\r
931 { "queen", ArgTrue, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
932 { "xqueen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
933 { "-queen", ArgFalse, (LPVOID) &appData.alwaysPromoteToQueen, FALSE },
\r
934 { "oldSaveStyle", ArgBoolean, (LPVOID) &appData.oldSaveStyle, TRUE },
\r
935 { "oldsave", ArgTrue, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
936 { "xoldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
937 { "-oldsave", ArgFalse, (LPVOID) &appData.oldSaveStyle, FALSE },
\r
938 { "quietPlay", ArgBoolean, (LPVOID) &appData.quietPlay, TRUE },
\r
939 { "quiet", ArgTrue, (LPVOID) &appData.quietPlay, FALSE },
\r
940 { "xquiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
941 { "-quiet", ArgFalse, (LPVOID) &appData.quietPlay, FALSE },
\r
942 { "getMoveList", ArgBoolean, (LPVOID) &appData.getMoveList, TRUE },
\r
943 { "moves", ArgTrue, (LPVOID) &appData.getMoveList, FALSE },
\r
944 { "xmoves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
945 { "-moves", ArgFalse, (LPVOID) &appData.getMoveList, FALSE },
\r
946 { "testLegality", ArgBoolean, (LPVOID) &appData.testLegality, TRUE },
\r
947 { "legal", ArgTrue, (LPVOID) &appData.testLegality, FALSE },
\r
948 { "xlegal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
949 { "-legal", ArgFalse, (LPVOID) &appData.testLegality, FALSE },
\r
950 { "premove", ArgBoolean, (LPVOID) &appData.premove, TRUE },
\r
951 { "pre", ArgTrue, (LPVOID) &appData.premove, FALSE },
\r
952 { "xpre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
953 { "-pre", ArgFalse, (LPVOID) &appData.premove, FALSE },
\r
954 { "premoveWhite", ArgBoolean, (LPVOID) &appData.premoveWhite, TRUE },
\r
955 { "prewhite", ArgTrue, (LPVOID) &appData.premoveWhite, FALSE },
\r
956 { "xprewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
957 { "-prewhite", ArgFalse, (LPVOID) &appData.premoveWhite, FALSE },
\r
958 { "premoveWhiteText", ArgString, (LPVOID) &appData.premoveWhiteText, TRUE },
\r
959 { "premoveBlack", ArgBoolean, (LPVOID) &appData.premoveBlack, TRUE },
\r
960 { "preblack", ArgTrue, (LPVOID) &appData.premoveBlack, FALSE },
\r
961 { "xpreblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
962 { "-preblack", ArgFalse, (LPVOID) &appData.premoveBlack, FALSE },
\r
963 { "premoveBlackText", ArgString, (LPVOID) &appData.premoveBlackText, TRUE },
\r
964 { "icsAlarm", ArgBoolean, (LPVOID) &appData.icsAlarm, TRUE},
\r
965 { "alarm", ArgTrue, (LPVOID) &appData.icsAlarm, FALSE},
\r
966 { "xalarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
967 { "-alarm", ArgFalse, (LPVOID) &appData.icsAlarm, FALSE},
\r
968 { "icsAlarmTime", ArgInt, (LPVOID) &appData.icsAlarmTime, TRUE},
\r
969 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
970 { "localLineEditing", ArgBoolean, (LPVOID) &appData.localLineEditing, FALSE},
\r
971 { "edit", ArgTrue, (LPVOID) &appData.localLineEditing, FALSE },
\r
972 { "xedit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
973 { "-edit", ArgFalse, (LPVOID) &appData.localLineEditing, FALSE },
\r
974 { "animateMoving", ArgBoolean, (LPVOID) &appData.animate, TRUE },
\r
975 { "animate", ArgTrue, (LPVOID) &appData.animate, FALSE },
\r
976 { "xanimate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
977 { "-animate", ArgFalse, (LPVOID) &appData.animate, FALSE },
\r
978 { "animateSpeed", ArgInt, (LPVOID) &appData.animSpeed, TRUE },
\r
979 { "animateDragging", ArgBoolean, (LPVOID) &appData.animateDragging, TRUE },
\r
980 { "drag", ArgTrue, (LPVOID) &appData.animateDragging, FALSE },
\r
981 { "xdrag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
982 { "-drag", ArgFalse, (LPVOID) &appData.animateDragging, FALSE },
\r
983 { "blindfold", ArgBoolean, (LPVOID) &appData.blindfold, TRUE },
\r
984 { "blind", ArgTrue, (LPVOID) &appData.blindfold, FALSE },
\r
985 { "xblind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
986 { "-blind", ArgFalse, (LPVOID) &appData.blindfold, FALSE },
\r
987 { "highlightLastMove", ArgBoolean,
\r
988 (LPVOID) &appData.highlightLastMove, TRUE },
\r
989 { "highlight", ArgTrue, (LPVOID) &appData.highlightLastMove, FALSE },
\r
990 { "xhighlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
991 { "-highlight", ArgFalse, (LPVOID) &appData.highlightLastMove, FALSE },
\r
992 { "highlightDragging", ArgBoolean,
\r
993 (LPVOID) &appData.highlightDragging, TRUE },
\r
994 { "highdrag", ArgTrue, (LPVOID) &appData.highlightDragging, FALSE },
\r
995 { "xhighdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
996 { "-highdrag", ArgFalse, (LPVOID) &appData.highlightDragging, FALSE },
\r
997 { "colorizeMessages", ArgBoolean, (LPVOID) &appData.colorize, TRUE },
\r
998 { "colorize", ArgTrue, (LPVOID) &appData.colorize, FALSE },
\r
999 { "xcolorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1000 { "-colorize", ArgFalse, (LPVOID) &appData.colorize, FALSE },
\r
1001 { "colorShout", ArgAttribs, (LPVOID) ColorShout, TRUE },
\r
1002 { "colorSShout", ArgAttribs, (LPVOID) ColorSShout, TRUE },
\r
1003 { "colorChannel1", ArgAttribs, (LPVOID) ColorChannel1, TRUE },
\r
1004 { "colorChannel", ArgAttribs, (LPVOID) ColorChannel, TRUE },
\r
1005 { "colorKibitz", ArgAttribs, (LPVOID) ColorKibitz, TRUE },
\r
1006 { "colorTell", ArgAttribs, (LPVOID) ColorTell, TRUE },
\r
1007 { "colorChallenge", ArgAttribs, (LPVOID) ColorChallenge, TRUE },
\r
1008 { "colorRequest", ArgAttribs, (LPVOID) ColorRequest, TRUE },
\r
1009 { "colorSeek", ArgAttribs, (LPVOID) ColorSeek, TRUE },
\r
1010 { "colorNormal", ArgAttribs, (LPVOID) ColorNormal, TRUE },
\r
1011 { "colorBackground", ArgColor, (LPVOID) &consoleBackgroundColor, TRUE },
\r
1012 { "soundShout", ArgFilename,
\r
1013 (LPVOID) &textAttribs[ColorShout].sound.name, TRUE },
\r
1014 { "soundSShout", ArgFilename,
\r
1015 (LPVOID) &textAttribs[ColorSShout].sound.name, TRUE },
\r
1016 { "soundChannel1", ArgFilename,
\r
1017 (LPVOID) &textAttribs[ColorChannel1].sound.name, TRUE },
\r
1018 { "soundChannel", ArgFilename,
\r
1019 (LPVOID) &textAttribs[ColorChannel].sound.name, TRUE },
\r
1020 { "soundKibitz", ArgFilename,
\r
1021 (LPVOID) &textAttribs[ColorKibitz].sound.name, TRUE },
\r
1022 { "soundTell", ArgFilename,
\r
1023 (LPVOID) &textAttribs[ColorTell].sound.name, TRUE },
\r
1024 { "soundChallenge", ArgFilename,
\r
1025 (LPVOID) &textAttribs[ColorChallenge].sound.name, TRUE },
\r
1026 { "soundRequest", ArgFilename,
\r
1027 (LPVOID) &textAttribs[ColorRequest].sound.name, TRUE },
\r
1028 { "soundSeek", ArgFilename,
\r
1029 (LPVOID) &textAttribs[ColorSeek].sound.name, TRUE },
\r
1030 { "soundMove", ArgFilename, (LPVOID) &sounds[(int)SoundMove].name, TRUE },
\r
1031 { "soundBell", ArgFilename, (LPVOID) &sounds[(int)SoundBell].name, TRUE },
\r
1032 { "soundIcsWin", ArgFilename, (LPVOID) &sounds[(int)SoundIcsWin].name,TRUE },
\r
1033 { "soundIcsLoss", ArgFilename,
\r
1034 (LPVOID) &sounds[(int)SoundIcsLoss].name, TRUE },
\r
1035 { "soundIcsDraw", ArgFilename,
\r
1036 (LPVOID) &sounds[(int)SoundIcsDraw].name, TRUE },
\r
1037 { "soundIcsUnfinished", ArgFilename,
\r
1038 (LPVOID) &sounds[(int)SoundIcsUnfinished].name, TRUE},
\r
1039 { "soundIcsAlarm", ArgFilename,
\r
1040 (LPVOID) &sounds[(int)SoundAlarm].name, TRUE },
\r
1041 { "reuseFirst", ArgBoolean, (LPVOID) &appData.reuseFirst, FALSE },
\r
1042 { "reuse", ArgTrue, (LPVOID) &appData.reuseFirst, FALSE },
\r
1043 { "xreuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1044 { "-reuse", ArgFalse, (LPVOID) &appData.reuseFirst, FALSE },
\r
1045 { "reuseChessPrograms", ArgBoolean,
\r
1046 (LPVOID) &appData.reuseFirst, FALSE }, /* backward compat only */
\r
1047 { "reuseSecond", ArgBoolean, (LPVOID) &appData.reuseSecond, FALSE },
\r
1048 { "reuse2", ArgTrue, (LPVOID) &appData.reuseSecond, FALSE },
\r
1049 { "xreuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1050 { "-reuse2", ArgFalse, (LPVOID) &appData.reuseSecond, FALSE },
\r
1051 { "comPortSettings", ArgCommSettings, (LPVOID) &dcb, TRUE },
\r
1052 { "x", ArgInt, (LPVOID) &boardX, TRUE },
\r
1053 { "y", ArgInt, (LPVOID) &boardY, TRUE },
\r
1054 { "icsX", ArgInt, (LPVOID) &consoleX, TRUE },
\r
1055 { "icsY", ArgInt, (LPVOID) &consoleY, TRUE },
\r
1056 { "icsW", ArgInt, (LPVOID) &consoleW, TRUE },
\r
1057 { "icsH", ArgInt, (LPVOID) &consoleH, TRUE },
\r
1058 { "analysisX", ArgInt, (LPVOID) &analysisX, TRUE },
\r
1059 { "analysisY", ArgInt, (LPVOID) &analysisY, TRUE },
\r
1060 { "analysisW", ArgInt, (LPVOID) &analysisW, TRUE },
\r
1061 { "analysisH", ArgInt, (LPVOID) &analysisH, TRUE },
\r
1062 { "commentX", ArgInt, (LPVOID) &commentX, TRUE },
\r
1063 { "commentY", ArgInt, (LPVOID) &commentY, TRUE },
\r
1064 { "commentW", ArgInt, (LPVOID) &commentW, TRUE },
\r
1065 { "commentH", ArgInt, (LPVOID) &commentH, TRUE },
\r
1066 { "tagsX", ArgInt, (LPVOID) &editTagsX, TRUE },
\r
1067 { "tagsY", ArgInt, (LPVOID) &editTagsY, TRUE },
\r
1068 { "tagsW", ArgInt, (LPVOID) &editTagsW, TRUE },
\r
1069 { "tagsH", ArgInt, (LPVOID) &editTagsH, TRUE },
\r
1070 { "gameListX", ArgInt, (LPVOID) &gameListX, TRUE },
\r
1071 { "gameListY", ArgInt, (LPVOID) &gameListY, TRUE },
\r
1072 { "gameListW", ArgInt, (LPVOID) &gameListW, TRUE },
\r
1073 { "gameListH", ArgInt, (LPVOID) &gameListH, TRUE },
\r
1074 { "settingsFile", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1075 { "ini", ArgSettingsFilename, (LPVOID) &settingsFileName, FALSE },
\r
1076 { "saveSettingsOnExit", ArgBoolean, (LPVOID) &saveSettingsOnExit, TRUE },
\r
1077 { "chessProgram", ArgBoolean, (LPVOID) &chessProgram, FALSE },
\r
1078 { "cp", ArgTrue, (LPVOID) &chessProgram, FALSE },
\r
1079 { "xcp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1080 { "-cp", ArgFalse, (LPVOID) &chessProgram, FALSE },
\r
1081 { "icsMenu", ArgString, (LPVOID) &icsTextMenuString, TRUE },
\r
1082 { "icsNames", ArgString, (LPVOID) &icsNames, TRUE },
\r
1083 { "firstChessProgramNames", ArgString, (LPVOID) &firstChessProgramNames,
\r
1085 { "secondChessProgramNames", ArgString, (LPVOID) &secondChessProgramNames,
\r
1087 { "initialMode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1088 { "mode", ArgString, (LPVOID) &appData.initialMode, FALSE },
\r
1089 { "variant", ArgString, (LPVOID) &appData.variant, FALSE },
\r
1090 { "firstProtocolVersion", ArgInt, (LPVOID) &appData.firstProtocolVersion, FALSE },
\r
1091 { "secondProtocolVersion", ArgInt, (LPVOID) &appData.secondProtocolVersion,FALSE },
\r
1092 { "showButtonBar", ArgBoolean, (LPVOID) &appData.showButtonBar, TRUE },
\r
1093 { "buttons", ArgTrue, (LPVOID) &appData.showButtonBar, FALSE },
\r
1094 { "xbuttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1095 { "-buttons", ArgFalse, (LPVOID) &appData.showButtonBar, FALSE },
\r
1096 /* [AS] New features */
\r
1097 { "firstScoreAbs", ArgBoolean, (LPVOID) &appData.firstScoreIsAbsolute, FALSE },
\r
1098 { "secondScoreAbs", ArgBoolean, (LPVOID) &appData.secondScoreIsAbsolute, FALSE },
\r
1099 { "pgnExtendedInfo", ArgBoolean, (LPVOID) &appData.saveExtendedInfoInPGN, TRUE },
\r
1100 { "hideThinkingFromHuman", ArgBoolean, (LPVOID) &appData.hideThinkingFromHuman, TRUE },
\r
1101 { "liteBackTextureFile", ArgString, (LPVOID) &appData.liteBackTextureFile, TRUE },
\r
1102 { "darkBackTextureFile", ArgString, (LPVOID) &appData.darkBackTextureFile, TRUE },
\r
1103 { "liteBackTextureMode", ArgInt, (LPVOID) &appData.liteBackTextureMode, TRUE },
\r
1104 { "darkBackTextureMode", ArgInt, (LPVOID) &appData.darkBackTextureMode, TRUE },
\r
1105 { "renderPiecesWithFont", ArgString, (LPVOID) &appData.renderPiecesWithFont, TRUE },
\r
1106 { "fontPieceToCharTable", ArgString, (LPVOID) &appData.fontToPieceTable, TRUE },
\r
1107 { "fontPieceBackColorWhite", ArgColor, (LPVOID) &appData.fontBackColorWhite, TRUE },
\r
1108 { "fontPieceForeColorWhite", ArgColor, (LPVOID) &appData.fontForeColorWhite, TRUE },
\r
1109 { "fontPieceBackColorBlack", ArgColor, (LPVOID) &appData.fontBackColorBlack, TRUE },
\r
1110 { "fontPieceForeColorBlack", ArgColor, (LPVOID) &appData.fontForeColorBlack, TRUE },
\r
1111 { "fontPieceSize", ArgInt, (LPVOID) &appData.fontPieceSize, TRUE },
\r
1112 { "overrideLineGap", ArgInt, (LPVOID) &appData.overrideLineGap, TRUE },
\r
1113 { "adjudicateLossThreshold", ArgInt, (LPVOID) &appData.adjudicateLossThreshold, TRUE },
\r
1114 { "delayBeforeQuit", ArgInt, (LPVOID) &appData.delayBeforeQuit, TRUE },
\r
1115 { "delayAfterQuit", ArgInt, (LPVOID) &appData.delayAfterQuit, TRUE },
\r
1116 { "nameOfDebugFile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1117 { "debugfile", ArgFilename, (LPVOID) &appData.nameOfDebugFile, FALSE },
\r
1118 { "pgnEventHeader", ArgString, (LPVOID) &appData.pgnEventHeader, TRUE },
\r
1119 { "defaultFrcPosition", ArgInt, (LPVOID) &appData.defaultFrcPosition, TRUE },
\r
1120 { "gameListTags", ArgString, (LPVOID) &appData.gameListTags, TRUE },
\r
1121 { "saveOutOfBookInfo", ArgBoolean, (LPVOID) &appData.saveOutOfBookInfo, TRUE },
\r
1122 { "showEvalInMoveHistory", ArgBoolean, (LPVOID) &appData.showEvalInMoveHistory, TRUE },
\r
1123 { "evalHistColorWhite", ArgColor, (LPVOID) &appData.evalHistColorWhite, TRUE },
\r
1124 { "evalHistColorBlack", ArgColor, (LPVOID) &appData.evalHistColorBlack, TRUE },
\r
1125 { "highlightMoveWithArrow", ArgBoolean, (LPVOID) &appData.highlightMoveWithArrow, TRUE },
\r
1126 { "highlightArrowColor", ArgColor, (LPVOID) &appData.highlightArrowColor, TRUE },
\r
1127 { "stickyWindows", ArgBoolean, (LPVOID) &appData.useStickyWindows, TRUE },
\r
1128 { "adjudicateDrawMoves", ArgInt, (LPVOID) &appData.adjudicateDrawMoves, TRUE },
\r
1129 { "autoDisplayComment", ArgBoolean, (LPVOID) &appData.autoDisplayComment, TRUE },
\r
1130 { "autoDisplayTags", ArgBoolean, (LPVOID) &appData.autoDisplayTags, TRUE },
\r
1131 { "firstIsUCI", ArgBoolean, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1132 { "fUCI", ArgTrue, (LPVOID) &appData.firstIsUCI, FALSE },
\r
1133 { "secondIsUCI", ArgBoolean, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1134 { "sUCI", ArgTrue, (LPVOID) &appData.secondIsUCI, FALSE },
\r
1135 { "firstHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1136 { "fNoOwnBookUCI", ArgFalse, (LPVOID) &appData.firstHasOwnBookUCI, FALSE },
\r
1137 { "secondHasOwnBookUCI", ArgBoolean, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1138 { "sNoOwnBookUCI", ArgFalse, (LPVOID) &appData.secondHasOwnBookUCI, FALSE },
\r
1139 { "polyglotDir", ArgFilename, (LPVOID) &appData.polyglotDir, TRUE },
\r
1140 { "usePolyglotBook", ArgBoolean, (LPVOID) &appData.usePolyglotBook, TRUE },
\r
1141 { "polyglotBook", ArgFilename, (LPVOID) &appData.polyglotBook, TRUE },
\r
1142 { "defaultHashSize", ArgInt, (LPVOID) &appData.defaultHashSize, TRUE },
\r
1143 { "defaultCacheSizeEGTB", ArgInt, (LPVOID) &appData.defaultCacheSizeEGTB, TRUE },
\r
1144 { "defaultPathEGTB", ArgFilename, (LPVOID) &appData.defaultPathEGTB, TRUE },
\r
1146 /* [AS] Layout stuff */
\r
1147 { "moveHistoryUp", ArgBoolean, (LPVOID) &wpMoveHistory.visible, TRUE },
\r
1148 { "moveHistoryX", ArgInt, (LPVOID) &wpMoveHistory.x, TRUE },
\r
1149 { "moveHistoryY", ArgInt, (LPVOID) &wpMoveHistory.y, TRUE },
\r
1150 { "moveHistoryW", ArgInt, (LPVOID) &wpMoveHistory.width, TRUE },
\r
1151 { "moveHistoryH", ArgInt, (LPVOID) &wpMoveHistory.height, TRUE },
\r
1153 { "evalGraphUp", ArgBoolean, (LPVOID) &wpEvalGraph.visible, TRUE },
\r
1154 { "evalGraphX", ArgInt, (LPVOID) &wpEvalGraph.x, TRUE },
\r
1155 { "evalGraphY", ArgInt, (LPVOID) &wpEvalGraph.y, TRUE },
\r
1156 { "evalGraphW", ArgInt, (LPVOID) &wpEvalGraph.width, TRUE },
\r
1157 { "evalGraphH", ArgInt, (LPVOID) &wpEvalGraph.height, TRUE },
\r
1159 { "engineOutputUp", ArgBoolean, (LPVOID) &wpEngineOutput.visible, TRUE },
\r
1160 { "engineOutputX", ArgInt, (LPVOID) &wpEngineOutput.x, TRUE },
\r
1161 { "engineOutputY", ArgInt, (LPVOID) &wpEngineOutput.y, TRUE },
\r
1162 { "engineOutputW", ArgInt, (LPVOID) &wpEngineOutput.width, TRUE },
\r
1163 { "engineOutputH", ArgInt, (LPVOID) &wpEngineOutput.height, TRUE },
\r
1165 /* [HGM] board-size, adjudication and misc. options */
\r
1166 { "boardWidth", ArgInt, (LPVOID) &appData.NrFiles, TRUE },
\r
1167 { "boardHeight", ArgInt, (LPVOID) &appData.NrRanks, TRUE },
\r
1168 { "holdingsSize", ArgInt, (LPVOID) &appData.holdingsSize, TRUE },
\r
1169 { "matchPause", ArgInt, (LPVOID) &appData.matchPause, TRUE },
\r
1170 { "pieceToCharTable", ArgString, (LPVOID) &appData.pieceToCharTable, FALSE },
\r
1171 { "flipBlack", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1172 { "allWhite", ArgBoolean, (LPVOID) &appData.allWhite, TRUE },
\r
1173 { "alphaRank", ArgBoolean, (LPVOID) &appData.alphaRank, FALSE },
\r
1174 { "testClaims", ArgBoolean, (LPVOID) &appData.testClaims, TRUE },
\r
1175 { "checkMates", ArgBoolean, (LPVOID) &appData.checkMates, TRUE },
\r
1176 { "materialDraws", ArgBoolean, (LPVOID) &appData.materialDraws, TRUE },
\r
1177 { "trivialDraws", ArgBoolean, (LPVOID) &appData.trivialDraws, TRUE },
\r
1178 { "ruleMoves", ArgInt, (LPVOID) &appData.ruleMoves, TRUE },
\r
1179 { "repeatsToDraw", ArgInt, (LPVOID) &appData.drawRepeats, TRUE },
\r
1182 { "zippyTalk", ArgBoolean, (LPVOID) &appData.zippyTalk, FALSE },
\r
1183 { "zt", ArgTrue, (LPVOID) &appData.zippyTalk, FALSE },
\r
1184 { "xzt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1185 { "-zt", ArgFalse, (LPVOID) &appData.zippyTalk, FALSE },
\r
1186 { "zippyPlay", ArgBoolean, (LPVOID) &appData.zippyPlay, FALSE },
\r
1187 { "zp", ArgTrue, (LPVOID) &appData.zippyPlay, FALSE },
\r
1188 { "xzp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1189 { "-zp", ArgFalse, (LPVOID) &appData.zippyPlay, FALSE },
\r
1190 { "zippyLines", ArgFilename, (LPVOID) &appData.zippyLines, FALSE },
\r
1191 { "zippyPinhead", ArgString, (LPVOID) &appData.zippyPinhead, FALSE },
\r
1192 { "zippyPassword", ArgString, (LPVOID) &appData.zippyPassword, FALSE },
\r
1193 { "zippyPassword2", ArgString, (LPVOID) &appData.zippyPassword2, FALSE },
\r
1194 { "zippyWrongPassword", ArgString, (LPVOID) &appData.zippyWrongPassword,
\r
1196 { "zippyAcceptOnly", ArgString, (LPVOID) &appData.zippyAcceptOnly, FALSE },
\r
1197 { "zippyUseI", ArgBoolean, (LPVOID) &appData.zippyUseI, FALSE },
\r
1198 { "zui", ArgTrue, (LPVOID) &appData.zippyUseI, FALSE },
\r
1199 { "xzui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1200 { "-zui", ArgFalse, (LPVOID) &appData.zippyUseI, FALSE },
\r
1201 { "zippyBughouse", ArgInt, (LPVOID) &appData.zippyBughouse, FALSE },
\r
1202 { "zippyNoplayCrafty", ArgBoolean, (LPVOID) &appData.zippyNoplayCrafty,
\r
1204 { "znc", ArgTrue, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1205 { "xznc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1206 { "-znc", ArgFalse, (LPVOID) &appData.zippyNoplayCrafty, FALSE },
\r
1207 { "zippyGameEnd", ArgString, (LPVOID) &appData.zippyGameEnd, FALSE },
\r
1208 { "zippyGameStart", ArgString, (LPVOID) &appData.zippyGameStart, FALSE },
\r
1209 { "zippyAdjourn", ArgBoolean, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1210 { "zadj", ArgTrue, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1211 { "xzadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1212 { "-zadj", ArgFalse, (LPVOID) &appData.zippyAdjourn, FALSE },
\r
1213 { "zippyAbort", ArgBoolean, (LPVOID) &appData.zippyAbort, FALSE },
\r
1214 { "zab", ArgTrue, (LPVOID) &appData.zippyAbort, FALSE },
\r
1215 { "xzab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1216 { "-zab", ArgFalse, (LPVOID) &appData.zippyAbort, FALSE },
\r
1217 { "zippyVariants", ArgString, (LPVOID) &appData.zippyVariants, FALSE },
\r
1218 { "zippyMaxGames", ArgInt, (LPVOID)&appData.zippyMaxGames, FALSE },
\r
1219 { "zippyReplayTimeout", ArgInt, (LPVOID)&appData.zippyReplayTimeout, FALSE },
\r
1220 /* Kludge to allow winboard.ini files from buggy 4.0.4 to be read: */
\r
1221 { "zippyReplyTimeout", ArgInt, (LPVOID)&junk, FALSE },
\r
1223 { NULL, ArgNone, NULL, FALSE }
\r
1227 /* Kludge for indirection files on command line */
\r
1228 char* lastIndirectionFilename;
\r
1229 ArgDescriptor argDescriptorIndirection =
\r
1230 { "", ArgSettingsFilename, (LPVOID) NULL, FALSE };
\r
1234 ExitArgError(char *msg, char *badArg)
\r
1236 char buf[MSG_SIZ];
\r
1238 sprintf(buf, "%s %s", msg, badArg);
\r
1239 DisplayFatalError(buf, 0, 2);
\r
1243 /* Command line font name parser. NULL name means do nothing.
\r
1244 Syntax like "Courier New:10.0 bi" or "Arial:10" or "Arial:10b"
\r
1245 For backward compatibility, syntax without the colon is also
\r
1246 accepted, but font names with digits in them won't work in that case.
\r
1249 ParseFontName(char *name, MyFontParams *mfp)
\r
1252 if (name == NULL) return;
\r
1254 q = strchr(p, ':');
\r
1256 if (q - p >= sizeof(mfp->faceName))
\r
1257 ExitArgError("Font name too long:", name);
\r
1258 memcpy(mfp->faceName, p, q - p);
\r
1259 mfp->faceName[q - p] = NULLCHAR;
\r
1262 q = mfp->faceName;
\r
1263 while (*p && !isdigit(*p)) {
\r
1265 if (q - mfp->faceName >= sizeof(mfp->faceName))
\r
1266 ExitArgError("Font name too long:", name);
\r
1268 while (q > mfp->faceName && q[-1] == ' ') q--;
\r
1271 if (!*p) ExitArgError("Font point size missing:", name);
\r
1272 mfp->pointSize = (float) atof(p);
\r
1273 mfp->bold = (strchr(p, 'b') != NULL);
\r
1274 mfp->italic = (strchr(p, 'i') != NULL);
\r
1275 mfp->underline = (strchr(p, 'u') != NULL);
\r
1276 mfp->strikeout = (strchr(p, 's') != NULL);
\r
1279 /* Color name parser.
\r
1280 X version accepts X color names, but this one
\r
1281 handles only the #rrggbb form (hex) or rrr,ggg,bbb (decimal) */
\r
1283 ParseColorName(char *name)
\r
1285 int red, green, blue, count;
\r
1286 char buf[MSG_SIZ];
\r
1288 count = sscanf(name, "#%2x%2x%2x", &red, &green, &blue);
\r
1290 count = sscanf(name, "%3d%*[^0-9]%3d%*[^0-9]%3d",
\r
1291 &red, &green, &blue);
\r
1294 sprintf(buf, "Can't parse color name %s", name);
\r
1295 DisplayError(buf, 0);
\r
1296 return RGB(0, 0, 0);
\r
1298 return PALETTERGB(red, green, blue);
\r
1302 void ParseAttribs(COLORREF *color, int *effects, char* argValue)
\r
1304 char *e = argValue;
\r
1308 if (*e == 'b') eff |= CFE_BOLD;
\r
1309 else if (*e == 'i') eff |= CFE_ITALIC;
\r
1310 else if (*e == 'u') eff |= CFE_UNDERLINE;
\r
1311 else if (*e == 's') eff |= CFE_STRIKEOUT;
\r
1312 else if (*e == '#' || isdigit(*e)) break;
\r
1316 *color = ParseColorName(e);
\r
1321 ParseBoardSize(char *name)
\r
1323 BoardSize bs = SizeTiny;
\r
1324 while (sizeInfo[bs].name != NULL) {
\r
1325 if (StrCaseCmp(name, sizeInfo[bs].name) == 0) return bs;
\r
1328 ExitArgError("Unrecognized board size value", name);
\r
1329 return bs; /* not reached */
\r
1334 StringGet(void *getClosure)
\r
1336 char **p = (char **) getClosure;
\r
1341 FileGet(void *getClosure)
\r
1344 FILE* f = (FILE*) getClosure;
\r
1353 /* Parse settings file named "name". If file found, return the
\r
1354 full name in fullname and return TRUE; else return FALSE */
\r
1356 ParseSettingsFile(char *name, char fullname[MSG_SIZ])
\r
1361 if (SearchPath(installDir, name, NULL, MSG_SIZ, fullname, &dummy)) {
\r
1362 f = fopen(fullname, "r");
\r
1364 ParseArgs(FileGet, f);
\r
1373 ParseArgs(GetFunc get, void *cl)
\r
1375 char argName[ARG_MAX];
\r
1376 char argValue[ARG_MAX];
\r
1377 ArgDescriptor *ad;
\r
1386 while (ch == ' ' || ch == '\n' || ch == '\t') ch = get(cl);
\r
1387 if (ch == NULLCHAR) break;
\r
1389 /* Comment to end of line */
\r
1391 while (ch != '\n' && ch != NULLCHAR) ch = get(cl);
\r
1393 } else if (ch == '/' || ch == '-') {
\r
1396 while (ch != ' ' && ch != '=' && ch != ':' && ch != NULLCHAR &&
\r
1397 ch != '\n' && ch != '\t') {
\r
1403 for (ad = argDescriptors; ad->argName != NULL; ad++)
\r
1404 if (strcmp(ad->argName, argName + 1) == 0) break;
\r
1406 if (ad->argName == NULL)
\r
1407 ExitArgError("Unrecognized argument", argName);
\r
1409 } else if (ch == '@') {
\r
1410 /* Indirection file */
\r
1411 ad = &argDescriptorIndirection;
\r
1414 /* Positional argument */
\r
1415 ad = &argDescriptors[posarg++];
\r
1416 strcpy(argName, ad->argName);
\r
1419 if (ad->argType == ArgTrue) {
\r
1420 *(Boolean *) ad->argLoc = TRUE;
\r
1423 if (ad->argType == ArgFalse) {
\r
1424 *(Boolean *) ad->argLoc = FALSE;
\r
1428 while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
\r
1429 if (ch == NULLCHAR || ch == '\n') {
\r
1430 ExitArgError("No value provided for argument", argName);
\r
1434 // Quoting with { }. No characters have to (or can) be escaped.
\r
1435 // Thus the string cannot contain a '}' character.
\r
1455 } else if (ch == '\'' || ch == '"') {
\r
1456 // Quoting with ' ' or " ", with \ as escape character.
\r
1457 // Inconvenient for long strings that may contain Windows filenames.
\r
1474 if (ch == start) {
\r
1483 if (ad->argType == ArgFilename
\r
1484 || ad->argType == ArgSettingsFilename) {
\r
1490 ExitArgError("Incomplete \\ escape in value for", argName);
\r
1514 for (i = 0; i < 3; i++) {
\r
1515 if (ch >= '0' && ch <= '7') {
\r
1516 octval = octval*8 + (ch - '0');
\r
1523 *q++ = (char) octval;
\r
1534 while (ch != ' ' && ch != NULLCHAR && ch != '\t' && ch != '\n') {
\r
1541 switch (ad->argType) {
\r
1543 *(int *) ad->argLoc = atoi(argValue);
\r
1547 *(float *) ad->argLoc = (float) atof(argValue);
\r
1552 *(char **) ad->argLoc = strdup(argValue);
\r
1555 case ArgSettingsFilename:
\r
1557 char fullname[MSG_SIZ];
\r
1558 if (ParseSettingsFile(argValue, fullname)) {
\r
1559 if (ad->argLoc != NULL) {
\r
1560 *(char **) ad->argLoc = strdup(fullname);
\r
1563 if (ad->argLoc != NULL) {
\r
1565 ExitArgError("Failed to open indirection file", argValue);
\r
1572 switch (argValue[0]) {
\r
1575 *(Boolean *) ad->argLoc = TRUE;
\r
1579 *(Boolean *) ad->argLoc = FALSE;
\r
1582 ExitArgError("Unrecognized boolean argument value", argValue);
\r
1588 *(COLORREF *)ad->argLoc = ParseColorName(argValue);
\r
1591 case ArgAttribs: {
\r
1592 ColorClass cc = (ColorClass)ad->argLoc;
\r
1593 ParseAttribs(&textAttribs[cc].color, &textAttribs[cc].effects, argValue);
\r
1597 case ArgBoardSize:
\r
1598 *(BoardSize *)ad->argLoc = ParseBoardSize(argValue);
\r
1602 ParseFontName(argValue, &font[boardSize][(int)ad->argLoc]->mfp);
\r
1605 case ArgCommSettings:
\r
1606 ParseCommSettings(argValue, &dcb);
\r
1610 ExitArgError("Unrecognized argument", argValue);
\r
1617 LFfromMFP(LOGFONT* lf, MyFontParams *mfp)
\r
1619 HDC hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
\r
1620 lf->lfHeight = -(int)(mfp->pointSize * GetDeviceCaps(hdc, LOGPIXELSY) / 72.0 + 0.5);
\r
1623 lf->lfEscapement = 0;
\r
1624 lf->lfOrientation = 0;
\r
1625 lf->lfWeight = mfp->bold ? FW_BOLD : FW_NORMAL;
\r
1626 lf->lfItalic = mfp->italic;
\r
1627 lf->lfUnderline = mfp->underline;
\r
1628 lf->lfStrikeOut = mfp->strikeout;
\r
1629 lf->lfCharSet = DEFAULT_CHARSET;
\r
1630 lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
1631 lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
1632 lf->lfQuality = DEFAULT_QUALITY;
\r
1633 lf->lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
\r
1634 strcpy(lf->lfFaceName, mfp->faceName);
\r
1638 CreateFontInMF(MyFont *mf)
\r
1640 LFfromMFP(&mf->lf, &mf->mfp);
\r
1641 if (mf->hf) DeleteObject(mf->hf);
\r
1642 mf->hf = CreateFontIndirect(&mf->lf);
\r
1646 SetDefaultTextAttribs()
\r
1649 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1650 ParseAttribs(&textAttribs[cc].color,
\r
1651 &textAttribs[cc].effects,
\r
1652 defaultTextAttribs[cc]);
\r
1657 SetDefaultSounds()
\r
1661 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1662 textAttribs[cc].sound.name = strdup("");
\r
1663 textAttribs[cc].sound.data = NULL;
\r
1665 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1666 sounds[sc].name = strdup("");
\r
1667 sounds[sc].data = NULL;
\r
1669 sounds[(int)SoundBell].name = strdup(SOUND_BELL);
\r
1677 for (cc = (ColorClass)0; cc < NColorClasses; cc++) {
\r
1678 MyLoadSound(&textAttribs[cc].sound);
\r
1680 for (sc = (SoundClass)0; sc < NSoundClasses; sc++) {
\r
1681 MyLoadSound(&sounds[sc]);
\r
1686 InitAppData(LPSTR lpCmdLine)
\r
1689 char buf[ARG_MAX], currDir[MSG_SIZ];
\r
1692 programName = szAppName;
\r
1694 /* Initialize to defaults */
\r
1695 lightSquareColor = ParseColorName(LIGHT_SQUARE_COLOR);
\r
1696 darkSquareColor = ParseColorName(DARK_SQUARE_COLOR);
\r
1697 whitePieceColor = ParseColorName(WHITE_PIECE_COLOR);
\r
1698 blackPieceColor = ParseColorName(BLACK_PIECE_COLOR);
\r
1699 highlightSquareColor = ParseColorName(HIGHLIGHT_SQUARE_COLOR);
\r
1700 premoveHighlightColor = ParseColorName(PREMOVE_HIGHLIGHT_COLOR);
\r
1701 consoleBackgroundColor = ParseColorName(COLOR_BKGD);
\r
1702 SetDefaultTextAttribs();
\r
1703 SetDefaultSounds();
\r
1704 appData.movesPerSession = MOVES_PER_SESSION;
\r
1705 appData.initString = INIT_STRING;
\r
1706 appData.secondInitString = INIT_STRING;
\r
1707 appData.firstComputerString = COMPUTER_STRING;
\r
1708 appData.secondComputerString = COMPUTER_STRING;
\r
1709 appData.firstChessProgram = FIRST_CHESS_PROGRAM;
\r
1710 appData.secondChessProgram = SECOND_CHESS_PROGRAM;
\r
1711 appData.firstPlaysBlack = FALSE;
\r
1712 appData.noChessProgram = FALSE;
\r
1713 chessProgram = FALSE;
\r
1714 appData.firstHost = FIRST_HOST;
\r
1715 appData.secondHost = SECOND_HOST;
\r
1716 appData.firstDirectory = FIRST_DIRECTORY;
\r
1717 appData.secondDirectory = SECOND_DIRECTORY;
\r
1718 appData.bitmapDirectory = "";
\r
1719 appData.remoteShell = REMOTE_SHELL;
\r
1720 appData.remoteUser = "";
\r
1721 appData.timeDelay = TIME_DELAY;
\r
1722 appData.timeControl = TIME_CONTROL;
\r
1723 appData.timeIncrement = TIME_INCREMENT;
\r
1724 appData.icsActive = FALSE;
\r
1725 appData.icsHost = "";
\r
1726 appData.icsPort = ICS_PORT;
\r
1727 appData.icsCommPort = ICS_COMM_PORT;
\r
1728 appData.icsLogon = ICS_LOGON;
\r
1729 appData.icsHelper = "";
\r
1730 appData.useTelnet = FALSE;
\r
1731 appData.telnetProgram = TELNET_PROGRAM;
\r
1732 appData.gateway = "";
\r
1733 appData.loadGameFile = "";
\r
1734 appData.loadGameIndex = 0;
\r
1735 appData.saveGameFile = "";
\r
1736 appData.autoSaveGames = FALSE;
\r
1737 appData.loadPositionFile = "";
\r
1738 appData.loadPositionIndex = 1;
\r
1739 appData.savePositionFile = "";
\r
1740 appData.matchMode = FALSE;
\r
1741 appData.matchGames = 0;
\r
1742 appData.monoMode = FALSE;
\r
1743 appData.debugMode = FALSE;
\r
1744 appData.clockMode = TRUE;
\r
1745 boardSize = (BoardSize) -1; /* determine by screen size */
\r
1746 appData.Iconic = FALSE; /*unused*/
\r
1747 appData.searchTime = "";
\r
1748 appData.searchDepth = 0;
\r
1749 appData.showCoords = FALSE;
\r
1750 appData.ringBellAfterMoves = TRUE; /*obsolete in WinBoard*/
\r
1751 appData.autoCallFlag = FALSE;
\r
1752 appData.flipView = FALSE;
\r
1753 appData.autoFlipView = TRUE;
\r
1754 appData.cmailGameName = "";
\r
1755 appData.alwaysPromoteToQueen = FALSE;
\r
1756 appData.oldSaveStyle = FALSE;
\r
1757 appData.quietPlay = FALSE;
\r
1758 appData.showThinking = FALSE;
\r
1759 appData.ponderNextMove = TRUE;
\r
1760 appData.periodicUpdates = TRUE;
\r
1761 appData.popupExitMessage = TRUE;
\r
1762 appData.popupMoveErrors = FALSE;
\r
1763 appData.autoObserve = FALSE;
\r
1764 appData.autoComment = FALSE;
\r
1765 appData.animate = TRUE;
\r
1766 appData.animSpeed = 10;
\r
1767 appData.animateDragging = TRUE;
\r
1768 appData.highlightLastMove = TRUE;
\r
1769 appData.getMoveList = TRUE;
\r
1770 appData.testLegality = TRUE;
\r
1771 appData.premove = TRUE;
\r
1772 appData.premoveWhite = FALSE;
\r
1773 appData.premoveWhiteText = "";
\r
1774 appData.premoveBlack = FALSE;
\r
1775 appData.premoveBlackText = "";
\r
1776 appData.icsAlarm = TRUE;
\r
1777 appData.icsAlarmTime = 5000;
\r
1778 appData.autoRaiseBoard = TRUE;
\r
1779 appData.localLineEditing = TRUE;
\r
1780 appData.colorize = TRUE;
\r
1781 appData.reuseFirst = TRUE;
\r
1782 appData.reuseSecond = TRUE;
\r
1783 appData.blindfold = FALSE;
\r
1784 dcb.DCBlength = sizeof(DCB);
\r
1785 dcb.BaudRate = 9600;
\r
1786 dcb.fBinary = TRUE;
\r
1787 dcb.fParity = FALSE;
\r
1788 dcb.fOutxCtsFlow = FALSE;
\r
1789 dcb.fOutxDsrFlow = FALSE;
\r
1790 dcb.fDtrControl = DTR_CONTROL_ENABLE;
\r
1791 dcb.fDsrSensitivity = FALSE;
\r
1792 dcb.fTXContinueOnXoff = TRUE;
\r
1793 dcb.fOutX = FALSE;
\r
1795 dcb.fNull = FALSE;
\r
1796 dcb.fRtsControl = RTS_CONTROL_ENABLE;
\r
1797 dcb.fAbortOnError = FALSE;
\r
1798 dcb.wReserved = 0;
\r
1800 dcb.Parity = SPACEPARITY;
\r
1801 dcb.StopBits = ONESTOPBIT;
\r
1802 settingsFileName = SETTINGS_FILE;
\r
1803 saveSettingsOnExit = TRUE;
\r
1804 boardX = CW_USEDEFAULT;
\r
1805 boardY = CW_USEDEFAULT;
\r
1806 consoleX = CW_USEDEFAULT;
\r
1807 consoleY = CW_USEDEFAULT;
\r
1808 consoleW = CW_USEDEFAULT;
\r
1809 consoleH = CW_USEDEFAULT;
\r
1810 analysisX = CW_USEDEFAULT;
\r
1811 analysisY = CW_USEDEFAULT;
\r
1812 analysisW = CW_USEDEFAULT;
\r
1813 analysisH = CW_USEDEFAULT;
\r
1814 commentX = CW_USEDEFAULT;
\r
1815 commentY = CW_USEDEFAULT;
\r
1816 commentW = CW_USEDEFAULT;
\r
1817 commentH = CW_USEDEFAULT;
\r
1818 editTagsX = CW_USEDEFAULT;
\r
1819 editTagsY = CW_USEDEFAULT;
\r
1820 editTagsW = CW_USEDEFAULT;
\r
1821 editTagsH = CW_USEDEFAULT;
\r
1822 gameListX = CW_USEDEFAULT;
\r
1823 gameListY = CW_USEDEFAULT;
\r
1824 gameListW = CW_USEDEFAULT;
\r
1825 gameListH = CW_USEDEFAULT;
\r
1826 icsTextMenuString = ICS_TEXT_MENU_DEFAULT;
\r
1827 icsNames = ICS_NAMES;
\r
1828 firstChessProgramNames = FCP_NAMES;
\r
1829 secondChessProgramNames = SCP_NAMES;
\r
1830 appData.initialMode = "";
\r
1831 appData.variant = "normal";
\r
1832 appData.firstProtocolVersion = PROTOVER;
\r
1833 appData.secondProtocolVersion = PROTOVER;
\r
1834 appData.showButtonBar = TRUE;
\r
1836 /* [AS] New properties (see comments in header file) */
\r
1837 appData.firstScoreIsAbsolute = FALSE;
\r
1838 appData.secondScoreIsAbsolute = FALSE;
\r
1839 appData.saveExtendedInfoInPGN = FALSE;
\r
1840 appData.hideThinkingFromHuman = FALSE;
\r
1841 appData.liteBackTextureFile = "";
\r
1842 appData.liteBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1843 appData.darkBackTextureFile = "";
\r
1844 appData.darkBackTextureMode = BACK_TEXTURE_MODE_PLAIN;
\r
1845 appData.renderPiecesWithFont = "";
\r
1846 appData.fontToPieceTable = "";
\r
1847 appData.fontBackColorWhite = 0;
\r
1848 appData.fontForeColorWhite = 0;
\r
1849 appData.fontBackColorBlack = 0;
\r
1850 appData.fontForeColorBlack = 0;
\r
1851 appData.fontPieceSize = 80;
\r
1852 appData.overrideLineGap = 1;
\r
1853 appData.adjudicateLossThreshold = 0;
\r
1854 appData.delayBeforeQuit = 0;
\r
1855 appData.delayAfterQuit = 0;
\r
1856 appData.nameOfDebugFile = "winboard.debug";
\r
1857 appData.pgnEventHeader = "Computer Chess Game";
\r
1858 appData.defaultFrcPosition = -1;
\r
1859 appData.gameListTags = GLT_DEFAULT_TAGS;
\r
1860 appData.saveOutOfBookInfo = TRUE;
\r
1861 appData.showEvalInMoveHistory = TRUE;
\r
1862 appData.evalHistColorWhite = ParseColorName( "#FFFFB0" );
\r
1863 appData.evalHistColorBlack = ParseColorName( "#AD5D3D" );
\r
1864 appData.highlightMoveWithArrow = FALSE;
\r
1865 appData.highlightArrowColor = ParseColorName( "#FFFF80" );
\r
1866 appData.useStickyWindows = TRUE;
\r
1867 appData.adjudicateDrawMoves = 0;
\r
1868 appData.autoDisplayComment = TRUE;
\r
1869 appData.autoDisplayTags = TRUE;
\r
1870 appData.firstIsUCI = FALSE;
\r
1871 appData.secondIsUCI = FALSE;
\r
1872 appData.firstHasOwnBookUCI = TRUE;
\r
1873 appData.secondHasOwnBookUCI = TRUE;
\r
1874 appData.polyglotDir = "";
\r
1875 appData.usePolyglotBook = FALSE;
\r
1876 appData.polyglotBook = "";
\r
1877 appData.defaultHashSize = 64;
\r
1878 appData.defaultCacheSizeEGTB = 4;
\r
1879 appData.defaultPathEGTB = "c:\\egtb";
\r
1881 InitWindowPlacement( &wpMoveHistory );
\r
1882 InitWindowPlacement( &wpEvalGraph );
\r
1883 InitWindowPlacement( &wpEngineOutput );
\r
1885 /* [HGM] User-selectable board size, adjudication control, miscellaneous */
\r
1886 appData.NrFiles = -1;
\r
1887 appData.NrRanks = -1;
\r
1888 appData.holdingsSize = -1;
\r
1889 appData.testClaims = FALSE;
\r
1890 appData.checkMates = FALSE;
\r
1891 appData.materialDraws= FALSE;
\r
1892 appData.trivialDraws = FALSE;
\r
1893 appData.ruleMoves = 51;
\r
1894 appData.drawRepeats = 6;
\r
1895 appData.matchPause = 10000;
\r
1896 appData.alphaRank = FALSE;
\r
1897 appData.allWhite = FALSE;
\r
1898 appData.upsideDown = FALSE;
\r
1901 appData.zippyTalk = ZIPPY_TALK;
\r
1902 appData.zippyPlay = ZIPPY_PLAY;
\r
1903 appData.zippyLines = ZIPPY_LINES;
\r
1904 appData.zippyPinhead = ZIPPY_PINHEAD;
\r
1905 appData.zippyPassword = ZIPPY_PASSWORD;
\r
1906 appData.zippyPassword2 = ZIPPY_PASSWORD2;
\r
1907 appData.zippyWrongPassword = ZIPPY_WRONG_PASSWORD;
\r
1908 appData.zippyAcceptOnly = ZIPPY_ACCEPT_ONLY;
\r
1909 appData.zippyUseI = ZIPPY_USE_I;
\r
1910 appData.zippyBughouse = ZIPPY_BUGHOUSE;
\r
1911 appData.zippyNoplayCrafty = ZIPPY_NOPLAY_CRAFTY;
\r
1912 appData.zippyGameEnd = ZIPPY_GAME_END;
\r
1913 appData.zippyGameStart = ZIPPY_GAME_START;
\r
1914 appData.zippyAdjourn = ZIPPY_ADJOURN;
\r
1915 appData.zippyAbort = ZIPPY_ABORT;
\r
1916 appData.zippyVariants = ZIPPY_VARIANTS;
\r
1917 appData.zippyMaxGames = ZIPPY_MAX_GAMES;
\r
1918 appData.zippyReplayTimeout = ZIPPY_REPLAY_TIMEOUT;
\r
1921 /* Point font array elements to structures and
\r
1922 parse default font names */
\r
1923 for (i=0; i<NUM_FONTS; i++) {
\r
1924 for (j=0; j<NUM_SIZES; j++) {
\r
1925 font[j][i] = &fontRec[j][i];
\r
1926 ParseFontName(font[j][i]->def, &font[j][i]->mfp);
\r
1930 /* Parse default settings file if any */
\r
1931 if (ParseSettingsFile(settingsFileName, buf)) {
\r
1932 settingsFileName = strdup(buf);
\r
1935 /* Parse command line */
\r
1936 ParseArgs(StringGet, &lpCmdLine);
\r
1938 /* [HGM] make sure board size is acceptable */
\r
1939 if(appData.NrFiles > BOARD_SIZE ||
\r
1940 appData.NrRanks > BOARD_SIZE )
\r
1941 DisplayFatalError("Recompile with BOARD_SIZE > 12, to support this size", 0, 2);
\r
1943 /* Propagate options that affect others */
\r
1944 if (appData.matchMode || appData.matchGames) chessProgram = TRUE;
\r
1945 if (appData.icsActive || appData.noChessProgram) {
\r
1946 chessProgram = FALSE; /* not local chess program mode */
\r
1949 /* Open startup dialog if needed */
\r
1950 if ((!appData.noChessProgram && !chessProgram && !appData.icsActive) ||
\r
1951 (appData.icsActive && *appData.icsHost == NULLCHAR) ||
\r
1952 (chessProgram && (*appData.firstChessProgram == NULLCHAR ||
\r
1953 *appData.secondChessProgram == NULLCHAR))) {
\r
1956 lpProc = MakeProcInstance((FARPROC)StartupDialog, hInst);
\r
1957 DialogBox(hInst, MAKEINTRESOURCE(DLG_Startup), NULL, (DLGPROC)lpProc);
\r
1958 FreeProcInstance(lpProc);
\r
1961 /* Make sure save files land in the right (?) directory */
\r
1962 if (GetFullPathName(appData.saveGameFile, MSG_SIZ, buf, &dummy)) {
\r
1963 appData.saveGameFile = strdup(buf);
\r
1965 if (GetFullPathName(appData.savePositionFile, MSG_SIZ, buf, &dummy)) {
\r
1966 appData.savePositionFile = strdup(buf);
\r
1969 /* Finish initialization for fonts and sounds */
\r
1970 for (i=0; i<NUM_FONTS; i++) {
\r
1971 for (j=0; j<NUM_SIZES; j++) {
\r
1972 CreateFontInMF(font[j][i]);
\r
1975 /* xboard, and older WinBoards, controlled the move sound with the
\r
1976 appData.ringBellAfterMoves option. In the current WinBoard, we
\r
1977 always turn the option on (so that the backend will call us),
\r
1978 then let the user turn the sound off by setting it to silence if
\r
1979 desired. To accommodate old winboard.ini files saved by old
\r
1980 versions of WinBoard, we also turn off the sound if the option
\r
1981 was initially set to false. */
\r
1982 if (!appData.ringBellAfterMoves) {
\r
1983 sounds[(int)SoundMove].name = strdup("");
\r
1984 appData.ringBellAfterMoves = TRUE;
\r
1986 GetCurrentDirectory(MSG_SIZ, currDir);
\r
1987 SetCurrentDirectory(installDir);
\r
1989 SetCurrentDirectory(currDir);
\r
1991 p = icsTextMenuString;
\r
1992 if (p[0] == '@') {
\r
1993 FILE* f = fopen(p + 1, "r");
\r
1995 DisplayFatalError(p + 1, errno, 2);
\r
1998 i = fread(buf, 1, sizeof(buf)-1, f);
\r
2000 buf[i] = NULLCHAR;
\r
2003 ParseIcsTextMenu(strdup(p));
\r
2010 HMENU hmenu = GetMenu(hwndMain);
\r
2012 (void) EnableMenuItem(hmenu, IDM_CommPort,
\r
2013 MF_BYCOMMAND|((appData.icsActive &&
\r
2014 *appData.icsCommPort != NULLCHAR) ?
\r
2015 MF_ENABLED : MF_GRAYED));
\r
2016 (void) CheckMenuItem(hmenu, IDM_SaveSettingsOnExit,
\r
2017 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
2018 MF_CHECKED : MF_UNCHECKED));
\r
2023 SaveSettings(char* name)
\r
2026 ArgDescriptor *ad;
\r
2027 WINDOWPLACEMENT wp;
\r
2028 char dir[MSG_SIZ];
\r
2030 if (!hwndMain) return;
\r
2032 GetCurrentDirectory(MSG_SIZ, dir);
\r
2033 SetCurrentDirectory(installDir);
\r
2034 f = fopen(name, "w");
\r
2035 SetCurrentDirectory(dir);
\r
2037 DisplayError(name, errno);
\r
2040 fprintf(f, ";\n");
\r
2041 fprintf(f, "; %s %s.%s Save Settings file\n", PRODUCT, VERSION, PATCHLEVEL);
\r
2042 fprintf(f, ";\n");
\r
2043 fprintf(f, "; You can edit the values of options that are already set in this file,\n");
\r
2044 fprintf(f, "; but if you add other options, the next Save Settings will not save them.\n");
\r
2045 fprintf(f, "; Use a shortcut, an @indirection file, or a .bat file instead.\n");
\r
2046 fprintf(f, ";\n");
\r
2048 wp.length = sizeof(WINDOWPLACEMENT);
\r
2049 GetWindowPlacement(hwndMain, &wp);
\r
2050 boardX = wp.rcNormalPosition.left;
\r
2051 boardY = wp.rcNormalPosition.top;
\r
2053 if (hwndConsole) {
\r
2054 GetWindowPlacement(hwndConsole, &wp);
\r
2055 consoleX = wp.rcNormalPosition.left;
\r
2056 consoleY = wp.rcNormalPosition.top;
\r
2057 consoleW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2058 consoleH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2061 if (analysisDialog) {
\r
2062 GetWindowPlacement(analysisDialog, &wp);
\r
2063 analysisX = wp.rcNormalPosition.left;
\r
2064 analysisY = wp.rcNormalPosition.top;
\r
2065 analysisW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2066 analysisH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2069 if (commentDialog) {
\r
2070 GetWindowPlacement(commentDialog, &wp);
\r
2071 commentX = wp.rcNormalPosition.left;
\r
2072 commentY = wp.rcNormalPosition.top;
\r
2073 commentW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2074 commentH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2077 if (editTagsDialog) {
\r
2078 GetWindowPlacement(editTagsDialog, &wp);
\r
2079 editTagsX = wp.rcNormalPosition.left;
\r
2080 editTagsY = wp.rcNormalPosition.top;
\r
2081 editTagsW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2082 editTagsH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2085 if (gameListDialog) {
\r
2086 GetWindowPlacement(gameListDialog, &wp);
\r
2087 gameListX = wp.rcNormalPosition.left;
\r
2088 gameListY = wp.rcNormalPosition.top;
\r
2089 gameListW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2090 gameListH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2093 /* [AS] Move history */
\r
2094 wpMoveHistory.visible = MoveHistoryIsUp();
\r
2096 if( moveHistoryDialog ) {
\r
2097 GetWindowPlacement(moveHistoryDialog, &wp);
\r
2098 wpMoveHistory.x = wp.rcNormalPosition.left;
\r
2099 wpMoveHistory.y = wp.rcNormalPosition.top;
\r
2100 wpMoveHistory.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2101 wpMoveHistory.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2104 /* [AS] Eval graph */
\r
2105 wpEvalGraph.visible = EvalGraphIsUp();
\r
2107 if( evalGraphDialog ) {
\r
2108 GetWindowPlacement(evalGraphDialog, &wp);
\r
2109 wpEvalGraph.x = wp.rcNormalPosition.left;
\r
2110 wpEvalGraph.y = wp.rcNormalPosition.top;
\r
2111 wpEvalGraph.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2112 wpEvalGraph.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2115 /* [AS] Engine output */
\r
2116 wpEngineOutput.visible = EngineOutputIsUp();
\r
2118 if( engineOutputDialog ) {
\r
2119 GetWindowPlacement(engineOutputDialog, &wp);
\r
2120 wpEngineOutput.x = wp.rcNormalPosition.left;
\r
2121 wpEngineOutput.y = wp.rcNormalPosition.top;
\r
2122 wpEngineOutput.width = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
\r
2123 wpEngineOutput.height = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
\r
2126 for (ad = argDescriptors; ad->argName != NULL; ad++) {
\r
2127 if (!ad->save) continue;
\r
2128 switch (ad->argType) {
\r
2131 char *p = *(char **)ad->argLoc;
\r
2132 if ((strchr(p, '\\') || strchr(p, '\n')) && !strchr(p, '}')) {
\r
2133 /* Quote multiline values or \-containing values
\r
2134 with { } if possible */
\r
2135 fprintf(f, "/%s={%s}\n", ad->argName, p);
\r
2137 /* Else quote with " " */
\r
2138 fprintf(f, "/%s=\"", ad->argName);
\r
2140 if (*p == '\n') fprintf(f, "\n");
\r
2141 else if (*p == '\r') fprintf(f, "\\r");
\r
2142 else if (*p == '\t') fprintf(f, "\\t");
\r
2143 else if (*p == '\b') fprintf(f, "\\b");
\r
2144 else if (*p == '\f') fprintf(f, "\\f");
\r
2145 else if (*p < ' ') fprintf(f, "\\%03o", *p);
\r
2146 else if (*p == '\"') fprintf(f, "\\\"");
\r
2147 else if (*p == '\\') fprintf(f, "\\\\");
\r
2151 fprintf(f, "\"\n");
\r
2156 fprintf(f, "/%s=%d\n", ad->argName, *(int *)ad->argLoc);
\r
2159 fprintf(f, "/%s=%g\n", ad->argName, *(float *)ad->argLoc);
\r
2162 fprintf(f, "/%s=%s\n", ad->argName,
\r
2163 (*(Boolean *)ad->argLoc) ? "true" : "false");
\r
2166 if (*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2169 if (!*(Boolean *)ad->argLoc) fprintf(f, "/%s\n", ad->argName);
\r
2173 COLORREF color = *(COLORREF *)ad->argLoc;
\r
2174 fprintf(f, "/%s=#%02x%02x%02x\n", ad->argName,
\r
2175 color&0xff, (color>>8)&0xff, (color>>16)&0xff);
\r
2180 MyTextAttribs* ta = &textAttribs[(ColorClass)ad->argLoc];
\r
2181 fprintf(f, "/%s=\"%s%s%s%s%s#%02x%02x%02x\"\n", ad->argName,
\r
2182 (ta->effects & CFE_BOLD) ? "b" : "",
\r
2183 (ta->effects & CFE_ITALIC) ? "i" : "",
\r
2184 (ta->effects & CFE_UNDERLINE) ? "u" : "",
\r
2185 (ta->effects & CFE_STRIKEOUT) ? "s" : "",
\r
2186 (ta->effects) ? " " : "",
\r
2187 ta->color&0xff, (ta->color >> 8)&0xff, (ta->color >> 16)&0xff);
\r
2191 if (strchr(*(char **)ad->argLoc, '\"')) {
\r
2192 fprintf(f, "/%s='%s'\n", ad->argName, *(char **)ad->argLoc);
\r
2194 fprintf(f, "/%s=\"%s\"\n", ad->argName, *(char **)ad->argLoc);
\r
2197 case ArgBoardSize:
\r
2198 fprintf(f, "/%s=%s\n", ad->argName,
\r
2199 sizeInfo[*(BoardSize *)ad->argLoc].name);
\r
2204 for (bs=0; bs<NUM_SIZES; bs++) {
\r
2205 MyFontParams *mfp = &font[bs][(int) ad->argLoc]->mfp;
\r
2206 fprintf(f, "/size=%s ", sizeInfo[bs].name);
\r
2207 fprintf(f, "/%s=\"%s:%g%s%s%s%s%s\"\n",
\r
2208 ad->argName, mfp->faceName, mfp->pointSize,
\r
2209 mfp->bold || mfp->italic || mfp->underline || mfp->strikeout ? " " : "",
\r
2210 mfp->bold ? "b" : "",
\r
2211 mfp->italic ? "i" : "",
\r
2212 mfp->underline ? "u" : "",
\r
2213 mfp->strikeout ? "s" : "");
\r
2217 case ArgCommSettings:
\r
2218 PrintCommSettings(f, ad->argName, (DCB *)ad->argLoc);
\r
2226 /*---------------------------------------------------------------------------*\
\r
2228 * GDI board drawing routines
\r
2230 \*---------------------------------------------------------------------------*/
\r
2232 /* [AS] Draw square using background texture */
\r
2233 static void DrawTile( int dx, int dy, int dw, int dh, HDC dst, HDC src, int mode, int sx, int sy )
\r
2238 return; /* Should never happen! */
\r
2241 SetGraphicsMode( dst, GM_ADVANCED );
\r
2248 /* X reflection */
\r
2253 x.eDx = (FLOAT) dw + dx - 1;
\r
2256 SetWorldTransform( dst, &x );
\r
2259 /* Y reflection */
\r
2265 x.eDy = (FLOAT) dh + dy - 1;
\r
2267 SetWorldTransform( dst, &x );
\r
2275 x.eDx = (FLOAT) dx;
\r
2276 x.eDy = (FLOAT) dy;
\r
2279 SetWorldTransform( dst, &x );
\r
2283 BitBlt( dst, dx, dy, dw, dh, src, sx, sy, SRCCOPY );
\r
2291 SetWorldTransform( dst, &x );
\r
2293 ModifyWorldTransform( dst, 0, MWT_IDENTITY );
\r
2296 /* [AS] [HGM] Make room for more piece types, so all pieces can be different */
\r
2298 PM_WP = (int) WhitePawn,
\r
2299 PM_WN = (int) WhiteKnight,
\r
2300 PM_WB = (int) WhiteBishop,
\r
2301 PM_WR = (int) WhiteRook,
\r
2302 PM_WQ = (int) WhiteQueen,
\r
2303 PM_WF = (int) WhiteFerz,
\r
2304 PM_WW = (int) WhiteWazir,
\r
2305 PM_WE = (int) WhiteAlfil,
\r
2306 PM_WM = (int) WhiteMan,
\r
2307 PM_WO = (int) WhiteCannon,
\r
2308 PM_WU = (int) WhiteUnicorn,
\r
2309 PM_WH = (int) WhiteNightrider,
\r
2310 PM_WA = (int) WhiteCardinal,
\r
2311 PM_WC = (int) WhiteMarshall,
\r
2312 PM_WG = (int) WhiteGrasshopper,
\r
2313 PM_WK = (int) WhiteKing,
\r
2314 PM_BP = (int) BlackPawn,
\r
2315 PM_BN = (int) BlackKnight,
\r
2316 PM_BB = (int) BlackBishop,
\r
2317 PM_BR = (int) BlackRook,
\r
2318 PM_BQ = (int) BlackQueen,
\r
2319 PM_BF = (int) BlackFerz,
\r
2320 PM_BW = (int) BlackWazir,
\r
2321 PM_BE = (int) BlackAlfil,
\r
2322 PM_BM = (int) BlackMan,
\r
2323 PM_BO = (int) BlackCannon,
\r
2324 PM_BU = (int) BlackUnicorn,
\r
2325 PM_BH = (int) BlackNightrider,
\r
2326 PM_BA = (int) BlackCardinal,
\r
2327 PM_BC = (int) BlackMarshall,
\r
2328 PM_BG = (int) BlackGrasshopper,
\r
2329 PM_BK = (int) BlackKing
\r
2332 static HFONT hPieceFont = NULL;
\r
2333 static HBITMAP hPieceMask[(int) EmptySquare];
\r
2334 static HBITMAP hPieceFace[(int) EmptySquare];
\r
2335 static int fontBitmapSquareSize = 0;
\r
2336 static char pieceToFontChar[(int) EmptySquare] =
\r
2337 { 'p', 'n', 'b', 'r', 'q',
\r
2338 'n', 'b', 'p', 'n', 'b', 'r', 'b', 'r', 'q', 'k',
\r
2339 'k', 'o', 'm', 'v', 't', 'w',
\r
2340 'v', 't', 'o', 'm', 'v', 't', 'v', 't', 'w', 'l',
\r
2343 extern BOOL SetCharTable( char *table, const char * map );
\r
2344 /* [HGM] moved to backend.c */
\r
2346 static void SetPieceBackground( HDC hdc, COLORREF color, int mode )
\r
2349 BYTE r1 = GetRValue( color );
\r
2350 BYTE g1 = GetGValue( color );
\r
2351 BYTE b1 = GetBValue( color );
\r
2357 /* Create a uniform background first */
\r
2358 hbrush = CreateSolidBrush( color );
\r
2359 SetRect( &rc, 0, 0, squareSize, squareSize );
\r
2360 FillRect( hdc, &rc, hbrush );
\r
2361 DeleteObject( hbrush );
\r
2364 /* Vertical gradient, good for pawn, knight and rook, less for queen and king */
\r
2365 int steps = squareSize / 2;
\r
2368 for( i=0; i<steps; i++ ) {
\r
2369 BYTE r = r1 - (r1-r2) * i / steps;
\r
2370 BYTE g = g1 - (g1-g2) * i / steps;
\r
2371 BYTE b = b1 - (b1-b2) * i / steps;
\r
2373 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2374 SetRect( &rc, i + squareSize - steps, 0, i + squareSize - steps + 1, squareSize );
\r
2375 FillRect( hdc, &rc, hbrush );
\r
2376 DeleteObject(hbrush);
\r
2379 else if( mode == 2 ) {
\r
2380 /* Diagonal gradient, good more or less for every piece */
\r
2381 POINT triangle[3];
\r
2382 HPEN hpen = SelectObject( hdc, GetStockObject(NULL_PEN) );
\r
2383 HBRUSH hbrush_old;
\r
2384 int steps = squareSize;
\r
2387 triangle[0].x = squareSize - steps;
\r
2388 triangle[0].y = squareSize;
\r
2389 triangle[1].x = squareSize;
\r
2390 triangle[1].y = squareSize;
\r
2391 triangle[2].x = squareSize;
\r
2392 triangle[2].y = squareSize - steps;
\r
2394 for( i=0; i<steps; i++ ) {
\r
2395 BYTE r = r1 - (r1-r2) * i / steps;
\r
2396 BYTE g = g1 - (g1-g2) * i / steps;
\r
2397 BYTE b = b1 - (b1-b2) * i / steps;
\r
2399 hbrush = CreateSolidBrush( RGB(r,g,b) );
\r
2400 hbrush_old = SelectObject( hdc, hbrush );
\r
2401 Polygon( hdc, triangle, 3 );
\r
2402 SelectObject( hdc, hbrush_old );
\r
2403 DeleteObject(hbrush);
\r
2408 SelectObject( hdc, hpen );
\r
2413 [AS] The method I use to create the bitmaps it a bit tricky, but it
\r
2414 seems to work ok. The main problem here is to find the "inside" of a chess
\r
2415 piece: follow the steps as explained below.
\r
2417 static void CreatePieceMaskFromFont( HDC hdc_window, HDC hdc, int index )
\r
2421 COLORREF chroma = RGB(0xFF,0x00,0xFF);
\r
2425 int backColor = whitePieceColor;
\r
2426 int foreColor = blackPieceColor;
\r
2427 int shapeIndex = index < 6 ? index+6 : index;
\r
2429 if( index < 6 && appData.fontBackColorWhite != appData.fontForeColorWhite ) {
\r
2430 backColor = appData.fontBackColorWhite;
\r
2431 foreColor = appData.fontForeColorWhite;
\r
2433 else if( index >= 6 && appData.fontBackColorBlack != appData.fontForeColorBlack ) {
\r
2434 backColor = appData.fontBackColorBlack;
\r
2435 foreColor = appData.fontForeColorBlack;
\r
2439 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2441 hbm_old = SelectObject( hdc, hbm );
\r
2445 rc.right = squareSize;
\r
2446 rc.bottom = squareSize;
\r
2448 /* Step 1: background is now black */
\r
2449 FillRect( hdc, &rc, GetStockObject(BLACK_BRUSH) );
\r
2451 GetTextExtentPoint32( hdc, &pieceToFontChar[index], 1, &sz );
\r
2453 pt.x = (squareSize - sz.cx) / 2;
\r
2454 pt.y = (squareSize - sz.cy) / 2;
\r
2456 SetBkMode( hdc, TRANSPARENT );
\r
2457 SetTextColor( hdc, chroma );
\r
2458 /* Step 2: the piece has been drawn in purple, there are now black and purple in this bitmap */
\r
2459 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2461 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
\r
2462 /* Step 3: the area outside the piece is filled with white */
\r
2463 FloodFill( hdc, 0, 0, chroma );
\r
2464 SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
\r
2466 Step 4: this is the tricky part, the area inside the piece is filled with black,
\r
2467 but if the start point is not inside the piece we're lost!
\r
2468 There should be a better way to do this... if we could create a region or path
\r
2469 from the fill operation we would be fine for example.
\r
2471 FloodFill( hdc, squareSize / 2, squareSize / 2, RGB(0xFF,0xFF,0xFF) );
\r
2473 SetTextColor( hdc, 0 );
\r
2475 Step 5: some fonts have "disconnected" areas that are skipped by the fill:
\r
2476 draw the piece again in black for safety.
\r
2478 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2480 SelectObject( hdc, hbm_old );
\r
2482 if( hPieceMask[index] != NULL ) {
\r
2483 DeleteObject( hPieceMask[index] );
\r
2486 hPieceMask[index] = hbm;
\r
2489 hbm = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2491 SelectObject( hdc, hbm );
\r
2494 HDC dc1 = CreateCompatibleDC( hdc_window );
\r
2495 HDC dc2 = CreateCompatibleDC( hdc_window );
\r
2496 HBITMAP bm2 = CreateCompatibleBitmap( hdc_window, squareSize, squareSize );
\r
2498 SelectObject( dc1, hPieceMask[index] );
\r
2499 SelectObject( dc2, bm2 );
\r
2500 FillRect( dc2, &rc, GetStockObject(WHITE_BRUSH) );
\r
2501 BitBlt( dc2, 0, 0, squareSize, squareSize, dc1, 0, 0, SRCINVERT );
\r
2504 Now dc2 contains the inverse of the piece mask, i.e. a mask that preserves
\r
2505 the piece background and deletes (makes transparent) the rest.
\r
2506 Thanks to that mask, we are free to paint the background with the greates
\r
2507 freedom, as we'll be able to mask off the unwanted parts when finished.
\r
2508 We use this, to make gradients and give the pieces a "roundish" look.
\r
2510 SetPieceBackground( hdc, backColor, 2 );
\r
2511 BitBlt( hdc, 0, 0, squareSize, squareSize, dc2, 0, 0, SRCAND );
\r
2515 DeleteObject( bm2 );
\r
2518 SetTextColor( hdc, foreColor );
\r
2519 TextOut( hdc, pt.x, pt.y, &pieceToFontChar[index], 1 );
\r
2521 SelectObject( hdc, hbm_old );
\r
2523 if( hPieceFace[index] != NULL ) {
\r
2524 DeleteObject( hPieceFace[index] );
\r
2527 hPieceFace[index] = hbm;
\r
2530 static int TranslatePieceToFontPiece( int piece )
\r
2558 case BlackCardinal:
\r
2560 case BlackMarshall:
\r
2564 case BlackNightrider:
\r
2570 case BlackUnicorn:
\r
2574 case BlackGrasshopper:
\r
2578 case WhiteCardinal:
\r
2580 case WhiteMarshall:
\r
2584 case WhiteNightrider:
\r
2590 case WhiteUnicorn:
\r
2594 case WhiteGrasshopper:
\r
2604 void CreatePiecesFromFont()
\r
2607 HDC hdc_window = NULL;
\r
2613 if( fontBitmapSquareSize < 0 ) {
\r
2614 /* Something went seriously wrong in the past: do not try to recreate fonts! */
\r
2618 if( appData.renderPiecesWithFont == NULL || appData.renderPiecesWithFont[0] == NULLCHAR || appData.renderPiecesWithFont[0] == '*' ) {
\r
2619 fontBitmapSquareSize = -1;
\r
2623 if( fontBitmapSquareSize != squareSize ) {
\r
2624 hdc_window = GetDC( hwndMain );
\r
2625 hdc = CreateCompatibleDC( hdc_window );
\r
2627 if( hPieceFont != NULL ) {
\r
2628 DeleteObject( hPieceFont );
\r
2631 for( i=0; i<12; i++ ) {
\r
2632 hPieceMask[i] = NULL;
\r
2633 hPieceFace[i] = NULL;
\r
2639 if( appData.fontPieceSize >= 50 && appData.fontPieceSize <= 150 ) {
\r
2640 fontHeight = appData.fontPieceSize;
\r
2643 fontHeight = (fontHeight * squareSize) / 100;
\r
2645 lf.lfHeight = -MulDiv( fontHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72 );
\r
2647 lf.lfEscapement = 0;
\r
2648 lf.lfOrientation = 0;
\r
2649 lf.lfWeight = FW_NORMAL;
\r
2651 lf.lfUnderline = 0;
\r
2652 lf.lfStrikeOut = 0;
\r
2653 lf.lfCharSet = DEFAULT_CHARSET;
\r
2654 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
\r
2655 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
\r
2656 lf.lfQuality = PROOF_QUALITY;
\r
2657 lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
\r
2658 strncpy( lf.lfFaceName, appData.renderPiecesWithFont, sizeof(lf.lfFaceName) );
\r
2659 lf.lfFaceName[ sizeof(lf.lfFaceName) - 1 ] = '\0';
\r
2661 hPieceFont = CreateFontIndirect( &lf );
\r
2663 if( hPieceFont == NULL ) {
\r
2664 fontBitmapSquareSize = -2;
\r
2667 /* Setup font-to-piece character table */
\r
2668 if( ! SetCharTable(pieceToFontChar, appData.fontToPieceTable) ) {
\r
2669 /* No (or wrong) global settings, try to detect the font */
\r
2670 if( strstr(lf.lfFaceName,"Alpha") != NULL ) {
\r
2672 SetCharTable(pieceToFontChar, "phbrqkojntwl");
\r
2674 else if( strstr(lf.lfFaceName,"DiagramTT") != NULL ) {
\r
2675 /* DiagramTT* family */
\r
2676 SetCharTable(pieceToFontChar, "PNLRQKpnlrqk");
\r
2678 else if( strstr(lf.lfFaceName,"WinboardF") != NULL ) {
\r
2679 /* Fairy symbols */
\r
2680 SetCharTable(pieceToFontChar, "PNBRQFWEMOUHACGSKpnbrqfwemouhacgsk");
\r
2682 else if( strstr(lf.lfFaceName,"GC2004D") != NULL ) {
\r
2683 /* Good Companion (Some characters get warped as literal :-( */
\r
2684 char s[] = "1cmWG0ñueOS¯®oYI23wgQU";
\r
2685 s[0]=0xB9; s[1]=0xA9; s[6]=0xB1; s[11]=0xBB; s[12]=0xAB; s[17]=0xB3;
\r
2686 SetCharTable(pieceToFontChar, s);
\r
2689 /* Cases, Condal, Leipzig, Lucena, Marroquin, Merida, Usual */
\r
2690 SetCharTable(pieceToFontChar, "pnbrqkomvtwl");
\r
2694 /* Create bitmaps */
\r
2695 hfont_old = SelectObject( hdc, hPieceFont );
\r
2697 CreatePieceMaskFromFont( hdc_window, hdc, PM_WP );
\r
2698 CreatePieceMaskFromFont( hdc_window, hdc, PM_WN );
\r
2699 CreatePieceMaskFromFont( hdc_window, hdc, PM_WB );
\r
2700 CreatePieceMaskFromFont( hdc_window, hdc, PM_WR );
\r
2701 CreatePieceMaskFromFont( hdc_window, hdc, PM_WQ );
\r
2702 CreatePieceMaskFromFont( hdc_window, hdc, PM_WK );
\r
2703 CreatePieceMaskFromFont( hdc_window, hdc, PM_BP );
\r
2704 CreatePieceMaskFromFont( hdc_window, hdc, PM_BN );
\r
2705 CreatePieceMaskFromFont( hdc_window, hdc, PM_BB );
\r
2706 CreatePieceMaskFromFont( hdc_window, hdc, PM_BR );
\r
2707 CreatePieceMaskFromFont( hdc_window, hdc, PM_BQ );
\r
2708 CreatePieceMaskFromFont( hdc_window, hdc, PM_BK );
\r
2710 CreatePieceMaskFromFont( hdc_window, hdc, PM_WA );
\r
2711 CreatePieceMaskFromFont( hdc_window, hdc, PM_WC );
\r
2712 CreatePieceMaskFromFont( hdc_window, hdc, PM_WF );
\r
2713 CreatePieceMaskFromFont( hdc_window, hdc, PM_WH );
\r
2714 CreatePieceMaskFromFont( hdc_window, hdc, PM_WE );
\r
2715 CreatePieceMaskFromFont( hdc_window, hdc, PM_WW );
\r
2716 CreatePieceMaskFromFont( hdc_window, hdc, PM_WU );
\r
2717 CreatePieceMaskFromFont( hdc_window, hdc, PM_WO );
\r
2718 CreatePieceMaskFromFont( hdc_window, hdc, PM_WG );
\r
2719 CreatePieceMaskFromFont( hdc_window, hdc, PM_WM );
\r
2720 CreatePieceMaskFromFont( hdc_window, hdc, PM_BA );
\r
2721 CreatePieceMaskFromFont( hdc_window, hdc, PM_BC );
\r
2722 CreatePieceMaskFromFont( hdc_window, hdc, PM_BF );
\r
2723 CreatePieceMaskFromFont( hdc_window, hdc, PM_BH );
\r
2724 CreatePieceMaskFromFont( hdc_window, hdc, PM_BE );
\r
2725 CreatePieceMaskFromFont( hdc_window, hdc, PM_BW );
\r
2726 CreatePieceMaskFromFont( hdc_window, hdc, PM_BU );
\r
2727 CreatePieceMaskFromFont( hdc_window, hdc, PM_BO );
\r
2728 CreatePieceMaskFromFont( hdc_window, hdc, PM_BG );
\r
2729 CreatePieceMaskFromFont( hdc_window, hdc, PM_BM );
\r
2732 SelectObject( hdc, hfont_old );
\r
2734 fontBitmapSquareSize = squareSize;
\r
2738 if( hdc != NULL ) {
\r
2742 if( hdc_window != NULL ) {
\r
2743 ReleaseDC( hwndMain, hdc_window );
\r
2748 DoLoadBitmap(HINSTANCE hinst, char *piece, int squareSize, char *suffix)
\r
2752 sprintf(name, "%s%d%s", piece, squareSize, suffix);
\r
2753 if (gameInfo.event &&
\r
2754 strcmp(gameInfo.event, "Easter Egg Hunt") == 0 &&
\r
2755 strcmp(name, "k80s") == 0) {
\r
2756 strcpy(name, "tim");
\r
2758 return LoadBitmap(hinst, name);
\r
2762 /* Insert a color into the program's logical palette
\r
2763 structure. This code assumes the given color is
\r
2764 the result of the RGB or PALETTERGB macro, and it
\r
2765 knows how those macros work (which is documented).
\r
2768 InsertInPalette(COLORREF color)
\r
2770 LPPALETTEENTRY pe = &(pLogPal->palPalEntry[pLogPal->palNumEntries]);
\r
2772 if (pLogPal->palNumEntries++ >= PALETTESIZE) {
\r
2773 DisplayFatalError("Too many colors", 0, 1);
\r
2774 pLogPal->palNumEntries--;
\r
2778 pe->peFlags = (char) 0;
\r
2779 pe->peRed = (char) (0xFF & color);
\r
2780 pe->peGreen = (char) (0xFF & (color >> 8));
\r
2781 pe->peBlue = (char) (0xFF & (color >> 16));
\r
2787 InitDrawingColors()
\r
2789 if (pLogPal == NULL) {
\r
2790 /* Allocate enough memory for a logical palette with
\r
2791 * PALETTESIZE entries and set the size and version fields
\r
2792 * of the logical palette structure.
\r
2794 pLogPal = (NPLOGPALETTE)
\r
2795 LocalAlloc(LMEM_FIXED, (sizeof(LOGPALETTE) +
\r
2796 (sizeof(PALETTEENTRY) * (PALETTESIZE))));
\r
2797 pLogPal->palVersion = 0x300;
\r
2799 pLogPal->palNumEntries = 0;
\r
2801 InsertInPalette(lightSquareColor);
\r
2802 InsertInPalette(darkSquareColor);
\r
2803 InsertInPalette(whitePieceColor);
\r
2804 InsertInPalette(blackPieceColor);
\r
2805 InsertInPalette(highlightSquareColor);
\r
2806 InsertInPalette(premoveHighlightColor);
\r
2808 /* create a logical color palette according the information
\r
2809 * in the LOGPALETTE structure.
\r
2811 hPal = CreatePalette((LPLOGPALETTE) pLogPal);
\r
2813 lightSquareBrush = CreateSolidBrush(lightSquareColor);
\r
2814 blackSquareBrush = CreateSolidBrush(blackPieceColor);
\r
2815 darkSquareBrush = CreateSolidBrush(darkSquareColor);
\r
2816 whitePieceBrush = CreateSolidBrush(whitePieceColor);
\r
2817 blackPieceBrush = CreateSolidBrush(blackPieceColor);
\r
2818 iconBkgndBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));
\r
2820 /* [AS] Force rendering of the font-based pieces */
\r
2821 if( fontBitmapSquareSize > 0 ) {
\r
2822 fontBitmapSquareSize = 0;
\r
2828 BoardWidth(int boardSize, int n)
\r
2829 { /* [HGM] argument n added to allow different width and height */
\r
2830 int lineGap = sizeInfo[boardSize].lineGap;
\r
2832 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2833 lineGap = appData.overrideLineGap;
\r
2836 return (n + 1) * lineGap +
\r
2837 n * sizeInfo[boardSize].squareSize;
\r
2840 /* Respond to board resize by dragging edge */
\r
2842 ResizeBoard(int newSizeX, int newSizeY, int flags)
\r
2844 BoardSize newSize = NUM_SIZES - 1;
\r
2845 static int recurse = 0;
\r
2846 if (IsIconic(hwndMain)) return;
\r
2847 if (recurse > 0) return;
\r
2849 while (newSize > 0 &&
\r
2850 (newSizeX < sizeInfo[newSize].cliWidth ||
\r
2851 newSizeY < sizeInfo[newSize].cliHeight)) {
\r
2854 boardSize = newSize;
\r
2855 InitDrawingSizes(boardSize, flags);
\r
2862 InitDrawingSizes(BoardSize boardSize, int flags)
\r
2864 int i, boardWidth, boardHeight; /* [HGM] height treated separately */
\r
2865 ChessSquare piece;
\r
2866 static int oldBoardSize = -1, oldTinyLayout = 0;
\r
2868 SIZE clockSize, messageSize;
\r
2870 char buf[MSG_SIZ];
\r
2872 HMENU hmenu = GetMenu(hwndMain);
\r
2873 RECT crect, wrect;
\r
2875 LOGBRUSH logbrush;
\r
2877 /* [HGM] call with -1 uses old size (for if nr of files, ranks changes) */
\r
2878 if(boardSize == (BoardSize)(-2) ) boardSize = oldBoardSize;
\r
2880 tinyLayout = sizeInfo[boardSize].tinyLayout;
\r
2881 smallLayout = sizeInfo[boardSize].smallLayout;
\r
2882 squareSize = sizeInfo[boardSize].squareSize;
\r
2883 lineGap = sizeInfo[boardSize].lineGap;
\r
2884 minorSize = 0; /* [HGM] Kludge to see if demagnified pieces need to be shifted */
\r
2886 if( appData.overrideLineGap >= 0 && appData.overrideLineGap <= 5 ) {
\r
2887 lineGap = appData.overrideLineGap;
\r
2890 if (tinyLayout != oldTinyLayout) {
\r
2891 long style = GetWindowLong(hwndMain, GWL_STYLE);
\r
2893 style &= ~WS_SYSMENU;
\r
2894 InsertMenu(hmenu, IDM_Exit, MF_BYCOMMAND, IDM_Minimize,
\r
2895 "&Minimize\tCtrl+F4");
\r
2897 style |= WS_SYSMENU;
\r
2898 RemoveMenu(hmenu, IDM_Minimize, MF_BYCOMMAND);
\r
2900 SetWindowLong(hwndMain, GWL_STYLE, style);
\r
2902 for (i=0; menuBarText[tinyLayout][i]; i++) {
\r
2903 ModifyMenu(hmenu, i, MF_STRING|MF_BYPOSITION|MF_POPUP,
\r
2904 (UINT)GetSubMenu(hmenu, i), menuBarText[tinyLayout][i]);
\r
2906 DrawMenuBar(hwndMain);
\r
2909 boardWidth = BoardWidth(boardSize, BOARD_WIDTH);
\r
2910 boardHeight = BoardWidth(boardSize, BOARD_HEIGHT);
\r
2912 /* Get text area sizes */
\r
2913 hdc = GetDC(hwndMain);
\r
2914 if (appData.clockMode) {
\r
2915 sprintf(buf, "White: %s", TimeString(23*60*60*1000L));
\r
2917 sprintf(buf, "White");
\r
2919 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
2920 GetTextExtentPoint(hdc, buf, strlen(buf), &clockSize);
\r
2921 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
2922 str = "We only care about the height here";
\r
2923 GetTextExtentPoint(hdc, str, strlen(str), &messageSize);
\r
2924 SelectObject(hdc, oldFont);
\r
2925 ReleaseDC(hwndMain, hdc);
\r
2927 /* Compute where everything goes */
\r
2928 whiteRect.left = OUTER_MARGIN;
\r
2929 whiteRect.right = whiteRect.left + boardWidth/2 - INNER_MARGIN/2;
\r
2930 whiteRect.top = OUTER_MARGIN;
\r
2931 whiteRect.bottom = whiteRect.top + clockSize.cy;
\r
2933 blackRect.left = whiteRect.right + INNER_MARGIN;
\r
2934 blackRect.right = blackRect.left + boardWidth/2 - 1;
\r
2935 blackRect.top = whiteRect.top;
\r
2936 blackRect.bottom = whiteRect.bottom;
\r
2938 messageRect.left = whiteRect.left + MESSAGE_LINE_LEFTMARGIN;
\r
2939 if (appData.showButtonBar) {
\r
2940 messageRect.right = blackRect.right
\r
2941 - N_BUTTONS*BUTTON_WIDTH - MESSAGE_LINE_LEFTMARGIN;
\r
2943 messageRect.right = blackRect.right;
\r
2945 messageRect.top = whiteRect.bottom + INNER_MARGIN;
\r
2946 messageRect.bottom = messageRect.top + messageSize.cy;
\r
2948 boardRect.left = whiteRect.left;
\r
2949 boardRect.right = boardRect.left + boardWidth;
\r
2950 boardRect.top = messageRect.bottom + INNER_MARGIN;
\r
2951 boardRect.bottom = boardRect.top + boardHeight;
\r
2953 sizeInfo[boardSize].cliWidth = boardRect.right + OUTER_MARGIN;
\r
2954 sizeInfo[boardSize].cliHeight = boardRect.bottom + OUTER_MARGIN;
\r
2955 winWidth = 2 * GetSystemMetrics(SM_CXFRAME) + boardRect.right + OUTER_MARGIN;
\r
2956 winHeight = 2 * GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYMENU) +
\r
2957 GetSystemMetrics(SM_CYCAPTION) + boardRect.bottom + OUTER_MARGIN;
\r
2958 GetWindowRect(hwndMain, &wrect);
\r
2959 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2960 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2961 /* compensate if menu bar wrapped */
\r
2962 GetClientRect(hwndMain, &crect);
\r
2963 offby = boardRect.bottom + OUTER_MARGIN - crect.bottom;
\r
2964 winHeight += offby;
\r
2966 case WMSZ_TOPLEFT:
\r
2967 SetWindowPos(hwndMain, NULL,
\r
2968 wrect.right - winWidth, wrect.bottom - winHeight,
\r
2969 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2972 case WMSZ_TOPRIGHT:
\r
2974 SetWindowPos(hwndMain, NULL,
\r
2975 wrect.left, wrect.bottom - winHeight,
\r
2976 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2979 case WMSZ_BOTTOMLEFT:
\r
2981 SetWindowPos(hwndMain, NULL,
\r
2982 wrect.right - winWidth, wrect.top,
\r
2983 winWidth, winHeight, SWP_NOCOPYBITS|SWP_NOZORDER);
\r
2986 case WMSZ_BOTTOMRIGHT:
\r
2990 SetWindowPos(hwndMain, NULL, 0, 0, winWidth, winHeight,
\r
2991 SWP_NOCOPYBITS|SWP_NOZORDER|SWP_NOMOVE);
\r
2996 for (i = 0; i < N_BUTTONS; i++) {
\r
2997 if (buttonDesc[i].hwnd != NULL) {
\r
2998 DestroyWindow(buttonDesc[i].hwnd);
\r
2999 buttonDesc[i].hwnd = NULL;
\r
3001 if (appData.showButtonBar) {
\r
3002 buttonDesc[i].hwnd =
\r
3003 CreateWindow("BUTTON", buttonDesc[i].label,
\r
3004 WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
\r
3005 boardRect.right - BUTTON_WIDTH*(N_BUTTONS-i),
\r
3006 messageRect.top, BUTTON_WIDTH, messageSize.cy, hwndMain,
\r
3007 (HMENU) buttonDesc[i].id,
\r
3008 (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
\r
3010 SendMessage(buttonDesc[i].hwnd, WM_SETFONT,
\r
3011 (WPARAM)font[boardSize][MESSAGE_FONT]->hf,
\r
3012 MAKELPARAM(FALSE, 0));
\r
3014 if (buttonDesc[i].id == IDM_Pause)
\r
3015 hwndPause = buttonDesc[i].hwnd;
\r
3016 buttonDesc[i].wndproc = (WNDPROC)
\r
3017 SetWindowLong(buttonDesc[i].hwnd, GWL_WNDPROC, (LONG) ButtonProc);
\r
3020 if (gridPen != NULL) DeleteObject(gridPen);
\r
3021 if (highlightPen != NULL) DeleteObject(highlightPen);
\r
3022 if (premovePen != NULL) DeleteObject(premovePen);
\r
3023 if (lineGap != 0) {
\r
3024 logbrush.lbStyle = BS_SOLID;
\r
3025 logbrush.lbColor = RGB(0, 0, 0); /* grid pen color = black */
\r
3027 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3028 lineGap, &logbrush, 0, NULL);
\r
3029 logbrush.lbColor = highlightSquareColor;
\r
3031 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3032 lineGap, &logbrush, 0, NULL);
\r
3034 logbrush.lbColor = premoveHighlightColor;
\r
3036 ExtCreatePen(PS_GEOMETRIC|PS_SOLID|PS_ENDCAP_FLAT|PS_JOIN_MITER,
\r
3037 lineGap, &logbrush, 0, NULL);
\r
3039 /* [HGM] Loop had to be split in part for vert. and hor. lines */
\r
3040 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
\r
3041 gridEndpoints[i*2].x = boardRect.left + lineGap / 2;
\r
3042 gridEndpoints[i*2].y = gridEndpoints[i*2 + 1].y =
\r
3043 boardRect.top + lineGap / 2 + (i * (squareSize + lineGap));
\r
3044 gridEndpoints[i*2 + 1].x = boardRect.left + lineGap / 2 +
\r
3045 BOARD_WIDTH * (squareSize + lineGap);
\r
3046 lineGap / 2 + (i * (squareSize + lineGap));
\r
3047 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3049 for (i = 0; i < BOARD_WIDTH + 1; i++) {
\r
3050 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].y = boardRect.top + lineGap / 2;
\r
3051 gridEndpoints[i*2 + BOARD_HEIGHT*2 + 2].x =
\r
3052 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].x = boardRect.left +
\r
3053 lineGap / 2 + (i * (squareSize + lineGap));
\r
3054 gridEndpoints[i*2 + 1 + BOARD_HEIGHT*2 + 2].y =
\r
3055 boardRect.top + BOARD_HEIGHT * (squareSize + lineGap);
\r
3056 gridVertexCounts[i*2] = gridVertexCounts[i*2 + 1] = 2;
\r
3061 /* [HGM] Gothic licensing requirement */
\r
3062 GothicPopUp( GOTHIC, gameInfo.variant == VariantGothic );
\r
3065 /* if (boardSize == oldBoardSize) return; [HGM] variant might have changed */
\r
3066 oldBoardSize = boardSize;
\r
3067 oldTinyLayout = tinyLayout;
\r
3069 /* Load piece bitmaps for this board size */
\r
3070 for (i=0; i<=2; i++) {
\r
3071 for (piece = WhitePawn;
\r
3072 (int) piece < (int) BlackPawn;
\r
3073 piece = (ChessSquare) ((int) piece + 1)) {
\r
3074 if (pieceBitmap[i][piece] != NULL)
\r
3075 DeleteObject(pieceBitmap[i][piece]);
\r
3079 pieceBitmap[0][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "s");
\r
3080 pieceBitmap[0][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "s");
\r
3081 pieceBitmap[0][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "s");
\r
3082 pieceBitmap[0][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "s");
\r
3083 pieceBitmap[0][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "s");
\r
3084 pieceBitmap[1][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "o");
\r
3085 pieceBitmap[1][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "o");
\r
3086 pieceBitmap[1][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "o");
\r
3087 pieceBitmap[1][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "o");
\r
3088 pieceBitmap[1][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "o");
\r
3089 pieceBitmap[2][WhitePawn] = DoLoadBitmap(hInst, "p", squareSize, "w");
\r
3090 pieceBitmap[2][WhiteKnight] = DoLoadBitmap(hInst, "n", squareSize, "w");
\r
3091 pieceBitmap[2][WhiteBishop] = DoLoadBitmap(hInst, "b", squareSize, "w");
\r
3092 pieceBitmap[2][WhiteRook] = DoLoadBitmap(hInst, "r", squareSize, "w");
\r
3093 pieceBitmap[2][WhiteKing] = DoLoadBitmap(hInst, "k", squareSize, "w");
\r
3094 if( !strcmp(appData.variant, "shogi") && (squareSize==72 || squareSize==49)) {
\r
3095 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3096 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3097 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3099 pieceBitmap[0][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "s");
\r
3100 pieceBitmap[1][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "o");
\r
3101 pieceBitmap[2][WhiteQueen] = DoLoadBitmap(hInst, "q", squareSize, "w");
\r
3103 if(squareSize==72 || squareSize==49) { /* experiment with some home-made bitmaps */
\r
3104 pieceBitmap[0][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "s");
\r
3105 pieceBitmap[1][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "o");
\r
3106 pieceBitmap[2][WhiteFerz] = DoLoadBitmap(hInst, "f", squareSize, "w");
\r
3107 pieceBitmap[0][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "s");
\r
3108 pieceBitmap[1][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "o");
\r
3109 pieceBitmap[2][WhiteWazir] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3110 pieceBitmap[0][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "s");
\r
3111 pieceBitmap[1][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "o");
\r
3112 pieceBitmap[2][WhiteAlfil] = DoLoadBitmap(hInst, "e", squareSize, "w");
\r
3113 pieceBitmap[0][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "s");
\r
3114 pieceBitmap[1][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "o");
\r
3115 pieceBitmap[2][WhiteMan] = DoLoadBitmap(hInst, "m", squareSize, "w");
\r
3116 pieceBitmap[0][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "s");
\r
3117 pieceBitmap[1][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "o");
\r
3118 pieceBitmap[2][WhiteCannon] = DoLoadBitmap(hInst, "o", squareSize, "w");
\r
3119 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "s");
\r
3120 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "o");
\r
3121 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "a", squareSize, "w");
\r
3122 if(gameInfo.variant == VariantShogi) { /* promoted Gold represemtations */
\r
3123 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "wp", squareSize, "s");
\r
3124 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "wp", squareSize, "o");
\r
3125 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3126 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "s");
\r
3127 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "wn", squareSize, "o");
\r
3128 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3129 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "s");
\r
3130 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "ws", squareSize, "o");
\r
3131 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3132 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "s");
\r
3133 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "wl", squareSize, "o");
\r
3134 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "w", squareSize, "w");
\r
3136 pieceBitmap[0][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "s");
\r
3137 pieceBitmap[1][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "o");
\r
3138 pieceBitmap[2][WhiteUnicorn] = DoLoadBitmap(hInst, "u", squareSize, "w");
\r
3139 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "s");
\r
3140 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "o");
\r
3141 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "h", squareSize, "w");
\r
3142 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "s");
\r
3143 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "o");
\r
3144 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "g", squareSize, "w");
\r
3145 pieceBitmap[0][WhiteSilver] = DoLoadBitmap(hInst, "l", squareSize, "s");
\r
3146 pieceBitmap[1][WhiteSilver] = DoLoadBitmap(hInst, "l", squareSize, "o");
\r
3147 pieceBitmap[2][WhiteSilver] = DoLoadBitmap(hInst, "l", squareSize, "w");
\r
3149 if(gameInfo.variant != VariantCrazyhouse && gameInfo.variant != VariantShogi) {
\r
3150 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "s");
\r
3151 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "o");
\r
3152 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "c", squareSize, "w");
\r
3154 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "s");
\r
3155 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "o");
\r
3156 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "dk", squareSize, "w");
\r
3158 } else { /* other size, no special bitmaps available. Use smaller symbols */
\r
3159 if((int)boardSize < 2) minorSize = sizeInfo[0].squareSize;
\r
3160 else minorSize = sizeInfo[(int)boardSize - 2].squareSize;
\r
3161 pieceBitmap[0][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "s");
\r
3162 pieceBitmap[1][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "o");
\r
3163 pieceBitmap[2][WhiteNightrider] = DoLoadBitmap(hInst, "n", minorSize, "w");
\r
3164 pieceBitmap[0][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "s");
\r
3165 pieceBitmap[1][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "o");
\r
3166 pieceBitmap[2][WhiteCardinal] = DoLoadBitmap(hInst, "b", minorSize, "w");
\r
3167 pieceBitmap[0][WhiteMarshall] = DoLoadBitmap(hInst, "r", minorSize, "s");
\r
3168 pieceBitmap[1][WhiteMarshall] = DoLoadBitmap(hInst, "r", minorSize, "o");
\r
3169 pieceBitmap[2][WhiteMarshall] = DoLoadBitmap(hInst, "r", minorSize, "w");
\r
3170 pieceBitmap[0][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "s");
\r
3171 pieceBitmap[1][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "o");
\r
3172 pieceBitmap[2][WhiteGrasshopper] = DoLoadBitmap(hInst, "q", minorSize, "w");
\r
3177 PieceBitmap(ChessSquare p, int kind)
\r
3179 if ((int) p >= (int) BlackPawn)
\r
3180 p = (ChessSquare) ((int) p - (int) BlackPawn + (int) WhitePawn);
\r
3182 return pieceBitmap[kind][(int) p];
\r
3185 /***************************************************************/
\r
3187 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
\r
3188 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
\r
3190 #define MIN3(a,b,c) (((a) < (b) && (a) < (c)) ? (a) : (((b) < (a) && (b) < (c)) ? (b) : (c)))
\r
3191 #define MAX3(a,b,c) (((a) > (b) && (a) > (c)) ? (a) : (((b) > (a) && (b) > (c)) ? (b) : (c)))
\r
3195 SquareToPos(int row, int column, int * x, int * y)
\r
3198 *x = boardRect.left + lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
3199 *y = boardRect.top + lineGap + row * (squareSize + lineGap);
\r
3201 *x = boardRect.left + lineGap + column * (squareSize + lineGap);
\r
3202 *y = boardRect.top + lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
3207 DrawCoordsOnDC(HDC hdc)
\r
3209 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
3210 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
3211 char str[2] = { NULLCHAR, NULLCHAR };
\r
3212 int oldMode, oldAlign, x, y, start, i;
\r
3216 if (!appData.showCoords)
\r
3219 start = flipView ? 1-(ONE!='1') : 23+(ONE!='1')-BOARD_HEIGHT;
\r
3221 oldBrush = SelectObject(hdc, GetStockObject(BLACK_BRUSH));
\r
3222 oldMode = SetBkMode(hdc, (appData.monoMode ? OPAQUE : TRANSPARENT));
\r
3223 oldAlign = GetTextAlign(hdc);
\r
3224 oldFont = SelectObject(hdc, font[boardSize][COORD_FONT]->hf);
\r
3226 y = boardRect.top + lineGap;
\r
3227 x = boardRect.left + lineGap;
\r
3229 SetTextAlign(hdc, TA_LEFT|TA_TOP);
\r
3230 for (i = 0; i < BOARD_HEIGHT; i++) {
\r
3231 str[0] = files[start + i];
\r
3232 ExtTextOut(hdc, x + 2, y + 1, 0, NULL, str, 1, NULL);
\r
3233 y += squareSize + lineGap;
\r
3236 start = flipView ? 12-BOARD_WIDTH : 12;
\r
3238 SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
\r
3239 for (i = 0; i < BOARD_WIDTH; i++) {
\r
3240 str[0] = ranks[start + i];
\r
3241 ExtTextOut(hdc, x + squareSize - 2, y - 1, 0, NULL, str, 1, NULL);
\r
3242 x += squareSize + lineGap;
\r
3245 SelectObject(hdc, oldBrush);
\r
3246 SetBkMode(hdc, oldMode);
\r
3247 SetTextAlign(hdc, oldAlign);
\r
3248 SelectObject(hdc, oldFont);
\r
3252 DrawGridOnDC(HDC hdc)
\r
3256 if (lineGap != 0) {
\r
3257 oldPen = SelectObject(hdc, gridPen);
\r
3258 PolyPolyline(hdc, gridEndpoints, gridVertexCounts, BOARD_WIDTH+BOARD_HEIGHT + 2);
\r
3259 SelectObject(hdc, oldPen);
\r
3263 #define HIGHLIGHT_PEN 0
\r
3264 #define PREMOVE_PEN 1
\r
3267 DrawHighlightOnDC(HDC hdc, BOOLEAN on, int x, int y, int pen)
\r
3270 HPEN oldPen, hPen;
\r
3271 if (lineGap == 0) return;
\r
3273 x1 = boardRect.left +
\r
3274 lineGap/2 + ((BOARD_WIDTH-1)-x) * (squareSize + lineGap);
\r
3275 y1 = boardRect.top +
\r
3276 lineGap/2 + y * (squareSize + lineGap);
\r
3278 x1 = boardRect.left +
\r
3279 lineGap/2 + x * (squareSize + lineGap);
\r
3280 y1 = boardRect.top +
\r
3281 lineGap/2 + ((BOARD_HEIGHT-1)-y) * (squareSize + lineGap);
\r
3283 hPen = pen ? premovePen : highlightPen;
\r
3284 oldPen = SelectObject(hdc, on ? hPen : gridPen);
\r
3285 MoveToEx(hdc, x1, y1, NULL);
\r
3286 LineTo(hdc, x1 + squareSize + lineGap, y1);
\r
3287 LineTo(hdc, x1 + squareSize + lineGap, y1 + squareSize + lineGap);
\r
3288 LineTo(hdc, x1, y1 + squareSize + lineGap);
\r
3289 LineTo(hdc, x1, y1);
\r
3290 SelectObject(hdc, oldPen);
\r
3294 DrawHighlightsOnDC(HDC hdc)
\r
3297 for (i=0; i<2; i++) {
\r
3298 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0)
\r
3299 DrawHighlightOnDC(hdc, TRUE,
\r
3300 highlightInfo.sq[i].x, highlightInfo.sq[i].y,
\r
3303 for (i=0; i<2; i++) {
\r
3304 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
3305 premoveHighlightInfo.sq[i].y >= 0) {
\r
3306 DrawHighlightOnDC(hdc, TRUE,
\r
3307 premoveHighlightInfo.sq[i].x,
\r
3308 premoveHighlightInfo.sq[i].y,
\r
3314 /* Note: sqcolor is used only in monoMode */
\r
3315 /* Note that this code is largely duplicated in woptions.c,
\r
3316 function DrawSampleSquare, so that needs to be updated too */
\r
3318 DrawPieceOnDC(HDC hdc, ChessSquare piece, int color, int sqcolor, int x, int y, HDC tmphdc)
\r
3320 HBITMAP oldBitmap;
\r
3324 if (appData.blindfold) return;
\r
3326 /* [AS] Use font-based pieces if needed */
\r
3327 if( fontBitmapSquareSize >= 0 && squareSize > 32 ) {
\r
3328 /* Create piece bitmaps, or do nothing if piece set is up to date */
\r
3329 CreatePiecesFromFont();
\r
3331 if( fontBitmapSquareSize == squareSize ) {
\r
3332 int index = TranslatePieceToFontPiece( piece );
\r
3334 SelectObject( tmphdc, hPieceMask[ index ] );
\r
3338 squareSize, squareSize,
\r
3343 SelectObject( tmphdc, hPieceFace[ index ] );
\r
3347 squareSize, squareSize,
\r
3356 if (appData.monoMode) {
\r
3357 SelectObject(tmphdc, PieceBitmap(piece,
\r
3358 color == sqcolor ? OUTLINE_PIECE : SOLID_PIECE));
\r
3359 BitBlt(hdc, x, y, squareSize, squareSize, tmphdc, 0, 0,
\r
3360 sqcolor ? SRCCOPY : NOTSRCCOPY);
\r
3362 tmpSize = squareSize;
\r
3364 (piece >= (int)WhiteNightrider && piece <= WhiteGrasshopper ||
\r
3365 piece >= (int)BlackNightrider && piece <= BlackGrasshopper) ) {
\r
3366 /* [HGM] no bitmap available for promoted pieces in Crazyhouse */
\r
3367 /* Bitmaps of smaller size are substituted, but we have to align them */
\r
3368 x += (squareSize - minorSize)>>1;
\r
3369 y += squareSize - minorSize - 2;
\r
3370 tmpSize = minorSize;
\r
3372 if (color || appData.allWhite ) {
\r
3373 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, WHITE_PIECE));
\r
3375 oldBrush = SelectObject(hdc, whitePieceBrush);
\r
3376 else oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3377 if(appData.upsideDown && !color)
\r
3378 StretchBlt(hdc, x, y+tmpSize, tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3380 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3382 /* Use black piece color for outline of white pieces */
\r
3383 /* Not sure this looks really good (though xboard does it).
\r
3384 Maybe better to have another selectable color, default black */
\r
3385 SelectObject(hdc, blackPieceBrush); /* could have own brush */
\r
3386 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3387 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3389 /* Use black for outline of white pieces */
\r
3390 SelectObject(tmphdc, PieceBitmap(piece, OUTLINE_PIECE));
\r
3391 if(appData.upsideDown && !color)
\r
3392 StretchBlt(hdc, x, y+tmpSize, tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, SRCAND);
\r
3394 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, SRCAND);
\r
3398 /* Use white piece color for details of black pieces */
\r
3399 /* Requires filled-in solid bitmaps (BLACK_PIECE class); the
\r
3400 WHITE_PIECE ones aren't always the right shape. */
\r
3401 /* Not sure this looks really good (though xboard does it).
\r
3402 Maybe better to have another selectable color, default medium gray? */
\r
3403 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, BLACK_PIECE));
\r
3404 oldBrush = SelectObject(hdc, whitePieceBrush); /* could have own brush */
\r
3405 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3406 SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3407 SelectObject(hdc, blackPieceBrush);
\r
3408 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3410 /* Use square color for details of black pieces */
\r
3411 oldBitmap = SelectObject(tmphdc, PieceBitmap(piece, SOLID_PIECE));
\r
3412 oldBrush = SelectObject(hdc, blackPieceBrush);
\r
3413 if(appData.upsideDown)
\r
3414 StretchBlt(hdc, x, y+tmpSize, tmpSize, -tmpSize, tmphdc, 0, 0, tmpSize, tmpSize, 0x00B8074A);
\r
3416 BitBlt(hdc, x, y, tmpSize, tmpSize, tmphdc, 0, 0, 0x00B8074A);
\r
3419 SelectObject(hdc, oldBrush);
\r
3420 SelectObject(tmphdc, oldBitmap);
\r
3424 /* [AS] Compute a drawing mode for a square, based on specified settings (see DrawTile) */
\r
3425 int GetBackTextureMode( int algo )
\r
3427 int result = BACK_TEXTURE_MODE_DISABLED;
\r
3431 case BACK_TEXTURE_MODE_PLAIN:
\r
3432 result = 1; /* Always use identity map */
\r
3434 case BACK_TEXTURE_MODE_FULL_RANDOM:
\r
3435 result = 1 + (myrandom() % 3); /* Pick a transformation at random */
\r
3443 [AS] Compute and save texture drawing info, otherwise we may not be able
\r
3444 to handle redraws cleanly (as random numbers would always be different).
\r
3446 VOID RebuildTextureSquareInfo()
\r
3456 ZeroMemory( &backTextureSquareInfo, sizeof(backTextureSquareInfo) );
\r
3458 if( liteBackTexture != NULL ) {
\r
3459 if( GetObject( liteBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3460 lite_w = bi.bmWidth;
\r
3461 lite_h = bi.bmHeight;
\r
3465 if( darkBackTexture != NULL ) {
\r
3466 if( GetObject( darkBackTexture, sizeof(bi), &bi ) > 0 ) {
\r
3467 dark_w = bi.bmWidth;
\r
3468 dark_h = bi.bmHeight;
\r
3472 for( row=0; row<BOARD_HEIGHT; row++ ) {
\r
3473 for( col=0; col<BOARD_WIDTH; col++ ) {
\r
3474 if( (col + row) & 1 ) {
\r
3476 if( lite_w >= squareSize && lite_h >= squareSize ) {
\r
3477 backTextureSquareInfo[row][col].x = col * (lite_w - squareSize) / BOARD_WIDTH;
\r
3478 backTextureSquareInfo[row][col].y = row * (lite_h - squareSize) / BOARD_HEIGHT;
\r
3479 backTextureSquareInfo[row][col].mode = GetBackTextureMode(liteBackTextureMode);
\r
3484 if( dark_w >= squareSize && dark_h >= squareSize ) {
\r
3485 backTextureSquareInfo[row][col].x = col * (dark_w - squareSize) / BOARD_WIDTH;
\r
3486 backTextureSquareInfo[row][col].y = row * (dark_h - squareSize) / BOARD_HEIGHT;
\r
3487 backTextureSquareInfo[row][col].mode = GetBackTextureMode(darkBackTextureMode);
\r
3494 /* [AS] Arrow highlighting support */
\r
3496 static int A_WIDTH = 5; /* Width of arrow body */
\r
3498 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
\r
3499 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
\r
3501 static double Sqr( double x )
\r
3506 static int Round( double x )
\r
3508 return (int) (x + 0.5);
\r
3511 /* Draw an arrow between two points using current settings */
\r
3512 VOID DrawArrowBetweenPoints( HDC hdc, int s_x, int s_y, int d_x, int d_y )
\r
3515 double dx, dy, j, k, x, y;
\r
3517 if( d_x == s_x ) {
\r
3518 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3520 arrow[0].x = s_x + A_WIDTH;
\r
3523 arrow[1].x = s_x + A_WIDTH;
\r
3524 arrow[1].y = d_y - h;
\r
3526 arrow[2].x = s_x + A_WIDTH*A_WIDTH_FACTOR;
\r
3527 arrow[2].y = d_y - h;
\r
3532 arrow[4].x = s_x - A_WIDTH*A_WIDTH_FACTOR;
\r
3533 arrow[4].y = d_y - h;
\r
3535 arrow[5].x = s_x - A_WIDTH;
\r
3536 arrow[5].y = d_y - h;
\r
3538 arrow[6].x = s_x - A_WIDTH;
\r
3541 else if( d_y == s_y ) {
\r
3542 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
\r
3545 arrow[0].y = s_y + A_WIDTH;
\r
3547 arrow[1].x = d_x - w;
\r
3548 arrow[1].y = s_y + A_WIDTH;
\r
3550 arrow[2].x = d_x - w;
\r
3551 arrow[2].y = s_y + A_WIDTH*A_WIDTH_FACTOR;
\r
3556 arrow[4].x = d_x - w;
\r
3557 arrow[4].y = s_y - A_WIDTH*A_WIDTH_FACTOR;
\r
3559 arrow[5].x = d_x - w;
\r
3560 arrow[5].y = s_y - A_WIDTH;
\r
3563 arrow[6].y = s_y - A_WIDTH;
\r
3566 /* [AS] Needed a lot of paper for this! :-) */
\r
3567 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
\r
3568 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
\r
3570 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
\r
3572 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
\r
3577 arrow[0].x = Round(x - j);
\r
3578 arrow[0].y = Round(y + j*dx);
\r
3580 arrow[1].x = Round(x + j);
\r
3581 arrow[1].y = Round(y - j*dx);
\r
3584 x = (double) d_x - k;
\r
3585 y = (double) d_y - k*dy;
\r
3588 x = (double) d_x + k;
\r
3589 y = (double) d_y + k*dy;
\r
3592 arrow[2].x = Round(x + j);
\r
3593 arrow[2].y = Round(y - j*dx);
\r
3595 arrow[3].x = Round(x + j*A_WIDTH_FACTOR);
\r
3596 arrow[3].y = Round(y - j*A_WIDTH_FACTOR*dx);
\r
3601 arrow[5].x = Round(x - j*A_WIDTH_FACTOR);
\r
3602 arrow[5].y = Round(y + j*A_WIDTH_FACTOR*dx);
\r
3604 arrow[6].x = Round(x - j);
\r
3605 arrow[6].y = Round(y + j*dx);
\r
3608 Polygon( hdc, arrow, 7 );
\r
3611 /* [AS] Draw an arrow between two squares */
\r
3612 VOID DrawArrowBetweenSquares( HDC hdc, int s_col, int s_row, int d_col, int d_row )
\r
3614 int s_x, s_y, d_x, d_y;
\r
3621 if( s_col == d_col && s_row == d_row ) {
\r
3625 /* Get source and destination points */
\r
3626 SquareToPos( s_row, s_col, &s_x, &s_y);
\r
3627 SquareToPos( d_row, d_col, &d_x, &d_y);
\r
3630 d_y += squareSize / 4;
\r
3632 else if( d_y < s_y ) {
\r
3633 d_y += 3 * squareSize / 4;
\r
3636 d_y += squareSize / 2;
\r
3640 d_x += squareSize / 4;
\r
3642 else if( d_x < s_x ) {
\r
3643 d_x += 3 * squareSize / 4;
\r
3646 d_x += squareSize / 2;
\r
3649 s_x += squareSize / 2;
\r
3650 s_y += squareSize / 2;
\r
3652 /* Adjust width */
\r
3653 A_WIDTH = squareSize / 14;
\r
3656 stLB.lbStyle = BS_SOLID;
\r
3657 stLB.lbColor = appData.highlightArrowColor;
\r
3660 hpen = CreatePen( PS_SOLID, 2, RGB(0x00,0x00,0x00) );
\r
3661 holdpen = SelectObject( hdc, hpen );
\r
3662 hbrush = CreateBrushIndirect( &stLB );
\r
3663 holdbrush = SelectObject( hdc, hbrush );
\r
3665 DrawArrowBetweenPoints( hdc, s_x, s_y, d_x, d_y );
\r
3667 SelectObject( hdc, holdpen );
\r
3668 SelectObject( hdc, holdbrush );
\r
3669 DeleteObject( hpen );
\r
3670 DeleteObject( hbrush );
\r
3673 BOOL HasHighlightInfo()
\r
3675 BOOL result = FALSE;
\r
3677 if( highlightInfo.sq[0].x >= 0 && highlightInfo.sq[0].y >= 0 &&
\r
3678 highlightInfo.sq[1].x >= 0 && highlightInfo.sq[1].y >= 0 )
\r
3686 BOOL IsDrawArrowEnabled()
\r
3688 BOOL result = FALSE;
\r
3690 if( appData.highlightMoveWithArrow && squareSize >= 32 ) {
\r
3697 VOID DrawArrowHighlight( HDC hdc )
\r
3699 if( IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3700 DrawArrowBetweenSquares( hdc,
\r
3701 highlightInfo.sq[0].x, highlightInfo.sq[0].y,
\r
3702 highlightInfo.sq[1].x, highlightInfo.sq[1].y );
\r
3706 HRGN GetArrowHighlightClipRegion( HDC hdc )
\r
3708 HRGN result = NULL;
\r
3710 if( HasHighlightInfo() ) {
\r
3711 int x1, y1, x2, y2;
\r
3712 int sx, sy, dx, dy;
\r
3714 SquareToPos(highlightInfo.sq[0].y, highlightInfo.sq[0].x, &x1, &y1 );
\r
3715 SquareToPos(highlightInfo.sq[1].y, highlightInfo.sq[1].x, &x2, &y2 );
\r
3717 sx = MIN( x1, x2 );
\r
3718 sy = MIN( y1, y2 );
\r
3719 dx = MAX( x1, x2 ) + squareSize;
\r
3720 dy = MAX( y1, y2 ) + squareSize;
\r
3722 result = CreateRectRgn( sx, sy, dx, dy );
\r
3729 Warning: this function modifies the behavior of several other functions.
\r
3731 Basically, Winboard is optimized to avoid drawing the whole board if not strictly
\r
3732 needed. Unfortunately, the decision whether or not to perform a full or partial
\r
3733 repaint is scattered all over the place, which is not good for features such as
\r
3734 "arrow highlighting" that require a full repaint of the board.
\r
3736 So, I've tried to patch the code where I thought it made sense (e.g. after or during
\r
3737 user interaction, when speed is not so important) but especially to avoid errors
\r
3738 in the displayed graphics.
\r
3740 In such patched places, I always try refer to this function so there is a single
\r
3741 place to maintain knowledge.
\r
3743 To restore the original behavior, just return FALSE unconditionally.
\r
3745 BOOL IsFullRepaintPreferrable()
\r
3747 BOOL result = FALSE;
\r
3749 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() ) {
\r
3750 /* Arrow may appear on the board */
\r
3758 This function is called by DrawPosition to know whether a full repaint must
\r
3761 Only DrawPosition may directly call this function, which makes use of
\r
3762 some state information. Other function should call DrawPosition specifying
\r
3763 the repaint flag, and can use IsFullRepaintPreferrable if needed.
\r
3765 BOOL DrawPositionNeedsFullRepaint()
\r
3767 BOOL result = FALSE;
\r
3770 Probably a slightly better policy would be to trigger a full repaint
\r
3771 when animInfo.piece changes state (i.e. empty -> non-empty and viceversa),
\r
3772 but animation is fast enough that it's difficult to notice.
\r
3774 if( animInfo.piece == EmptySquare ) {
\r
3775 if( (appData.highlightLastMove || appData.highlightDragging) && IsDrawArrowEnabled() && HasHighlightInfo() ) {
\r
3784 DrawBoardOnDC(HDC hdc, Board board, HDC tmphdc)
\r
3786 int row, column, x, y, square_color, piece_color;
\r
3787 ChessSquare piece;
\r
3789 HDC texture_hdc = NULL;
\r
3791 /* [AS] Initialize background textures if needed */
\r
3792 if( liteBackTexture != NULL || darkBackTexture != NULL ) {
\r
3793 if( backTextureSquareSize != squareSize ) {
\r
3794 backTextureSquareSize = squareSize;
\r
3795 RebuildTextureSquareInfo();
\r
3798 texture_hdc = CreateCompatibleDC( hdc );
\r
3801 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3802 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3804 SquareToPos(row, column, &x, &y);
\r
3806 piece = board[row][column];
\r
3808 square_color = ((column + row) % 2) == 1;
\r
3809 if(!strcmp(appData.variant, "xiangqi") ) {
\r
3810 square_color = !InPalace(row, column);
\r
3811 if(BOARD_HEIGHT&1) { if(row==BOARD_HEIGHT/2) square_color ^= 1; }
\r
3812 else if(row < BOARD_HEIGHT/2) square_color ^= 1;
\r
3814 piece_color = (int) piece < (int) BlackPawn;
\r
3818 /* [HGM] holdings file: light square or black */
\r
3819 if(column == BOARD_LEFT-2) {
\r
3820 if( row > BOARD_HEIGHT - gameInfo.holdingsSize - 1 )
\r
3823 DisplayHoldingsCount(hdc, x, y, 0, 0); /* black out */
\r
3827 if(column == BOARD_RGHT + 1 ) {
\r
3828 if( row < gameInfo.holdingsSize )
\r
3831 DisplayHoldingsCount(hdc, x, y, 0, 0);
\r
3835 if(column == BOARD_LEFT-1 ) /* left align */
\r
3836 DisplayHoldingsCount(hdc, x, y, 0, (int) board[row][column]);
\r
3837 else if( column == BOARD_RGHT) /* right align */
\r
3838 DisplayHoldingsCount(hdc, x, y, 1, (int) board[row][column]);
\r
3841 if (appData.monoMode) {
\r
3842 if (piece == EmptySquare) {
\r
3843 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0,
\r
3844 square_color ? WHITENESS : BLACKNESS);
\r
3846 DrawPieceOnDC(hdc, piece, piece_color, square_color, x, y, tmphdc);
\r
3849 else if( backTextureSquareInfo[row][column].mode > 0 ) {
\r
3850 /* [AS] Draw the square using a texture bitmap */
\r
3851 HBITMAP hbm = SelectObject( texture_hdc, square_color ? liteBackTexture : darkBackTexture );
\r
3854 squareSize, squareSize,
\r
3857 backTextureSquareInfo[row][column].mode,
\r
3858 backTextureSquareInfo[row][column].x,
\r
3859 backTextureSquareInfo[row][column].y );
\r
3861 SelectObject( texture_hdc, hbm );
\r
3863 if (piece != EmptySquare) {
\r
3864 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3868 HBRUSH brush = square_color ? lightSquareBrush : darkSquareBrush;
\r
3870 oldBrush = SelectObject(hdc, brush );
\r
3871 BitBlt(hdc, x, y, squareSize, squareSize, 0, 0, 0, PATCOPY);
\r
3872 SelectObject(hdc, oldBrush);
\r
3873 if (piece != EmptySquare)
\r
3874 DrawPieceOnDC(hdc, piece, piece_color, -1, x, y, tmphdc);
\r
3879 if( texture_hdc != NULL ) {
\r
3880 DeleteDC( texture_hdc );
\r
3884 #define MAX_CLIPS 200 /* more than enough */
\r
3887 HDCDrawPosition(HDC hdc, BOOLEAN repaint, Board board)
\r
3889 static Board lastReq, lastDrawn;
\r
3890 static HighlightInfo lastDrawnHighlight, lastDrawnPremove;
\r
3891 static int lastDrawnFlipView = 0;
\r
3892 static int lastReqValid = 0, lastDrawnValid = 0;
\r
3893 int releaseDC, x, y, x2, y2, row, column, num_clips = 0, i;
\r
3896 HBITMAP bufferBitmap;
\r
3897 HBITMAP oldBitmap;
\r
3899 HRGN clips[MAX_CLIPS];
\r
3900 ChessSquare dragged_piece = EmptySquare;
\r
3902 /* I'm undecided on this - this function figures out whether a full
\r
3903 * repaint is necessary on its own, so there's no real reason to have the
\r
3904 * caller tell it that. I think this can safely be set to FALSE - but
\r
3905 * if we trust the callers not to request full repaints unnessesarily, then
\r
3906 * we could skip some clipping work. In other words, only request a full
\r
3907 * redraw when the majority of pieces have changed positions (ie. flip,
\r
3908 * gamestart and similar) --Hawk
\r
3910 Boolean fullrepaint = repaint;
\r
3912 if( DrawPositionNeedsFullRepaint() ) {
\r
3913 fullrepaint = TRUE;
\r
3917 if( fullrepaint ) {
\r
3918 static int repaint_count = 0;
\r
3922 sprintf( buf, "FULL repaint: %d\n", repaint_count );
\r
3923 OutputDebugString( buf );
\r
3927 if (board == NULL) {
\r
3928 if (!lastReqValid) {
\r
3933 CopyBoard(lastReq, board);
\r
3937 if (doingSizing) {
\r
3941 if (IsIconic(hwndMain)) {
\r
3945 if (hdc == NULL) {
\r
3946 hdc = GetDC(hwndMain);
\r
3947 if (!appData.monoMode) {
\r
3948 SelectPalette(hdc, hPal, FALSE);
\r
3949 RealizePalette(hdc);
\r
3953 releaseDC = FALSE;
\r
3957 fprintf(debugFP, "*******************************\n"
\r
3959 "dragInfo.from (%d,%d)\n"
\r
3960 "dragInfo.start (%d,%d)\n"
\r
3961 "dragInfo.pos (%d,%d)\n"
\r
3962 "dragInfo.lastpos (%d,%d)\n",
\r
3963 repaint ? "TRUE" : "FALSE",
\r
3964 dragInfo.from.x, dragInfo.from.y,
\r
3965 dragInfo.start.x, dragInfo.start.y,
\r
3966 dragInfo.pos.x, dragInfo.pos.y,
\r
3967 dragInfo.lastpos.x, dragInfo.lastpos.y);
\r
3968 fprintf(debugFP, "prev: ");
\r
3969 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3970 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3971 fprintf(debugFP, "%d ", lastDrawn[row][column]);
\r
3974 fprintf(debugFP, "\n");
\r
3975 fprintf(debugFP, "board: ");
\r
3976 for (row = 0; row < BOARD_HEIGHT; row++) {
\r
3977 for (column = 0; column < BOARD_WIDTH; column++) {
\r
3978 fprintf(debugFP, "%d ", board[row][column]);
\r
3981 fprintf(debugFP, "\n");
\r
3985 /* Create some work-DCs */
\r
3986 hdcmem = CreateCompatibleDC(hdc);
\r
3987 tmphdc = CreateCompatibleDC(hdc);
\r
3989 /* If dragging is in progress, we temporarely remove the piece */
\r
3990 /* [HGM] or temporarily decrease count if stacked */
\r
3991 /* !! Moved to before board compare !! */
\r
3992 if (dragInfo.from.x >= 0 && dragInfo.pos.x >= 0) {
\r
3993 dragged_piece = board[dragInfo.from.y][dragInfo.from.x];
\r
3994 if(dragInfo.from.x == BOARD_LEFT-2 ) {
\r
3995 if(--board[dragInfo.from.y][dragInfo.from.x+1] == 0 )
\r
3996 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
3998 if(dragInfo.from.x == BOARD_RGHT+1) {
\r
3999 if(--board[dragInfo.from.y][dragInfo.from.x-1] == 0 )
\r
4000 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4002 board[dragInfo.from.y][dragInfo.from.x] = EmptySquare;
\r
4005 /* Figure out which squares need updating by comparing the
\r
4006 * newest board with the last drawn board and checking if
\r
4007 * flipping has changed.
\r
4009 if (!fullrepaint && lastDrawnValid && lastDrawnFlipView == flipView) {
\r
4010 for (row = 0; row < BOARD_HEIGHT; row++) { /* [HGM] true size, not 8 */
\r
4011 for (column = 0; column < BOARD_WIDTH; column++) {
\r
4012 if (lastDrawn[row][column] != board[row][column]) {
\r
4013 SquareToPos(row, column, &x, &y);
\r
4014 clips[num_clips++] =
\r
4015 CreateRectRgn(x, y, x + squareSize, y + squareSize);
\r
4019 for (i=0; i<2; i++) {
\r
4020 if (lastDrawnHighlight.sq[i].x != highlightInfo.sq[i].x ||
\r
4021 lastDrawnHighlight.sq[i].y != highlightInfo.sq[i].y) {
\r
4022 if (lastDrawnHighlight.sq[i].x >= 0 &&
\r
4023 lastDrawnHighlight.sq[i].y >= 0) {
\r
4024 SquareToPos(lastDrawnHighlight.sq[i].y,
\r
4025 lastDrawnHighlight.sq[i].x, &x, &y);
\r
4026 clips[num_clips++] =
\r
4027 CreateRectRgn(x - lineGap, y - lineGap,
\r
4028 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4030 if (highlightInfo.sq[i].x >= 0 && highlightInfo.sq[i].y >= 0) {
\r
4031 SquareToPos(highlightInfo.sq[i].y, highlightInfo.sq[i].x, &x, &y);
\r
4032 clips[num_clips++] =
\r
4033 CreateRectRgn(x - lineGap, y - lineGap,
\r
4034 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4038 for (i=0; i<2; i++) {
\r
4039 if (lastDrawnPremove.sq[i].x != premoveHighlightInfo.sq[i].x ||
\r
4040 lastDrawnPremove.sq[i].y != premoveHighlightInfo.sq[i].y) {
\r
4041 if (lastDrawnPremove.sq[i].x >= 0 &&
\r
4042 lastDrawnPremove.sq[i].y >= 0) {
\r
4043 SquareToPos(lastDrawnPremove.sq[i].y,
\r
4044 lastDrawnPremove.sq[i].x, &x, &y);
\r
4045 clips[num_clips++] =
\r
4046 CreateRectRgn(x - lineGap, y - lineGap,
\r
4047 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4049 if (premoveHighlightInfo.sq[i].x >= 0 &&
\r
4050 premoveHighlightInfo.sq[i].y >= 0) {
\r
4051 SquareToPos(premoveHighlightInfo.sq[i].y,
\r
4052 premoveHighlightInfo.sq[i].x, &x, &y);
\r
4053 clips[num_clips++] =
\r
4054 CreateRectRgn(x - lineGap, y - lineGap,
\r
4055 x + squareSize + lineGap, y + squareSize + lineGap);
\r
4060 fullrepaint = TRUE;
\r
4063 /* Create a buffer bitmap - this is the actual bitmap
\r
4064 * being written to. When all the work is done, we can
\r
4065 * copy it to the real DC (the screen). This avoids
\r
4066 * the problems with flickering.
\r
4068 GetClientRect(hwndMain, &Rect);
\r
4069 bufferBitmap = CreateCompatibleBitmap(hdc, Rect.right-Rect.left+1,
\r
4070 Rect.bottom-Rect.top+1);
\r
4071 oldBitmap = SelectObject(hdcmem, bufferBitmap);
\r
4072 if (!appData.monoMode) {
\r
4073 SelectPalette(hdcmem, hPal, FALSE);
\r
4076 /* Create clips for dragging */
\r
4077 if (!fullrepaint) {
\r
4078 if (dragInfo.from.x >= 0) {
\r
4079 SquareToPos(dragInfo.from.y, dragInfo.from.x, &x, &y);
\r
4080 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4082 if (dragInfo.start.x >= 0) {
\r
4083 SquareToPos(dragInfo.start.y, dragInfo.start.x, &x, &y);
\r
4084 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4086 if (dragInfo.pos.x >= 0) {
\r
4087 x = dragInfo.pos.x - squareSize / 2;
\r
4088 y = dragInfo.pos.y - squareSize / 2;
\r
4089 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4091 if (dragInfo.lastpos.x >= 0) {
\r
4092 x = dragInfo.lastpos.x - squareSize / 2;
\r
4093 y = dragInfo.lastpos.y - squareSize / 2;
\r
4094 clips[num_clips++] = CreateRectRgn(x, y, x+squareSize, y+squareSize);
\r
4098 /* Are we animating a move?
\r
4100 * - remove the piece from the board (temporarely)
\r
4101 * - calculate the clipping region
\r
4103 if (!fullrepaint) {
\r
4104 if (animInfo.piece != EmptySquare) {
\r
4105 board[animInfo.from.y][animInfo.from.x] = EmptySquare;
\r
4106 x = boardRect.left + animInfo.lastpos.x;
\r
4107 y = boardRect.top + animInfo.lastpos.y;
\r
4108 x2 = boardRect.left + animInfo.pos.x;
\r
4109 y2 = boardRect.top + animInfo.pos.y;
\r
4110 clips[num_clips++] = CreateRectRgn(MIN(x,x2), MIN(y,y2), MAX(x,x2)+squareSize, MAX(y,y2)+squareSize);
\r
4111 /* Slight kludge. The real problem is that after AnimateMove is
\r
4112 done, the position on the screen does not match lastDrawn.
\r
4113 This currently causes trouble only on e.p. captures in
\r
4114 atomic, where the piece moves to an empty square and then
\r
4115 explodes. The old and new positions both had an empty square
\r
4116 at the destination, but animation has drawn a piece there and
\r
4117 we have to remember to erase it. */
\r
4118 lastDrawn[animInfo.to.y][animInfo.to.x] = animInfo.piece;
\r
4122 /* No clips? Make sure we have fullrepaint set to TRUE */
\r
4123 if (num_clips == 0)
\r
4124 fullrepaint = TRUE;
\r
4126 /* Set clipping on the memory DC */
\r
4127 if (!fullrepaint) {
\r
4128 SelectClipRgn(hdcmem, clips[0]);
\r
4129 for (x = 1; x < num_clips; x++) {
\r
4130 if (ExtSelectClipRgn(hdcmem, clips[x], RGN_OR) == ERROR)
\r
4131 abort(); // this should never ever happen!
\r
4135 /* Do all the drawing to the memory DC */
\r
4136 DrawGridOnDC(hdcmem);
\r
4137 DrawHighlightsOnDC(hdcmem);
\r
4138 DrawBoardOnDC(hdcmem, board, tmphdc);
\r
4140 if( appData.highlightMoveWithArrow ) {
\r
4141 DrawArrowHighlight(hdcmem);
\r
4144 DrawCoordsOnDC(hdcmem);
\r
4146 CopyBoard(lastDrawn, board); /* [HGM] Moved to here from end of routine, */
\r
4147 /* to make sure lastDrawn contains what is actually drawn */
\r
4149 /* Put the dragged piece back into place and draw it (out of place!) */
\r
4150 if (dragged_piece != EmptySquare) {
\r
4151 /* [HGM] or restack */
\r
4152 if(dragInfo.from.x == BOARD_LEFT-2 )
\r
4153 board[dragInfo.from.y][dragInfo.from.x+1]++;
\r
4155 if(dragInfo.from.x == BOARD_RGHT+1 )
\r
4156 board[dragInfo.from.y][dragInfo.from.x-1]++;
\r
4157 board[dragInfo.from.y][dragInfo.from.x] = dragged_piece;
\r
4158 x = dragInfo.pos.x - squareSize / 2;
\r
4159 y = dragInfo.pos.y - squareSize / 2;
\r
4160 DrawPieceOnDC(hdcmem, dragged_piece,
\r
4161 ((int) dragged_piece < (int) BlackPawn),
\r
4162 (dragInfo.from.y + dragInfo.from.x) % 2, x, y, tmphdc);
\r
4165 /* Put the animated piece back into place and draw it */
\r
4166 if (animInfo.piece != EmptySquare) {
\r
4167 board[animInfo.from.y][animInfo.from.x] = animInfo.piece;
\r
4168 x = boardRect.left + animInfo.pos.x;
\r
4169 y = boardRect.top + animInfo.pos.y;
\r
4170 DrawPieceOnDC(hdcmem, animInfo.piece,
\r
4171 ((int) animInfo.piece < (int) BlackPawn),
\r
4172 (animInfo.from.y + animInfo.from.x) % 2, x, y, tmphdc);
\r
4175 /* Release the bufferBitmap by selecting in the old bitmap
\r
4176 * and delete the memory DC
\r
4178 SelectObject(hdcmem, oldBitmap);
\r
4181 /* Set clipping on the target DC */
\r
4182 if (!fullrepaint) {
\r
4183 SelectClipRgn(hdc, clips[0]);
\r
4184 for (x = 1; x < num_clips; x++) {
\r
4185 if (ExtSelectClipRgn(hdc, clips[x], RGN_OR) == ERROR)
\r
4186 abort(); // this should never ever happen!
\r
4190 /* Copy the new bitmap onto the screen in one go.
\r
4191 * This way we avoid any flickering
\r
4193 oldBitmap = SelectObject(tmphdc, bufferBitmap);
\r
4194 BitBlt(hdc, boardRect.left, boardRect.top,
\r
4195 boardRect.right - boardRect.left,
\r
4196 boardRect.bottom - boardRect.top,
\r
4197 tmphdc, boardRect.left, boardRect.top, SRCCOPY);
\r
4198 SelectObject(tmphdc, oldBitmap);
\r
4200 /* Massive cleanup */
\r
4201 for (x = 0; x < num_clips; x++)
\r
4202 DeleteObject(clips[x]);
\r
4205 DeleteObject(bufferBitmap);
\r
4208 ReleaseDC(hwndMain, hdc);
\r
4210 if (lastDrawnFlipView != flipView) {
\r
4212 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_CHECKED);
\r
4214 CheckMenuItem(GetMenu(hwndMain),IDM_FlipView, MF_BYCOMMAND|MF_UNCHECKED);
\r
4217 /* CopyBoard(lastDrawn, board);*/
\r
4218 lastDrawnHighlight = highlightInfo;
\r
4219 lastDrawnPremove = premoveHighlightInfo;
\r
4220 lastDrawnFlipView = flipView;
\r
4221 lastDrawnValid = 1;
\r
4225 /*---------------------------------------------------------------------------*\
\r
4226 | CLIENT PAINT PROCEDURE
\r
4227 | This is the main event-handler for the WM_PAINT message.
\r
4229 \*---------------------------------------------------------------------------*/
\r
4231 PaintProc(HWND hwnd)
\r
4237 if(hdc = BeginPaint(hwnd, &ps)) {
\r
4238 if (IsIconic(hwnd)) {
\r
4239 DrawIcon(hdc, 2, 2, iconCurrent);
\r
4241 if (!appData.monoMode) {
\r
4242 SelectPalette(hdc, hPal, FALSE);
\r
4243 RealizePalette(hdc);
\r
4245 HDCDrawPosition(hdc, 1, NULL);
\r
4247 SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
4248 ExtTextOut(hdc, messageRect.left, messageRect.top,
\r
4249 ETO_CLIPPED|ETO_OPAQUE,
\r
4250 &messageRect, messageText, strlen(messageText), NULL);
\r
4251 SelectObject(hdc, oldFont);
\r
4252 DisplayBothClocks();
\r
4254 EndPaint(hwnd,&ps);
\r
4262 * If the user selects on a border boundary, return -1; if off the board,
\r
4263 * return -2. Otherwise map the event coordinate to the square.
\r
4264 * The offset boardRect.left or boardRect.top must already have been
\r
4265 * subtracted from x.
\r
4268 EventToSquare(int x)
\r
4275 if ((x % (squareSize + lineGap)) >= squareSize)
\r
4277 x /= (squareSize + lineGap);
\r
4278 if (x >= BOARD_SIZE)
\r
4289 DropEnable dropEnables[] = {
\r
4290 { 'P', DP_Pawn, "Pawn" },
\r
4291 { 'N', DP_Knight, "Knight" },
\r
4292 { 'B', DP_Bishop, "Bishop" },
\r
4293 { 'R', DP_Rook, "Rook" },
\r
4294 { 'Q', DP_Queen, "Queen" },
\r
4298 SetupDropMenu(HMENU hmenu)
\r
4300 int i, count, enable;
\r
4302 extern char white_holding[], black_holding[];
\r
4303 char item[MSG_SIZ];
\r
4305 for (i=0; i<sizeof(dropEnables)/sizeof(DropEnable); i++) {
\r
4306 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
\r
4307 dropEnables[i].piece);
\r
4309 while (p && *p++ == dropEnables[i].piece) count++;
\r
4310 sprintf(item, "%s %d", dropEnables[i].name, count);
\r
4311 enable = count > 0 || !appData.testLegality
\r
4312 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
\r
4313 && !appData.icsActive);
\r
4314 ModifyMenu(hmenu, dropEnables[i].command,
\r
4315 MF_BYCOMMAND | (enable ? MF_ENABLED : MF_GRAYED) | MF_STRING,
\r
4316 dropEnables[i].command, item);
\r
4320 static int fromX = -1, fromY = -1, toX, toY;
\r
4322 /* Event handler for mouse messages */
\r
4324 MouseEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4328 static int recursive = 0;
\r
4330 BOOLEAN needsRedraw = FALSE;
\r
4331 BOOLEAN saveAnimate;
\r
4332 BOOLEAN forceFullRepaint = IsFullRepaintPreferrable(); /* [AS] */
\r
4333 static BOOLEAN sameAgain = FALSE;
\r
4334 ChessMove moveType;
\r
4337 if (message == WM_MBUTTONUP) {
\r
4338 /* Hideous kludge to fool TrackPopupMenu into paying attention
\r
4339 to the middle button: we simulate pressing the left button too!
\r
4341 PostMessage(hwnd, WM_LBUTTONDOWN, wParam, lParam);
\r
4342 PostMessage(hwnd, WM_LBUTTONUP, wParam, lParam);
\r
4348 pt.x = LOWORD(lParam);
\r
4349 pt.y = HIWORD(lParam);
\r
4350 x = EventToSquare(pt.x - boardRect.left);
\r
4351 y = EventToSquare(pt.y - boardRect.top);
\r
4352 if (!flipView && y >= 0) {
\r
4353 y = BOARD_HEIGHT - 1 - y;
\r
4355 if (flipView && x >= 0) {
\r
4356 x = BOARD_WIDTH - 1 - x;
\r
4359 switch (message) {
\r
4360 case WM_LBUTTONDOWN:
\r
4362 sameAgain = FALSE;
\r
4364 /* Downclick vertically off board; check if on clock */
\r
4365 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4366 if (gameMode == EditPosition) {
\r
4367 SetWhiteToPlayEvent();
\r
4368 } else if (gameMode == IcsPlayingBlack ||
\r
4369 gameMode == MachinePlaysWhite) {
\r
4371 } else if (gameMode == EditGame) {
\r
4372 AdjustClock(flipClock, -1);
\r
4374 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4375 if (gameMode == EditPosition) {
\r
4376 SetBlackToPlayEvent();
\r
4377 } else if (gameMode == IcsPlayingWhite ||
\r
4378 gameMode == MachinePlaysBlack) {
\r
4380 } else if (gameMode == EditGame) {
\r
4381 AdjustClock(!flipClock, -1);
\r
4384 if (!appData.highlightLastMove) {
\r
4385 ClearHighlights();
\r
4386 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4388 fromX = fromY = -1;
\r
4389 dragInfo.start.x = dragInfo.start.y = -1;
\r
4390 dragInfo.from = dragInfo.start;
\r
4392 } else if (x < 0 || y < 0
\r
4393 /* [HGM] block clicks between board and holdings */
\r
4394 || x == BOARD_LEFT-1 || x == BOARD_RGHT
\r
4395 || x == BOARD_LEFT-2 && y < BOARD_HEIGHT-gameInfo.holdingsSize
\r
4396 || x == BOARD_RGHT+1 && y >= gameInfo.holdingsSize
\r
4397 /* EditPosition, empty square, or different color piece;
\r
4398 click-click move is possible */
\r
4401 } else if (fromX == x && fromY == y) {
\r
4402 /* Downclick on same square again */
\r
4403 ClearHighlights();
\r
4404 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4405 sameAgain = TRUE;
\r
4406 } else if (fromX != -1 &&
\r
4407 x != BOARD_LEFT-2 && x != BOARD_RGHT+1
\r
4409 /* Downclick on different square. */
\r
4410 /* [HGM] if on holdings file, should count as new first click ! */
\r
4411 { /* [HGM] <sameColor> now always do UserMoveTest(), and check colors there */
\r
4414 /* [HGM] <popupFix> UserMoveEvent requires two calls now,
\r
4415 to make sure move is legal before showing promotion popup */
\r
4416 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4417 if(moveType != ImpossibleMove) {
\r
4418 /* [HGM] We use PromotionToKnight in Shogi to indicate frorced promotion */
\r
4419 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4420 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4421 appData.alwaysPromoteToQueen) {
\r
4422 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4423 if (!appData.highlightLastMove) {
\r
4424 ClearHighlights();
\r
4425 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4428 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4429 SetHighlights(fromX, fromY, toX, toY);
\r
4430 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4431 /* [HGM] <popupFix> Popup calls FinishMove now.
\r
4432 If promotion to Q is legal, all are legal! */
\r
4433 PromotionPopup(hwnd);
\r
4434 } else { /* not a promotion */
\r
4435 if (appData.animate || appData.highlightLastMove) {
\r
4436 SetHighlights(fromX, fromY, toX, toY);
\r
4438 ClearHighlights();
\r
4440 FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4441 if (appData.animate && !appData.highlightLastMove) {
\r
4442 ClearHighlights();
\r
4443 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4447 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4448 fromX = fromY = -1;
\r
4451 ClearHighlights();
\r
4452 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4454 /* First downclick, or restart on a square with same color piece */
\r
4455 if (!frozen && OKToStartUserMove(x, y)) {
\r
4458 dragInfo.lastpos = pt;
\r
4459 dragInfo.from.x = fromX;
\r
4460 dragInfo.from.y = fromY;
\r
4461 dragInfo.start = dragInfo.from;
\r
4462 SetCapture(hwndMain);
\r
4464 fromX = fromY = -1;
\r
4465 dragInfo.start.x = dragInfo.start.y = -1;
\r
4466 dragInfo.from = dragInfo.start;
\r
4467 DrawPosition(forceFullRepaint || FALSE, NULL); /* [AS] */
\r
4471 case WM_LBUTTONUP:
\r
4473 if (fromX == -1) break;
\r
4474 if (x == fromX && y == fromY) {
\r
4475 /* Upclick on same square */
\r
4477 /* Clicked same square twice: abort click-click move */
\r
4478 fromX = fromY = -1;
\r
4480 ClearPremoveHighlights();
\r
4482 /* First square clicked: start click-click move */
\r
4483 SetHighlights(fromX, fromY, -1, -1);
\r
4485 dragInfo.from.x = dragInfo.from.y = -1;
\r
4486 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4487 } else if (dragInfo.from.x < 0 || dragInfo.from.y < 0) {
\r
4488 /* Errant click; ignore */
\r
4491 /* Finish drag move. */
\r
4492 if (appData.debugMode) {
\r
4493 fprintf(debugFP, "release\n");
\r
4495 dragInfo.from.x = dragInfo.from.y = -1;
\r
4498 saveAnimate = appData.animate; /* sorry, Hawk :) */
\r
4499 appData.animate = appData.animate && !appData.animateDragging;
\r
4500 moveType = UserMoveTest(fromX, fromY, toX, toY, NULLCHAR);
\r
4501 if(moveType != ImpossibleMove) {
\r
4502 /* [HGM] use move type to determine if move is promotion.
\r
4503 Knight is Shogi kludge for mandatory promotion, Queen means choice */
\r
4504 if (moveType == WhitePromotionKnight || moveType == BlackPromotionKnight ||
\r
4505 (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen) &&
\r
4506 appData.alwaysPromoteToQueen)
\r
4507 FinishMove(moveType, fromX, fromY, toX, toY, 'q');
\r
4509 if (moveType == WhitePromotionQueen || moveType == BlackPromotionQueen ) {
\r
4510 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4511 PromotionPopup(hwnd); /* [HGM] Popup now calls FinishMove */
\r
4512 } else FinishMove(moveType, fromX, fromY, toX, toY, NULLCHAR);
\r
4514 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
\r
4515 appData.animate = saveAnimate;
\r
4516 fromX = fromY = -1;
\r
4517 if (appData.highlightDragging && !appData.highlightLastMove) {
\r
4518 ClearHighlights();
\r
4520 if (appData.animate || appData.animateDragging ||
\r
4521 appData.highlightDragging || gotPremove) {
\r
4522 DrawPosition(forceFullRepaint || FALSE, NULL);
\r
4525 dragInfo.start.x = dragInfo.start.y = -1;
\r
4526 dragInfo.pos = dragInfo.lastpos = dragInfo.start;
\r
4529 case WM_MOUSEMOVE:
\r
4530 if ((appData.animateDragging || appData.highlightDragging)
\r
4531 && (wParam & MK_LBUTTON)
\r
4532 && dragInfo.from.x >= 0)
\r
4534 BOOL full_repaint = FALSE;
\r
4536 sameAgain = FALSE; /* [HGM] if we drag something around, do keep square selected */
\r
4537 if (appData.animateDragging) {
\r
4538 dragInfo.pos = pt;
\r
4540 if (appData.highlightDragging) {
\r
4541 SetHighlights(fromX, fromY, x, y);
\r
4542 if( IsDrawArrowEnabled() && (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) ) {
\r
4543 full_repaint = TRUE;
\r
4547 DrawPosition( full_repaint, NULL);
\r
4549 dragInfo.lastpos = dragInfo.pos;
\r
4553 case WM_MBUTTONDOWN:
\r
4554 case WM_RBUTTONDOWN:
\r
4557 fromX = fromY = -1;
\r
4558 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
4559 dragInfo.start.x = dragInfo.start.y = -1;
\r
4560 dragInfo.from = dragInfo.start;
\r
4561 dragInfo.lastpos = dragInfo.pos;
\r
4562 if (appData.highlightDragging) {
\r
4563 ClearHighlights();
\r
4566 /* [HGM] right mouse button in clock area edit-game mode ups clock */
\r
4567 if (PtInRect((LPRECT) &whiteRect, pt)) {
\r
4568 if (gameMode == EditGame) AdjustClock(flipClock, 1);
\r
4569 } else if (PtInRect((LPRECT) &blackRect, pt)) {
\r
4570 if (gameMode == EditGame) AdjustClock(!flipClock, 1);
\r
4573 DrawPosition(TRUE, NULL);
\r
4575 switch (gameMode) {
\r
4576 case EditPosition:
\r
4577 case IcsExamining:
\r
4578 if (x < 0 || y < 0) break;
\r
4581 if (message == WM_MBUTTONDOWN) {
\r
4582 buttonCount = 3; /* even if system didn't think so */
\r
4583 if (wParam & MK_SHIFT)
\r
4584 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4586 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4587 } else { /* message == WM_RBUTTONDOWN */
\r
4589 if (buttonCount == 3) {
\r
4590 if (wParam & MK_SHIFT)
\r
4591 MenuPopup(hwnd, pt, LoadMenu(hInst, "WhitePieceMenu"), -1);
\r
4593 MenuPopup(hwnd, pt, LoadMenu(hInst, "BlackPieceMenu"), -1);
\r
4595 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4598 /* Just have one menu, on the right button. Windows users don't
\r
4599 think to try the middle one, and sometimes other software steals
\r
4600 it, or it doesn't really exist. */
\r
4601 if(gameInfo.variant != VariantShogi)
\r
4602 MenuPopup(hwnd, pt, LoadMenu(hInst, "PieceMenu"), -1);
\r
4604 MenuPopup(hwnd, pt, LoadMenu(hInst, "ShogiPieceMenu"), -1);
\r
4608 case IcsPlayingWhite:
\r
4609 case IcsPlayingBlack:
\r
4611 case MachinePlaysWhite:
\r
4612 case MachinePlaysBlack:
\r
4613 if (appData.testLegality &&
\r
4614 gameInfo.variant != VariantBughouse &&
\r
4615 gameInfo.variant != VariantCrazyhouse) break;
\r
4616 if (x < 0 || y < 0) break;
\r
4619 hmenu = LoadMenu(hInst, "DropPieceMenu");
\r
4620 SetupDropMenu(hmenu);
\r
4621 MenuPopup(hwnd, pt, hmenu, -1);
\r
4632 /* Preprocess messages for buttons in main window */
\r
4634 ButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4636 int id = GetWindowLong(hwnd, GWL_ID);
\r
4639 for (i=0; i<N_BUTTONS; i++) {
\r
4640 if (buttonDesc[i].id == id) break;
\r
4642 if (i == N_BUTTONS) return 0;
\r
4643 switch (message) {
\r
4648 dir = (wParam == VK_LEFT) ? -1 : 1;
\r
4649 SetFocus(buttonDesc[(i + dir + N_BUTTONS) % N_BUTTONS].hwnd);
\r
4656 SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(buttonDesc[i].id, 0), 0);
\r
4659 if (appData.icsActive) {
\r
4660 if (GetKeyState(VK_SHIFT) < 0) {
\r
4662 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4663 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4667 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4668 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4675 if (appData.icsActive) {
\r
4676 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4677 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4679 SendMessage(h, WM_CHAR, wParam, lParam);
\r
4681 } else if (isalpha((char)wParam) || isdigit((char)wParam)){
\r
4682 PopUpMoveDialog((char)wParam);
\r
4688 return CallWindowProc(buttonDesc[i].wndproc, hwnd, message, wParam, lParam);
\r
4691 /* Process messages for Promotion dialog box */
\r
4693 Promotion(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
4697 switch (message) {
\r
4698 case WM_INITDIALOG: /* message: initialize dialog box */
\r
4699 /* Center the dialog over the application window */
\r
4700 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
4701 ShowWindow(GetDlgItem(hDlg, PB_King),
\r
4702 (!appData.testLegality || gameInfo.variant == VariantSuicide ||
\r
4703 gameInfo.variant == VariantGiveaway) ?
\r
4704 SW_SHOW : SW_HIDE);
\r
4705 /* [HGM] Only allow C & A promotions if these pieces are defined */
\r
4706 ShowWindow(GetDlgItem(hDlg, PB_Archbishop),
\r
4707 (PieceToChar(WhiteCardinal) != '.' ||
\r
4708 PieceToChar(BlackCardinal) != '.' ) ?
\r
4709 SW_SHOW : SW_HIDE);
\r
4710 ShowWindow(GetDlgItem(hDlg, PB_Chancellor),
\r
4711 (PieceToChar(WhiteMarshall) != '.' ||
\r
4712 PieceToChar(BlackMarshall) != '.' ) ?
\r
4713 SW_SHOW : SW_HIDE);
\r
4714 /* [HGM] Hide B & R button in Shogi, use Q as promote, N as defer */
\r
4715 ShowWindow(GetDlgItem(hDlg, PB_Rook),
\r
4716 gameInfo.variant != VariantShogi ?
\r
4717 SW_SHOW : SW_HIDE);
\r
4718 ShowWindow(GetDlgItem(hDlg, PB_Bishop),
\r
4719 gameInfo.variant != VariantShogi ?
\r
4720 SW_SHOW : SW_HIDE);
\r
4721 ShowWindow(GetDlgItem(hDlg, IDC_Yes),
\r
4722 gameInfo.variant == VariantShogi ?
\r
4723 SW_SHOW : SW_HIDE);
\r
4724 ShowWindow(GetDlgItem(hDlg, IDC_No),
\r
4725 gameInfo.variant == VariantShogi ?
\r
4726 SW_SHOW : SW_HIDE);
\r
4729 case WM_COMMAND: /* message: received a command */
\r
4730 switch (LOWORD(wParam)) {
\r
4732 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4733 ClearHighlights();
\r
4734 DrawPosition(FALSE, NULL);
\r
4737 promoChar = PieceToChar(BlackKing);
\r
4740 promoChar = gameInfo.variant == VariantShogi ? '+' : PieceToChar(BlackQueen);
\r
4743 promoChar = PieceToChar(BlackRook);
\r
4746 promoChar = PieceToChar(BlackBishop);
\r
4748 case PB_Chancellor:
\r
4749 promoChar = PieceToChar(BlackMarshall);
\r
4751 case PB_Archbishop:
\r
4752 promoChar = PieceToChar(BlackCardinal);
\r
4755 promoChar = gameInfo.variant == VariantShogi ? '=' : PieceToChar(BlackKnight);
\r
4760 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
4761 /* [HGM] <popupFix> Call FinishMove rather than UserMoveEvent, as we
\r
4762 only show the popup when we are already sure the move is valid or
\r
4763 legal. We pass a faulty move type, but the kludge is that FinishMove
\r
4764 will figure out it is a promotion from the promoChar. */
\r
4765 FinishMove(NormalMove, fromX, fromY, toX, toY, promoChar);
\r
4766 if (!appData.highlightLastMove) {
\r
4767 ClearHighlights();
\r
4768 DrawPosition(FALSE, NULL);
\r
4775 /* Pop up promotion dialog */
\r
4777 PromotionPopup(HWND hwnd)
\r
4781 lpProc = MakeProcInstance((FARPROC)Promotion, hInst);
\r
4782 DialogBox(hInst, MAKEINTRESOURCE(DLG_PromotionKing),
\r
4783 hwnd, (DLGPROC)lpProc);
\r
4784 FreeProcInstance(lpProc);
\r
4787 /* Toggle ShowThinking */
\r
4789 ToggleShowThinking()
\r
4791 ShowThinkingEvent(!appData.showThinking);
\r
4795 LoadGameDialog(HWND hwnd, char* title)
\r
4799 char fileTitle[MSG_SIZ];
\r
4800 f = OpenFileDialog(hwnd, FALSE, "",
\r
4801 appData.oldSaveStyle ? "gam" : "pgn",
\r
4803 title, &number, fileTitle, NULL);
\r
4805 cmailMsgLoaded = FALSE;
\r
4806 if (number == 0) {
\r
4807 int error = GameListBuild(f);
\r
4809 DisplayError("Cannot build game list", error);
\r
4810 } else if (!ListEmpty(&gameList) &&
\r
4811 ((ListGame *) gameList.tailPred)->number > 1) {
\r
4812 GameListPopUp(f, fileTitle);
\r
4815 GameListDestroy();
\r
4818 LoadGame(f, number, fileTitle, FALSE);
\r
4823 ChangedConsoleFont()
\r
4826 CHARRANGE tmpsel, sel;
\r
4827 MyFont *f = font[boardSize][CONSOLE_FONT];
\r
4828 HWND hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4829 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4832 cfmt.cbSize = sizeof(CHARFORMAT);
\r
4833 cfmt.dwMask = CFM_FACE|CFM_SIZE|CFM_CHARSET;
\r
4834 strcpy(cfmt.szFaceName, font[boardSize][CONSOLE_FONT]->mfp.faceName);
\r
4835 /* yHeight is expressed in twips. A twip is 1/20 of a font's point
\r
4836 * size. This was undocumented in the version of MSVC++ that I had
\r
4837 * when I wrote the code, but is apparently documented now.
\r
4839 cfmt.yHeight = (int)(f->mfp.pointSize * 20.0 + 0.5);
\r
4840 cfmt.bCharSet = f->lf.lfCharSet;
\r
4841 cfmt.bPitchAndFamily = f->lf.lfPitchAndFamily;
\r
4842 SendMessage(hText, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4843 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cfmt);
\r
4844 /* Why are the following seemingly needed too? */
\r
4845 SendMessage(hText, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4846 SendMessage(hInput, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cfmt);
\r
4847 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
4849 tmpsel.cpMax = -1; /*999999?*/
\r
4850 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&tmpsel);
\r
4851 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cfmt);
\r
4852 /* Trying putting this here too. It still seems to tickle a RichEdit
\r
4853 * bug: sometimes RichEdit indents the first line of a paragraph too.
\r
4855 paraf.cbSize = sizeof(paraf);
\r
4856 paraf.dwMask = PFM_OFFSET | PFM_STARTINDENT;
\r
4857 paraf.dxStartIndent = 0;
\r
4858 paraf.dxOffset = WRAP_INDENT;
\r
4859 SendMessage(hText, EM_SETPARAFORMAT, 0, (LPARAM) ¶f);
\r
4860 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
4863 /*---------------------------------------------------------------------------*\
\r
4865 * Window Proc for main window
\r
4867 \*---------------------------------------------------------------------------*/
\r
4869 /* Process messages for main window, etc. */
\r
4871 WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
4874 int wmId, wmEvent;
\r
4878 char fileTitle[MSG_SIZ];
\r
4879 static SnapData sd;
\r
4881 switch (message) {
\r
4883 case WM_PAINT: /* message: repaint portion of window */
\r
4887 case WM_ERASEBKGND:
\r
4888 if (IsIconic(hwnd)) {
\r
4889 /* Cheat; change the message */
\r
4890 return (DefWindowProc(hwnd, WM_ICONERASEBKGND, wParam, lParam));
\r
4892 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
4896 case WM_LBUTTONDOWN:
\r
4897 case WM_MBUTTONDOWN:
\r
4898 case WM_RBUTTONDOWN:
\r
4899 case WM_LBUTTONUP:
\r
4900 case WM_MBUTTONUP:
\r
4901 case WM_RBUTTONUP:
\r
4902 case WM_MOUSEMOVE:
\r
4903 MouseEvent(hwnd, message, wParam, lParam);
\r
4908 if (appData.icsActive) {
\r
4909 if (wParam == '\t') {
\r
4910 if (GetKeyState(VK_SHIFT) < 0) {
\r
4912 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4913 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4917 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
4918 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4922 HWND h = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
4923 if (IsIconic(hwndConsole)) ShowWindow(hwndConsole, SW_RESTORE);
\r
4925 SendMessage(h, message, wParam, lParam);
\r
4927 } else if (isalpha((char)wParam) || isdigit((char)wParam)) {
\r
4928 PopUpMoveDialog((char)wParam);
\r
4932 case WM_PALETTECHANGED:
\r
4933 if (hwnd != (HWND)wParam && !appData.monoMode) {
\r
4935 HDC hdc = GetDC(hwndMain);
\r
4936 SelectPalette(hdc, hPal, TRUE);
\r
4937 nnew = RealizePalette(hdc);
\r
4939 paletteChanged = TRUE;
\r
4941 UpdateColors(hdc);
\r
4943 InvalidateRect(hwnd, &boardRect, FALSE);/*faster!*/
\r
4946 ReleaseDC(hwnd, hdc);
\r
4950 case WM_QUERYNEWPALETTE:
\r
4951 if (!appData.monoMode /*&& paletteChanged*/) {
\r
4953 HDC hdc = GetDC(hwndMain);
\r
4954 paletteChanged = FALSE;
\r
4955 SelectPalette(hdc, hPal, FALSE);
\r
4956 nnew = RealizePalette(hdc);
\r
4958 InvalidateRect(hwnd, &boardRect, FALSE);
\r
4960 ReleaseDC(hwnd, hdc);
\r
4965 case WM_COMMAND: /* message: command from application menu */
\r
4966 wmId = LOWORD(wParam);
\r
4967 wmEvent = HIWORD(wParam);
\r
4972 AnalysisPopDown();
\r
4975 case IDM_NewGameFRC:
\r
4976 if( NewGameFRC() == 0 ) {
\r
4978 AnalysisPopDown();
\r
4982 case IDM_NewVariant:
\r
4983 NewVariantPopup(hwnd);
\r
4986 case IDM_LoadGame:
\r
4987 LoadGameDialog(hwnd, "Load Game from File");
\r
4990 case IDM_LoadNextGame:
\r
4994 case IDM_LoadPrevGame:
\r
4998 case IDM_ReloadGame:
\r
5002 case IDM_LoadPosition:
\r
5003 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
\r
5004 Reset(FALSE, TRUE);
\r
5007 f = OpenFileDialog(hwnd, FALSE, "",
\r
5008 appData.oldSaveStyle ? "pos" : "fen",
\r
5010 "Load Position from File", &number, fileTitle, NULL);
\r
5012 LoadPosition(f, number, fileTitle);
\r
5016 case IDM_LoadNextPosition:
\r
5017 ReloadPosition(1);
\r
5020 case IDM_LoadPrevPosition:
\r
5021 ReloadPosition(-1);
\r
5024 case IDM_ReloadPosition:
\r
5025 ReloadPosition(0);
\r
5028 case IDM_SaveGame:
\r
5029 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
5030 f = OpenFileDialog(hwnd, TRUE, defName,
\r
5031 appData.oldSaveStyle ? "gam" : "pgn",
\r
5033 "Save Game to File", NULL, fileTitle, NULL);
\r
5035 SaveGame(f, 0, "");
\r
5039 case IDM_SavePosition:
\r
5040 defName = DefaultFileName(appData.oldSaveStyle ? "pos" : "fen");
\r
5041 f = OpenFileDialog(hwnd, TRUE, defName,
\r
5042 appData.oldSaveStyle ? "pos" : "fen",
\r
5044 "Save Position to File", NULL, fileTitle, NULL);
\r
5046 SavePosition(f, 0, "");
\r
5050 case IDM_CopyGame:
\r
5051 CopyGameToClipboard();
\r
5054 case IDM_PasteGame:
\r
5055 PasteGameFromClipboard();
\r
5058 case IDM_CopyGameListToClipboard:
\r
5059 CopyGameListToClipboard();
\r
5062 /* [AS] Autodetect FEN or PGN data */
\r
5063 case IDM_PasteAny:
\r
5064 PasteGameOrFENFromClipboard();
\r
5067 /* [AS] Move history */
\r
5068 case IDM_ShowMoveHistory:
\r
5069 if( MoveHistoryIsUp() ) {
\r
5070 MoveHistoryPopDown();
\r
5073 MoveHistoryPopUp();
\r
5077 /* [AS] Eval graph */
\r
5078 case IDM_ShowEvalGraph:
\r
5079 if( EvalGraphIsUp() ) {
\r
5080 EvalGraphPopDown();
\r
5087 /* [AS] Engine output */
\r
5088 case IDM_ShowEngineOutput:
\r
5089 if( EngineOutputIsUp() ) {
\r
5090 EngineOutputPopDown();
\r
5093 EngineOutputPopUp();
\r
5097 /* [AS] User adjudication */
\r
5098 case IDM_UserAdjudication_White:
\r
5099 UserAdjudicationEvent( +1 );
\r
5102 case IDM_UserAdjudication_Black:
\r
5103 UserAdjudicationEvent( -1 );
\r
5106 case IDM_UserAdjudication_Draw:
\r
5107 UserAdjudicationEvent( 0 );
\r
5110 /* [AS] Game list options dialog */
\r
5111 case IDM_GameListOptions:
\r
5112 GameListOptions();
\r
5115 case IDM_CopyPosition:
\r
5116 CopyFENToClipboard();
\r
5119 case IDM_PastePosition:
\r
5120 PasteFENFromClipboard();
\r
5123 case IDM_MailMove:
\r
5127 case IDM_ReloadCMailMsg:
\r
5128 Reset(TRUE, TRUE);
\r
5129 ReloadCmailMsgEvent(FALSE);
\r
5132 case IDM_Minimize:
\r
5133 ShowWindow(hwnd, SW_MINIMIZE);
\r
5140 case IDM_MachineWhite:
\r
5141 MachineWhiteEvent();
\r
5143 * refresh the tags dialog only if it's visible
\r
5145 if (gameMode == MachinePlaysWhite && IsWindowVisible(editTagsDialog)) {
\r
5147 tags = PGNTags(&gameInfo);
\r
5148 TagsPopUp(tags, CmailMsg());
\r
5153 case IDM_MachineBlack:
\r
5154 MachineBlackEvent();
\r
5156 * refresh the tags dialog only if it's visible
\r
5158 if (gameMode == MachinePlaysBlack && IsWindowVisible(editTagsDialog)) {
\r
5160 tags = PGNTags(&gameInfo);
\r
5161 TagsPopUp(tags, CmailMsg());
\r
5166 case IDM_TwoMachines:
\r
5167 TwoMachinesEvent();
\r
5169 * refresh the tags dialog only if it's visible
\r
5171 if (gameMode == TwoMachinesPlay && IsWindowVisible(editTagsDialog)) {
\r
5173 tags = PGNTags(&gameInfo);
\r
5174 TagsPopUp(tags, CmailMsg());
\r
5179 case IDM_AnalysisMode:
\r
5180 if (!first.analysisSupport) {
\r
5181 char buf[MSG_SIZ];
\r
5182 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5183 DisplayError(buf, 0);
\r
5185 if (!appData.showThinking) ToggleShowThinking();
\r
5186 AnalyzeModeEvent();
\r
5190 case IDM_AnalyzeFile:
\r
5191 if (!first.analysisSupport) {
\r
5192 char buf[MSG_SIZ];
\r
5193 sprintf(buf, "%s does not support analysis", first.tidy);
\r
5194 DisplayError(buf, 0);
\r
5196 if (!appData.showThinking) ToggleShowThinking();
\r
5197 AnalyzeFileEvent();
\r
5198 LoadGameDialog(hwnd, "Analyze Game from File");
\r
5199 AnalysisPeriodicEvent(1);
\r
5203 case IDM_IcsClient:
\r
5207 case IDM_EditGame:
\r
5211 case IDM_EditPosition:
\r
5212 EditPositionEvent();
\r
5215 case IDM_Training:
\r
5219 case IDM_ShowGameList:
\r
5220 ShowGameListProc();
\r
5223 case IDM_EditTags:
\r
5227 case IDM_EditComment:
\r
5228 if (commentDialogUp && editComment) {
\r
5231 EditCommentEvent();
\r
5251 case IDM_CallFlag:
\r
5271 case IDM_StopObserving:
\r
5272 StopObservingEvent();
\r
5275 case IDM_StopExamining:
\r
5276 StopExaminingEvent();
\r
5279 case IDM_TypeInMove:
\r
5280 PopUpMoveDialog('\000');
\r
5283 case IDM_Backward:
\r
5285 SetFocus(hwndMain);
\r
5290 SetFocus(hwndMain);
\r
5295 SetFocus(hwndMain);
\r
5300 SetFocus(hwndMain);
\r
5307 case IDM_TruncateGame:
\r
5308 TruncateGameEvent();
\r
5315 case IDM_RetractMove:
\r
5316 RetractMoveEvent();
\r
5319 case IDM_FlipView:
\r
5320 flipView = !flipView;
\r
5321 DrawPosition(FALSE, NULL);
\r
5324 case IDM_FlipClock:
\r
5325 flipClock = !flipClock;
\r
5326 DisplayBothClocks();
\r
5329 case IDM_GeneralOptions:
\r
5330 GeneralOptionsPopup(hwnd);
\r
5331 DrawPosition(TRUE, NULL);
\r
5334 case IDM_BoardOptions:
\r
5335 BoardOptionsPopup(hwnd);
\r
5338 case IDM_EnginePlayOptions:
\r
5339 EnginePlayOptionsPopup(hwnd);
\r
5342 case IDM_OptionsUCI:
\r
5343 UciOptionsPopup(hwnd);
\r
5346 case IDM_IcsOptions:
\r
5347 IcsOptionsPopup(hwnd);
\r
5351 FontsOptionsPopup(hwnd);
\r
5355 SoundOptionsPopup(hwnd);
\r
5358 case IDM_CommPort:
\r
5359 CommPortOptionsPopup(hwnd);
\r
5362 case IDM_LoadOptions:
\r
5363 LoadOptionsPopup(hwnd);
\r
5366 case IDM_SaveOptions:
\r
5367 SaveOptionsPopup(hwnd);
\r
5370 case IDM_TimeControl:
\r
5371 TimeControlOptionsPopup(hwnd);
\r
5374 case IDM_SaveSettings:
\r
5375 SaveSettings(settingsFileName);
\r
5378 case IDM_SaveSettingsOnExit:
\r
5379 saveSettingsOnExit = !saveSettingsOnExit;
\r
5380 (void) CheckMenuItem(GetMenu(hwndMain), IDM_SaveSettingsOnExit,
\r
5381 MF_BYCOMMAND|(saveSettingsOnExit ?
\r
5382 MF_CHECKED : MF_UNCHECKED));
\r
5393 case IDM_AboutGame:
\r
5398 appData.debugMode = !appData.debugMode;
\r
5399 if (appData.debugMode) {
\r
5400 char dir[MSG_SIZ];
\r
5401 GetCurrentDirectory(MSG_SIZ, dir);
\r
5402 SetCurrentDirectory(installDir);
\r
5403 debugFP = fopen(appData.nameOfDebugFile, "w");
\r
5404 SetCurrentDirectory(dir);
\r
5405 setbuf(debugFP, NULL);
\r
5412 case IDM_HELPCONTENTS:
\r
5413 if (!WinHelp (hwnd, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
5414 MessageBox (GetFocus(),
\r
5415 "Unable to activate help",
\r
5416 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5420 case IDM_HELPSEARCH:
\r
5421 if (!WinHelp(hwnd, "winboard.hlp", HELP_PARTIALKEY, (DWORD)(LPSTR)"")) {
\r
5422 MessageBox (GetFocus(),
\r
5423 "Unable to activate help",
\r
5424 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5428 case IDM_HELPHELP:
\r
5429 if(!WinHelp(hwnd, (LPSTR)NULL, HELP_HELPONHELP, 0)) {
\r
5430 MessageBox (GetFocus(),
\r
5431 "Unable to activate help",
\r
5432 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
5437 lpProc = MakeProcInstance((FARPROC)About, hInst);
\r
5439 (gameInfo.event && strcmp(gameInfo.event, "Easter Egg Hunt") == 0) ?
\r
5440 "AboutBox2" : "AboutBox", hwnd, (DLGPROC)lpProc);
\r
5441 FreeProcInstance(lpProc);
\r
5444 case IDM_DirectCommand1:
\r
5445 AskQuestionEvent("Direct Command",
\r
5446 "Send to chess program:", "", "1");
\r
5448 case IDM_DirectCommand2:
\r
5449 AskQuestionEvent("Direct Command",
\r
5450 "Send to second chess program:", "", "2");
\r
5453 case EP_WhitePawn:
\r
5454 EditPositionMenuEvent(WhitePawn, fromX, fromY);
\r
5455 fromX = fromY = -1;
\r
5458 case EP_WhiteKnight:
\r
5459 EditPositionMenuEvent(WhiteKnight, fromX, fromY);
\r
5460 fromX = fromY = -1;
\r
5463 case EP_WhiteBishop:
\r
5464 EditPositionMenuEvent(WhiteBishop, fromX, fromY);
\r
5465 fromX = fromY = -1;
\r
5468 case EP_WhiteRook:
\r
5469 EditPositionMenuEvent(WhiteRook, fromX, fromY);
\r
5470 fromX = fromY = -1;
\r
5473 case EP_WhiteQueen:
\r
5474 EditPositionMenuEvent(WhiteQueen, fromX, fromY);
\r
5475 fromX = fromY = -1;
\r
5478 case EP_WhiteFerz:
\r
5479 EditPositionMenuEvent(WhiteFerz, fromX, fromY);
\r
5480 fromX = fromY = -1;
\r
5483 case EP_WhiteWazir:
\r
5484 EditPositionMenuEvent(WhiteWazir, fromX, fromY);
\r
5485 fromX = fromY = -1;
\r
5488 case EP_WhiteAlfil:
\r
5489 EditPositionMenuEvent(WhiteAlfil, fromX, fromY);
\r
5490 fromX = fromY = -1;
\r
5493 case EP_WhiteCannon:
\r
5494 EditPositionMenuEvent(WhiteCannon, fromX, fromY);
\r
5495 fromX = fromY = -1;
\r
5498 case EP_WhiteCardinal:
\r
5499 EditPositionMenuEvent(WhiteCardinal, fromX, fromY);
\r
5500 fromX = fromY = -1;
\r
5503 case EP_WhiteMarshall:
\r
5504 EditPositionMenuEvent(WhiteMarshall, fromX, fromY);
\r
5505 fromX = fromY = -1;
\r
5508 case EP_WhiteKing:
\r
5509 EditPositionMenuEvent(WhiteKing, fromX, fromY);
\r
5510 fromX = fromY = -1;
\r
5513 case EP_BlackPawn:
\r
5514 EditPositionMenuEvent(BlackPawn, fromX, fromY);
\r
5515 fromX = fromY = -1;
\r
5518 case EP_BlackKnight:
\r
5519 EditPositionMenuEvent(BlackKnight, fromX, fromY);
\r
5520 fromX = fromY = -1;
\r
5523 case EP_BlackBishop:
\r
5524 EditPositionMenuEvent(BlackBishop, fromX, fromY);
\r
5525 fromX = fromY = -1;
\r
5528 case EP_BlackRook:
\r
5529 EditPositionMenuEvent(BlackRook, fromX, fromY);
\r
5530 fromX = fromY = -1;
\r
5533 case EP_BlackQueen:
\r
5534 EditPositionMenuEvent(BlackQueen, fromX, fromY);
\r
5535 fromX = fromY = -1;
\r
5538 case EP_BlackFerz:
\r
5539 EditPositionMenuEvent(BlackFerz, fromX, fromY);
\r
5540 fromX = fromY = -1;
\r
5543 case EP_BlackWazir:
\r
5544 EditPositionMenuEvent(BlackWazir, fromX, fromY);
\r
5545 fromX = fromY = -1;
\r
5548 case EP_BlackAlfil:
\r
5549 EditPositionMenuEvent(BlackAlfil, fromX, fromY);
\r
5550 fromX = fromY = -1;
\r
5553 case EP_BlackCannon:
\r
5554 EditPositionMenuEvent(BlackCannon, fromX, fromY);
\r
5555 fromX = fromY = -1;
\r
5558 case EP_BlackCardinal:
\r
5559 EditPositionMenuEvent(BlackCardinal, fromX, fromY);
\r
5560 fromX = fromY = -1;
\r
5563 case EP_BlackMarshall:
\r
5564 EditPositionMenuEvent(BlackMarshall, fromX, fromY);
\r
5565 fromX = fromY = -1;
\r
5568 case EP_BlackKing:
\r
5569 EditPositionMenuEvent(BlackKing, fromX, fromY);
\r
5570 fromX = fromY = -1;
\r
5573 case EP_EmptySquare:
\r
5574 EditPositionMenuEvent(EmptySquare, fromX, fromY);
\r
5575 fromX = fromY = -1;
\r
5578 case EP_ClearBoard:
\r
5579 EditPositionMenuEvent(ClearBoard, fromX, fromY);
\r
5580 fromX = fromY = -1;
\r
5584 EditPositionMenuEvent(WhitePlay, fromX, fromY);
\r
5585 fromX = fromY = -1;
\r
5589 EditPositionMenuEvent(BlackPlay, fromX, fromY);
\r
5590 fromX = fromY = -1;
\r
5594 EditPositionMenuEvent(PromotePiece, fromX, fromY);
\r
5595 fromX = fromY = -1;
\r
5599 EditPositionMenuEvent(DemotePiece, fromX, fromY);
\r
5600 fromX = fromY = -1;
\r
5604 DropMenuEvent(WhitePawn, fromX, fromY);
\r
5605 fromX = fromY = -1;
\r
5609 DropMenuEvent(WhiteKnight, fromX, fromY);
\r
5610 fromX = fromY = -1;
\r
5614 DropMenuEvent(WhiteBishop, fromX, fromY);
\r
5615 fromX = fromY = -1;
\r
5619 DropMenuEvent(WhiteRook, fromX, fromY);
\r
5620 fromX = fromY = -1;
\r
5624 DropMenuEvent(WhiteQueen, fromX, fromY);
\r
5625 fromX = fromY = -1;
\r
5629 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5635 case CLOCK_TIMER_ID:
\r
5636 KillTimer(hwnd, clockTimerEvent); /* Simulate one-shot timer as in X */
\r
5637 clockTimerEvent = 0;
\r
5638 DecrementClocks(); /* call into back end */
\r
5640 case LOAD_GAME_TIMER_ID:
\r
5641 KillTimer(hwnd, loadGameTimerEvent); /* Simulate one-shot timer as in X*/
\r
5642 loadGameTimerEvent = 0;
\r
5643 AutoPlayGameLoop(); /* call into back end */
\r
5645 case ANALYSIS_TIMER_ID:
\r
5646 if ((gameMode == AnalyzeMode || gameMode == AnalyzeFile) &&
\r
5647 appData.periodicUpdates) {
\r
5648 AnalysisPeriodicEvent(0);
\r
5650 KillTimer(hwnd, analysisTimerEvent);
\r
5651 analysisTimerEvent = 0;
\r
5654 case DELAYED_TIMER_ID:
\r
5655 KillTimer(hwnd, delayedTimerEvent);
\r
5656 delayedTimerEvent = 0;
\r
5657 delayedTimerCallback();
\r
5662 case WM_USER_Input:
\r
5663 InputEvent(hwnd, message, wParam, lParam);
\r
5666 /* [AS] Also move "attached" child windows */
\r
5667 case WM_WINDOWPOSCHANGING:
\r
5668 if( hwnd == hwndMain && appData.useStickyWindows ) {
\r
5669 LPWINDOWPOS lpwp = (LPWINDOWPOS) lParam;
\r
5671 if( ((lpwp->flags & SWP_NOMOVE) == 0) && ((lpwp->flags & SWP_NOSIZE) != 0) ) {
\r
5672 /* Window is moving */
\r
5675 GetWindowRect( hwnd, &rcMain );
\r
5677 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, moveHistoryDialog, &wpMoveHistory );
\r
5678 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, evalGraphDialog, &wpEvalGraph );
\r
5679 ReattachAfterMove( &rcMain, lpwp->x, lpwp->y, engineOutputDialog, &wpEngineOutput );
\r
5684 /* [AS] Snapping */
\r
5685 case WM_ENTERSIZEMOVE:
\r
5686 if (hwnd == hwndMain) {
\r
5687 doingSizing = TRUE;
\r
5690 return OnEnterSizeMove( &sd, hwnd, wParam, lParam );
\r
5694 if (hwnd == hwndMain) {
\r
5695 lastSizing = wParam;
\r
5700 return OnMoving( &sd, hwnd, wParam, lParam );
\r
5702 case WM_EXITSIZEMOVE:
\r
5703 if (hwnd == hwndMain) {
\r
5705 doingSizing = FALSE;
\r
5706 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5707 GetClientRect(hwnd, &client);
\r
5708 ResizeBoard(client.right, client.bottom, lastSizing);
\r
5711 return OnExitSizeMove( &sd, hwnd, wParam, lParam );
\r
5714 case WM_DESTROY: /* message: window being destroyed */
\r
5715 PostQuitMessage(0);
\r
5719 if (hwnd == hwndMain) {
\r
5724 default: /* Passes it on if unprocessed */
\r
5725 return (DefWindowProc(hwnd, message, wParam, lParam));
\r
5730 /*---------------------------------------------------------------------------*\
\r
5732 * Misc utility routines
\r
5734 \*---------------------------------------------------------------------------*/
\r
5737 * Decent random number generator, at least not as bad as Windows
\r
5738 * standard rand, which returns a value in the range 0 to 0x7fff.
\r
5740 unsigned int randstate;
\r
5745 randstate = randstate * 1664525 + 1013904223;
\r
5746 return (int) randstate & 0x7fffffff;
\r
5750 mysrandom(unsigned int seed)
\r
5757 * returns TRUE if user selects a different color, FALSE otherwise
\r
5761 ChangeColor(HWND hwnd, COLORREF *which)
\r
5763 static BOOL firstTime = TRUE;
\r
5764 static DWORD customColors[16];
\r
5766 COLORREF newcolor;
\r
5771 /* Make initial colors in use available as custom colors */
\r
5772 /* Should we put the compiled-in defaults here instead? */
\r
5774 customColors[i++] = lightSquareColor & 0xffffff;
\r
5775 customColors[i++] = darkSquareColor & 0xffffff;
\r
5776 customColors[i++] = whitePieceColor & 0xffffff;
\r
5777 customColors[i++] = blackPieceColor & 0xffffff;
\r
5778 customColors[i++] = highlightSquareColor & 0xffffff;
\r
5779 customColors[i++] = premoveHighlightColor & 0xffffff;
\r
5781 for (ccl = (ColorClass) 0; ccl < NColorClasses && i < 16; ccl++) {
\r
5782 customColors[i++] = textAttribs[ccl].color;
\r
5784 while (i < 16) customColors[i++] = RGB(255, 255, 255);
\r
5785 firstTime = FALSE;
\r
5788 cc.lStructSize = sizeof(cc);
\r
5789 cc.hwndOwner = hwnd;
\r
5790 cc.hInstance = NULL;
\r
5791 cc.rgbResult = (DWORD) (*which & 0xffffff);
\r
5792 cc.lpCustColors = (LPDWORD) customColors;
\r
5793 cc.Flags = CC_RGBINIT|CC_FULLOPEN;
\r
5795 if (!ChooseColor(&cc)) return FALSE;
\r
5797 newcolor = (COLORREF) (0x2000000 | cc.rgbResult);
\r
5798 if (newcolor == *which) return FALSE;
\r
5799 *which = newcolor;
\r
5803 InitDrawingColors();
\r
5804 InvalidateRect(hwnd, &boardRect, FALSE);
\r
5809 MyLoadSound(MySound *ms)
\r
5815 if (ms->data) free(ms->data);
\r
5818 switch (ms->name[0]) {
\r
5824 /* System sound from Control Panel. Don't preload here. */
\r
5828 if (ms->name[1] == NULLCHAR) {
\r
5829 /* "!" alone = silence */
\r
5832 /* Builtin wave resource. Error if not found. */
\r
5833 HANDLE h = FindResource(hInst, ms->name + 1, "WAVE");
\r
5834 if (h == NULL) break;
\r
5835 ms->data = (void *)LoadResource(hInst, h);
\r
5836 if (h == NULL) break;
\r
5841 /* .wav file. Error if not found. */
\r
5842 f = fopen(ms->name, "rb");
\r
5843 if (f == NULL) break;
\r
5844 if (fstat(fileno(f), &st) < 0) break;
\r
5845 ms->data = malloc(st.st_size);
\r
5846 if (fread(ms->data, st.st_size, 1, f) < 1) break;
\r
5852 char buf[MSG_SIZ];
\r
5853 sprintf(buf, "Error loading sound %s", ms->name);
\r
5854 DisplayError(buf, GetLastError());
\r
5860 MyPlaySound(MySound *ms)
\r
5862 BOOLEAN ok = FALSE;
\r
5863 switch (ms->name[0]) {
\r
5869 /* System sound from Control Panel (deprecated feature).
\r
5870 "$" alone or an unset sound name gets default beep (still in use). */
\r
5871 if (ms->name[1]) {
\r
5872 ok = PlaySound(ms->name + 1, NULL, SND_ALIAS|SND_ASYNC);
\r
5874 if (!ok) ok = MessageBeep(MB_OK);
\r
5877 /* Builtin wave resource, or "!" alone for silence */
\r
5878 if (ms->name[1]) {
\r
5879 if (ms->data == NULL) return FALSE;
\r
5880 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5886 /* .wav file. Error if not found. */
\r
5887 if (ms->data == NULL) return FALSE;
\r
5888 ok = PlaySound(ms->data, NULL, SND_MEMORY|SND_ASYNC);
\r
5891 /* Don't print an error: this can happen innocently if the sound driver
\r
5892 is busy; for instance, if another instance of WinBoard is playing
\r
5893 a sound at about the same time. */
\r
5896 char buf[MSG_SIZ];
\r
5897 sprintf(buf, "Error playing sound %s", ms->name);
\r
5898 DisplayError(buf, GetLastError());
\r
5906 OldOpenFileHook(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
5909 OPENFILENAME *ofn;
\r
5910 static UINT *number; /* gross that this is static */
\r
5912 switch (message) {
\r
5913 case WM_INITDIALOG: /* message: initialize dialog box */
\r
5914 /* Center the dialog over the application window */
\r
5915 ofn = (OPENFILENAME *) lParam;
\r
5916 if (ofn->Flags & OFN_ENABLETEMPLATE) {
\r
5917 number = (UINT *) ofn->lCustData;
\r
5918 SendMessage(GetDlgItem(hDlg, edt2), WM_SETTEXT, 0, (LPARAM) "");
\r
5922 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
5923 return FALSE; /* Allow for further processing */
\r
5926 if ((LOWORD(wParam) == IDOK) && (number != NULL)) {
\r
5927 *number = GetDlgItemInt(hDlg, OPT_IndexNumberOld, &ok, FALSE);
\r
5929 return FALSE; /* Allow for further processing */
\r
5935 OpenFileHook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
\r
5937 static UINT *number;
\r
5938 OPENFILENAME *ofname;
\r
5941 case WM_INITDIALOG:
\r
5942 ofname = (OPENFILENAME *)lParam;
\r
5943 number = (UINT *)(ofname->lCustData);
\r
5946 ofnot = (OFNOTIFY *)lParam;
\r
5947 if (ofnot->hdr.code == CDN_FILEOK) {
\r
5948 *number = GetDlgItemInt(hdlg, OPT_IndexNumber, NULL, FALSE);
\r
5957 OpenFileDialog(HWND hwnd, BOOL write, char *defName, char *defExt,
\r
5958 char *nameFilt, char *dlgTitle, UINT *number,
\r
5959 char fileTitle[MSG_SIZ], char fileName[MSG_SIZ])
\r
5961 OPENFILENAME openFileName;
\r
5962 char buf1[MSG_SIZ];
\r
5965 if (fileName == NULL) fileName = buf1;
\r
5966 if (defName == NULL) {
\r
5967 strcpy(fileName, "*.");
\r
5968 strcat(fileName, defExt);
\r
5970 strcpy(fileName, defName);
\r
5972 if (fileTitle) strcpy(fileTitle, "");
\r
5973 if (number) *number = 0;
\r
5975 openFileName.lStructSize = sizeof(OPENFILENAME);
\r
5976 openFileName.hwndOwner = hwnd;
\r
5977 openFileName.hInstance = (HANDLE) hInst;
\r
5978 openFileName.lpstrFilter = nameFilt;
\r
5979 openFileName.lpstrCustomFilter = (LPSTR) NULL;
\r
5980 openFileName.nMaxCustFilter = 0L;
\r
5981 openFileName.nFilterIndex = 1L;
\r
5982 openFileName.lpstrFile = fileName;
\r
5983 openFileName.nMaxFile = MSG_SIZ;
\r
5984 openFileName.lpstrFileTitle = fileTitle;
\r
5985 openFileName.nMaxFileTitle = fileTitle ? MSG_SIZ : 0;
\r
5986 openFileName.lpstrInitialDir = NULL;
\r
5987 openFileName.lpstrTitle = dlgTitle;
\r
5988 openFileName.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
\r
5989 | (write ? 0 : OFN_FILEMUSTEXIST)
\r
5990 | (number ? OFN_ENABLETEMPLATE | OFN_ENABLEHOOK: 0)
\r
5991 | (oldDialog ? 0 : OFN_EXPLORER);
\r
5992 openFileName.nFileOffset = 0;
\r
5993 openFileName.nFileExtension = 0;
\r
5994 openFileName.lpstrDefExt = defExt;
\r
5995 openFileName.lCustData = (LONG) number;
\r
5996 openFileName.lpfnHook = oldDialog ?
\r
5997 (LPOFNHOOKPROC) OldOpenFileHook : (LPOFNHOOKPROC) OpenFileHook;
\r
5998 openFileName.lpTemplateName = (LPSTR)(oldDialog ? 1536 : DLG_IndexNumber);
\r
6000 if (write ? GetSaveFileName(&openFileName) :
\r
6001 GetOpenFileName(&openFileName)) {
\r
6002 /* open the file */
\r
6003 f = fopen(openFileName.lpstrFile, write ? "a" : "rb");
\r
6005 MessageBox(hwnd, "File open failed", NULL,
\r
6006 MB_OK|MB_ICONEXCLAMATION);
\r
6010 int err = CommDlgExtendedError();
\r
6011 if (err != 0) DisplayError("Internal error in file dialog box", err);
\r
6020 MenuPopup(HWND hwnd, POINT pt, HMENU hmenu, UINT def)
\r
6022 HMENU hmenuTrackPopup; /* floating pop-up menu */
\r
6025 * Get the first pop-up menu in the menu template. This is the
\r
6026 * menu that TrackPopupMenu displays.
\r
6028 hmenuTrackPopup = GetSubMenu(hmenu, 0);
\r
6030 SetMenuDefaultItem(hmenuTrackPopup, def, FALSE);
\r
6033 * TrackPopup uses screen coordinates, so convert the
\r
6034 * coordinates of the mouse click to screen coordinates.
\r
6036 ClientToScreen(hwnd, (LPPOINT) &pt);
\r
6038 /* Draw and track the floating pop-up menu. */
\r
6039 TrackPopupMenu(hmenuTrackPopup, TPM_CENTERALIGN | TPM_RIGHTBUTTON,
\r
6040 pt.x, pt.y, 0, hwnd, NULL);
\r
6042 /* Destroy the menu.*/
\r
6043 DestroyMenu(hmenu);
\r
6048 int sizeX, sizeY, newSizeX, newSizeY;
\r
6050 } ResizeEditPlusButtonsClosure;
\r
6053 ResizeEditPlusButtonsCallback(HWND hChild, LPARAM lparam)
\r
6055 ResizeEditPlusButtonsClosure *cl = (ResizeEditPlusButtonsClosure *)lparam;
\r
6059 if (hChild == cl->hText) return TRUE;
\r
6060 GetWindowRect(hChild, &rect); /* gives screen coords */
\r
6061 pt.x = rect.left + (cl->newSizeX - cl->sizeX)/2;
\r
6062 pt.y = rect.top + cl->newSizeY - cl->sizeY;
\r
6063 ScreenToClient(cl->hDlg, &pt);
\r
6064 cl->hdwp = DeferWindowPos(cl->hdwp, hChild, NULL,
\r
6065 pt.x, pt.y, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
\r
6069 /* Resize a dialog that has a (rich) edit field filling most of
\r
6070 the top, with a row of buttons below */
\r
6072 ResizeEditPlusButtons(HWND hDlg, HWND hText, int sizeX, int sizeY, int newSizeX, int newSizeY)
\r
6075 int newTextHeight, newTextWidth;
\r
6076 ResizeEditPlusButtonsClosure cl;
\r
6078 /*if (IsIconic(hDlg)) return;*/
\r
6079 if (newSizeX == sizeX && newSizeY == sizeY) return;
\r
6081 cl.hdwp = BeginDeferWindowPos(8);
\r
6083 GetWindowRect(hText, &rectText); /* gives screen coords */
\r
6084 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
6085 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
6086 if (newTextHeight < 0) {
\r
6087 newSizeY += -newTextHeight;
\r
6088 newTextHeight = 0;
\r
6090 cl.hdwp = DeferWindowPos(cl.hdwp, hText, NULL, 0, 0,
\r
6091 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
6097 cl.newSizeX = newSizeX;
\r
6098 cl.newSizeY = newSizeY;
\r
6099 EnumChildWindows(hDlg, ResizeEditPlusButtonsCallback, (LPARAM)&cl);
\r
6101 EndDeferWindowPos(cl.hdwp);
\r
6104 BOOL CenterWindowEx(HWND hwndChild, HWND hwndParent, int mode)
\r
6106 RECT rChild, rParent;
\r
6107 int wChild, hChild, wParent, hParent;
\r
6108 int wScreen, hScreen, xNew, yNew;
\r
6111 /* Get the Height and Width of the child window */
\r
6112 GetWindowRect (hwndChild, &rChild);
\r
6113 wChild = rChild.right - rChild.left;
\r
6114 hChild = rChild.bottom - rChild.top;
\r
6116 /* Get the Height and Width of the parent window */
\r
6117 GetWindowRect (hwndParent, &rParent);
\r
6118 wParent = rParent.right - rParent.left;
\r
6119 hParent = rParent.bottom - rParent.top;
\r
6121 /* Get the display limits */
\r
6122 hdc = GetDC (hwndChild);
\r
6123 wScreen = GetDeviceCaps (hdc, HORZRES);
\r
6124 hScreen = GetDeviceCaps (hdc, VERTRES);
\r
6125 ReleaseDC(hwndChild, hdc);
\r
6127 /* Calculate new X position, then adjust for screen */
\r
6128 xNew = rParent.left + ((wParent - wChild) /2);
\r
6131 } else if ((xNew+wChild) > wScreen) {
\r
6132 xNew = wScreen - wChild;
\r
6135 /* Calculate new Y position, then adjust for screen */
\r
6137 yNew = rParent.top + ((hParent - hChild) /2);
\r
6140 yNew = rParent.top + GetSystemMetrics( SM_CYCAPTION ) * 2 / 3;
\r
6145 } else if ((yNew+hChild) > hScreen) {
\r
6146 yNew = hScreen - hChild;
\r
6149 /* Set it, and return */
\r
6150 return SetWindowPos (hwndChild, NULL,
\r
6151 xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
\r
6154 /* Center one window over another */
\r
6155 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
\r
6157 return CenterWindowEx( hwndChild, hwndParent, 0 );
\r
6160 /*---------------------------------------------------------------------------*\
\r
6162 * Startup Dialog functions
\r
6164 \*---------------------------------------------------------------------------*/
\r
6166 InitComboStrings(HANDLE hwndCombo, char **cd)
\r
6168 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6170 while (*cd != NULL) {
\r
6171 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) *cd);
\r
6177 InitComboStringsFromOption(HANDLE hwndCombo, char *str)
\r
6179 char buf1[ARG_MAX];
\r
6182 if (str[0] == '@') {
\r
6183 FILE* f = fopen(str + 1, "r");
\r
6185 DisplayFatalError(str + 1, errno, 2);
\r
6188 len = fread(buf1, 1, sizeof(buf1)-1, f);
\r
6190 buf1[len] = NULLCHAR;
\r
6194 SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
\r
6197 char buf[MSG_SIZ];
\r
6198 char *end = strchr(str, '\n');
\r
6199 if (end == NULL) return;
\r
6200 memcpy(buf, str, end - str);
\r
6201 buf[end - str] = NULLCHAR;
\r
6202 SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) buf);
\r
6208 SetStartupDialogEnables(HWND hDlg)
\r
6210 EnableWindow(GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6211 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6212 appData.zippyPlay && IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6213 EnableWindow(GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6214 IsDlgButtonChecked(hDlg, OPT_ChessEngine));
\r
6215 EnableWindow(GetDlgItem(hDlg, OPT_ChessServerName),
\r
6216 IsDlgButtonChecked(hDlg, OPT_ChessServer));
\r
6217 EnableWindow(GetDlgItem(hDlg, OPT_AdditionalOptions),
\r
6218 IsDlgButtonChecked(hDlg, OPT_AnyAdditional));
\r
6219 EnableWindow(GetDlgItem(hDlg, IDOK),
\r
6220 IsDlgButtonChecked(hDlg, OPT_ChessEngine) ||
\r
6221 IsDlgButtonChecked(hDlg, OPT_ChessServer) ||
\r
6222 IsDlgButtonChecked(hDlg, OPT_View));
\r
6226 QuoteForFilename(char *filename)
\r
6228 int dquote, space;
\r
6229 dquote = strchr(filename, '"') != NULL;
\r
6230 space = strchr(filename, ' ') != NULL;
\r
6231 if (dquote || space) {
\r
6243 InitEngineBox(HWND hDlg, HWND hwndCombo, char* nthcp, char* nthd, char* nthdir, char *nthnames)
\r
6245 char buf[MSG_SIZ];
\r
6248 InitComboStringsFromOption(hwndCombo, nthnames);
\r
6249 q = QuoteForFilename(nthcp);
\r
6250 sprintf(buf, "%s%s%s", q, nthcp, q);
\r
6251 if (*nthdir != NULLCHAR) {
\r
6252 q = QuoteForFilename(nthdir);
\r
6253 sprintf(buf + strlen(buf), " /%s=%s%s%s", nthd, q, nthdir, q);
\r
6255 if (*nthcp == NULLCHAR) {
\r
6256 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6257 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6258 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6259 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6264 StartupDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6266 char buf[MSG_SIZ];
\r
6270 switch (message) {
\r
6271 case WM_INITDIALOG:
\r
6272 /* Center the dialog */
\r
6273 CenterWindow (hDlg, GetDesktopWindow());
\r
6274 /* Initialize the dialog items */
\r
6275 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_ChessEngineName),
\r
6276 appData.firstChessProgram, "fd", appData.firstDirectory,
\r
6277 firstChessProgramNames);
\r
6278 InitEngineBox(hDlg, GetDlgItem(hDlg, OPT_SecondChessEngineName),
\r
6279 appData.secondChessProgram, "sd", appData.secondDirectory,
\r
6280 secondChessProgramNames);
\r
6281 hwndCombo = GetDlgItem(hDlg, OPT_ChessServerName);
\r
6282 InitComboStringsFromOption(hwndCombo, icsNames);
\r
6283 sprintf(buf, "%s /icsport=%s", appData.icsHost, appData.icsPort);
\r
6284 if (*appData.icsHelper != NULLCHAR) {
\r
6285 char *q = QuoteForFilename(appData.icsHelper);
\r
6286 sprintf(buf + strlen(buf), " /icshelper=%s%s%s", q, appData.icsHelper, q);
\r
6288 if (*appData.icsHost == NULLCHAR) {
\r
6289 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
\r
6290 /*SendMessage(hwndCombo, CB_SHOWDROPDOWN, (WPARAM) TRUE, (LPARAM) 0); !!too soon */
\r
6291 } else if (SendMessage(hwndCombo, CB_SELECTSTRING, (WPARAM) -1, (LPARAM) buf) == CB_ERR) {
\r
6292 SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) -1, (LPARAM) 0);
\r
6293 SendMessage(hwndCombo, WM_SETTEXT, (WPARAM) 0, (LPARAM) buf);
\r
6296 if (appData.icsActive) {
\r
6297 CheckDlgButton(hDlg, OPT_ChessServer, BST_CHECKED);
\r
6299 else if (appData.noChessProgram) {
\r
6300 CheckDlgButton(hDlg, OPT_View, BST_CHECKED);
\r
6303 CheckDlgButton(hDlg, OPT_ChessEngine, BST_CHECKED);
\r
6306 SetStartupDialogEnables(hDlg);
\r
6310 switch (LOWORD(wParam)) {
\r
6312 if (IsDlgButtonChecked(hDlg, OPT_ChessEngine)) {
\r
6313 strcpy(buf, "/fcp=");
\r
6314 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6316 ParseArgs(StringGet, &p);
\r
6317 strcpy(buf, "/scp=");
\r
6318 GetDlgItemText(hDlg, OPT_SecondChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6320 ParseArgs(StringGet, &p);
\r
6321 appData.noChessProgram = FALSE;
\r
6322 appData.icsActive = FALSE;
\r
6323 } else if (IsDlgButtonChecked(hDlg, OPT_ChessServer)) {
\r
6324 strcpy(buf, "/ics /icshost=");
\r
6325 GetDlgItemText(hDlg, OPT_ChessServerName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6327 ParseArgs(StringGet, &p);
\r
6328 if (appData.zippyPlay) {
\r
6329 strcpy(buf, "/fcp=");
\r
6330 GetDlgItemText(hDlg, OPT_ChessEngineName, buf + strlen(buf), sizeof(buf) - strlen(buf));
\r
6332 ParseArgs(StringGet, &p);
\r
6334 } else if (IsDlgButtonChecked(hDlg, OPT_View)) {
\r
6335 appData.noChessProgram = TRUE;
\r
6336 appData.icsActive = FALSE;
\r
6338 MessageBox(hDlg, "Choose an option, or cancel to exit",
\r
6339 "Option Error", MB_OK|MB_ICONEXCLAMATION);
\r
6342 if (IsDlgButtonChecked(hDlg, OPT_AnyAdditional)) {
\r
6343 GetDlgItemText(hDlg, OPT_AdditionalOptions, buf, sizeof(buf));
\r
6345 ParseArgs(StringGet, &p);
\r
6347 EndDialog(hDlg, TRUE);
\r
6354 case IDM_HELPCONTENTS:
\r
6355 if (!WinHelp (hDlg, "winboard.hlp", HELP_KEY,(DWORD)(LPSTR)"CONTENTS")) {
\r
6356 MessageBox (GetFocus(),
\r
6357 "Unable to activate help",
\r
6358 szAppName, MB_SYSTEMMODAL|MB_OK|MB_ICONHAND);
\r
6363 SetStartupDialogEnables(hDlg);
\r
6371 /*---------------------------------------------------------------------------*\
\r
6373 * About box dialog functions
\r
6375 \*---------------------------------------------------------------------------*/
\r
6377 /* Process messages for "About" dialog box */
\r
6379 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6381 switch (message) {
\r
6382 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6383 /* Center the dialog over the application window */
\r
6384 CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
\r
6385 SetDlgItemText(hDlg, ABOUTBOX_Version, programVersion);
\r
6388 case WM_COMMAND: /* message: received a command */
\r
6389 if (LOWORD(wParam) == IDOK /* "OK" box selected? */
\r
6390 || LOWORD(wParam) == IDCANCEL) { /* System menu close command? */
\r
6391 EndDialog(hDlg, TRUE); /* Exit the dialog */
\r
6399 /*---------------------------------------------------------------------------*\
\r
6401 * Comment Dialog functions
\r
6403 \*---------------------------------------------------------------------------*/
\r
6406 CommentDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6408 static HANDLE hwndText = NULL;
\r
6409 int len, newSizeX, newSizeY, flags;
\r
6410 static int sizeX, sizeY;
\r
6415 switch (message) {
\r
6416 case WM_INITDIALOG: /* message: initialize dialog box */
\r
6417 /* Initialize the dialog items */
\r
6418 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6419 SetDlgItemText(hDlg, OPT_CommentText, commentText);
\r
6420 EnableWindow(GetDlgItem(hDlg, OPT_CancelComment), editComment);
\r
6421 EnableWindow(GetDlgItem(hDlg, OPT_ClearComment), editComment);
\r
6422 EnableWindow(GetDlgItem(hDlg, OPT_EditComment), !editComment);
\r
6423 SendMessage(hwndText, EM_SETREADONLY, !editComment, 0);
\r
6424 SetWindowText(hDlg, commentTitle);
\r
6425 if (editComment) {
\r
6426 SetFocus(hwndText);
\r
6428 SetFocus(GetDlgItem(hDlg, IDOK));
\r
6430 SendMessage(GetDlgItem(hDlg, OPT_CommentText),
\r
6431 WM_SETFONT, (WPARAM)font[boardSize][COMMENT_FONT]->hf,
\r
6432 MAKELPARAM(FALSE, 0));
\r
6433 /* Size and position the dialog */
\r
6434 if (!commentDialog) {
\r
6435 commentDialog = hDlg;
\r
6436 flags = SWP_NOZORDER;
\r
6437 GetClientRect(hDlg, &rect);
\r
6438 sizeX = rect.right;
\r
6439 sizeY = rect.bottom;
\r
6440 if (commentX != CW_USEDEFAULT && commentY != CW_USEDEFAULT &&
\r
6441 commentW != CW_USEDEFAULT && commentH != CW_USEDEFAULT) {
\r
6442 WINDOWPLACEMENT wp;
\r
6443 EnsureOnScreen(&commentX, &commentY);
\r
6444 wp.length = sizeof(WINDOWPLACEMENT);
\r
6446 wp.showCmd = SW_SHOW;
\r
6447 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
6448 wp.rcNormalPosition.left = commentX;
\r
6449 wp.rcNormalPosition.right = commentX + commentW;
\r
6450 wp.rcNormalPosition.top = commentY;
\r
6451 wp.rcNormalPosition.bottom = commentY + commentH;
\r
6452 SetWindowPlacement(hDlg, &wp);
\r
6454 GetClientRect(hDlg, &rect);
\r
6455 newSizeX = rect.right;
\r
6456 newSizeY = rect.bottom;
\r
6457 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
6458 newSizeX, newSizeY);
\r
6465 case WM_COMMAND: /* message: received a command */
\r
6466 switch (LOWORD(wParam)) {
\r
6468 if (editComment) {
\r
6470 /* Read changed options from the dialog box */
\r
6471 hwndText = GetDlgItem(hDlg, OPT_CommentText);
\r
6472 len = GetWindowTextLength(hwndText);
\r
6473 str = (char *) malloc(len + 1);
\r
6474 GetWindowText(hwndText, str, len + 1);
\r
6483 ReplaceComment(commentIndex, str);
\r
6490 case OPT_CancelComment:
\r
6494 case OPT_ClearComment:
\r
6495 SetDlgItemText(hDlg, OPT_CommentText, "");
\r
6498 case OPT_EditComment:
\r
6499 EditCommentEvent();
\r
6508 newSizeX = LOWORD(lParam);
\r
6509 newSizeY = HIWORD(lParam);
\r
6510 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
6515 case WM_GETMINMAXINFO:
\r
6516 /* Prevent resizing window too small */
\r
6517 mmi = (MINMAXINFO *) lParam;
\r
6518 mmi->ptMinTrackSize.x = 100;
\r
6519 mmi->ptMinTrackSize.y = 100;
\r
6526 EitherCommentPopUp(int index, char *title, char *str, BOOLEAN edit)
\r
6531 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, edit ? MF_CHECKED : MF_UNCHECKED);
\r
6533 if (str == NULL) str = "";
\r
6534 p = (char *) malloc(2 * strlen(str) + 2);
\r
6537 if (*str == '\n') *q++ = '\r';
\r
6541 if (commentText != NULL) free(commentText);
\r
6543 commentIndex = index;
\r
6544 commentTitle = title;
\r
6546 editComment = edit;
\r
6548 if (commentDialog) {
\r
6549 SendMessage(commentDialog, WM_INITDIALOG, 0, 0);
\r
6550 if (!commentDialogUp) ShowWindow(commentDialog, SW_SHOW);
\r
6552 lpProc = MakeProcInstance((FARPROC)CommentDialog, hInst);
\r
6553 CreateDialog(hInst, MAKEINTRESOURCE(DLG_EditComment),
\r
6554 hwndMain, (DLGPROC)lpProc);
\r
6555 FreeProcInstance(lpProc);
\r
6557 commentDialogUp = TRUE;
\r
6561 /*---------------------------------------------------------------------------*\
\r
6563 * Type-in move dialog functions
\r
6565 \*---------------------------------------------------------------------------*/
\r
6568 TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6570 char move[MSG_SIZ];
\r
6572 ChessMove moveType;
\r
6573 int fromX, fromY, toX, toY;
\r
6576 switch (message) {
\r
6577 case WM_INITDIALOG:
\r
6578 move[0] = (char) lParam;
\r
6579 move[1] = NULLCHAR;
\r
6580 CenterWindowEx(hDlg, GetWindow(hDlg, GW_OWNER), 1 );
\r
6581 hInput = GetDlgItem(hDlg, OPT_Move);
\r
6582 SetWindowText(hInput, move);
\r
6584 SendMessage(hInput, EM_SETSEL, (WPARAM)9999, (LPARAM)9999);
\r
6588 switch (LOWORD(wParam)) {
\r
6590 if (gameMode != EditGame && currentMove != forwardMostMove &&
\r
6591 gameMode != Training) {
\r
6592 DisplayMoveError("Displayed move is not current");
\r
6594 GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
\r
6595 if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove,
\r
6596 &moveType, &fromX, &fromY, &toX, &toY, &promoChar)) {
\r
6597 if (gameMode != Training)
\r
6598 forwardMostMove = currentMove;
\r
6599 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
\r
6601 DisplayMoveError("Could not parse move");
\r
6604 EndDialog(hDlg, TRUE);
\r
6607 EndDialog(hDlg, FALSE);
\r
6618 PopUpMoveDialog(char firstchar)
\r
6622 if ((gameMode == BeginningOfGame && !appData.icsActive) ||
\r
6623 gameMode == MachinePlaysWhite || gameMode == MachinePlaysBlack ||
\r
6624 gameMode == AnalyzeMode || gameMode == EditGame ||
\r
6625 gameMode == EditPosition || gameMode == IcsExamining ||
\r
6626 gameMode == IcsPlayingWhite || gameMode == IcsPlayingBlack ||
\r
6627 gameMode == Training) {
\r
6628 lpProc = MakeProcInstance((FARPROC)TypeInMoveDialog, hInst);
\r
6629 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_TypeInMove),
\r
6630 hwndMain, (DLGPROC)lpProc, (LPARAM)firstchar);
\r
6631 FreeProcInstance(lpProc);
\r
6635 /*---------------------------------------------------------------------------*\
\r
6639 \*---------------------------------------------------------------------------*/
\r
6641 /* Nonmodal error box */
\r
6642 LRESULT CALLBACK ErrorDialog(HWND hDlg, UINT message,
\r
6643 WPARAM wParam, LPARAM lParam);
\r
6646 ErrorPopUp(char *title, char *content)
\r
6650 BOOLEAN modal = hwndMain == NULL;
\r
6668 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6669 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6672 MessageBox(NULL, errorMessage, errorTitle, MB_OK|MB_ICONEXCLAMATION);
\r
6674 lpProc = MakeProcInstance((FARPROC)ErrorDialog, hInst);
\r
6675 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6676 hwndMain, (DLGPROC)lpProc);
\r
6677 FreeProcInstance(lpProc);
\r
6684 if (!appData.popupMoveErrors && moveErrorMessageUp) DisplayMessage("", "");
\r
6685 if (errorDialog == NULL) return;
\r
6686 DestroyWindow(errorDialog);
\r
6687 errorDialog = NULL;
\r
6691 ErrorDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6696 switch (message) {
\r
6697 case WM_INITDIALOG:
\r
6698 GetWindowRect(hDlg, &rChild);
\r
6701 SetWindowPos(hDlg, NULL, rChild.left,
\r
6702 rChild.top + boardRect.top - (rChild.bottom - rChild.top),
\r
6703 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6707 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6708 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6709 and it doesn't work when you resize the dialog.
\r
6710 For now, just give it a default position.
\r
6712 SetWindowPos(hDlg, NULL, boardRect.left+8, boardRect.top+8, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
\r
6714 errorDialog = hDlg;
\r
6715 SetWindowText(hDlg, errorTitle);
\r
6716 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6717 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6721 switch (LOWORD(wParam)) {
\r
6724 if (errorDialog == hDlg) errorDialog = NULL;
\r
6725 DestroyWindow(hDlg);
\r
6737 HWND gothicDialog = NULL;
\r
6740 GothicDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
6744 int height = GetSystemMetrics(SM_CYCAPTION)+GetSystemMetrics(SM_CYFRAME);
\r
6746 switch (message) {
\r
6747 case WM_INITDIALOG:
\r
6748 GetWindowRect(hDlg, &rChild);
\r
6750 SetWindowPos(hDlg, NULL, boardX, boardY-height, winWidth, height,
\r
6754 [AS] It seems that the above code wants to move the dialog up in the "caption
\r
6755 area" of the main window, but it uses the dialog height as an hard-coded constant,
\r
6756 and it doesn't work when you resize the dialog.
\r
6757 For now, just give it a default position.
\r
6759 gothicDialog = hDlg;
\r
6760 SetWindowText(hDlg, errorTitle);
\r
6761 hwndText = GetDlgItem(hDlg, OPT_ErrorText);
\r
6762 SetDlgItemText(hDlg, OPT_ErrorText, errorMessage);
\r
6766 switch (LOWORD(wParam)) {
\r
6769 if (errorDialog == hDlg) errorDialog = NULL;
\r
6770 DestroyWindow(hDlg);
\r
6782 GothicPopUp(char *title, char up)
\r
6786 BOOLEAN modal = hwndMain == NULL;
\r
6788 strncpy(errorTitle, title, sizeof(errorTitle));
\r
6789 errorTitle[sizeof(errorTitle) - 1] = '\0';
\r
6791 if(up && gothicDialog == NULL) {
\r
6792 lpProc = MakeProcInstance((FARPROC)GothicDialog, hInst);
\r
6793 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Error),
\r
6794 hwndMain, (DLGPROC)lpProc);
\r
6795 FreeProcInstance(lpProc);
\r
6796 } else if(!up && gothicDialog != NULL) {
\r
6797 DestroyWindow(gothicDialog);
\r
6798 gothicDialog = NULL;
\r
6803 /*---------------------------------------------------------------------------*\
\r
6805 * Ics Interaction console functions
\r
6807 \*---------------------------------------------------------------------------*/
\r
6809 #define HISTORY_SIZE 64
\r
6810 static char *history[HISTORY_SIZE];
\r
6811 int histIn = 0, histP = 0;
\r
6814 SaveInHistory(char *cmd)
\r
6816 if (history[histIn] != NULL) {
\r
6817 free(history[histIn]);
\r
6818 history[histIn] = NULL;
\r
6820 if (*cmd == NULLCHAR) return;
\r
6821 history[histIn] = StrSave(cmd);
\r
6822 histIn = (histIn + 1) % HISTORY_SIZE;
\r
6823 if (history[histIn] != NULL) {
\r
6824 free(history[histIn]);
\r
6825 history[histIn] = NULL;
\r
6831 PrevInHistory(char *cmd)
\r
6834 if (histP == histIn) {
\r
6835 if (history[histIn] != NULL) free(history[histIn]);
\r
6836 history[histIn] = StrSave(cmd);
\r
6838 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
6839 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
6841 return history[histP];
\r
6847 if (histP == histIn) return NULL;
\r
6848 histP = (histP + 1) % HISTORY_SIZE;
\r
6849 return history[histP];
\r
6856 BOOLEAN immediate;
\r
6857 } IcsTextMenuEntry;
\r
6858 #define ICS_TEXT_MENU_SIZE (IDM_CommandXLast - IDM_CommandX + 1)
\r
6859 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
\r
6862 ParseIcsTextMenu(char *icsTextMenuString)
\r
6865 IcsTextMenuEntry *e = icsTextMenuEntry;
\r
6866 char *p = icsTextMenuString;
\r
6867 while (e->item != NULL && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6870 if (e->command != NULL) {
\r
6872 e->command = NULL;
\r
6876 e = icsTextMenuEntry;
\r
6877 while (*p && e < icsTextMenuEntry + ICS_TEXT_MENU_SIZE) {
\r
6878 if (*p == ';' || *p == '\n') {
\r
6879 e->item = strdup("-");
\r
6880 e->command = NULL;
\r
6882 } else if (*p == '-') {
\r
6883 e->item = strdup("-");
\r
6884 e->command = NULL;
\r
6888 char *q, *r, *s, *t;
\r
6890 q = strchr(p, ',');
\r
6891 if (q == NULL) break;
\r
6893 r = strchr(q + 1, ',');
\r
6894 if (r == NULL) break;
\r
6896 s = strchr(r + 1, ',');
\r
6897 if (s == NULL) break;
\r
6900 t = strchr(s + 1, c);
\r
6903 t = strchr(s + 1, c);
\r
6905 if (t != NULL) *t = NULLCHAR;
\r
6906 e->item = strdup(p);
\r
6907 e->command = strdup(q + 1);
\r
6908 e->getname = *(r + 1) != '0';
\r
6909 e->immediate = *(s + 1) != '0';
\r
6913 if (t == NULL) break;
\r
6922 LoadIcsTextMenu(IcsTextMenuEntry *e)
\r
6926 hmenu = LoadMenu(hInst, "TextMenu");
\r
6927 h = GetSubMenu(hmenu, 0);
\r
6929 if (strcmp(e->item, "-") == 0) {
\r
6930 AppendMenu(h, MF_SEPARATOR, 0, 0);
\r
6932 if (e->item[0] == '|') {
\r
6933 AppendMenu(h, MF_STRING|MF_MENUBARBREAK,
\r
6934 IDM_CommandX + i, &e->item[1]);
\r
6936 AppendMenu(h, MF_STRING, IDM_CommandX + i, e->item);
\r
6945 WNDPROC consoleTextWindowProc;
\r
6948 CommandX(HWND hwnd, char *command, BOOLEAN getname, BOOLEAN immediate)
\r
6950 char buf[MSG_SIZ], name[MSG_SIZ];
\r
6951 HWND hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
6955 SetWindowText(hInput, command);
\r
6957 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
6959 sel.cpMin = 999999;
\r
6960 sel.cpMax = 999999;
\r
6961 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
6966 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
6967 if (sel.cpMin == sel.cpMax) {
\r
6968 /* Expand to surrounding word */
\r
6971 tr.chrg.cpMax = sel.cpMin;
\r
6972 tr.chrg.cpMin = --sel.cpMin;
\r
6973 if (sel.cpMin < 0) break;
\r
6974 tr.lpstrText = name;
\r
6975 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6976 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6980 tr.chrg.cpMin = sel.cpMax;
\r
6981 tr.chrg.cpMax = ++sel.cpMax;
\r
6982 tr.lpstrText = name;
\r
6983 if (SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr) < 1) break;
\r
6984 } while (isalpha(name[0]) || isdigit(name[0]) || name[0] == '-');
\r
6987 if (sel.cpMax == sel.cpMin || sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6988 MessageBeep(MB_ICONEXCLAMATION);
\r
6992 tr.lpstrText = name;
\r
6993 SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) &tr);
\r
6995 if (sel.cpMax - sel.cpMin > MSG_SIZ/2) {
\r
6996 MessageBeep(MB_ICONEXCLAMATION);
\r
6999 SendMessage(hwnd, EM_GETSELTEXT, 0, (LPARAM) name);
\r
7002 sprintf(buf, "%s %s", command, name);
\r
7003 SetWindowText(hInput, buf);
\r
7004 SendMessage(hInput, WM_CHAR, '\r', 0);
\r
7006 sprintf(buf, "%s %s ", command, name); /* trailing space */
\r
7007 SetWindowText(hInput, buf);
\r
7008 sel.cpMin = 999999;
\r
7009 sel.cpMax = 999999;
\r
7010 SendMessage(hInput, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7016 ConsoleTextSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7021 switch (message) {
\r
7023 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7026 SendMessage(hwnd, EM_LINESCROLL, 0, -999999);
\r
7029 sel.cpMin = 999999;
\r
7030 sel.cpMax = 999999;
\r
7031 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7032 SendMessage(hwnd, EM_SCROLLCARET, 0, 0);
\r
7037 if (wParam == '\t') {
\r
7038 if (GetKeyState(VK_SHIFT) < 0) {
\r
7040 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7041 if (buttonDesc[0].hwnd) {
\r
7042 SetFocus(buttonDesc[0].hwnd);
\r
7044 SetFocus(hwndMain);
\r
7048 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleInput));
\r
7051 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7053 SendMessage(hInput, message, wParam, lParam);
\r
7057 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7059 return SendMessage(hInput, message, wParam, lParam);
\r
7060 case WM_MBUTTONDOWN:
\r
7061 return SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7062 case WM_RBUTTONDOWN:
\r
7063 if (!(GetKeyState(VK_SHIFT) & ~1)) {
\r
7064 /* Move selection here if it was empty */
\r
7066 pt.x = LOWORD(lParam);
\r
7067 pt.y = HIWORD(lParam);
\r
7068 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7069 if (sel.cpMin == sel.cpMax) {
\r
7070 sel.cpMin = SendMessage(hwnd, EM_CHARFROMPOS, 0, (LPARAM)&pt); /*doc is wrong*/
\r
7071 sel.cpMax = sel.cpMin;
\r
7072 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7074 SendMessage(hwnd, EM_HIDESELECTION, FALSE, FALSE);
\r
7077 case WM_RBUTTONUP:
\r
7078 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7079 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7080 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7083 HMENU hmenu = LoadIcsTextMenu(icsTextMenuEntry);
\r
7084 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7085 if (sel.cpMin == sel.cpMax) {
\r
7086 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7087 EnableMenuItem(hmenu, IDM_QuickPaste, MF_BYCOMMAND|MF_GRAYED);
\r
7089 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7090 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7092 pt.x = LOWORD(lParam);
\r
7093 pt.y = HIWORD(lParam);
\r
7094 MenuPopup(hwnd, pt, hmenu, -1);
\r
7098 switch (LOWORD(wParam)) {
\r
7099 case IDM_QuickPaste:
\r
7101 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7102 if (sel.cpMin == sel.cpMax) {
\r
7103 MessageBeep(MB_ICONEXCLAMATION);
\r
7106 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7107 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
7108 SendMessage(hInput, WM_PASTE, 0, 0);
\r
7113 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7116 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7119 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7123 int i = LOWORD(wParam) - IDM_CommandX;
\r
7124 if (i >= 0 && i < ICS_TEXT_MENU_SIZE &&
\r
7125 icsTextMenuEntry[i].command != NULL) {
\r
7126 CommandX(hwnd, icsTextMenuEntry[i].command,
\r
7127 icsTextMenuEntry[i].getname,
\r
7128 icsTextMenuEntry[i].immediate);
\r
7136 return (*consoleTextWindowProc)(hwnd, message, wParam, lParam);
\r
7139 WNDPROC consoleInputWindowProc;
\r
7142 ConsoleInputSubclass(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7144 char buf[MSG_SIZ];
\r
7146 static BOOL sendNextChar = FALSE;
\r
7147 static BOOL quoteNextChar = FALSE;
\r
7148 InputSource *is = consoleInputSource;
\r
7152 switch (message) {
\r
7154 if (!appData.localLineEditing || sendNextChar) {
\r
7155 is->buf[0] = (CHAR) wParam;
\r
7157 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7158 sendNextChar = FALSE;
\r
7161 if (quoteNextChar) {
\r
7162 buf[0] = (char) wParam;
\r
7163 buf[1] = NULLCHAR;
\r
7164 SendMessage(hwnd, EM_REPLACESEL, TRUE, (LPARAM) buf);
\r
7165 quoteNextChar = FALSE;
\r
7169 case '\r': /* Enter key */
\r
7170 is->count = GetWindowText(hwnd, is->buf, INPUT_SOURCE_BUF_SIZE-1);
\r
7171 if (consoleEcho) SaveInHistory(is->buf);
\r
7172 is->buf[is->count++] = '\n';
\r
7173 is->buf[is->count] = NULLCHAR;
\r
7174 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7175 if (consoleEcho) {
\r
7176 ConsoleOutput(is->buf, is->count, TRUE);
\r
7177 } else if (appData.localLineEditing) {
\r
7178 ConsoleOutput("\n", 1, TRUE);
\r
7181 case '\033': /* Escape key */
\r
7182 SetWindowText(hwnd, "");
\r
7183 cf.cbSize = sizeof(CHARFORMAT);
\r
7184 cf.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
7185 if (consoleEcho) {
\r
7186 cf.crTextColor = textAttribs[ColorNormal].color;
\r
7188 cf.crTextColor = COLOR_ECHOOFF;
\r
7190 cf.dwEffects = textAttribs[ColorNormal].effects;
\r
7191 SendMessage(hwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
7193 case '\t': /* Tab key */
\r
7194 if (GetKeyState(VK_SHIFT) < 0) {
\r
7196 SetFocus(GetDlgItem(hwndConsole, OPT_ConsoleText));
\r
7199 if (IsIconic(hwndMain)) ShowWindow(hwndMain, SW_RESTORE);
\r
7200 if (buttonDesc[0].hwnd) {
\r
7201 SetFocus(buttonDesc[0].hwnd);
\r
7203 SetFocus(hwndMain);
\r
7207 case '\023': /* Ctrl+S */
\r
7208 sendNextChar = TRUE;
\r
7210 case '\021': /* Ctrl+Q */
\r
7211 quoteNextChar = TRUE;
\r
7220 GetWindowText(hwnd, buf, MSG_SIZ);
\r
7221 p = PrevInHistory(buf);
\r
7223 SetWindowText(hwnd, p);
\r
7224 sel.cpMin = 999999;
\r
7225 sel.cpMax = 999999;
\r
7226 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7231 p = NextInHistory();
\r
7233 SetWindowText(hwnd, p);
\r
7234 sel.cpMin = 999999;
\r
7235 sel.cpMax = 999999;
\r
7236 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7242 if (!(GetKeyState(VK_CONTROL) & ~1)) break;
\r
7246 SendDlgItemMessage(hwndConsole, OPT_ConsoleText, message, wParam, lParam);
\r
7250 case WM_MBUTTONDOWN:
\r
7251 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7252 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7254 case WM_RBUTTONUP:
\r
7255 if (GetKeyState(VK_SHIFT) & ~1) {
\r
7256 SendDlgItemMessage(hwndConsole, OPT_ConsoleText,
\r
7257 WM_COMMAND, MAKEWPARAM(IDM_QuickPaste, 0), 0);
\r
7261 hmenu = LoadMenu(hInst, "InputMenu");
\r
7262 SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM)&sel);
\r
7263 if (sel.cpMin == sel.cpMax) {
\r
7264 EnableMenuItem(hmenu, IDM_Copy, MF_BYCOMMAND|MF_GRAYED);
\r
7265 EnableMenuItem(hmenu, IDM_Cut, MF_BYCOMMAND|MF_GRAYED);
\r
7267 if (!IsClipboardFormatAvailable(CF_TEXT)) {
\r
7268 EnableMenuItem(hmenu, IDM_Paste, MF_BYCOMMAND|MF_GRAYED);
\r
7270 pt.x = LOWORD(lParam);
\r
7271 pt.y = HIWORD(lParam);
\r
7272 MenuPopup(hwnd, pt, hmenu, -1);
\r
7276 switch (LOWORD(wParam)) {
\r
7278 SendMessage(hwnd, EM_UNDO, 0, 0);
\r
7280 case IDM_SelectAll:
\r
7282 sel.cpMax = -1; /*999999?*/
\r
7283 SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7286 SendMessage(hwnd, WM_CUT, 0, 0);
\r
7289 SendMessage(hwnd, WM_PASTE, 0, 0);
\r
7292 SendMessage(hwnd, WM_COPY, 0, 0);
\r
7297 return (*consoleInputWindowProc)(hwnd, message, wParam, lParam);
\r
7300 #define CO_MAX 100000
\r
7301 #define CO_TRIM 1000
\r
7304 ConsoleWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
7306 static SnapData sd;
\r
7307 static HWND hText, hInput, hFocus;
\r
7308 InputSource *is = consoleInputSource;
\r
7310 static int sizeX, sizeY;
\r
7311 int newSizeX, newSizeY;
\r
7314 switch (message) {
\r
7315 case WM_INITDIALOG: /* message: initialize dialog box */
\r
7316 hwndConsole = hDlg;
\r
7317 hText = GetDlgItem(hDlg, OPT_ConsoleText);
\r
7318 hInput = GetDlgItem(hDlg, OPT_ConsoleInput);
\r
7320 consoleTextWindowProc = (WNDPROC)
\r
7321 SetWindowLong(hText, GWL_WNDPROC, (LONG) ConsoleTextSubclass);
\r
7322 SendMessage(hText, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7323 consoleInputWindowProc = (WNDPROC)
\r
7324 SetWindowLong(hInput, GWL_WNDPROC, (LONG) ConsoleInputSubclass);
\r
7325 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
7326 Colorize(ColorNormal, TRUE);
\r
7327 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &consoleCF);
\r
7328 ChangedConsoleFont();
\r
7329 GetClientRect(hDlg, &rect);
\r
7330 sizeX = rect.right;
\r
7331 sizeY = rect.bottom;
\r
7332 if (consoleX != CW_USEDEFAULT && consoleY != CW_USEDEFAULT &&
\r
7333 consoleW != CW_USEDEFAULT && consoleH != CW_USEDEFAULT) {
\r
7334 WINDOWPLACEMENT wp;
\r
7335 EnsureOnScreen(&consoleX, &consoleY);
\r
7336 wp.length = sizeof(WINDOWPLACEMENT);
\r
7338 wp.showCmd = SW_SHOW;
\r
7339 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
7340 wp.rcNormalPosition.left = consoleX;
\r
7341 wp.rcNormalPosition.right = consoleX + consoleW;
\r
7342 wp.rcNormalPosition.top = consoleY;
\r
7343 wp.rcNormalPosition.bottom = consoleY + consoleH;
\r
7344 SetWindowPlacement(hDlg, &wp);
\r
7358 if (IsIconic(hDlg)) break;
\r
7359 newSizeX = LOWORD(lParam);
\r
7360 newSizeY = HIWORD(lParam);
\r
7361 if (sizeX != newSizeX || sizeY != newSizeY) {
\r
7362 RECT rectText, rectInput;
\r
7364 int newTextHeight, newTextWidth;
\r
7365 GetWindowRect(hText, &rectText);
\r
7366 newTextWidth = rectText.right - rectText.left + newSizeX - sizeX;
\r
7367 newTextHeight = rectText.bottom - rectText.top + newSizeY - sizeY;
\r
7368 if (newTextHeight < 0) {
\r
7369 newSizeY += -newTextHeight;
\r
7370 newTextHeight = 0;
\r
7372 SetWindowPos(hText, NULL, 0, 0,
\r
7373 newTextWidth, newTextHeight, SWP_NOZORDER|SWP_NOMOVE);
\r
7374 GetWindowRect(hInput, &rectInput); /* gives screen coords */
\r
7375 pt.x = rectInput.left;
\r
7376 pt.y = rectInput.top + newSizeY - sizeY;
\r
7377 ScreenToClient(hDlg, &pt);
\r
7378 SetWindowPos(hInput, NULL,
\r
7379 pt.x, pt.y, /* needs client coords */
\r
7380 rectInput.right - rectInput.left + newSizeX - sizeX,
\r
7381 rectInput.bottom - rectInput.top, SWP_NOZORDER);
\r
7387 case WM_GETMINMAXINFO:
\r
7388 /* Prevent resizing window too small */
\r
7389 mmi = (MINMAXINFO *) lParam;
\r
7390 mmi->ptMinTrackSize.x = 100;
\r
7391 mmi->ptMinTrackSize.y = 100;
\r
7394 /* [AS] Snapping */
\r
7395 case WM_ENTERSIZEMOVE:
\r
7396 return OnEnterSizeMove( &sd, hDlg, wParam, lParam );
\r
7399 return OnSizing( &sd, hDlg, wParam, lParam );
\r
7402 return OnMoving( &sd, hDlg, wParam, lParam );
\r
7404 case WM_EXITSIZEMOVE:
\r
7405 return OnExitSizeMove( &sd, hDlg, wParam, lParam );
\r
7408 return DefWindowProc(hDlg, message, wParam, lParam);
\r
7416 if (hwndConsole) return;
\r
7417 hCons = CreateDialog(hInst, szConsoleName, 0, NULL);
\r
7418 SendMessage(hCons, WM_INITDIALOG, 0, 0);
\r
7423 ConsoleOutput(char* data, int length, int forceVisible)
\r
7428 char buf[CO_MAX+1];
\r
7431 static int delayLF = 0;
\r
7432 CHARRANGE savesel, sel;
\r
7434 if (hwndConsole == NULL || length > CO_MAX-100 || length == 0) return;
\r
7442 while (length--) {
\r
7450 } else if (*p == '\007') {
\r
7451 MyPlaySound(&sounds[(int)SoundBell]);
\r
7458 hText = GetDlgItem(hwndConsole, OPT_ConsoleText);
\r
7459 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7460 /* Save current selection */
\r
7461 SendMessage(hText, EM_EXGETSEL, 0, (LPARAM)&savesel);
\r
7462 exlen = GetWindowTextLength(hText);
\r
7463 /* Find out whether current end of text is visible */
\r
7464 SendMessage(hText, EM_GETRECT, 0, (LPARAM) &rect);
\r
7465 SendMessage(hText, EM_POSFROMCHAR, (WPARAM) &pEnd, exlen);
\r
7466 /* Trim existing text if it's too long */
\r
7467 if (exlen + (q - buf) > CO_MAX) {
\r
7468 trim = (CO_TRIM > (q - buf)) ? CO_TRIM : (q - buf);
\r
7471 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7472 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM)"");
\r
7474 savesel.cpMin -= trim;
\r
7475 savesel.cpMax -= trim;
\r
7476 if (exlen < 0) exlen = 0;
\r
7477 if (savesel.cpMin < 0) savesel.cpMin = 0;
\r
7478 if (savesel.cpMax < savesel.cpMin) savesel.cpMax = savesel.cpMin;
\r
7480 /* Append the new text */
\r
7481 sel.cpMin = exlen;
\r
7482 sel.cpMax = exlen;
\r
7483 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7484 SendMessage(hText, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&consoleCF);
\r
7485 SendMessage(hText, EM_REPLACESEL, 0, (LPARAM) buf);
\r
7486 if (forceVisible || exlen == 0 ||
\r
7487 (rect.left <= pEnd.x && pEnd.x < rect.right &&
\r
7488 rect.top <= pEnd.y && pEnd.y < rect.bottom)) {
\r
7489 /* Scroll to make new end of text visible if old end of text
\r
7490 was visible or new text is an echo of user typein */
\r
7491 sel.cpMin = 9999999;
\r
7492 sel.cpMax = 9999999;
\r
7493 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7494 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7495 SendMessage(hText, EM_SCROLLCARET, 0, 0);
\r
7496 SendMessage(hText, EM_HIDESELECTION, TRUE, FALSE);
\r
7498 if (savesel.cpMax == exlen || forceVisible) {
\r
7499 /* Move insert point to new end of text if it was at the old
\r
7500 end of text or if the new text is an echo of user typein */
\r
7501 sel.cpMin = 9999999;
\r
7502 sel.cpMax = 9999999;
\r
7503 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&sel);
\r
7505 /* Restore previous selection */
\r
7506 SendMessage(hText, EM_EXSETSEL, 0, (LPARAM)&savesel);
\r
7508 SendMessage(hText, EM_HIDESELECTION, FALSE, FALSE);
\r
7515 DisplayHoldingsCount(HDC hdc, int x, int y, int rightAlign, int copyNumber)
\r
7519 COLORREF oldFg, oldBg;
\r
7523 if(copyNumber > 1) sprintf(buf, "%d", copyNumber); else buf[0] = 0;
\r
7525 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7526 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7527 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7530 rect.right = x + squareSize;
\r
7532 rect.bottom = y + squareSize;
\r
7535 ExtTextOut(hdc, x + MESSAGE_LINE_LEFTMARGIN
\r
7536 + (rightAlign ? (squareSize*2)/3 : 0),
\r
7537 y, ETO_CLIPPED|ETO_OPAQUE,
\r
7538 &rect, str, strlen(str), NULL);
\r
7540 (void) SetTextColor(hdc, oldFg);
\r
7541 (void) SetBkColor(hdc, oldBg);
\r
7542 (void) SelectObject(hdc, oldFont);
\r
7546 DisplayAClock(HDC hdc, int timeRemaining, int highlight,
\r
7547 RECT *rect, char *color, char *flagFell)
\r
7551 COLORREF oldFg, oldBg;
\r
7554 if (appData.clockMode) {
\r
7556 sprintf(buf, "%c %s %s %s", color[0], TimeString(timeRemaining), flagFell);
\r
7558 sprintf(buf, "%s: %s %s", color, TimeString(timeRemaining), flagFell);
\r
7565 oldFg = SetTextColor(hdc, RGB(255, 255, 255)); /* white */
\r
7566 oldBg = SetBkColor(hdc, RGB(0, 0, 0)); /* black */
\r
7568 oldFg = SetTextColor(hdc, RGB(0, 0, 0)); /* black */
\r
7569 oldBg = SetBkColor(hdc, RGB(255, 255, 255)); /* white */
\r
7571 oldFont = SelectObject(hdc, font[boardSize][CLOCK_FONT]->hf);
\r
7573 ExtTextOut(hdc, rect->left + MESSAGE_LINE_LEFTMARGIN,
\r
7574 rect->top, ETO_CLIPPED|ETO_OPAQUE,
\r
7575 rect, str, strlen(str), NULL);
\r
7577 (void) SetTextColor(hdc, oldFg);
\r
7578 (void) SetBkColor(hdc, oldBg);
\r
7579 (void) SelectObject(hdc, oldFont);
\r
7584 DoReadFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7590 if( count <= 0 ) {
\r
7591 if (appData.debugMode) {
\r
7592 fprintf( debugFP, "DoReadFile: trying to read past end of buffer, overflow = %d\n", count );
\r
7595 return ERROR_INVALID_USER_BUFFER;
\r
7598 ResetEvent(ovl->hEvent);
\r
7599 ovl->Offset = ovl->OffsetHigh = 0;
\r
7600 ok = ReadFile(hFile, buf, count, outCount, ovl);
\r
7604 err = GetLastError();
\r
7605 if (err == ERROR_IO_PENDING) {
\r
7606 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7610 err = GetLastError();
\r
7617 DoWriteFile(HANDLE hFile, char *buf, int count, DWORD *outCount,
\r
7622 ResetEvent(ovl->hEvent);
\r
7623 ovl->Offset = ovl->OffsetHigh = 0;
\r
7624 ok = WriteFile(hFile, buf, count, outCount, ovl);
\r
7628 err = GetLastError();
\r
7629 if (err == ERROR_IO_PENDING) {
\r
7630 ok = GetOverlappedResult(hFile, ovl, outCount, TRUE);
\r
7634 err = GetLastError();
\r
7640 /* [AS] If input is line by line and a line exceed the buffer size, force an error */
\r
7641 void CheckForInputBufferFull( InputSource * is )
\r
7643 if( is->lineByLine && (is->next - is->buf) >= INPUT_SOURCE_BUF_SIZE ) {
\r
7644 /* Look for end of line */
\r
7645 char * p = is->buf;
\r
7647 while( p < is->next && *p != '\n' ) {
\r
7651 if( p >= is->next ) {
\r
7652 if (appData.debugMode) {
\r
7653 fprintf( debugFP, "Input line exceeded buffer size (source id=%u)\n", is->id );
\r
7656 is->error = ERROR_BROKEN_PIPE; /* [AS] Just any non-successful code! */
\r
7657 is->count = (DWORD) -1;
\r
7658 is->next = is->buf;
\r
7664 InputThread(LPVOID arg)
\r
7669 is = (InputSource *) arg;
\r
7670 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
7671 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
7672 while (is->hThread != NULL) {
\r
7673 is->error = DoReadFile(is->hFile, is->next,
\r
7674 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7675 &is->count, &ovl);
\r
7676 if (is->error == NO_ERROR) {
\r
7677 is->next += is->count;
\r
7679 if (is->error == ERROR_BROKEN_PIPE) {
\r
7680 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7683 is->count = (DWORD) -1;
\r
7684 /* [AS] The (is->count <= 0) check below is not useful for unsigned values! */
\r
7689 CheckForInputBufferFull( is );
\r
7691 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7693 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7695 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7698 CloseHandle(ovl.hEvent);
\r
7699 CloseHandle(is->hFile);
\r
7701 if (appData.debugMode) {
\r
7702 fprintf( debugFP, "Input thread terminated (id=%u, error=%d, count=%d)\n", is->id, is->error, is->count );
\r
7709 /* Windows 95 beta 2 won't let you do overlapped i/o on a console or pipe */
\r
7711 NonOvlInputThread(LPVOID arg)
\r
7718 is = (InputSource *) arg;
\r
7719 while (is->hThread != NULL) {
\r
7720 is->error = ReadFile(is->hFile, is->next,
\r
7721 INPUT_SOURCE_BUF_SIZE - (is->next - is->buf),
\r
7722 &is->count, NULL) ? NO_ERROR : GetLastError();
\r
7723 if (is->error == NO_ERROR) {
\r
7724 /* Change CRLF to LF */
\r
7725 if (is->next > is->buf) {
\r
7727 i = is->count + 1;
\r
7735 if (prev == '\r' && *p == '\n') {
\r
7747 if (is->error == ERROR_BROKEN_PIPE) {
\r
7748 /* Correct for MS brain damage. EOF reading a pipe is not an error. */
\r
7751 is->count = (DWORD) -1;
\r
7755 CheckForInputBufferFull( is );
\r
7757 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7759 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7761 if (is->count < 0) break; /* Quit on error */
\r
7763 CloseHandle(is->hFile);
\r
7768 SocketInputThread(LPVOID arg)
\r
7772 is = (InputSource *) arg;
\r
7773 while (is->hThread != NULL) {
\r
7774 is->count = recv(is->sock, is->buf, INPUT_SOURCE_BUF_SIZE, 0);
\r
7775 if ((int)is->count == SOCKET_ERROR) {
\r
7776 is->count = (DWORD) -1;
\r
7777 is->error = WSAGetLastError();
\r
7779 is->error = NO_ERROR;
\r
7780 is->next += is->count;
\r
7781 if (is->count == 0 && is->second == is) {
\r
7782 /* End of file on stderr; quit with no message */
\r
7786 SendMessage(hwndMain, WM_USER_Input, 0, (LPARAM) is);
\r
7788 if( is->count == ((DWORD) -1) ) break; /* [AS] */
\r
7790 if (is->count <= 0) break; /* Quit on EOF or error */
\r
7796 InputEvent(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
7800 is = (InputSource *) lParam;
\r
7801 if (is->lineByLine) {
\r
7802 /* Feed in lines one by one */
\r
7803 char *p = is->buf;
\r
7805 while (q < is->next) {
\r
7806 if (*q++ == '\n') {
\r
7807 (is->func)(is, is->closure, p, q - p, NO_ERROR);
\r
7812 /* Move any partial line to the start of the buffer */
\r
7814 while (p < is->next) {
\r
7819 if (is->error != NO_ERROR || is->count == 0) {
\r
7820 /* Notify backend of the error. Note: If there was a partial
\r
7821 line at the end, it is not flushed through. */
\r
7822 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7825 /* Feed in the whole chunk of input at once */
\r
7826 (is->func)(is, is->closure, is->buf, is->count, is->error);
\r
7827 is->next = is->buf;
\r
7831 /*---------------------------------------------------------------------------*\
\r
7833 * Menu enables. Used when setting various modes.
\r
7835 \*---------------------------------------------------------------------------*/
\r
7843 SetMenuEnables(HMENU hmenu, Enables *enab)
\r
7845 while (enab->item > 0) {
\r
7846 (void) EnableMenuItem(hmenu, enab->item, enab->flags);
\r
7851 Enables gnuEnables[] = {
\r
7852 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7853 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7854 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7855 { IDM_Accept, MF_BYCOMMAND|MF_GRAYED },
\r
7856 { IDM_Decline, MF_BYCOMMAND|MF_GRAYED },
\r
7857 { IDM_Rematch, MF_BYCOMMAND|MF_GRAYED },
\r
7858 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7859 { IDM_StopExamining, MF_BYCOMMAND|MF_GRAYED },
\r
7860 { IDM_StopObserving, MF_BYCOMMAND|MF_GRAYED },
\r
7861 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7865 Enables icsEnables[] = {
\r
7866 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7867 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7868 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7869 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7870 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7871 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7872 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7873 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7874 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7875 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7876 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7877 { IDM_IcsOptions, MF_BYCOMMAND|MF_ENABLED },
\r
7882 Enables zippyEnables[] = {
\r
7883 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7884 { IDM_Hint, MF_BYCOMMAND|MF_ENABLED },
\r
7885 { IDM_Book, MF_BYCOMMAND|MF_ENABLED },
\r
7890 Enables ncpEnables[] = {
\r
7891 { IDM_MailMove, MF_BYCOMMAND|MF_GRAYED },
\r
7892 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_GRAYED },
\r
7893 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7894 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7895 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7896 { IDM_AnalysisMode, MF_BYCOMMAND|MF_GRAYED },
\r
7897 { IDM_AnalyzeFile, MF_BYCOMMAND|MF_GRAYED },
\r
7898 { IDM_IcsClient, MF_BYCOMMAND|MF_GRAYED },
\r
7899 { ACTION_POS, MF_BYPOSITION|MF_GRAYED },
\r
7900 { IDM_Revert, MF_BYCOMMAND|MF_GRAYED },
\r
7901 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7902 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7903 { IDM_TimeControl, MF_BYCOMMAND|MF_GRAYED },
\r
7904 { IDM_Hint, MF_BYCOMMAND|MF_GRAYED },
\r
7905 { IDM_Book, MF_BYCOMMAND|MF_GRAYED },
\r
7909 Enables trainingOnEnables[] = {
\r
7910 { IDM_EditComment, MF_BYCOMMAND|MF_GRAYED },
\r
7911 { IDM_Pause, MF_BYCOMMAND|MF_GRAYED },
\r
7912 { IDM_Forward, MF_BYCOMMAND|MF_GRAYED },
\r
7913 { IDM_Backward, MF_BYCOMMAND|MF_GRAYED },
\r
7914 { IDM_ToEnd, MF_BYCOMMAND|MF_GRAYED },
\r
7915 { IDM_ToStart, MF_BYCOMMAND|MF_GRAYED },
\r
7916 { IDM_MoveNow, MF_BYCOMMAND|MF_GRAYED },
\r
7917 { IDM_TruncateGame, MF_BYCOMMAND|MF_GRAYED },
\r
7921 Enables trainingOffEnables[] = {
\r
7922 { IDM_EditComment, MF_BYCOMMAND|MF_ENABLED },
\r
7923 { IDM_Pause, MF_BYCOMMAND|MF_ENABLED },
\r
7924 { IDM_Forward, MF_BYCOMMAND|MF_ENABLED },
\r
7925 { IDM_Backward, MF_BYCOMMAND|MF_ENABLED },
\r
7926 { IDM_ToEnd, MF_BYCOMMAND|MF_ENABLED },
\r
7927 { IDM_ToStart, MF_BYCOMMAND|MF_ENABLED },
\r
7928 { IDM_MoveNow, MF_BYCOMMAND|MF_ENABLED },
\r
7929 { IDM_TruncateGame, MF_BYCOMMAND|MF_ENABLED },
\r
7933 /* These modify either ncpEnables or gnuEnables */
\r
7934 Enables cmailEnables[] = {
\r
7935 { IDM_MailMove, MF_BYCOMMAND|MF_ENABLED },
\r
7936 { IDM_ReloadCMailMsg, MF_BYCOMMAND|MF_ENABLED },
\r
7937 { ACTION_POS, MF_BYPOSITION|MF_ENABLED },
\r
7938 { IDM_CallFlag, MF_BYCOMMAND|MF_GRAYED },
\r
7939 { IDM_Draw, MF_BYCOMMAND|MF_ENABLED },
\r
7940 { IDM_Adjourn, MF_BYCOMMAND|MF_GRAYED },
\r
7941 { IDM_Abort, MF_BYCOMMAND|MF_GRAYED },
\r
7945 Enables machineThinkingEnables[] = {
\r
7946 { IDM_LoadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7947 { IDM_LoadNextGame, MF_BYCOMMAND|MF_GRAYED },
\r
7948 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_GRAYED },
\r
7949 { IDM_ReloadGame, MF_BYCOMMAND|MF_GRAYED },
\r
7950 { IDM_PasteGame, MF_BYCOMMAND|MF_GRAYED },
\r
7951 { IDM_LoadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7952 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7953 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7954 { IDM_ReloadPosition, MF_BYCOMMAND|MF_GRAYED },
\r
7955 { IDM_PastePosition, MF_BYCOMMAND|MF_GRAYED },
\r
7956 { IDM_MachineWhite, MF_BYCOMMAND|MF_GRAYED },
\r
7957 { IDM_MachineBlack, MF_BYCOMMAND|MF_GRAYED },
\r
7958 { IDM_TwoMachines, MF_BYCOMMAND|MF_GRAYED },
\r
7959 { IDM_TypeInMove, MF_BYCOMMAND|MF_GRAYED },
\r
7960 { IDM_RetractMove, MF_BYCOMMAND|MF_GRAYED },
\r
7964 Enables userThinkingEnables[] = {
\r
7965 { IDM_LoadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7966 { IDM_LoadNextGame, MF_BYCOMMAND|MF_ENABLED },
\r
7967 { IDM_LoadPrevGame, MF_BYCOMMAND|MF_ENABLED },
\r
7968 { IDM_ReloadGame, MF_BYCOMMAND|MF_ENABLED },
\r
7969 { IDM_PasteGame, MF_BYCOMMAND|MF_ENABLED },
\r
7970 { IDM_LoadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7971 { IDM_LoadNextPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7972 { IDM_LoadPrevPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7973 { IDM_ReloadPosition, MF_BYCOMMAND|MF_ENABLED },
\r
7974 { IDM_PastePosition, MF_BYCOMMAND|MF_ENABLED },
\r
7975 { IDM_MachineWhite, MF_BYCOMMAND|MF_ENABLED },
\r
7976 { IDM_MachineBlack, MF_BYCOMMAND|MF_ENABLED },
\r
7977 { IDM_TwoMachines, MF_BYCOMMAND|MF_ENABLED },
\r
7978 { IDM_TypeInMove, MF_BYCOMMAND|MF_ENABLED },
\r
7979 { IDM_RetractMove, MF_BYCOMMAND|MF_ENABLED },
\r
7983 /*---------------------------------------------------------------------------*\
\r
7985 * Front-end interface functions exported by XBoard.
\r
7986 * Functions appear in same order as prototypes in frontend.h.
\r
7988 \*---------------------------------------------------------------------------*/
\r
7992 static UINT prevChecked = 0;
\r
7993 static int prevPausing = 0;
\r
7996 if (pausing != prevPausing) {
\r
7997 prevPausing = pausing;
\r
7998 (void) CheckMenuItem(GetMenu(hwndMain), IDM_Pause,
\r
7999 MF_BYCOMMAND|(pausing ? MF_CHECKED : MF_UNCHECKED));
\r
8000 if (hwndPause) SetWindowText(hwndPause, pausing ? "C" : "P");
\r
8003 switch (gameMode) {
\r
8004 case BeginningOfGame:
\r
8005 if (appData.icsActive)
\r
8006 nowChecked = IDM_IcsClient;
\r
8007 else if (appData.noChessProgram)
\r
8008 nowChecked = IDM_EditGame;
\r
8010 nowChecked = IDM_MachineBlack;
\r
8012 case MachinePlaysBlack:
\r
8013 nowChecked = IDM_MachineBlack;
\r
8015 case MachinePlaysWhite:
\r
8016 nowChecked = IDM_MachineWhite;
\r
8018 case TwoMachinesPlay:
\r
8019 nowChecked = IDM_TwoMachines;
\r
8022 nowChecked = IDM_AnalysisMode;
\r
8025 nowChecked = IDM_AnalyzeFile;
\r
8028 nowChecked = IDM_EditGame;
\r
8030 case PlayFromGameFile:
\r
8031 nowChecked = IDM_LoadGame;
\r
8033 case EditPosition:
\r
8034 nowChecked = IDM_EditPosition;
\r
8037 nowChecked = IDM_Training;
\r
8039 case IcsPlayingWhite:
\r
8040 case IcsPlayingBlack:
\r
8041 case IcsObserving:
\r
8043 nowChecked = IDM_IcsClient;
\r
8050 if (prevChecked != 0)
\r
8051 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8052 prevChecked, MF_BYCOMMAND|MF_UNCHECKED);
\r
8053 if (nowChecked != 0)
\r
8054 (void) CheckMenuItem(GetMenu(hwndMain),
\r
8055 nowChecked, MF_BYCOMMAND|MF_CHECKED);
\r
8057 if (nowChecked == IDM_LoadGame || nowChecked == IDM_Training) {
\r
8058 (void) EnableMenuItem(GetMenu(hwndMain), IDM_Training,
\r
8059 MF_BYCOMMAND|MF_ENABLED);
\r
8061 (void) EnableMenuItem(GetMenu(hwndMain),
\r
8062 IDM_Training, MF_BYCOMMAND|MF_GRAYED);
\r
8065 prevChecked = nowChecked;
\r
8071 HMENU hmenu = GetMenu(hwndMain);
\r
8072 SetMenuEnables(hmenu, icsEnables);
\r
8073 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), ICS_POS,
\r
8074 MF_BYPOSITION|MF_ENABLED);
\r
8076 if (appData.zippyPlay) {
\r
8077 SetMenuEnables(hmenu, zippyEnables);
\r
8085 SetMenuEnables(GetMenu(hwndMain), gnuEnables);
\r
8091 HMENU hmenu = GetMenu(hwndMain);
\r
8092 SetMenuEnables(hmenu, ncpEnables);
\r
8093 EnableMenuItem(GetSubMenu(hmenu, OPTIONS_POS), SOUNDS_POS,
\r
8094 MF_BYPOSITION|MF_GRAYED);
\r
8095 DrawMenuBar(hwndMain);
\r
8101 SetMenuEnables(GetMenu(hwndMain), cmailEnables);
\r
8105 SetTrainingModeOn()
\r
8108 SetMenuEnables(GetMenu(hwndMain), trainingOnEnables);
\r
8109 for (i = 0; i < N_BUTTONS; i++) {
\r
8110 if (buttonDesc[i].hwnd != NULL)
\r
8111 EnableWindow(buttonDesc[i].hwnd, FALSE);
\r
8116 VOID SetTrainingModeOff()
\r
8119 SetMenuEnables(GetMenu(hwndMain), trainingOffEnables);
\r
8120 for (i = 0; i < N_BUTTONS; i++) {
\r
8121 if (buttonDesc[i].hwnd != NULL)
\r
8122 EnableWindow(buttonDesc[i].hwnd, TRUE);
\r
8128 SetUserThinkingEnables()
\r
8130 SetMenuEnables(GetMenu(hwndMain), userThinkingEnables);
\r
8134 SetMachineThinkingEnables()
\r
8136 HMENU hMenu = GetMenu(hwndMain);
\r
8137 int flags = MF_BYCOMMAND|MF_ENABLED;
\r
8139 SetMenuEnables(hMenu, machineThinkingEnables);
\r
8141 if (gameMode == MachinePlaysBlack) {
\r
8142 (void)EnableMenuItem(hMenu, IDM_MachineBlack, flags);
\r
8143 } else if (gameMode == MachinePlaysWhite) {
\r
8144 (void)EnableMenuItem(hMenu, IDM_MachineWhite, flags);
\r
8145 } else if (gameMode == TwoMachinesPlay) {
\r
8146 (void)EnableMenuItem(hMenu, IDM_TwoMachines, flags);
\r
8152 DisplayTitle(char *str)
\r
8154 char title[MSG_SIZ], *host;
\r
8155 if (str[0] != NULLCHAR) {
\r
8156 strcpy(title, str);
\r
8157 } else if (appData.icsActive) {
\r
8158 if (appData.icsCommPort[0] != NULLCHAR)
\r
8161 host = appData.icsHost;
\r
8162 sprintf(title, "%s: %s", szTitle, host);
\r
8163 } else if (appData.noChessProgram) {
\r
8164 strcpy(title, szTitle);
\r
8166 strcpy(title, szTitle);
\r
8167 strcat(title, ": ");
\r
8168 strcat(title, first.tidy);
\r
8170 SetWindowText(hwndMain, title);
\r
8175 DisplayMessage(char *str1, char *str2)
\r
8179 int remain = MESSAGE_TEXT_MAX - 1;
\r
8182 moveErrorMessageUp = FALSE; /* turned on later by caller if needed */
\r
8183 messageText[0] = NULLCHAR;
\r
8185 len = strlen(str1);
\r
8186 if (len > remain) len = remain;
\r
8187 strncpy(messageText, str1, len);
\r
8188 messageText[len] = NULLCHAR;
\r
8191 if (*str2 && remain >= 2) {
\r
8193 strcat(messageText, " ");
\r
8196 len = strlen(str2);
\r
8197 if (len > remain) len = remain;
\r
8198 strncat(messageText, str2, len);
\r
8200 messageText[MESSAGE_TEXT_MAX - 1] = NULLCHAR;
\r
8202 if (IsIconic(hwndMain)) return;
\r
8203 hdc = GetDC(hwndMain);
\r
8204 oldFont = SelectObject(hdc, font[boardSize][MESSAGE_FONT]->hf);
\r
8205 ExtTextOut(hdc, messageRect.left, messageRect.top, ETO_CLIPPED|ETO_OPAQUE,
\r
8206 &messageRect, messageText, strlen(messageText), NULL);
\r
8207 (void) SelectObject(hdc, oldFont);
\r
8208 (void) ReleaseDC(hwndMain, hdc);
\r
8212 DisplayError(char *str, int error)
\r
8214 char buf[MSG_SIZ*2], buf2[MSG_SIZ];
\r
8220 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8221 NULL, error, LANG_NEUTRAL,
\r
8222 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8224 sprintf(buf, "%s:\n%s", str, buf2);
\r
8226 ErrorMap *em = errmap;
\r
8227 while (em->err != 0 && em->err != error) em++;
\r
8228 if (em->err != 0) {
\r
8229 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8231 sprintf(buf, "%s:\nError code %d", str, error);
\r
8236 ErrorPopUp("Error", buf);
\r
8241 DisplayMoveError(char *str)
\r
8243 fromX = fromY = -1;
\r
8244 ClearHighlights();
\r
8245 DrawPosition(FALSE, NULL);
\r
8246 if (appData.popupMoveErrors) {
\r
8247 ErrorPopUp("Error", str);
\r
8249 DisplayMessage(str, "");
\r
8250 moveErrorMessageUp = TRUE;
\r
8255 DisplayFatalError(char *str, int error, int exitStatus)
\r
8257 char buf[2*MSG_SIZ], buf2[MSG_SIZ];
\r
8259 char *label = exitStatus ? "Fatal Error" : "Exiting";
\r
8262 len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
\r
8263 NULL, error, LANG_NEUTRAL,
\r
8264 (LPSTR) buf2, MSG_SIZ, NULL);
\r
8266 sprintf(buf, "%s:\n%s", str, buf2);
\r
8268 ErrorMap *em = errmap;
\r
8269 while (em->err != 0 && em->err != error) em++;
\r
8270 if (em->err != 0) {
\r
8271 sprintf(buf, "%s:\n%s", str, em->msg);
\r
8273 sprintf(buf, "%s:\nError code %d", str, error);
\r
8278 if (appData.debugMode) {
\r
8279 fprintf(debugFP, "%s: %s\n", label, str);
\r
8281 if (appData.popupExitMessage) {
\r
8282 (void) MessageBox(hwndMain, str, label, MB_OK|
\r
8283 (exitStatus ? MB_ICONSTOP : MB_ICONINFORMATION));
\r
8285 ExitEvent(exitStatus);
\r
8290 DisplayInformation(char *str)
\r
8292 (void) MessageBox(hwndMain, str, "Information", MB_OK|MB_ICONINFORMATION);
\r
8297 DisplayNote(char *str)
\r
8299 ErrorPopUp("Note", str);
\r
8304 char *title, *question, *replyPrefix;
\r
8309 QuestionDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8311 static QuestionParams *qp;
\r
8312 char reply[MSG_SIZ];
\r
8315 switch (message) {
\r
8316 case WM_INITDIALOG:
\r
8317 qp = (QuestionParams *) lParam;
\r
8318 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8319 SetWindowText(hDlg, qp->title);
\r
8320 SetDlgItemText(hDlg, OPT_QuestionText, qp->question);
\r
8321 SetFocus(GetDlgItem(hDlg, OPT_QuestionInput));
\r
8325 switch (LOWORD(wParam)) {
\r
8327 strcpy(reply, qp->replyPrefix);
\r
8328 if (*reply) strcat(reply, " ");
\r
8329 len = strlen(reply);
\r
8330 GetDlgItemText(hDlg, OPT_QuestionInput, reply + len, sizeof(reply) - len);
\r
8331 strcat(reply, "\n");
\r
8332 OutputToProcess(qp->pr, reply, strlen(reply), &err);
\r
8333 EndDialog(hDlg, TRUE);
\r
8334 if (err) DisplayFatalError("Error writing to chess program", err, 1);
\r
8337 EndDialog(hDlg, FALSE);
\r
8348 AskQuestion(char* title, char *question, char *replyPrefix, ProcRef pr)
\r
8350 QuestionParams qp;
\r
8354 qp.question = question;
\r
8355 qp.replyPrefix = replyPrefix;
\r
8357 lpProc = MakeProcInstance((FARPROC)QuestionDialog, hInst);
\r
8358 DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_Question),
\r
8359 hwndMain, (DLGPROC)lpProc, (LPARAM)&qp);
\r
8360 FreeProcInstance(lpProc);
\r
8363 /* [AS] Pick FRC position */
\r
8364 LRESULT CALLBACK NewGameFRC_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8366 static int * lpIndexFRC;
\r
8372 case WM_INITDIALOG:
\r
8373 lpIndexFRC = (int *) lParam;
\r
8375 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8377 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETLIMITTEXT, sizeof(buf)-1, 0 );
\r
8378 SetDlgItemInt( hDlg, IDC_NFG_Edit, *lpIndexFRC, TRUE );
\r
8379 SendDlgItemMessage( hDlg, IDC_NFG_Edit, EM_SETSEL, 0, -1 );
\r
8380 SetFocus(GetDlgItem(hDlg, IDC_NFG_Edit));
\r
8385 switch( LOWORD(wParam) ) {
\r
8387 *lpIndexFRC = GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8388 EndDialog( hDlg, 0 );
\r
8391 EndDialog( hDlg, 1 );
\r
8393 case IDC_NFG_Edit:
\r
8394 if( HIWORD(wParam) == EN_CHANGE ) {
\r
8395 GetDlgItemInt(hDlg, IDC_NFG_Edit, &index_is_ok, TRUE );
\r
8397 EnableWindow( GetDlgItem(hDlg, IDOK), index_is_ok );
\r
8400 case IDC_NFG_Random:
\r
8401 sprintf( buf, "%d", myrandom() % 960 );
\r
8402 SetDlgItemText(hDlg, IDC_NFG_Edit, buf );
\r
8415 int index = appData.defaultFrcPosition;
\r
8416 FARPROC lpProc = MakeProcInstance( (FARPROC) NewGameFRC_Proc, hInst );
\r
8418 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_NewGameFRC), hwndMain, (DLGPROC)lpProc, (LPARAM)&index );
\r
8420 if( result == 0 ) {
\r
8421 appData.defaultFrcPosition = index;
\r
8427 /* [AS] Game list options */
\r
8433 static GLT_Item GLT_ItemInfo[] = {
\r
8434 { GLT_EVENT, "Event" },
\r
8435 { GLT_SITE, "Site" },
\r
8436 { GLT_DATE, "Date" },
\r
8437 { GLT_ROUND, "Round" },
\r
8438 { GLT_PLAYERS, "Players" },
\r
8439 { GLT_RESULT, "Result" },
\r
8440 { GLT_WHITE_ELO, "White Rating" },
\r
8441 { GLT_BLACK_ELO, "Black Rating" },
\r
8442 { GLT_TIME_CONTROL,"Time Control" },
\r
8443 { GLT_VARIANT, "Variant" },
\r
8444 { GLT_OUT_OF_BOOK,PGN_OUT_OF_BOOK },
\r
8448 const char * GLT_FindItem( char id )
\r
8450 const char * result = 0;
\r
8452 GLT_Item * list = GLT_ItemInfo;
\r
8454 while( list->id != 0 ) {
\r
8455 if( list->id == id ) {
\r
8456 result = list->name;
\r
8466 void GLT_AddToList( HWND hDlg, int iDlgItem, char id, int index )
\r
8468 const char * name = GLT_FindItem( id );
\r
8471 if( index >= 0 ) {
\r
8472 SendDlgItemMessage( hDlg, iDlgItem, LB_INSERTSTRING, index, (LPARAM) name );
\r
8475 SendDlgItemMessage( hDlg, iDlgItem, LB_ADDSTRING, 0, (LPARAM) name );
\r
8480 void GLT_TagsToList( HWND hDlg, char * tags )
\r
8484 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_RESETCONTENT, 0, 0 );
\r
8487 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8491 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_ADDSTRING, 0, (LPARAM) "\t --- Hidden tags ---" );
\r
8493 pc = GLT_ALL_TAGS;
\r
8496 if( strchr( tags, *pc ) == 0 ) {
\r
8497 GLT_AddToList( hDlg, IDC_GameListTags, *pc, -1 );
\r
8502 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, 0, 0 );
\r
8505 char GLT_ListItemToTag( HWND hDlg, int index )
\r
8507 char result = '\0';
\r
8510 GLT_Item * list = GLT_ItemInfo;
\r
8512 if( SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, index, (LPARAM) name ) != LB_ERR ) {
\r
8513 while( list->id != 0 ) {
\r
8514 if( strcmp( list->name, name ) == 0 ) {
\r
8515 result = list->id;
\r
8526 void GLT_MoveSelection( HWND hDlg, int delta )
\r
8528 int idx1 = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCURSEL, 0, 0 );
\r
8529 int idx2 = idx1 + delta;
\r
8530 int count = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8532 if( idx1 >=0 && idx1 < count && idx2 >= 0 && idx2 < count ) {
\r
8535 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETTEXT, idx1, (LPARAM) buf );
\r
8536 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_DELETESTRING, idx1, 0 );
\r
8537 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_INSERTSTRING, idx2, (LPARAM) buf );
\r
8538 SendDlgItemMessage( hDlg, IDC_GameListTags, LB_SETCURSEL, idx2, 0 );
\r
8542 LRESULT CALLBACK GameListOptions_Proc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
8544 static char glt[64];
\r
8545 static char * lpUserGLT;
\r
8549 case WM_INITDIALOG:
\r
8550 lpUserGLT = (char *) lParam;
\r
8552 strcpy( glt, lpUserGLT );
\r
8554 CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
\r
8556 /* Initialize list */
\r
8557 GLT_TagsToList( hDlg, glt );
\r
8559 SetFocus( GetDlgItem(hDlg, IDC_GameListTags) );
\r
8564 switch( LOWORD(wParam) ) {
\r
8567 char * pc = lpUserGLT;
\r
8569 int cnt = (int) SendDlgItemMessage( hDlg, IDC_GameListTags, LB_GETCOUNT, 0, 0 );
\r
8573 id = GLT_ListItemToTag( hDlg, idx );
\r
8577 } while( id != '\0' );
\r
8579 EndDialog( hDlg, 0 );
\r
8582 EndDialog( hDlg, 1 );
\r
8585 case IDC_GLT_Default:
\r
8586 strcpy( glt, GLT_DEFAULT_TAGS );
\r
8587 GLT_TagsToList( hDlg, glt );
\r
8590 case IDC_GLT_Restore:
\r
8591 strcpy( glt, lpUserGLT );
\r
8592 GLT_TagsToList( hDlg, glt );
\r
8596 GLT_MoveSelection( hDlg, -1 );
\r
8599 case IDC_GLT_Down:
\r
8600 GLT_MoveSelection( hDlg, +1 );
\r
8610 int GameListOptions()
\r
8614 FARPROC lpProc = MakeProcInstance( (FARPROC) GameListOptions_Proc, hInst );
\r
8616 strcpy( glt, appData.gameListTags );
\r
8618 result = DialogBoxParam( hInst, MAKEINTRESOURCE(DLG_GameListOptions), hwndMain, (DLGPROC)lpProc, (LPARAM)glt );
\r
8620 if( result == 0 ) {
\r
8621 /* [AS] Memory leak here! */
\r
8622 appData.gameListTags = strdup( glt );
\r
8630 DisplayIcsInteractionTitle(char *str)
\r
8632 char consoleTitle[MSG_SIZ];
\r
8634 sprintf(consoleTitle, "%s: %s", szConsoleTitle, str);
\r
8635 SetWindowText(hwndConsole, consoleTitle);
\r
8639 DrawPosition(int fullRedraw, Board board)
\r
8641 HDCDrawPosition(NULL, (BOOLEAN) fullRedraw, board);
\r
8648 fromX = fromY = -1;
\r
8649 if (dragInfo.pos.x != -1 || dragInfo.pos.y != -1) {
\r
8650 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8651 dragInfo.pos.x = dragInfo.pos.y = -1;
\r
8652 dragInfo.lastpos = dragInfo.pos;
\r
8653 dragInfo.start.x = dragInfo.start.y = -1;
\r
8654 dragInfo.from = dragInfo.start;
\r
8656 DrawPosition(TRUE, NULL);
\r
8662 CommentPopUp(char *title, char *str)
\r
8664 HWND hwnd = GetActiveWindow();
\r
8665 EitherCommentPopUp(0, title, str, FALSE);
\r
8666 SetActiveWindow(hwnd);
\r
8670 CommentPopDown(void)
\r
8672 CheckMenuItem(GetMenu(hwndMain), IDM_EditComment, MF_UNCHECKED);
\r
8673 if (commentDialog) {
\r
8674 ShowWindow(commentDialog, SW_HIDE);
\r
8676 commentDialogUp = FALSE;
\r
8680 EditCommentPopUp(int index, char *title, char *str)
\r
8682 EitherCommentPopUp(index, title, str, TRUE);
\r
8689 MyPlaySound(&sounds[(int)SoundMove]);
\r
8692 VOID PlayIcsWinSound()
\r
8694 MyPlaySound(&sounds[(int)SoundIcsWin]);
\r
8697 VOID PlayIcsLossSound()
\r
8699 MyPlaySound(&sounds[(int)SoundIcsLoss]);
\r
8702 VOID PlayIcsDrawSound()
\r
8704 MyPlaySound(&sounds[(int)SoundIcsDraw]);
\r
8707 VOID PlayIcsUnfinishedSound()
\r
8709 MyPlaySound(&sounds[(int)SoundIcsUnfinished]);
\r
8715 MyPlaySound(&sounds[(int)SoundAlarm]);
\r
8723 consoleEcho = TRUE;
\r
8724 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8725 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&consoleCF);
\r
8726 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, consoleBackgroundColor);
\r
8735 consoleEcho = FALSE;
\r
8736 hInput = GetDlgItem(hwndConsole, OPT_ConsoleInput);
\r
8737 /* This works OK: set text and background both to the same color */
\r
8739 cf.crTextColor = COLOR_ECHOOFF;
\r
8740 SendMessage(hInput, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf);
\r
8741 SendMessage(hInput, EM_SETBKGNDCOLOR, FALSE, cf.crTextColor);
\r
8744 /* No Raw()...? */
\r
8746 void Colorize(ColorClass cc, int continuation)
\r
8748 currentColorClass = cc;
\r
8749 consoleCF.dwMask = CFM_COLOR|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT;
\r
8750 consoleCF.crTextColor = textAttribs[cc].color;
\r
8751 consoleCF.dwEffects = textAttribs[cc].effects;
\r
8752 if (!continuation) MyPlaySound(&textAttribs[cc].sound);
\r
8758 static char buf[MSG_SIZ];
\r
8759 DWORD bufsiz = MSG_SIZ;
\r
8761 if (!GetUserName(buf, &bufsiz)) {
\r
8762 /*DisplayError("Error getting user name", GetLastError());*/
\r
8763 strcpy(buf, "User");
\r
8771 static char buf[MSG_SIZ];
\r
8772 DWORD bufsiz = MSG_SIZ;
\r
8774 if (!GetComputerName(buf, &bufsiz)) {
\r
8775 /*DisplayError("Error getting host name", GetLastError());*/
\r
8776 strcpy(buf, "Unknown");
\r
8783 ClockTimerRunning()
\r
8785 return clockTimerEvent != 0;
\r
8791 if (clockTimerEvent == 0) return FALSE;
\r
8792 KillTimer(hwndMain, clockTimerEvent);
\r
8793 clockTimerEvent = 0;
\r
8798 StartClockTimer(long millisec)
\r
8800 clockTimerEvent = SetTimer(hwndMain, (UINT) CLOCK_TIMER_ID,
\r
8801 (UINT) millisec, NULL);
\r
8805 DisplayWhiteClock(long timeRemaining, int highlight)
\r
8808 hdc = GetDC(hwndMain);
\r
8809 char *flag = whiteFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8811 if (!IsIconic(hwndMain)) {
\r
8812 DisplayAClock(hdc, timeRemaining, highlight, flipClock ? &blackRect : &whiteRect, "White", flag);
\r
8814 if (highlight && iconCurrent == iconBlack) {
\r
8815 iconCurrent = iconWhite;
\r
8816 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8817 if (IsIconic(hwndMain)) {
\r
8818 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8821 (void) ReleaseDC(hwndMain, hdc);
\r
8823 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8827 DisplayBlackClock(long timeRemaining, int highlight)
\r
8830 char *flag = blackFlag && gameMode == TwoMachinesPlay ? "(!)" : "";
\r
8832 hdc = GetDC(hwndMain);
\r
8833 if (!IsIconic(hwndMain)) {
\r
8834 DisplayAClock(hdc, timeRemaining, highlight, flipClock ? &whiteRect : &blackRect, "Black", flag);
\r
8836 if (highlight && iconCurrent == iconWhite) {
\r
8837 iconCurrent = iconBlack;
\r
8838 PostMessage(hwndMain, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8839 if (IsIconic(hwndMain)) {
\r
8840 DrawIcon(hdc, 2, 2, iconCurrent);
\r
8843 (void) ReleaseDC(hwndMain, hdc);
\r
8845 PostMessage(hwndConsole, WM_SETICON, (WPARAM) TRUE, (LPARAM) iconCurrent);
\r
8850 LoadGameTimerRunning()
\r
8852 return loadGameTimerEvent != 0;
\r
8856 StopLoadGameTimer()
\r
8858 if (loadGameTimerEvent == 0) return FALSE;
\r
8859 KillTimer(hwndMain, loadGameTimerEvent);
\r
8860 loadGameTimerEvent = 0;
\r
8865 StartLoadGameTimer(long millisec)
\r
8867 loadGameTimerEvent = SetTimer(hwndMain, (UINT) LOAD_GAME_TIMER_ID,
\r
8868 (UINT) millisec, NULL);
\r
8876 char fileTitle[MSG_SIZ];
\r
8878 defName = DefaultFileName(appData.oldSaveStyle ? "gam" : "pgn");
\r
8879 f = OpenFileDialog(hwndMain, TRUE, defName,
\r
8880 appData.oldSaveStyle ? "gam" : "pgn",
\r
8882 "Save Game to File", NULL, fileTitle, NULL);
\r
8884 SaveGame(f, 0, "");
\r
8891 ScheduleDelayedEvent(DelayedEventCallback cb, long millisec)
\r
8893 if (delayedTimerEvent != 0) {
\r
8894 if (appData.debugMode) {
\r
8895 fprintf(debugFP, "ScheduleDelayedEvent: event already scheduled\n");
\r
8897 KillTimer(hwndMain, delayedTimerEvent);
\r
8898 delayedTimerEvent = 0;
\r
8899 delayedTimerCallback();
\r
8901 delayedTimerCallback = cb;
\r
8902 delayedTimerEvent = SetTimer(hwndMain, (UINT) DELAYED_TIMER_ID,
\r
8903 (UINT) millisec, NULL);
\r
8906 DelayedEventCallback
\r
8909 if (delayedTimerEvent) {
\r
8910 return delayedTimerCallback;
\r
8917 CancelDelayedEvent()
\r
8919 if (delayedTimerEvent) {
\r
8920 KillTimer(hwndMain, delayedTimerEvent);
\r
8921 delayedTimerEvent = 0;
\r
8925 /* Start a child process running the given program.
\r
8926 The process's standard output can be read from "from", and its
\r
8927 standard input can be written to "to".
\r
8928 Exit with fatal error if anything goes wrong.
\r
8929 Returns an opaque pointer that can be used to destroy the process
\r
8933 StartChildProcess(char *cmdLine, char *dir, ProcRef *pr)
\r
8935 #define BUFSIZE 4096
\r
8937 HANDLE hChildStdinRd, hChildStdinWr,
\r
8938 hChildStdoutRd, hChildStdoutWr;
\r
8939 HANDLE hChildStdinWrDup, hChildStdoutRdDup;
\r
8940 SECURITY_ATTRIBUTES saAttr;
\r
8942 PROCESS_INFORMATION piProcInfo;
\r
8943 STARTUPINFO siStartInfo;
\r
8945 char buf[MSG_SIZ];
\r
8948 if (appData.debugMode) {
\r
8949 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n", dir, cmdLine);
\r
8954 /* Set the bInheritHandle flag so pipe handles are inherited. */
\r
8955 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
\r
8956 saAttr.bInheritHandle = TRUE;
\r
8957 saAttr.lpSecurityDescriptor = NULL;
\r
8960 * The steps for redirecting child's STDOUT:
\r
8961 * 1. Create anonymous pipe to be STDOUT for child.
\r
8962 * 2. Create a noninheritable duplicate of read handle,
\r
8963 * and close the inheritable read handle.
\r
8966 /* Create a pipe for the child's STDOUT. */
\r
8967 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
\r
8968 return GetLastError();
\r
8971 /* Duplicate the read handle to the pipe, so it is not inherited. */
\r
8972 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
\r
8973 GetCurrentProcess(), &hChildStdoutRdDup, 0,
\r
8974 FALSE, /* not inherited */
\r
8975 DUPLICATE_SAME_ACCESS);
\r
8977 return GetLastError();
\r
8979 CloseHandle(hChildStdoutRd);
\r
8982 * The steps for redirecting child's STDIN:
\r
8983 * 1. Create anonymous pipe to be STDIN for child.
\r
8984 * 2. Create a noninheritable duplicate of write handle,
\r
8985 * and close the inheritable write handle.
\r
8988 /* Create a pipe for the child's STDIN. */
\r
8989 if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
\r
8990 return GetLastError();
\r
8993 /* Duplicate the write handle to the pipe, so it is not inherited. */
\r
8994 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
\r
8995 GetCurrentProcess(), &hChildStdinWrDup, 0,
\r
8996 FALSE, /* not inherited */
\r
8997 DUPLICATE_SAME_ACCESS);
\r
8999 return GetLastError();
\r
9001 CloseHandle(hChildStdinWr);
\r
9003 /* Arrange to (1) look in dir for the child .exe file, and
\r
9004 * (2) have dir be the child's working directory. Interpret
\r
9005 * dir relative to the directory WinBoard loaded from. */
\r
9006 GetCurrentDirectory(MSG_SIZ, buf);
\r
9007 SetCurrentDirectory(installDir);
\r
9008 SetCurrentDirectory(dir);
\r
9010 /* Now create the child process. */
\r
9012 siStartInfo.cb = sizeof(STARTUPINFO);
\r
9013 siStartInfo.lpReserved = NULL;
\r
9014 siStartInfo.lpDesktop = NULL;
\r
9015 siStartInfo.lpTitle = NULL;
\r
9016 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
\r
9017 siStartInfo.cbReserved2 = 0;
\r
9018 siStartInfo.lpReserved2 = NULL;
\r
9019 siStartInfo.hStdInput = hChildStdinRd;
\r
9020 siStartInfo.hStdOutput = hChildStdoutWr;
\r
9021 siStartInfo.hStdError = hChildStdoutWr;
\r
9023 fSuccess = CreateProcess(NULL,
\r
9024 cmdLine, /* command line */
\r
9025 NULL, /* process security attributes */
\r
9026 NULL, /* primary thread security attrs */
\r
9027 TRUE, /* handles are inherited */
\r
9028 DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,
\r
9029 NULL, /* use parent's environment */
\r
9031 &siStartInfo, /* STARTUPINFO pointer */
\r
9032 &piProcInfo); /* receives PROCESS_INFORMATION */
\r
9034 err = GetLastError();
\r
9035 SetCurrentDirectory(buf); /* return to prev directory */
\r
9040 /* Close the handles we don't need in the parent */
\r
9041 CloseHandle(piProcInfo.hThread);
\r
9042 CloseHandle(hChildStdinRd);
\r
9043 CloseHandle(hChildStdoutWr);
\r
9045 /* Prepare return value */
\r
9046 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9047 cp->kind = CPReal;
\r
9048 cp->hProcess = piProcInfo.hProcess;
\r
9049 cp->pid = piProcInfo.dwProcessId;
\r
9050 cp->hFrom = hChildStdoutRdDup;
\r
9051 cp->hTo = hChildStdinWrDup;
\r
9053 *pr = (void *) cp;
\r
9055 /* Klaus Friedel says that this Sleep solves a problem under Windows
\r
9056 2000 where engines sometimes don't see the initial command(s)
\r
9057 from WinBoard and hang. I don't understand how that can happen,
\r
9058 but the Sleep is harmless, so I've put it in. Others have also
\r
9059 reported what may be the same problem, so hopefully this will fix
\r
9060 it for them too. */
\r
9068 DestroyChildProcess(ProcRef pr, int/*boolean*/ signal)
\r
9072 cp = (ChildProc *) pr;
\r
9073 if (cp == NULL) return;
\r
9075 switch (cp->kind) {
\r
9077 /* TerminateProcess is considered harmful, so... */
\r
9078 CloseHandle(cp->hTo); /* Closing this will give the child an EOF and hopefully kill it */
\r
9079 if (cp->hFrom) CloseHandle(cp->hFrom); /* if NULL, InputThread will close it */
\r
9080 /* The following doesn't work because the chess program
\r
9081 doesn't "have the same console" as WinBoard. Maybe
\r
9082 we could arrange for this even though neither WinBoard
\r
9083 nor the chess program uses a console for stdio? */
\r
9084 /*!!if (signal) GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, cp->pid);*/
\r
9086 /* [AS] Special termination modes for misbehaving programs... */
\r
9087 if( signal == 9 ) {
\r
9088 if ( appData.debugMode) {
\r
9089 fprintf( debugFP, "Terminating process %u\n", cp->pid );
\r
9092 TerminateProcess( cp->hProcess, 0 );
\r
9094 else if( signal == 10 ) {
\r
9095 DWORD dw = WaitForSingleObject( cp->hProcess, 3*1000 ); // Wait 3 seconds at most
\r
9097 if( dw != WAIT_OBJECT_0 ) {
\r
9098 if ( appData.debugMode) {
\r
9099 fprintf( debugFP, "Process %u still alive after timeout, killing...\n", cp->pid );
\r
9102 TerminateProcess( cp->hProcess, 0 );
\r
9106 CloseHandle(cp->hProcess);
\r
9110 if (cp->hFrom) CloseHandle(cp->hFrom);
\r
9114 closesocket(cp->sock);
\r
9119 if (signal) send(cp->sock2, "\017", 1, 0); /* 017 = 15 = SIGTERM */
\r
9120 closesocket(cp->sock);
\r
9121 closesocket(cp->sock2);
\r
9129 InterruptChildProcess(ProcRef pr)
\r
9133 cp = (ChildProc *) pr;
\r
9134 if (cp == NULL) return;
\r
9135 switch (cp->kind) {
\r
9137 /* The following doesn't work because the chess program
\r
9138 doesn't "have the same console" as WinBoard. Maybe
\r
9139 we could arrange for this even though neither WinBoard
\r
9140 nor the chess program uses a console for stdio */
\r
9141 /*!!GenerateConsoleCtrlEvent(CTRL_C_EVENT, cp->pid);*/
\r
9146 /* Can't interrupt */
\r
9150 send(cp->sock2, "\002", 1, 0); /* 2 = SIGINT */
\r
9157 OpenTelnet(char *host, char *port, ProcRef *pr)
\r
9159 char cmdLine[MSG_SIZ];
\r
9161 if (port[0] == NULLCHAR) {
\r
9162 sprintf(cmdLine, "%s %s", appData.telnetProgram, host);
\r
9164 sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
\r
9166 return StartChildProcess(cmdLine, "", pr);
\r
9170 /* Code to open TCP sockets */
\r
9173 OpenTCP(char *host, char *port, ProcRef *pr)
\r
9178 struct sockaddr_in sa, mysa;
\r
9179 struct hostent FAR *hp;
\r
9180 unsigned short uport;
\r
9181 WORD wVersionRequested;
\r
9184 /* Initialize socket DLL */
\r
9185 wVersionRequested = MAKEWORD(1, 1);
\r
9186 err = WSAStartup(wVersionRequested, &wsaData);
\r
9187 if (err != 0) return err;
\r
9190 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9191 err = WSAGetLastError();
\r
9196 /* Bind local address using (mostly) don't-care values.
\r
9198 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9199 mysa.sin_family = AF_INET;
\r
9200 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9201 uport = (unsigned short) 0;
\r
9202 mysa.sin_port = htons(uport);
\r
9203 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9204 == SOCKET_ERROR) {
\r
9205 err = WSAGetLastError();
\r
9210 /* Resolve remote host name */
\r
9211 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9212 if (!(hp = gethostbyname(host))) {
\r
9213 unsigned int b0, b1, b2, b3;
\r
9215 err = WSAGetLastError();
\r
9217 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9218 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9219 hp->h_addrtype = AF_INET;
\r
9221 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9222 hp->h_addr_list[0] = (char *) malloc(4);
\r
9223 hp->h_addr_list[0][0] = (char) b0;
\r
9224 hp->h_addr_list[0][1] = (char) b1;
\r
9225 hp->h_addr_list[0][2] = (char) b2;
\r
9226 hp->h_addr_list[0][3] = (char) b3;
\r
9232 sa.sin_family = hp->h_addrtype;
\r
9233 uport = (unsigned short) atoi(port);
\r
9234 sa.sin_port = htons(uport);
\r
9235 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9237 /* Make connection */
\r
9238 if (connect(s, (struct sockaddr *) &sa,
\r
9239 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9240 err = WSAGetLastError();
\r
9245 /* Prepare return value */
\r
9246 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9247 cp->kind = CPSock;
\r
9249 *pr = (ProcRef *) cp;
\r
9255 OpenCommPort(char *name, ProcRef *pr)
\r
9260 char fullname[MSG_SIZ];
\r
9262 if (*name != '\\')
\r
9263 sprintf(fullname, "\\\\.\\%s", name);
\r
9265 strcpy(fullname, name);
\r
9267 h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
\r
9268 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
\r
9269 if (h == (HANDLE) -1) {
\r
9270 return GetLastError();
\r
9274 if (!SetCommState(h, (LPDCB) &dcb)) return GetLastError();
\r
9276 /* Accumulate characters until a 100ms pause, then parse */
\r
9277 ct.ReadIntervalTimeout = 100;
\r
9278 ct.ReadTotalTimeoutMultiplier = 0;
\r
9279 ct.ReadTotalTimeoutConstant = 0;
\r
9280 ct.WriteTotalTimeoutMultiplier = 0;
\r
9281 ct.WriteTotalTimeoutConstant = 0;
\r
9282 if (!SetCommTimeouts(h, (LPCOMMTIMEOUTS) &ct)) return GetLastError();
\r
9284 /* Prepare return value */
\r
9285 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9286 cp->kind = CPComm;
\r
9289 *pr = (ProcRef *) cp;
\r
9295 OpenLoopback(ProcRef *pr)
\r
9297 DisplayFatalError("Not implemented", 0, 1);
\r
9303 OpenRcmd(char* host, char* user, char* cmd, ProcRef* pr)
\r
9308 struct sockaddr_in sa, mysa;
\r
9309 struct hostent FAR *hp;
\r
9310 unsigned short uport;
\r
9311 WORD wVersionRequested;
\r
9314 char stderrPortStr[MSG_SIZ];
\r
9316 /* Initialize socket DLL */
\r
9317 wVersionRequested = MAKEWORD(1, 1);
\r
9318 err = WSAStartup(wVersionRequested, &wsaData);
\r
9319 if (err != 0) return err;
\r
9321 /* Resolve remote host name */
\r
9322 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
\r
9323 if (!(hp = gethostbyname(host))) {
\r
9324 unsigned int b0, b1, b2, b3;
\r
9326 err = WSAGetLastError();
\r
9328 if (sscanf(host, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) == 4) {
\r
9329 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
\r
9330 hp->h_addrtype = AF_INET;
\r
9332 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
\r
9333 hp->h_addr_list[0] = (char *) malloc(4);
\r
9334 hp->h_addr_list[0][0] = (char) b0;
\r
9335 hp->h_addr_list[0][1] = (char) b1;
\r
9336 hp->h_addr_list[0][2] = (char) b2;
\r
9337 hp->h_addr_list[0][3] = (char) b3;
\r
9343 sa.sin_family = hp->h_addrtype;
\r
9344 uport = (unsigned short) 514;
\r
9345 sa.sin_port = htons(uport);
\r
9346 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
\r
9348 /* Bind local socket to unused "privileged" port address
\r
9350 s = INVALID_SOCKET;
\r
9351 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9352 mysa.sin_family = AF_INET;
\r
9353 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9354 for (fromPort = 1023;; fromPort--) {
\r
9355 if (fromPort < 0) {
\r
9357 return WSAEADDRINUSE;
\r
9359 if (s == INVALID_SOCKET) {
\r
9360 if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9361 err = WSAGetLastError();
\r
9366 uport = (unsigned short) fromPort;
\r
9367 mysa.sin_port = htons(uport);
\r
9368 if (bind(s, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9369 == SOCKET_ERROR) {
\r
9370 err = WSAGetLastError();
\r
9371 if (err == WSAEADDRINUSE) continue;
\r
9375 if (connect(s, (struct sockaddr *) &sa,
\r
9376 sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
\r
9377 err = WSAGetLastError();
\r
9378 if (err == WSAEADDRINUSE) {
\r
9389 /* Bind stderr local socket to unused "privileged" port address
\r
9391 s2 = INVALID_SOCKET;
\r
9392 memset((char *) &mysa, 0, sizeof(struct sockaddr_in));
\r
9393 mysa.sin_family = AF_INET;
\r
9394 mysa.sin_addr.s_addr = INADDR_ANY;
\r
9395 for (fromPort = 1023;; fromPort--) {
\r
9396 if (fromPort == prevStderrPort) continue; // don't reuse port
\r
9397 if (fromPort < 0) {
\r
9398 (void) closesocket(s);
\r
9400 return WSAEADDRINUSE;
\r
9402 if (s2 == INVALID_SOCKET) {
\r
9403 if ((s2 = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
\r
9404 err = WSAGetLastError();
\r
9410 uport = (unsigned short) fromPort;
\r
9411 mysa.sin_port = htons(uport);
\r
9412 if (bind(s2, (struct sockaddr *) &mysa, sizeof(struct sockaddr_in))
\r
9413 == SOCKET_ERROR) {
\r
9414 err = WSAGetLastError();
\r
9415 if (err == WSAEADDRINUSE) continue;
\r
9416 (void) closesocket(s);
\r
9420 if (listen(s2, 1) == SOCKET_ERROR) {
\r
9421 err = WSAGetLastError();
\r
9422 if (err == WSAEADDRINUSE) {
\r
9424 s2 = INVALID_SOCKET;
\r
9427 (void) closesocket(s);
\r
9428 (void) closesocket(s2);
\r
9434 prevStderrPort = fromPort; // remember port used
\r
9435 sprintf(stderrPortStr, "%d", fromPort);
\r
9437 if (send(s, stderrPortStr, strlen(stderrPortStr) + 1, 0) == SOCKET_ERROR) {
\r
9438 err = WSAGetLastError();
\r
9439 (void) closesocket(s);
\r
9440 (void) closesocket(s2);
\r
9445 if (send(s, UserName(), strlen(UserName()) + 1, 0) == SOCKET_ERROR) {
\r
9446 err = WSAGetLastError();
\r
9447 (void) closesocket(s);
\r
9448 (void) closesocket(s2);
\r
9452 if (*user == NULLCHAR) user = UserName();
\r
9453 if (send(s, user, strlen(user) + 1, 0) == SOCKET_ERROR) {
\r
9454 err = WSAGetLastError();
\r
9455 (void) closesocket(s);
\r
9456 (void) closesocket(s2);
\r
9460 if (send(s, cmd, strlen(cmd) + 1, 0) == SOCKET_ERROR) {
\r
9461 err = WSAGetLastError();
\r
9462 (void) closesocket(s);
\r
9463 (void) closesocket(s2);
\r
9468 if ((s3 = accept(s2, NULL, NULL)) == INVALID_SOCKET) {
\r
9469 err = WSAGetLastError();
\r
9470 (void) closesocket(s);
\r
9471 (void) closesocket(s2);
\r
9475 (void) closesocket(s2); /* Stop listening */
\r
9477 /* Prepare return value */
\r
9478 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
\r
9479 cp->kind = CPRcmd;
\r
9482 *pr = (ProcRef *) cp;
\r
9489 AddInputSource(ProcRef pr, int lineByLine,
\r
9490 InputCallback func, VOIDSTAR closure)
\r
9492 InputSource *is, *is2 = NULL;
\r
9493 ChildProc *cp = (ChildProc *) pr;
\r
9495 is = (InputSource *) calloc(1, sizeof(InputSource));
\r
9496 is->lineByLine = lineByLine;
\r
9498 is->closure = closure;
\r
9499 is->second = NULL;
\r
9500 is->next = is->buf;
\r
9501 if (pr == NoProc) {
\r
9502 is->kind = CPReal;
\r
9503 consoleInputSource = is;
\r
9505 is->kind = cp->kind;
\r
9507 [AS] Try to avoid a race condition if the thread is given control too early:
\r
9508 we create all threads suspended so that the is->hThread variable can be
\r
9509 safely assigned, then let the threads start with ResumeThread.
\r
9511 switch (cp->kind) {
\r
9513 is->hFile = cp->hFrom;
\r
9514 cp->hFrom = NULL; /* now owned by InputThread */
\r
9516 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) NonOvlInputThread,
\r
9517 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9521 is->hFile = cp->hFrom;
\r
9522 cp->hFrom = NULL; /* now owned by InputThread */
\r
9524 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) InputThread,
\r
9525 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9529 is->sock = cp->sock;
\r
9531 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9532 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9536 is2 = (InputSource *) calloc(1, sizeof(InputSource));
\r
9538 is->sock = cp->sock;
\r
9540 is2->sock = cp->sock2;
\r
9541 is2->second = is2;
\r
9543 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9544 (LPVOID) is, CREATE_SUSPENDED, &is->id);
\r
9546 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SocketInputThread,
\r
9547 (LPVOID) is2, CREATE_SUSPENDED, &is2->id);
\r
9551 if( is->hThread != NULL ) {
\r
9552 ResumeThread( is->hThread );
\r
9555 if( is2 != NULL && is2->hThread != NULL ) {
\r
9556 ResumeThread( is2->hThread );
\r
9560 return (InputSourceRef) is;
\r
9564 RemoveInputSource(InputSourceRef isr)
\r
9568 is = (InputSource *) isr;
\r
9569 is->hThread = NULL; /* tell thread to stop */
\r
9570 CloseHandle(is->hThread);
\r
9571 if (is->second != NULL) {
\r
9572 is->second->hThread = NULL;
\r
9573 CloseHandle(is->second->hThread);
\r
9579 OutputToProcess(ProcRef pr, char *message, int count, int *outError)
\r
9582 int outCount = SOCKET_ERROR;
\r
9583 ChildProc *cp = (ChildProc *) pr;
\r
9584 static OVERLAPPED ovl;
\r
9586 if (pr == NoProc) {
\r
9587 ConsoleOutput(message, count, FALSE);
\r
9591 if (ovl.hEvent == NULL) {
\r
9592 ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
9594 ovl.Internal = ovl.InternalHigh = ovl.Offset = ovl.OffsetHigh = 0;
\r
9596 switch (cp->kind) {
\r
9599 outCount = send(cp->sock, message, count, 0);
\r
9600 if (outCount == SOCKET_ERROR) {
\r
9601 *outError = WSAGetLastError();
\r
9603 *outError = NO_ERROR;
\r
9608 if (WriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9609 &dOutCount, NULL)) {
\r
9610 *outError = NO_ERROR;
\r
9611 outCount = (int) dOutCount;
\r
9613 *outError = GetLastError();
\r
9618 *outError = DoWriteFile(((ChildProc *)pr)->hTo, message, count,
\r
9619 &dOutCount, &ovl);
\r
9620 if (*outError == NO_ERROR) {
\r
9621 outCount = (int) dOutCount;
\r
9629 OutputToProcessDelayed(ProcRef pr, char *message, int count, int *outError,
\r
9632 /* Ignore delay, not implemented for WinBoard */
\r
9633 return OutputToProcess(pr, message, count, outError);
\r
9638 CmailSigHandlerCallBack(InputSourceRef isr, VOIDSTAR closure,
\r
9639 char *buf, int count, int error)
\r
9641 DisplayFatalError("Not implemented", 0, 1);
\r
9644 /* see wgamelist.c for Game List functions */
\r
9645 /* see wedittags.c for Edit Tags functions */
\r
9652 char buf[MSG_SIZ];
\r
9655 if (SearchPath(installDir, appData.icsLogon, NULL, MSG_SIZ, buf, &dummy)) {
\r
9656 f = fopen(buf, "r");
\r
9658 ProcessICSInitScript(f);
\r
9666 StartAnalysisClock()
\r
9668 if (analysisTimerEvent) return;
\r
9669 analysisTimerEvent = SetTimer(hwndMain, (UINT) ANALYSIS_TIMER_ID,
\r
9670 (UINT) 2000, NULL);
\r
9674 AnalysisDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
\r
9676 static HANDLE hwndText;
\r
9678 static int sizeX, sizeY;
\r
9679 int newSizeX, newSizeY, flags;
\r
9682 switch (message) {
\r
9683 case WM_INITDIALOG: /* message: initialize dialog box */
\r
9684 /* Initialize the dialog items */
\r
9685 hwndText = GetDlgItem(hDlg, OPT_AnalysisText);
\r
9686 SetWindowText(hDlg, analysisTitle);
\r
9687 SetDlgItemText(hDlg, OPT_AnalysisText, analysisText);
\r
9688 /* Size and position the dialog */
\r
9689 if (!analysisDialog) {
\r
9690 analysisDialog = hDlg;
\r
9691 flags = SWP_NOZORDER;
\r
9692 GetClientRect(hDlg, &rect);
\r
9693 sizeX = rect.right;
\r
9694 sizeY = rect.bottom;
\r
9695 if (analysisX != CW_USEDEFAULT && analysisY != CW_USEDEFAULT &&
\r
9696 analysisW != CW_USEDEFAULT && analysisH != CW_USEDEFAULT) {
\r
9697 WINDOWPLACEMENT wp;
\r
9698 EnsureOnScreen(&analysisX, &analysisY);
\r
9699 wp.length = sizeof(WINDOWPLACEMENT);
\r
9701 wp.showCmd = SW_SHOW;
\r
9702 wp.ptMaxPosition.x = wp.ptMaxPosition.y = 0;
\r
9703 wp.rcNormalPosition.left = analysisX;
\r
9704 wp.rcNormalPosition.right = analysisX + analysisW;
\r
9705 wp.rcNormalPosition.top = analysisY;
\r
9706 wp.rcNormalPosition.bottom = analysisY + analysisH;
\r
9707 SetWindowPlacement(hDlg, &wp);
\r
9709 GetClientRect(hDlg, &rect);
\r
9710 newSizeX = rect.right;
\r
9711 newSizeY = rect.bottom;
\r
9712 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY,
\r
9713 newSizeX, newSizeY);
\r
9720 case WM_COMMAND: /* message: received a command */
\r
9721 switch (LOWORD(wParam)) {
\r
9731 newSizeX = LOWORD(lParam);
\r
9732 newSizeY = HIWORD(lParam);
\r
9733 ResizeEditPlusButtons(hDlg, hwndText, sizeX, sizeY, newSizeX, newSizeY);
\r
9738 case WM_GETMINMAXINFO:
\r
9739 /* Prevent resizing window too small */
\r
9740 mmi = (MINMAXINFO *) lParam;
\r
9741 mmi->ptMinTrackSize.x = 100;
\r
9742 mmi->ptMinTrackSize.y = 100;
\r
9749 AnalysisPopUp(char* title, char* str)
\r
9755 EngineOutputPopUp();
\r
9758 if (str == NULL) str = "";
\r
9759 p = (char *) malloc(2 * strlen(str) + 2);
\r
9762 if (*str == '\n') *q++ = '\r';
\r
9766 if (analysisText != NULL) free(analysisText);
\r
9769 if (analysisDialog) {
\r
9770 SetWindowText(analysisDialog, title);
\r
9771 SetDlgItemText(analysisDialog, OPT_AnalysisText, analysisText);
\r
9772 ShowWindow(analysisDialog, SW_SHOW);
\r
9774 analysisTitle = title;
\r
9775 lpProc = MakeProcInstance((FARPROC)AnalysisDialog, hInst);
\r
9776 CreateDialog(hInst, MAKEINTRESOURCE(DLG_Analysis),
\r
9777 hwndMain, (DLGPROC)lpProc);
\r
9778 FreeProcInstance(lpProc);
\r
9780 analysisDialogUp = TRUE;
\r
9786 if (analysisDialog) {
\r
9787 ShowWindow(analysisDialog, SW_HIDE);
\r
9789 analysisDialogUp = FALSE;
\r
9794 SetHighlights(int fromX, int fromY, int toX, int toY)
\r
9796 highlightInfo.sq[0].x = fromX;
\r
9797 highlightInfo.sq[0].y = fromY;
\r
9798 highlightInfo.sq[1].x = toX;
\r
9799 highlightInfo.sq[1].y = toY;
\r
9805 highlightInfo.sq[0].x = highlightInfo.sq[0].y =
\r
9806 highlightInfo.sq[1].x = highlightInfo.sq[1].y = -1;
\r
9810 SetPremoveHighlights(int fromX, int fromY, int toX, int toY)
\r
9812 premoveHighlightInfo.sq[0].x = fromX;
\r
9813 premoveHighlightInfo.sq[0].y = fromY;
\r
9814 premoveHighlightInfo.sq[1].x = toX;
\r
9815 premoveHighlightInfo.sq[1].y = toY;
\r
9819 ClearPremoveHighlights()
\r
9821 premoveHighlightInfo.sq[0].x = premoveHighlightInfo.sq[0].y =
\r
9822 premoveHighlightInfo.sq[1].x = premoveHighlightInfo.sq[1].y = -1;
\r
9826 ShutDownFrontEnd()
\r
9828 if (saveSettingsOnExit) SaveSettings(settingsFileName);
\r
9829 DeleteClipboardTempFiles();
\r
9835 if (IsIconic(hwndMain))
\r
9836 ShowWindow(hwndMain, SW_RESTORE);
\r
9838 SetActiveWindow(hwndMain);
\r
9842 * Prototypes for animation support routines
\r
9844 static void ScreenSquare(int column, int row, POINT * pt);
\r
9845 static void Tween( POINT * start, POINT * mid, POINT * finish, int factor,
\r
9846 POINT frames[], int * nFrames);
\r
9852 AnimateMove(board, fromX, fromY, toX, toY)
\r
9859 ChessSquare piece;
\r
9860 POINT start, finish, mid;
\r
9861 POINT frames[kFactor * 2 + 1];
\r
9864 if (!appData.animate) return;
\r
9865 if (doingSizing) return;
\r
9866 if (fromY < 0 || fromX < 0) return;
\r
9867 piece = board[fromY][fromX];
\r
9868 if (piece >= EmptySquare) return;
\r
9870 ScreenSquare(fromX, fromY, &start);
\r
9871 ScreenSquare(toX, toY, &finish);
\r
9873 /* All pieces except knights move in straight line */
\r
9874 if (piece != WhiteKnight && piece != BlackKnight) {
\r
9875 mid.x = start.x + (finish.x - start.x) / 2;
\r
9876 mid.y = start.y + (finish.y - start.y) / 2;
\r
9878 /* Knight: make diagonal movement then straight */
\r
9879 if (abs(toY - fromY) < abs(toX - fromX)) {
\r
9880 mid.x = start.x + (finish.x - start.x) / 2;
\r
9884 mid.y = start.y + (finish.y - start.y) / 2;
\r
9888 /* Don't use as many frames for very short moves */
\r
9889 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
\r
9890 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
\r
9892 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
\r
9894 animInfo.from.x = fromX;
\r
9895 animInfo.from.y = fromY;
\r
9896 animInfo.to.x = toX;
\r
9897 animInfo.to.y = toY;
\r
9898 animInfo.lastpos = start;
\r
9899 animInfo.piece = piece;
\r
9900 for (n = 0; n < nFrames; n++) {
\r
9901 animInfo.pos = frames[n];
\r
9902 DrawPosition(FALSE, NULL);
\r
9903 animInfo.lastpos = animInfo.pos;
\r
9904 Sleep(appData.animSpeed);
\r
9906 animInfo.pos = finish;
\r
9907 DrawPosition(FALSE, NULL);
\r
9908 animInfo.piece = EmptySquare;
\r
9911 /* Convert board position to corner of screen rect and color */
\r
9914 ScreenSquare(column, row, pt)
\r
9915 int column; int row; POINT * pt;
\r
9918 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
\r
9919 pt->y = lineGap + row * (squareSize + lineGap);
\r
9921 pt->x = lineGap + column * (squareSize + lineGap);
\r
9922 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
\r
9926 /* Generate a series of frame coords from start->mid->finish.
\r
9927 The movement rate doubles until the half way point is
\r
9928 reached, then halves back down to the final destination,
\r
9929 which gives a nice slow in/out effect. The algorithmn
\r
9930 may seem to generate too many intermediates for short
\r
9931 moves, but remember that the purpose is to attract the
\r
9932 viewers attention to the piece about to be moved and
\r
9933 then to where it ends up. Too few frames would be less
\r
9937 Tween(start, mid, finish, factor, frames, nFrames)
\r
9938 POINT * start; POINT * mid;
\r
9939 POINT * finish; int factor;
\r
9940 POINT frames[]; int * nFrames;
\r
9942 int n, fraction = 1, count = 0;
\r
9944 /* Slow in, stepping 1/16th, then 1/8th, ... */
\r
9945 for (n = 0; n < factor; n++)
\r
9947 for (n = 0; n < factor; n++) {
\r
9948 frames[count].x = start->x + (mid->x - start->x) / fraction;
\r
9949 frames[count].y = start->y + (mid->y - start->y) / fraction;
\r
9951 fraction = fraction / 2;
\r
9955 frames[count] = *mid;
\r
9958 /* Slow out, stepping 1/2, then 1/4, ... */
\r
9960 for (n = 0; n < factor; n++) {
\r
9961 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
\r
9962 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
\r
9964 fraction = fraction * 2;
\r
9970 HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current )
\r
9975 sprintf( buf, "HistorySet: first=%d, last=%d, current=%d (%s)\n",
\r
9976 first, last, current, current >= 0 ? movelist[current] : "n/a" );
\r
9978 OutputDebugString( buf );
\r
9981 MoveHistorySet( movelist, first, last, current, pvInfoList );
\r
9983 EvalGraphSet( first, last, current, pvInfoList );
\r
9986 void SetProgramStats( FrontEndProgramStats * stats )
\r
9991 sprintf( buf, "SetStats for %d: depth=%d, nodes=%lu, score=%5.2f, time=%5.2f, pv=%s\n",
\r
9992 stats->which, stats->depth, stats->nodes, stats->score / 100.0, stats->time / 100.0, stats->pv == 0 ? "n/a" : stats->pv );
\r
9994 OutputDebugString( buf );
\r
9997 EngineOutputUpdate( stats );
\r